diff options
-rw-r--r-- | cgen.c | 5 | ||||
-rw-r--r-- | decls_cgen.c | 8 | ||||
-rw-r--r-- | main.c | 3 | ||||
-rw-r--r-- | test.toc | 53 | ||||
-rw-r--r-- | types.c | 92 |
5 files changed, 96 insertions, 65 deletions
@@ -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) { @@ -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) @@ -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(); @@ -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; } |