summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2020-05-12 16:45:04 -0400
committerLeo Tenenbaum <pommicket@gmail.com>2020-05-12 16:45:04 -0400
commit2f9e7e8a3a8239bc4b4f880cc5e91c23cdd154dc (patch)
treee660c6cece49b3abc8000b5b8ef00d7ed43aba11
parentd5e0c67e29e7da0e393a9e0d50cfa36f9829165d (diff)
fixed struct #ifs
-rw-r--r--cgen.c5
-rw-r--r--decls_cgen.c8
-rw-r--r--main.c3
-rw-r--r--test.toc53
-rw-r--r--types.c92
5 files changed, 96 insertions, 65 deletions
diff --git a/cgen.c b/cgen.c
index a88f516..4702226 100644
--- a/cgen.c
+++ b/cgen.c
@@ -143,7 +143,7 @@ static void cgen_defs_decl(CGenerator *g, Declaration *d);
}
-#define cgen_recurse_subtypes(f, g, type) \
+#define cgen_recurse_subtypes(g, type, f) \
switch (type->kind) { \
case TYPE_STRUCT: \
/* don't descend into fields */ \
@@ -2171,10 +2171,11 @@ static void cgen_defs_type(CGenerator *g, Type *t) {
if (t->kind == TYPE_STRUCT) {
StructDef *sdef = t->struc;
if (!(sdef->flags & STRUCT_DEF_CGEN_FN_DEFS)) {
- cgen_defs_block(g, &sdef->body);
sdef->flags |= STRUCT_DEF_CGEN_FN_DEFS;
+ cgen_defs_block(g, &sdef->body);
}
}
+ cgen_recurse_subtypes(g, t, cgen_defs_type);
}
static void cgen_defs_fn(CGenerator *g, FnExpr *f) {
diff --git a/decls_cgen.c b/decls_cgen.c
index 5d527cd..896c287 100644
--- a/decls_cgen.c
+++ b/decls_cgen.c
@@ -30,6 +30,7 @@ static void cgen_sdecls_type(CGenerator *g, Type *type) {
/* we'll actually define the struct later; here we can just declare it */
if ((sdef->flags & STRUCT_DEF_RESOLVED) && !(sdef->flags & STRUCT_DEF_CGEN_DECLARED)) {
+ sdef->flags |= STRUCT_DEF_CGEN_DECLARED;
cgen_write(g, "struct ");
if (!sdef->name) {
sdef->c.id = ++g->ident_counter;
@@ -38,10 +39,9 @@ static void cgen_sdecls_type(CGenerator *g, Type *type) {
cgen_write(g, ";");
cgen_nl(g);
cgen_sdecls_block(g, &sdef->body);
- sdef->flags |= STRUCT_DEF_CGEN_DECLARED;
}
}
- cgen_recurse_subtypes(cgen_sdecls_type, g, type);
+ cgen_recurse_subtypes(g, type, cgen_sdecls_type);
}
static char *cgen_nms_prefix_part(CGenerator *g, Namespace *n) {
@@ -171,6 +171,7 @@ static void cgen_decls_type(CGenerator *g, Type *type) {
if (type->kind == TYPE_STRUCT) {
StructDef *sdef = type->struc;
if ((sdef->flags & STRUCT_DEF_RESOLVED) && !(sdef->flags & STRUCT_DEF_CGEN_DEFINED)) {
+ sdef->flags |= STRUCT_DEF_CGEN_DEFINED;
/* generate struct definition */
cgen_write(g, "struct ");
cgen_struct_name(g, sdef);
@@ -189,11 +190,10 @@ static void cgen_decls_type(CGenerator *g, Type *type) {
cgen_write(g, "};");
cgen_nl(g);
cgen_decls_block(g, &sdef->body);
- sdef->flags |= STRUCT_DEF_CGEN_DEFINED;
}
}
- cgen_recurse_subtypes(cgen_decls_type, g, type);
+ cgen_recurse_subtypes(g, type, cgen_decls_type);
}
static void cgen_single_fn_decl(CGenerator *g, FnExpr *f, U64 which_are_const) {
diff --git a/main.c b/main.c
index c45fb0b..a46460f 100644
--- a/main.c
+++ b/main.c
@@ -8,7 +8,8 @@
/*
@TODO:
-struct_add_block needs serious changes, now that #ifs generate *inline* blocks
+test #include inside a struct
+cgen_recurse_subtypes should go inside struct params. maybe it could also go into the body?
get rid of UNARY_LEN?
detect circular declarations (A ::= B; B ::= A)
either detect circular #includes or set a #include depth limit (maybe sometimes you want finite circular includes with #if)
diff --git a/test.toc b/test.toc
index 7697c24..cdeb73f 100644
--- a/test.toc
+++ b/test.toc
@@ -1,16 +1,47 @@
-#include "tests/std/io.toc";
+#include "tests/std/io.toc", io;
+#include "std/mem.toc";
-Foo ::= struct {
- x : int;
- N ::= 5;
- S ::= "hello!";
- f ::= fn() []char {
- S
+main ::= fn() {
+ nums := news(int, 10);
+ for x, i := &nums {
+ *x = i*i;
+ }
+ l := slice_to_ll(nums);
+ p := &l;
+ while p {
+ io.puti(p.head);
+ p = p.tail;
}
+ f: Foo;
+ f.k = -173;
+ f.b = new(Bar);
+ f.b.f.b = new(Bar);
+ f.b.f.b.f.k = 9;
+ io.puti(f.k);
+ io.puti(f.b.f.k);
+ io.puti(f.b.f.b.f.k);
}
-main ::= fn() {
- puts(Foo.f());
-
+slice_to_ll ::= fn(t::=, slice: []t) use ll: LinkedList(t) {
+ head = slice[0];
+ if slice.len == 1 {
+ tail = null;
+ } else {
+ tail = new(LinkedList(t));
+ *tail = slice_to_ll(slice[1:]);
+ }
+}
+
+LinkedList ::= struct (of :: Type) {
+ head: of;
+ tail: &LinkedList(of);
+}
+
+Foo ::= struct {
+ k: int;
+ b: &Bar;
+}
+
+Bar ::= struct {
+ f: Foo;
}
-main();
diff --git a/types.c b/types.c
index 51128f6..da7efcb 100644
--- a/types.c
+++ b/types.c
@@ -140,17 +140,16 @@ static Status struct_add_used_struct(Typer *tr, StructDef *to, StructDef *add, D
return true;
}
-/* new_stmts is what s->body.stmts will become after typing is done */
-static Status struct_add_block(Typer *tr, Block *b, StructDef *s, Statement **new_stmts) {
- arr_foreach(b->stmts, Statement, stmt) {
- if (stmt->kind == STMT_EXPR) {
- if (stmt->expr->kind == EXPR_BLOCK) {
- if (!struct_add_block(tr, stmt->expr->block, s, new_stmts))
- return false;
- continue;
- }
+/* create s->fields, also check to make sure the struct's statements are valid */
+static Status struct_add_stmts(Typer *tr, StructDef *s, Statement *stmts) {
+ arr_foreach(stmts, Statement, stmt) {
+ StatementKind kind = stmt->kind;
+ if (kind == STMT_INLINE_BLOCK) {
+ if (!struct_add_stmts(tr, s, stmt->inline_block))
+ return false;
+ continue;
}
- if (stmt->kind != STMT_DECL) {
+ if (kind != STMT_DECL) {
err_print(stmt->where, "structs can only contain declarations.");
return false;
}
@@ -165,7 +164,6 @@ static Status struct_add_block(Typer *tr, Block *b, StructDef *s, Statement **ne
err_print(d->where, "struct members can't be inferred.");
return false;
}
- typer_arr_add(tr, *new_stmts, *stmt);
} else {
if (flags & DECL_SEMI_CONST) {
err_print(d->where, "struct members can't be semi-constant.");
@@ -184,7 +182,6 @@ static Status struct_add_block(Typer *tr, Block *b, StructDef *s, Statement **ne
(*ident)->used_from = NULL;
++i;
}
- typer_arr_add(tr, *new_stmts, *stmt);
}
if (flags & DECL_USE) {
/* add everything in the used struct to the namespace */
@@ -205,25 +202,33 @@ static Status struct_add_block(Typer *tr, Block *b, StructDef *s, Statement **ne
if (!struct_add_used_struct(tr, s, d->type.struc, d))
return false;
}
- if (b != &s->body) {
- /* we need to translate d's identifiers to s's scope */
- arr_foreach(d->idents, Identifier, ip) {
- Identifier redeclared = ident_get(&s->body.idents, (*ip)->str);
- if (redeclared) {
- char *str = ident_to_str(*ip);
- err_print(d->where, "Redeclaration of struct member %s", str);
- info_print(ident_decl_location(redeclared), "Previous declaration was here.");
- free(str);
- return false;
- }
- *ip = ident_translate_forced(*ip, &s->body.idents);
- (*ip)->decl = d;
- }
- }
}
return true;
}
+/*
+ set the field pointers of the declarations in this struct, so that when we look up the declaration of
+ a member of the struct, we know which Field it refers to.
+ this needs to be a different step after struct_add_stmts, because the pointers to Fields can change
+ during struct_add_stmts
+*/
+static void struct_set_decl_field_ptrs(Typer *tr, StructDef *s, Statement *stmts) {
+ Field *field = s->fields;
+ arr_foreach(stmts, Statement, stmt) {
+ if (stmt->kind == STMT_INLINE_BLOCK) {
+ struct_set_decl_field_ptrs(tr, s, stmt->inline_block);
+ continue;
+ }
+ assert(stmt->kind == STMT_DECL);
+ Declaration *decl = stmt->decl;
+ if (!(decl->flags & DECL_IS_CONST)) {
+ assert(!(decl->flags & DECL_HAS_EXPR));
+ decl->field = field;
+ field += arr_len(decl->idents);
+ }
+ }
+}
+
static size_t compiler_alignof(Type *t) {
assert(t->flags & TYPE_IS_RESOLVED);
switch (t->kind) {
@@ -292,24 +297,14 @@ static Status struct_resolve(Typer *tr, StructDef *s) {
if (!(s->flags & STRUCT_DEF_RESOLVED)) {
s->flags |= STRUCT_DEF_RESOLVING;
{ /* resolving stuff */
- if (!types_block(tr, &s->body))
+ Block *body = &s->body;
+ if (!types_block(tr, body))
goto fail;
s->fields = NULL;
- Statement *new_stmts = NULL;
- if (!struct_add_block(tr, &s->body, s, &new_stmts))
+ Statement *stmts = body->stmts;
+ if (!struct_add_stmts(tr, s, stmts))
goto fail;
- s->body.stmts = new_stmts;
- /* set the field of each declaration, so that we can lookup struct members quickly */
- Field *field = s->fields;
- arr_foreach(new_stmts, Statement, stmt) {
- assert(stmt->kind == STMT_DECL);
- Declaration *decl = stmt->decl;
- if (!(decl->flags & DECL_IS_CONST)) {
- assert(!(decl->flags & DECL_HAS_EXPR));
- decl->field = field;
- field += arr_len(decl->idents);
- }
- }
+ struct_set_decl_field_ptrs(tr, s, stmts);
s->instance_id = 0;
}
/* find offsets and size */
@@ -1533,9 +1528,10 @@ static Status get_struct_constant(StructDef *struc, String ident, Expression *e)
return true;
} else {
char *member_s = cstr(ident.str, ident.len);
- char *struc_s = struc->name ? ident_to_str(struc->name) : "anonymous struct";
+ char *struc_s = get_struct_name(struc);
err_print(e->where, "Cannot get value %s from struct %s. Are you missing parameters to this struct?", member_s, struc_s);
free(member_s);
+ free(struc_s);
return false;
}
}
@@ -3185,6 +3181,12 @@ static Status types_expr(Typer *tr, Expression *e) {
if (!struct_resolve(tr, struc)) return false;
Identifier struct_ident = ident_get_with_len(&struc->body.idents, rhs->ident_str.str, rhs->ident_str.len);
+ if (!struct_ident) {
+ char *struc_s = get_struct_name(struc);
+ char *member_s = str_to_cstr(rhs->ident_str);
+ err_print(e->where, "%s is not a member of structure %s.", member_s, struc_s);
+ return false;
+ }
UsedFrom *uf = struct_ident->used_from;
if (uf) {
/* foo.baz => (foo.bar).baz */
@@ -3209,10 +3211,6 @@ static Status types_expr(Typer *tr, Expression *e) {
e->binary.field = field;
*t = *field->type;
} else {
- /*
- this call will fail if rhs->ident_str isn't a member of the structure.
- kind of weird to have that check here but whatever
- */
if (!get_struct_constant(struct_type->struc, rhs->ident_str, e))
return false;
}