diff --git a/libc3/compare.c b/libc3/compare.c
index c7d62f2..9761e10 100644
--- a/libc3/compare.c
+++ b/libc3/compare.c
@@ -14,6 +14,7 @@
#include <err.h>
#include <string.h>
#include "compare.h"
+#include "data.h"
#include "integer.h"
#include "list.h"
#include "tag.h"
@@ -388,6 +389,60 @@ s8 compare_str (const s_str *a, const s_str *b)
return 0;
}
+s8 compare_struct (const s_struct *a, const s_struct *b)
+{
+ uw i;
+ int r;
+ const s_sym *type;
+ assert(a);
+ assert(b);
+ if (a == b)
+ return 0;
+ r = compare_struct_type(a->type, b->type);
+ if (r)
+ return r;
+ if (! a->data && ! b->data) {
+ if (a->tag == b->tag)
+ return 0;
+ i = 0;
+ while (i < a->type->map.count) {
+ r = compare_tag(a->tag + i, b->tag + i);
+ if (r)
+ return r;
+ }
+ }
+ if (a->data == b->data)
+ return 0;
+ if (! a->data)
+ return -1;
+ if (! b->data)
+ return 1;
+ while (i < a->type->map.count) {
+ tag_type(a->type->map.value + i, &type);
+ r = data_compare(type, (s8 *) a->data + a->type->offset[i],
+ (s8 *) b->data + b->type->offset[i]);
+ if (r)
+ return r;
+ }
+ return 0;
+}
+
+s8 compare_struct_type (const s_struct_type *a, const s_struct_type *b)
+{
+ int r;
+ assert(a);
+ assert(b);
+ if (a == b)
+ return 0;
+ r = compare_sym(a->module, b->module);
+ if (r)
+ return r;
+ r = compare_map(&a->map, &b->map);
+ if (r)
+ return r;
+ return 0;
+}
+
s8 compare_sym (const s_sym *a, const s_sym *b)
{
if (a == b)
diff --git a/libc3/compare.h b/libc3/compare.h
index bb6db50..8c91c6e 100644
--- a/libc3/compare.h
+++ b/libc3/compare.h
@@ -18,6 +18,7 @@
#define COMPARE_PROTOTYPE(type) \
s8 compare_##type (type a, type b)
+s8 compare_array (const s_array *a, const s_array *b);
s8 compare_bool (bool a, bool b);
s8 compare_call (const s_call *a, const s_call *b);
s8 compare_cfn (const s_cfn *a, const s_cfn *b);
@@ -38,11 +39,13 @@ s8 compare_integer_u64 (const s_integer *a, u64 b);
s8 compare_list (const s_list *a, const s_list *b);
s8 compare_map (const s_map *a, const s_map *b);
s8 compare_ptag (const p_tag a, const p_tag b);
+s8 compare_ptr (const void *a, const void *b);
s8 compare_quote (const s_quote *a, const s_quote *b);
COMPARE_PROTOTYPE(s8);
COMPARE_PROTOTYPE(s16);
COMPARE_PROTOTYPE(s32);
COMPARE_PROTOTYPE(s64);
+COMPARE_PROTOTYPE(sw);
s8 compare_str (const s_str *a, const s_str *b);
s8 compare_struct (const s_struct *a, const s_struct *b);
s8 compare_struct_type (const s_struct_type *a, const s_struct_type *b);
@@ -53,5 +56,6 @@ COMPARE_PROTOTYPE(u8);
COMPARE_PROTOTYPE(u16);
COMPARE_PROTOTYPE(u32);
COMPARE_PROTOTYPE(u64);
+COMPARE_PROTOTYPE(uw);
#endif /* LIBC3_COMPARE_H */
diff --git a/libc3/data.c b/libc3/data.c
index 136cb47..66b3f51 100644
--- a/libc3/data.c
+++ b/libc3/data.c
@@ -313,6 +313,93 @@ bool data_clean (const s_sym *type, void *data)
return false;
}
+bool data_compare (const s_sym *type, const void *a, const void *b)
+{
+ const s_struct_type *st;
+ if (type == sym_1("Array"))
+ return compare_array(a, b);
+ if (type == sym_1("Bool"))
+ return compare_bool(*(bool *) a, *(bool *) b);
+ if (type == sym_1("Call"))
+ return compare_call(a, b);
+ if (type == sym_1("Cfn"))
+ return compare_cfn(a, b);
+ if (type == sym_1("Character"))
+ return compare_character(*(character *) a, *(character *) b);
+ if (type == sym_1("F32"))
+ return compare_f32(*(f64 *) a, *(f64 *) b);
+ if (type == sym_1("F64"))
+ return compare_f64(*(f64 *) a, *(f64 *) b);
+ if (type == sym_1("Fact"))
+ return compare_fact(a, b);
+ if (type == sym_1("Fn"))
+ return compare_fn(a, b);
+ if (type == sym_1("Ident"))
+ return compare_ident(a, b);
+ if (type == sym_1("Integer"))
+ return compare_integer(a, b);
+ if (type == sym_1("List"))
+ return compare_list(a, b);
+ if (type == sym_1("Ptag"))
+ return compare_ptag(a, b);
+ if (type == sym_1("Ptr"))
+ return compare_ptr(a, b);
+ if (type == sym_1("PtrFree"))
+ return compare_ptr(a, b);
+ if (type == sym_1("Quote"))
+ return compare_quote(a, b);
+ if (type == sym_1("S8"))
+ return compare_s8(*(s8 *) a, *(s8 *) b);
+ if (type == sym_1("S16"))
+ return compare_s16(*(s16 *) a, *(s16 *) b);
+ if (type == sym_1("S32"))
+ return compare_s32(*(s32 *) a, *(s32 *) b);
+ if (type == sym_1("S64"))
+ return compare_s64(*(s64 *) a, *(s64 *) b);
+ if (type == sym_1("Str"))
+ return compare_str(a, b);
+ if (type == sym_1("Struct"))
+ return compare_struct(a, b);
+ if (type == sym_1("Sw"))
+ return compare_sw(*(sw *) a, *(sw *) b);
+ if (type == sym_1("Sym"))
+ return compare_sym(a, b);
+ if (type == sym_1("Tuple"))
+ return compare_tuple(a, b);
+ if (type == sym_1("U8"))
+ return compare_u8(*(u8 *) a, *(u8 *) b);
+ if (type == sym_1("U16"))
+ return compare_u16(*(u16 *) a, *(u16 *) b);
+ if (type == sym_1("U32"))
+ return compare_u32(*(u32 *) a, *(u32 *) b);
+ if (type == sym_1("U64"))
+ return compare_u64(*(u64 *) a, *(u64 *) b);
+ if (type == sym_1("Uw"))
+ return compare_uw(*(uw *) a, *(uw *) b);
+ if (type == sym_1("Var"))
+ return compare_ptr(a, b);
+ if (type == sym_1("Void"))
+ return 0;
+ /*
+ if (sym_is_array_type(type)) {
+ */
+ st = struct_type_find(type);
+ if (st) {
+ s_struct sa = {0};
+ s_struct sb = {0};
+ sa.type = st;
+ sa.data = (void *) a;
+ sb.type = st;
+ sb.data = (void *) a;
+ return compare_struct(&sa, &sb);
+ }
+ err_write_1("data_compare: unknown type: ");
+ err_inspect_sym(&type);
+ err_write_1("\n");
+ assert(! "data_compare: unknown type");
+ return false;
+}
+
bool data_hash_update (const s_sym *type, t_hash *hash, const void *data)
{
const s_struct_type *st;
diff --git a/libc3/data.h b/libc3/data.h
index ed0d0c5..8843394 100644
--- a/libc3/data.h
+++ b/libc3/data.h
@@ -24,6 +24,7 @@
sw data_buf_inspect (const s_sym *type, s_buf *buf, const void *v);
sw data_buf_inspect_size (const s_sym *type, const void *v);
bool data_clean (const s_sym *type, void *v);
+bool data_compare (const s_sym *type, const void *a, const void *b);
bool data_hash_update (const s_sym *type, t_hash *hash,
const void *s);
void * data_init_cast (const s_sym *type, void *v, const s_tag *src);
diff --git a/libc3/env.c b/libc3/env.c
index 6266f76..4dd22fe 100644
--- a/libc3/env.c
+++ b/libc3/env.c
@@ -689,17 +689,27 @@ bool env_eval_struct (s_env *env, const s_struct *s, s_tag *dest)
return false;
i = 0;
while (i < t->type->map.count) {
- if (! tag_type(t->type->map.value + i, &type) ||
- ! env_eval_tag(env, s->tag + i, &tag))
+ if (! tag_type(t->type->map.value + i, &type))
goto ko;
- if (! data_init_cast(type, (s8 *) t->data + t->type->offset[i],
- &tag)) {
- warnx("env_eval_struct:"
- " invalid type %s for key %s, expected %s.",
- tag_type_to_string(tag.type),
- t->type->map.key[i].data.sym->str.ptr.ps8,
- tag_type_to_string(t->type->map.value[i].type));
- goto ko_tag;
+ if (s->tag) {
+ if (! env_eval_tag(env, s->tag + i, &tag))
+ goto ko;
+ if (! data_init_cast(type, (s8 *) t->data + t->type->offset[i],
+ &tag)) {
+ warnx("env_eval_struct:"
+ " invalid type %s for key %s, expected %s.",
+ tag_type_to_string(tag.type),
+ t->type->map.key[i].data.sym->str.ptr.ps8,
+ tag_type_to_string(t->type->map.value[i].type));
+ goto ko_tag;
+ }
+ tag_clean(&tag);
+ }
+ else {
+ const void *value;
+ if (! tag_to_const_pointer(t->type->map.value + i, type, &value))
+ goto ko;
+ data_init_copy(type, (s8 *) t->data + t->type->offset[i], value);
}
i++;
}
diff --git a/libc3/types.h b/libc3/types.h
index 3bbd936..45bc68c 100644
--- a/libc3/types.h
+++ b/libc3/types.h
@@ -245,11 +245,11 @@ struct quote {
s_tag *tag;
};
-struct struct_type {
- const s_sym *module;
- s_map map;
- uw *offset;
- uw size;
+struct struct_ {
+ void *data;
+ s_tag *tag;
+ bool free_data;
+ const s_struct_type *type;
};
struct sym_list {
@@ -316,11 +316,11 @@ struct str {
u_ptr ptr; /**< Pointer to memory. */
};
-struct struct_ {
- void *data;
- s_tag *tag;
- bool free_data;
- const s_struct_type *type;
+struct struct_type {
+ const s_sym *module;
+ s_map map;
+ uw *offset;
+ uw size;
};
/* 3 */
diff --git a/test/ic3/struct.out.expected b/test/ic3/struct.out.expected
index fd4317b..f907a63 100644
--- a/test/ic3/struct.out.expected
+++ b/test/ic3/struct.out.expected
@@ -2,9 +2,5 @@
0.0
%GL.Point3D{x: 0.0, y: 0.0, z: 0.0}
%GL.Point3D{x: 0.0, y: 0.0, z: 0.0}
-[position: %GL.Point3D{x: 0.0, y: 0.0, z: 0.0},
- normal: %GL.Point3D{x: 0.0, y: 0.0, z: 0.0},
- tex_coord: %GL.Point2D{x: 0.0, y: 0.0}]
-[position: %GL.Point3D{x: 0.0, y: 0.0, z: 0.0},
- normal: %GL.Point3D{x: 0.0, y: 0.0, z: 0.0},
- tex_coord: %GL.Point2D{x: 0.0, y: 0.0}]
+[position: %GL.Point3D{x: 0.0, y: 0.0, z: 0.0}, normal: %GL.Point3D{x: 0.0, y: 0.0, z: 0.0}, tex_coord: %GL.Point2D{x: 0.0, y: 0.0}]
+[position: %GL.Point3D{x: 0.0, y: 0.0, z: 0.0}, normal: %GL.Point3D{x: 0.0, y: 0.0, z: 0.0}, tex_coord: %GL.Point2D{x: 0.0, y: 0.0}]