diff --git a/.ic3_history b/.ic3_history
index adeaf15..df2e675 100644
--- a/.ic3_history
+++ b/.ic3_history
@@ -36,3 +36,4 @@ Map.map
Map.to_list
%{name: "Quentin", id: 1000}
make
+%GL.Sphere{}
diff --git a/ic3/.ic3_history b/ic3/.ic3_history
index 38a7a99..ff867c0 100644
--- a/ic3/.ic3_history
+++ b/ic3/.ic3_history
@@ -1,3 +1,7 @@
a = (U8) { 1, 2, 3 }
1
a = (U8) { 1, 2, 3 }
+quote %GL.Sphere{}
+quote %GL.Sphere{segments_u: 100}
+%GL.Sphere{segments_u: 100}
+%GL.Sphere{segments_u: 100 + 1}
diff --git a/libc3/buf_inspect.c b/libc3/buf_inspect.c
index 4395d65..befdb79 100644
--- a/libc3/buf_inspect.c
+++ b/libc3/buf_inspect.c
@@ -1707,7 +1707,15 @@ sw buf_inspect_struct (s_buf *buf, const s_struct *s)
result += r;
while (i < s->type.map.count) {
k = s->type.map.key + i;
- assert(k->type == TAG_SYM);
+ if (k->type != TAG_SYM) {
+ err_write_1("buf_inspect_struct: key type is not a symbol: ");
+ err_inspect_tag(k);
+ err_write_1(" (");
+ err_write_1(tag_type_to_string(k->type));
+ err_puts(")");
+ assert(k->type == TAG_SYM);
+ return -1;
+ }
if (sym_has_reserved_characters(k->data.sym)) {
if ((r = buf_write_str(buf, &k->data.sym->str)) < 0)
return r;
@@ -1719,10 +1727,22 @@ sw buf_inspect_struct (s_buf *buf, const s_struct *s)
if ((r = buf_write_1(buf, ": ")) < 0)
return r;
result += r;
- buf_inspect = tag_type_to_buf_inspect(s->type.map.value[i].type);
- if ((r = buf_inspect(buf, (s8 *) s->data + s->type.offset[i])) < 0)
- return r;
- result += r;
+ if (s->data) {
+ buf_inspect = tag_type_to_buf_inspect(s->type.map.value[i].type);
+ if ((r = buf_inspect(buf, (s8 *) s->data + s->type.offset[i])) < 0)
+ return r;
+ result += r;
+ }
+ else if (s->tag) {
+ if ((r = buf_inspect_tag(buf, s->tag + i)) < 0)
+ return r;
+ result += r;
+ }
+ else {
+ if ((r = buf_inspect_tag(buf, s->type.map.value + i)) < 0)
+ return r;
+ result += r;
+ }
i++;
if (i < s->type.map.count) {
if ((r = buf_write_1(buf, ", ")) < 0)
diff --git a/libc3/buf_parse.c b/libc3/buf_parse.c
index c7779a9..a5d7d9c 100644
--- a/libc3/buf_parse.c
+++ b/libc3/buf_parse.c
@@ -2493,33 +2493,35 @@ sw buf_parse_struct (s_buf *buf, s_struct *dest)
if ((r = buf_read_1(buf, "}")) < 0)
goto restore;
result += r;
- while (r == 0) {
- *keys_end = list_new(NULL);
- if ((r = buf_parse_map_key(buf, &(*keys_end)->tag)) <= 0)
- goto restore;
- result += r;
- keys_end = &(*keys_end)->next.data.list;
- if ((r = buf_parse_comments(buf)) < 0)
- goto restore;
- result += r;
- if ((r = buf_ignore_spaces(buf)) < 0)
- goto restore;
- result += r;
- *values_end = list_new(NULL);
- if ((r = buf_parse_tag(buf, &(*values_end)->tag)) <= 0)
- goto restore;
- result += r;
- values_end = &(*values_end)->next.data.list;
- if ((r = buf_parse_comments(buf)) < 0)
- goto restore;
- result += r;
- if ((r = buf_ignore_spaces(buf)) < 0)
- goto restore;
- result += r;
- if ((r = buf_read_1(buf, "}")) < 0)
- goto restore;
- result += r;
- if (r == 0) {
+ if (r == 0) {
+ while (1) {
+ *keys_end = list_new(NULL);
+ if ((r = buf_parse_map_key(buf, &(*keys_end)->tag)) <= 0)
+ goto restore;
+ result += r;
+ keys_end = &(*keys_end)->next.data.list;
+ if ((r = buf_parse_comments(buf)) < 0)
+ goto restore;
+ result += r;
+ if ((r = buf_ignore_spaces(buf)) < 0)
+ goto restore;
+ result += r;
+ *values_end = list_new(NULL);
+ if ((r = buf_parse_tag(buf, &(*values_end)->tag)) <= 0)
+ goto restore;
+ result += r;
+ values_end = &(*values_end)->next.data.list;
+ if ((r = buf_parse_comments(buf)) < 0)
+ goto restore;
+ result += r;
+ if ((r = buf_ignore_spaces(buf)) < 0)
+ goto restore;
+ result += r;
+ if ((r = buf_read_1(buf, "}")) < 0)
+ goto restore;
+ result += r;
+ if (r > 0)
+ break;
if ((r = buf_read_1(buf, ",")) <= 0)
goto restore;
result += r;
@@ -2891,7 +2893,7 @@ sw buf_parse_tag_primary (s_buf *buf, s_tag *dest)
(r = buf_parse_tag_quote(buf, dest)) != 0 ||
(r = buf_parse_tag_cfn(buf, dest)) != 0 ||
(r = buf_parse_tag_fn(buf, dest)) != 0 ||
- //(r = buf_parse_tag_module_name(buf, dest)) != 0 ||
+ (r = buf_parse_tag_struct(buf, dest)) != 0 ||
(r = buf_parse_tag_ident(buf, dest)) != 0 ||
(r = buf_parse_tag_list(buf, dest)) != 0 ||
(r = buf_parse_tag_sym(buf, dest)) != 0)
@@ -2934,6 +2936,16 @@ sw buf_parse_tag_str (s_buf *buf, s_tag *dest)
return r;
}
+sw buf_parse_tag_struct (s_buf *buf, s_tag *dest)
+{
+ sw r;
+ assert(buf);
+ assert(dest);
+ if ((r = buf_parse_struct(buf, &dest->data.struct_)) > 0)
+ dest->type = TAG_STRUCT;
+ return r;
+}
+
sw buf_parse_tag_sym (s_buf *buf, s_tag *dest)
{
sw r;
diff --git a/libc3/buf_parse.h b/libc3/buf_parse.h
index 6365e3e..9c6766b 100644
--- a/libc3/buf_parse.h
+++ b/libc3/buf_parse.h
@@ -118,8 +118,7 @@ sw buf_parse_tag_number (s_buf *buf, s_tag *dest);
sw buf_parse_tag_primary (s_buf *buf, s_tag *dest);
sw buf_parse_tag_quote (s_buf *buf, s_tag *dest);
sw buf_parse_tag_str (s_buf *buf, s_tag *dest);
-sw buf_parse_tag_str_character (s_buf *buf, s_tag *dest);
-sw buf_parse_tag_str_u8 (s_buf *buf, s_tag *dest);
+sw buf_parse_tag_struct (s_buf *buf, s_tag *dest);
sw buf_parse_tag_sym (s_buf *buf, s_tag *dest);
sw buf_parse_tag_tuple (s_buf *buf, s_tag *dest);
sw buf_parse_tuple (s_buf *buf, s_tuple *dest);
diff --git a/libc3/struct.c b/libc3/struct.c
index ecf89c0..9bc954f 100644
--- a/libc3/struct.c
+++ b/libc3/struct.c
@@ -27,20 +27,31 @@ void struct_clean (s_struct *s)
{
f_clean clean;
s8 *data;
- uw i = 0;
+ uw i;
const s_sym *sym;
assert(s);
data = s->data;
- while (i < s->type.map.count) {
- if (tag_type(s->type.map.value + i, &sym)) {
- clean = sym_to_clean(sym);
- if (clean)
- clean(data + s->type.offset[i]);
+ if (data) {
+ i = 0;
+ while (i < s->type.map.count) {
+ if (tag_type(s->type.map.value + i, &sym)) {
+ clean = sym_to_clean(sym);
+ if (clean)
+ clean(data + s->type.offset[i]);
+ i++;
+ }
+ }
+ if (s->free_data)
+ free(data);
+ }
+ if (s->tag) {
+ i = 0;
+ while (i < s->type.map.count) {
+ tag_clean(s->tag + i);
i++;
}
+ free(s->tag);
}
- if (s->free)
- free(data);
struct_type_clean(&s->type);
}
@@ -51,6 +62,23 @@ void struct_delete (s_struct *s)
free(s);
}
+bool struct_find_key_index (const s_struct *s, const s_sym *key,
+ uw *dest)
+{
+ uw i = 0;
+ assert(s);
+ assert(key);
+ while (i < s->type.map.count) {
+ assert(s->type.map.key[i].type == TAG_SYM);
+ if (s->type.map.key[i].data.sym == key) {
+ *dest = i;
+ return true;
+ }
+ i++;
+ }
+ return false;
+}
+
s_struct * struct_init (s_struct *s, const s_sym *module)
{
s_struct tmp = {0};
@@ -58,12 +86,21 @@ s_struct * struct_init (s_struct *s, const s_sym *module)
assert(module);
if (! struct_type_init_from_env(&tmp.type, module, &g_c3_env))
return NULL;
- tmp.free = true;
+ *s = tmp;
+ return s;
+}
+
+s_struct * struct_allocate (s_struct *s)
+{
+ s_struct tmp;
+ assert(s);
+ assert(! s->data);
+ tmp = *s;
+ tmp.free_data = true;
tmp.data = calloc(1, tmp.type.size);
if (! tmp.data) {
- warn("struct_init: data");
- assert(! "struct_init: data: failed to allocate memory");
- struct_type_clean(&tmp.type);
+ warn("struct_allocate: data");
+ assert(! "struct_allocate: data: failed to allocate memory");
return NULL;
}
*s = tmp;
@@ -81,47 +118,50 @@ s_struct * struct_init_1 (s_struct *s, const s8 *p)
s_struct * struct_init_copy (s_struct *s, const s_struct *src)
{
- f_clean clean;
f_init_copy init_copy;
- uw i = 0;
+ uw i;
uw size;
const s_sym *sym;
- s_struct tmp;
+ s_struct tmp = {0};
assert(s);
assert(src);
if (! struct_type_init_copy(&tmp.type, &src->type))
return NULL;
- tmp.free = true;
- tmp.data = calloc(1, tmp.type.size);
- while (i < tmp.type.map.count) {
- if (tag_type(tmp.type.map.value + i, &sym)) {
- init_copy = sym_to_init_copy(sym);
- if (init_copy) {
- if (! init_copy((s8 *) tmp.data + tmp.type.offset[i],
- (s8 *) src->data + tmp.type.offset[i]))
- goto ko;
- }
- else {
- size = tag_size(tmp.type.map.value + i);
- memcpy((s8 *) tmp.data + tmp.type.offset[i],
- (s8 *) src->data + tmp.type.offset[i],
- size);
+ if (src->data) {
+ tmp.free_data = true;
+ tmp.data = calloc(1, tmp.type.size);
+ i = 0;
+ while (i < tmp.type.map.count) {
+ if (tag_type(tmp.type.map.value + i, &sym)) {
+ init_copy = sym_to_init_copy(sym);
+ if (init_copy) {
+ if (! init_copy((s8 *) tmp.data + tmp.type.offset[i],
+ (s8 *) src->data + tmp.type.offset[i]))
+ goto ko;
+ }
+ else {
+ size = tag_size(tmp.type.map.value + i);
+ memcpy((s8 *) tmp.data + tmp.type.offset[i],
+ (s8 *) src->data + tmp.type.offset[i],
+ size);
+ }
}
+ i++;
+ }
+ }
+ if (src->tag) {
+ tmp.tag = calloc(tmp.type.map.count, sizeof(s_tag));
+ i = 0;
+ while (i < tmp.type.map.count) {
+ if (! tag_init_copy(tmp.tag + i, src->tag + i))
+ goto ko;
+ i++;
}
- i++;
}
*s = tmp;
return s;
ko:
- while (i > 0) {
- i--;
- tag_type(tmp.type.map.value + i, &sym);
- clean = sym_to_clean(sym);
- if (clean)
- clean((s8 *) tmp.data + tmp.type.offset[i]);
- }
- free(tmp.data);
- struct_type_clean(&tmp.type);
+ struct_clean(&tmp);
return NULL;
}
@@ -129,6 +169,7 @@ s_struct * struct_init_from_lists (s_struct *s, const s_sym *module,
const s_list *keys,
const s_list *values)
{
+ uw i;
const s_list *k;
s_struct tmp = {0};
const s_list *v;
@@ -137,21 +178,45 @@ s_struct * struct_init_from_lists (s_struct *s, const s_sym *module,
assert(list_length(keys) == list_length(values));
if (! struct_init(&tmp, module))
return NULL;
+ tmp.tag = calloc(tmp.type.map.count, sizeof(s_tag));
+ if (! tmp.tag) {
+ warn("struct_init_from_lists: tag");
+ assert(! "struct_init_from_lists: failed to allocate memory");
+ return NULL;
+ }
k = keys;
v = values;
while (k && v) {
assert(k->tag.type == TAG_SYM);
- if (k->tag.type != TAG_SYM)
- errx(1, "struct_init_from_lists: key that is not a symbol: %s",
- tag_type_to_string(k->tag.type));
- if (! struct_set(&tmp, k->tag.data.sym, &v->tag))
- errx(1, "struct_init_from_lists: struct_set(%s) failed",
- k->tag.data.sym->str.ptr.ps8);
+ if (k->tag.type != TAG_SYM) {
+ warnx("struct_init_from_lists: key that is not a symbol: %s",
+ tag_type_to_string(k->tag.type));
+ assert(! "struct_init_from_lists: key that is not a symbol");
+ goto ko;
+ }
+ if (! struct_find_key_index(&tmp, k->tag.data.sym, &i)) {
+ warnx("struct_init_from_lists: cannot find key in defstruct: %s",
+ k->tag.data.sym->str.ptr.ps8);
+ assert(! "struct_init_from_lists: cannot find key in defstruct");
+ goto ko;
+ }
+ if (! tag_init_copy(tmp.tag + i, &v->tag))
+ goto ko;
k = list_next(k);
v = list_next(v);
}
+ i = 0;
+ while (i < tmp.type.map.count) {
+ if (! tmp.tag[i].type)
+ if (! tag_init_copy(tmp.tag + i, tmp.type.map.value + i))
+ goto ko;
+ i++;
+ }
*s = tmp;
return s;
+ ko:
+ struct_clean(&tmp);
+ return NULL;
}
s_struct * struct_init_with_data (s_struct *s, const s_sym *module,
@@ -162,7 +227,7 @@ s_struct * struct_init_with_data (s_struct *s, const s_sym *module,
assert(module);
if (! struct_type_init_from_env(&tmp.type, module, &g_c3_env))
return NULL;
- tmp.free = free_data;
+ tmp.free_data = free_data;
tmp.data = data;
*s = tmp;
return s;
diff --git a/libc3/struct.h b/libc3/struct.h
index 9eb1def..fafc034 100644
--- a/libc3/struct.h
+++ b/libc3/struct.h
@@ -43,4 +43,8 @@ s_struct * struct_new_with_data (const s_sym *module, bool free_data,
s_struct * struct_set (s_struct *s, const s_sym *key,
const s_tag *value);
+/* Observers. */
+bool struct_find_key_index (const s_struct *s, const s_sym *key,
+ uw *dest);
+
#endif /* LIBC3_STRUCT_H */
diff --git a/libc3/struct_type.c b/libc3/struct_type.c
index da47dcc..1f93dcb 100644
--- a/libc3/struct_type.c
+++ b/libc3/struct_type.c
@@ -75,6 +75,7 @@ s_struct_type * struct_type_init (s_struct_type *st, const s_sym *module,
offset = struct_type_padding(offset, size);
st->offset[i] = offset;
offset += size;
+ i++;
s = list_next(s);
}
st->size = offset;
diff --git a/libc3/sym.c b/libc3/sym.c
index 29d4c51..c68618e 100644
--- a/libc3/sym.c
+++ b/libc3/sym.c
@@ -417,6 +417,10 @@ ffi_type * sym_to_ffi_type (const s_sym *sym, ffi_type *result_type)
return &ffi_type_sint32;
if (sym == sym_1("S64"))
return &ffi_type_sint64;
+ if (sym == sym_1("Str"))
+ return &ffi_type_pointer;
+ if (sym == sym_1("Struct"))
+ return &ffi_type_pointer;
if (sym == sym_1("Sym"))
return &ffi_type_pointer;
if (sym == sym_1("Sw"))
@@ -502,6 +506,8 @@ f_init_copy sym_to_init_copy (const s_sym *type)
return (f_init_copy) tuple_init_copy;
if (type == sym_1("Var"))
return (f_init_copy) var_init_copy;
+ if (type == sym_1("Void"))
+ return (f_init_copy) void_init_copy;
err_write_1("sym_to_init_copy: unknown type: ");
err_write_1(type->str.ptr.ps8);
err_write_1("\n");
diff --git a/libc3/types.h b/libc3/types.h
index 6be11b8..cfa2b47 100644
--- a/libc3/types.h
+++ b/libc3/types.h
@@ -325,7 +325,8 @@ struct str {
struct struct_ {
void *data;
- bool free;
+ s_tag *tag;
+ bool free_data;
s_struct_type type;
};