diff --git a/fec/src/ast.h b/fec/src/ast.h index efbf887..2118872 100644 --- a/fec/src/ast.h +++ b/fec/src/ast.h @@ -37,6 +37,12 @@ struct FeNode { unsigned flags; }; +/* Bits in FeNode.flags. 0x100 and above belong to own.h. */ +#define FE_NODE_PACKED 0x1U +#define FE_NODE_STATIC 0x2U +#define FE_NODE_SHARED 0x4U +#define FE_NODE_PUB 0x8U + typedef struct FeAst { FeArena arena; FeNode *root; diff --git a/fec/src/check.c b/fec/src/check.c index 3983a75..e900f4b 100644 --- a/fec/src/check.c +++ b/fec/src/check.c @@ -8,7 +8,7 @@ #include typedef struct FeSym FeSym; -typedef struct FeScope FeScope; +/* FeScope is forward declared in check.h. */ struct FeSym { const char *name; @@ -156,7 +156,7 @@ static char *unit_cname(FeCheck *c, const char *name) u = c->ast->root && c->ast->root->text ? c->ast->root->text : "unit"; n = (unsigned long)strlen("fe_") + (unsigned long)strlen(u) + (unsigned long)strlen(name ? name : "name") + 2UL; - p = (char *)fe_arena_alloc(&c->ast->arena, n); + p = (char *)fe_arena_alloc(&c->arena, n); if (!p) return 0; strcpy(p, "fe_"); strcat(p, u); @@ -173,7 +173,7 @@ static char *local_cname(FeCheck *c, const char *name) sprintf(number, "%u", c->local_serial++); n = (unsigned long)strlen("fe_l_") + (unsigned long)strlen(name) + (unsigned long)strlen(number) + 2UL; - p = (char *)fe_arena_alloc(&c->ast->arena, n); + p = (char *)fe_arena_alloc(&c->arena, n); if (!p) return 0; strcpy(p, "fe_l_"); strcat(p, name ? name : "local"); @@ -185,7 +185,7 @@ static char *local_cname(FeCheck *c, const char *name) static FeScope *scope_new(FeCheckerState *s, FeScope *parent) { FeScope *scope; - scope = (FeScope *)fe_arena_alloc(&s->c->ast->arena, sizeof(FeScope)); + scope = (FeScope *)fe_arena_alloc(&s->c->arena, sizeof(FeScope)); if (!scope) { err(s->c, s->c->ast->root->loc, "out of memory creating scope"); return parent; @@ -234,7 +234,7 @@ static FeSym *add_symbol(FeCheckerState *s, FeScope *scope, } if (scope->count == scope->capacity) { capacity = scope->capacity ? scope->capacity * 2U : 8U; - items = (FeSym *)fe_arena_alloc(&s->c->ast->arena, + items = (FeSym *)fe_arena_alloc(&s->c->arena, capacity * sizeof(FeSym)); if (!items) { err(s->c, decl ? decl->loc : s->c->ast->root->loc, @@ -267,16 +267,38 @@ static FeSym *add_symbol(FeCheckerState *s, FeScope *scope, return sym; } -void fe_check_init(FeCheck *c, FeAst *ast, FeDiags *diags, +/* Make `unit` the one being checked. Types intern against its name, cnames + are built from it, and diagnostics quote its source rather than whichever + file happened to be parsed last. */ +static void enter_unit(FeCheck *c, unsigned index) +{ + FeUnit *u = &c->build->units[index]; + c->unit = u; + c->ast = &u->ast; + c->types.unit_name = u->name[0] ? u->name : "unit"; + fe_diags_source(c->diags, u->source, u->size); +} + +void fe_check_init(FeCheck *c, FeBuild *build, FeDiags *diags, unsigned pointer_bits, int no_checks) { - c->ast = ast; + unsigned i; + fe_arena_init(&c->arena, 16384); + c->build = build; + c->unit = 0; + c->ast = build->count ? &build->units[0].ast : 0; + for (i = 0; i < FE_BUILD_UNIT_MAX; ++i) c->unit_scope[i] = 0; c->diags = diags; c->pointer_bits = pointer_bits; c->local_serial = 0; c->no_checks = no_checks; - fe_types_init(&c->types, &ast->arena, pointer_bits); - c->types.unit_name = ast->root && ast->root->text ? ast->root->text : "unit"; + fe_types_init(&c->types, &c->arena, pointer_bits); + c->types.unit_name = "unit"; +} + +void fe_check_destroy(FeCheck *c) +{ + fe_arena_destroy(&c->arena); } static FeType *check_expr(FeCheckerState *s, FeNode *n); @@ -517,7 +539,7 @@ static void own_release_after_stmt(FeCheckerState *s, FeScope *scope, static FeOwnState *flow_own_new(FeCheckerState *s, unsigned count) { if (!s || !count) return 0; - return (FeOwnState *)fe_arena_alloc(&s->c->ast->arena, + return (FeOwnState *)fe_arena_alloc(&s->c->arena, count*sizeof(FeOwnState)); } @@ -554,7 +576,7 @@ typedef struct FeFlowBorrow { static FeFlowBorrow *flow_borrow_new(FeCheckerState *s, unsigned count) { if (!s || !count) return 0; - return (FeFlowBorrow *)fe_arena_alloc(&s->c->ast->arena, + return (FeFlowBorrow *)fe_arena_alloc(&s->c->arena, count*sizeof(FeFlowBorrow)); } @@ -1737,7 +1759,7 @@ static void check_fn(FeCheck *c, FeNode *fn, FeScope *globals) s.loop_depth=0; s.defer_depth=0; s.fn_node=fn; - fe_own_liveness_init(&s.liveness,&c->ast->arena); + fe_own_liveness_init(&s.liveness,&c->arena); fe_own_collect_last_uses(&s.liveness,fn); fn->sem_type = s.ret; for (x = fn->a ? fn->a->children : 0; x; x = x->next) { @@ -1765,7 +1787,7 @@ static void check_method(FeCheck *c, FeNode *fn, FeScope *globals, s.loop_depth=0; s.defer_depth=0; s.fn_node=fn; - fe_own_liveness_init(&s.liveness,&c->ast->arena); + fe_own_liveness_init(&s.liveness,&c->arena); fe_own_collect_last_uses(&s.liveness,fn); fn->sem_type=s.ret; for(x=fn->a ? fn->a->children : 0; x; x=x->next) { @@ -2776,26 +2798,13 @@ static void m7_validate_error_decl(FeCheck *c, FeNode *decl) } } -int fe_check_program(FeCheck *c) +/* Everything a unit declares, before any body anywhere is looked at. */ +static void declare_unit(FeCheck *c) { - FeCheckerState s; FeNode *n; - FeNode *m; - FeSym *sym; - FeType *t; - FeType *iv; - char method_name[128]; - s.c=c; - s.scope=scope_new(&s,0); - s.globals=s.scope; - s.ret=fe_type_intern(&c->types,"void"); - s.loop_depth=0; - s.defer_depth=0; - s.fn_node=0; - fe_own_liveness_init(&s.liveness,&c->ast->arena); for (n=c->ast->root ? c->ast->root->children : 0;n;n=n->next) if (n->kind==FE_N_STRUCT) - fe_type_declare_struct(&c->types,n,(n->flags & 1U)!=0); + fe_type_declare_struct(&c->types,n,(n->flags & FE_NODE_PACKED)!=0); for (n=c->ast->root ? c->ast->root->children : 0;n;n=n->next) { m7_check_storage(c,n); if (n->kind==FE_N_ERROR_DECL) m7_validate_error_decl(c,n); @@ -2805,7 +2814,20 @@ int fe_check_program(FeCheck *c) for (n=c->ast->root ? c->ast->root->children : 0;n;n=n->next) if (n->kind==FE_N_ERROR_DECL) fe_type_declare_error(&c->types,n); check_type_cycles(c); - fe_type_layout_all(&c->types); +} + +/* The unit's top-level names, in a scope of their own so that another unit + can look into it later without inheriting anything else. */ +static FeScope *declare_unit_scope(FeCheck *c, FeCheckerState *s) +{ + FeNode *n; + FeNode *m; + FeType *t; + FeScope *globals; + char method_name[128]; + globals=scope_new(s,0); + s->scope=globals; + s->globals=globals; for (n=c->ast->root ? c->ast->root->children : 0;n;n=n->next) { if (n->kind==FE_N_STRUCT) { for (m=n->children;m;m=m->next) if (m->kind==FE_N_FN) { @@ -2816,21 +2838,31 @@ int fe_check_program(FeCheck *c) } if (n->kind==FE_N_GLOBAL || n->kind==FE_N_CONST) { t=n->a ? node_type(c,n->a) : unknown(c); - add_symbol(&s,s.globals,n->text,t,0,n->kind==FE_N_GLOBAL, + add_symbol(s,globals,n->text,t,0,n->kind==FE_N_GLOBAL, n->b!=0,unit_cname(c,n->text ? n->text : "global"),n); } } for (n=c->ast->root ? c->ast->root->children : 0;n;n=n->next) if (n->kind==FE_N_FN) { t=fe_type_intern(&c->types,""); - add_symbol(&s,s.globals,n->text,t,n,0,1, + add_symbol(s,globals,n->text,t,n,0,1, unit_cname(c,n->text ? n->text : "fn"),n); } + return globals; +} + +static void check_unit_bodies(FeCheck *c, FeCheckerState *s) +{ + FeNode *n; + FeNode *m; + FeSym *sym; + FeType *t; + FeType *iv; for (n=c->ast->root ? c->ast->root->children : 0;n;n=n->next) if (n->kind==FE_N_GLOBAL || n->kind==FE_N_CONST) { - sym=find_current(s.globals,n->text ? n->text : ""); + sym=find_current(s->globals,n->text ? n->text : ""); if (n->b) { - iv=m7_check_expected(&s,n->b,sym ? sym->type : 0); + iv=m7_check_expected(s,n->b,sym ? sym->type : 0); if (sym && sym->type->kind==FE_TYPE_UNKNOWN) { sym->type=iv; n->sem_type=iv; @@ -2840,27 +2872,40 @@ int fe_check_program(FeCheck *c) } } for (n=c->ast->root ? c->ast->root->children : 0;n;n=n->next) - if (n->kind==FE_N_FN) check_fn(c,n,s.globals); + if (n->kind==FE_N_FN) check_fn(c,n,s->globals); for (n=c->ast->root ? c->ast->root->children : 0;n;n=n->next) if (n->kind==FE_N_STRUCT) { t=fe_type_intern(&c->types,n->text); for (m=n->children;m;m=m->next) - if (m->kind==FE_N_FN) check_method(c,m,s.globals,t); + if (m->kind==FE_N_FN) check_method(c,m,s->globals,t); } - fe_type_layout_all(&c->types); - return c->diags->errors==0; } -FeType *fe_check_expr_type(FeCheck *c, FeNode *n) +int fe_check_program(FeCheck *c) { FeCheckerState s; + unsigned u; s.c=c; - s.scope=scope_new(&s,0); - s.globals=s.scope; + s.scope=0; + s.globals=0; s.ret=fe_type_intern(&c->types,"void"); s.loop_depth=0; s.defer_depth=0; s.fn_node=0; - fe_own_liveness_init(&s.liveness,&c->ast->arena); - return check_expr(&s,n); + fe_own_liveness_init(&s.liveness,&c->arena); + for (u=0;ubuild->count;++u) { enter_unit(c,u); declare_unit(c); } + fe_type_layout_all(&c->types); + for (u=0;ubuild->count;++u) { + enter_unit(c,u); + c->unit_scope[u]=declare_unit_scope(c,&s); + } + for (u=0;ubuild->count;++u) { + enter_unit(c,u); + s.scope=c->unit_scope[u]; + s.globals=c->unit_scope[u]; + check_unit_bodies(c,&s); + } + fe_type_layout_all(&c->types); + return c->diags->errors==0; } + diff --git a/fec/src/check.h b/fec/src/check.h index b26388a..dcb4da9 100644 --- a/fec/src/check.h +++ b/fec/src/check.h @@ -3,9 +3,22 @@ #include "types.h" #include "diag.h" +#include "resolve.h" +typedef struct FeScope FeScope; + +/* The checker spans a whole build, not one file. Names cross unit boundaries, + so every unit's declarations have to exist before any unit's bodies are + looked at, and they all have to be interned in one type context or the same + spelling in two units would not be the same type. */ typedef struct FeCheck { - FeAst *ast; + /* Scopes, symbols and types outlive whichever unit is current, so they + come from the checker's own arena rather than from an AST's. */ + FeArena arena; + FeBuild *build; + FeAst *ast; /* the unit being checked now */ + FeUnit *unit; /* its entry in the build */ + FeScope *unit_scope[FE_BUILD_UNIT_MAX]; FeTypeCtx types; FeDiags *diags; unsigned pointer_bits; @@ -13,9 +26,9 @@ typedef struct FeCheck { int no_checks; } FeCheck; -void fe_check_init(FeCheck *c, FeAst *ast, FeDiags *diags, +void fe_check_init(FeCheck *c, FeBuild *build, FeDiags *diags, unsigned pointer_bits, int no_checks); +void fe_check_destroy(FeCheck *c); int fe_check_program(FeCheck *c); -FeType *fe_check_expr_type(FeCheck *c, FeNode *n); #endif diff --git a/fec/src/driver.c b/fec/src/driver.c index 168380b..dddcd72 100644 --- a/fec/src/driver.c +++ b/fec/src/driver.c @@ -90,13 +90,11 @@ int main(int argc, char **argv) every unit's AST. */ { FeBuild build; - unsigned u; int ok=fe_build_load(&build,file,&d); - for(u=0;ok && usource,unit->size); - fe_check_init(&check,&unit->ast,&d,pointer_bits,no_checks); + if(ok){ + fe_check_init(&check,&build,&d,pointer_bits,no_checks); if(!fe_check_program(&check)) ok=0; + fe_check_destroy(&check); } fe_build_destroy(&build); /* Semantic analysis is the last pass there is. A code generator diff --git a/fec/src/parser.c b/fec/src/parser.c index 7d8a8e6..4fcc251 100644 --- a/fec/src/parser.c +++ b/fec/src/parser.c @@ -194,14 +194,14 @@ static FeNode *params(FeParser *p) static FeNode *fn_decl(FeParser *p, int pub, int external, int interrupt, int interrupt_safe) { FeToken t=p->current, name; FeNode *n; - (void)pub; (void)external; (void)interrupt; (void)interrupt_safe; + (void)external; (void)interrupt; (void)interrupt_safe; want(p,FE_TOK_FN,"expected 'fn'"); if(!is_name(p)){error(p,"expected function name");return fe_node(p->ast,FE_N_ERROR_NODE,t.loc,"fn",2);} - name=p->current; n=toknode(p,FE_N_FN,t); n->text=fe_arena_strdup(&p->ast->arena,name.begin,name.length); next(p); n->a=params(p); if(eat(p,FE_TOK_ARROW)) n->b=type(p); if(eat(p,FE_TOK_SEMI)) return n; n->c=block(p); return n; + name=p->current; n=toknode(p,FE_N_FN,t); if(pub) n->flags|=FE_NODE_PUB; n->text=fe_arena_strdup(&p->ast->arena,name.begin,name.length); next(p); n->a=params(p); if(eat(p,FE_TOK_ARROW)) n->b=type(p); if(eat(p,FE_TOK_SEMI)) return n; n->c=block(p); return n; } -static FeNode *field(FeParser *p) +static FeNode *field(FeParser *p, int pub) { FeToken t=p->current; FeNode *n; - if(!is_name(p)){error(p,"expected field name");recover(p);return 0;} next(p);n=toknode(p,FE_N_FIELD,t);want(p,FE_TOK_COLON,"expected ':' after field");n->a=type(p);if(!eat(p,FE_TOK_COMMA) && !is(p,FE_TOK_RBRACE)) error(p,"expected ',' after field");return n; + if(!is_name(p)){error(p,"expected field name");recover(p);return 0;} next(p);n=toknode(p,FE_N_FIELD,t);if(pub)n->flags|=FE_NODE_PUB;want(p,FE_TOK_COLON,"expected ':' after field");n->a=type(p);if(!eat(p,FE_TOK_COMMA) && !is(p,FE_TOK_RBRACE)) error(p,"expected ',' after field");return n; } static FeNode *decl(FeParser *p) { @@ -214,11 +214,11 @@ static FeNode *decl(FeParser *p) if(!is(p,FE_TOK_PACKED)) t=p->current; if(is(p,FE_TOK_FN)) return fn_decl(p,pub,external,interrupt,interrupt_safe); if(eat(p,FE_TOK_PACKED)) t=p->previous; - if(eat(p,FE_TOK_STRUCT)) { n=toknode(p,FE_N_STRUCT,t);if(t.kind==FE_TOK_PACKED)n->flags|=1U;if(!is_name(p)){error(p,"expected struct name");return n;}next(p);n->text=fe_arena_strdup(&p->ast->arena,p->previous.begin,p->previous.length);if(eat(p,FE_TOK_LPAREN)){while(!is(p,FE_TOK_RPAREN)&&!is(p,FE_TOK_EOF)){fe_node_add(n,type(p));if(!eat(p,FE_TOK_COMMA))break;}want(p,FE_TOK_RPAREN,"expected ')' after generic parameters");}want(p,FE_TOK_LBRACE,"expected '{' in struct");while(!is(p,FE_TOK_RBRACE)&&!is(p,FE_TOK_EOF)){if(is(p,FE_TOK_PUB))next(p);if(is(p,FE_TOK_FN))fe_node_add(n,fn_decl(p,0,0,0,0));else fe_node_add(n,field(p));}want(p,FE_TOK_RBRACE,"expected '}' after struct");return n; } - if(eat(p,FE_TOK_ENUM)) { n=toknode(p,FE_N_ENUM,t);if(is_name(p)){next(p);n->text=fe_arena_strdup(&p->ast->arena,p->previous.begin,p->previous.length);}else error(p,"expected enum name");want(p,FE_TOK_LBRACE,"expected '{' in enum");while(!is(p,FE_TOK_RBRACE)&&!is(p,FE_TOK_EOF)){FeNode *v=toknode(p,FE_N_VARIANT,p->current);if(is_name(p))next(p);else{error(p,"expected variant name");recover(p);break;}if(eat(p,FE_TOK_LPAREN)){v->a=type(p);want(p,FE_TOK_RPAREN,"expected ')' in variant");}else if(eat(p,FE_TOK_LBRACE)){while(!is(p,FE_TOK_RBRACE)&&!is(p,FE_TOK_EOF))fe_node_add(v,field(p));want(p,FE_TOK_RBRACE,"expected '}' in variant");}fe_node_add(n,v);if(!eat(p,FE_TOK_COMMA))break;}want(p,FE_TOK_RBRACE,"expected '}' after enum");return n; } - if(eat(p,FE_TOK_ERROR_KW)) { n=toknode(p,FE_N_ERROR_DECL,t);if(is_name(p)){next(p);n->text=fe_arena_strdup(&p->ast->arena,p->previous.begin,p->previous.length);}else error(p,"expected error name");want(p,FE_TOK_LBRACE,"expected '{' in error declaration");while(!is(p,FE_TOK_RBRACE)&&!is(p,FE_TOK_EOF)){FeNode *v=toknode(p,FE_N_VARIANT,p->current);if(is_name(p))next(p);else{error(p,"expected error member");recover(p);break;}want(p,FE_TOK_EQ,"expected '=' in error member");v->a=expr(p,0);want(p,FE_TOK_COMMA,"expected ',' in error declaration");fe_node_add(n,v);}want(p,FE_TOK_RBRACE,"expected '}' after error");return n; } + if(eat(p,FE_TOK_STRUCT)) { n=toknode(p,FE_N_STRUCT,t);if(pub)n->flags|=FE_NODE_PUB;if(t.kind==FE_TOK_PACKED)n->flags|=FE_NODE_PACKED;if(!is_name(p)){error(p,"expected struct name");return n;}next(p);n->text=fe_arena_strdup(&p->ast->arena,p->previous.begin,p->previous.length);if(eat(p,FE_TOK_LPAREN)){while(!is(p,FE_TOK_RPAREN)&&!is(p,FE_TOK_EOF)){fe_node_add(n,type(p));if(!eat(p,FE_TOK_COMMA))break;}want(p,FE_TOK_RPAREN,"expected ')' after generic parameters");}want(p,FE_TOK_LBRACE,"expected '{' in struct");while(!is(p,FE_TOK_RBRACE)&&!is(p,FE_TOK_EOF)){int mpub=eat(p,FE_TOK_PUB);if(is(p,FE_TOK_FN))fe_node_add(n,fn_decl(p,mpub,0,0,0));else fe_node_add(n,field(p,mpub));}want(p,FE_TOK_RBRACE,"expected '}' after struct");return n; } + if(eat(p,FE_TOK_ENUM)) { n=toknode(p,FE_N_ENUM,t);if(pub)n->flags|=FE_NODE_PUB;if(is_name(p)){next(p);n->text=fe_arena_strdup(&p->ast->arena,p->previous.begin,p->previous.length);}else error(p,"expected enum name");want(p,FE_TOK_LBRACE,"expected '{' in enum");while(!is(p,FE_TOK_RBRACE)&&!is(p,FE_TOK_EOF)){FeNode *v=toknode(p,FE_N_VARIANT,p->current);if(is_name(p))next(p);else{error(p,"expected variant name");recover(p);break;}if(eat(p,FE_TOK_LPAREN)){v->a=type(p);want(p,FE_TOK_RPAREN,"expected ')' in variant");}else if(eat(p,FE_TOK_LBRACE)){while(!is(p,FE_TOK_RBRACE)&&!is(p,FE_TOK_EOF))fe_node_add(v,field(p,1));want(p,FE_TOK_RBRACE,"expected '}' in variant");}fe_node_add(n,v);if(!eat(p,FE_TOK_COMMA))break;}want(p,FE_TOK_RBRACE,"expected '}' after enum");return n; } + if(eat(p,FE_TOK_ERROR_KW)) { n=toknode(p,FE_N_ERROR_DECL,t);if(pub)n->flags|=FE_NODE_PUB;if(is_name(p)){next(p);n->text=fe_arena_strdup(&p->ast->arena,p->previous.begin,p->previous.length);}else error(p,"expected error name");want(p,FE_TOK_LBRACE,"expected '{' in error declaration");while(!is(p,FE_TOK_RBRACE)&&!is(p,FE_TOK_EOF)){FeNode *v=toknode(p,FE_N_VARIANT,p->current);if(is_name(p))next(p);else{error(p,"expected error member");recover(p);break;}want(p,FE_TOK_EQ,"expected '=' in error member");v->a=expr(p,0);want(p,FE_TOK_COMMA,"expected ',' in error declaration");fe_node_add(n,v);}want(p,FE_TOK_RBRACE,"expected '}' after error");return n; } if(eat(p,FE_TOK_SHARED)) { shared=1; if(eat(p,FE_TOK_ATOMIC)) atomic=1; if(!is(p,FE_TOK_VAR)) error(p,"expected 'var' after shared"); } - if(is(p,FE_TOK_CONST)||is(p,FE_TOK_STATIC)||is(p,FE_TOK_VAR)) { FeTokKind kk=p->current.kind;next(p);n=toknode(p,kk==FE_TOK_CONST?FE_N_CONST:FE_N_GLOBAL,t);if(kk==FE_TOK_STATIC)n->flags|=2U;if(shared)n->flags|=4U;if(is_name(p)){next(p);n->text=fe_arena_strdup(&p->ast->arena,p->previous.begin,p->previous.length);}else error(p,"expected declaration name");if(eat(p,FE_TOK_COLON))n->a=type(p);want(p,FE_TOK_EQ,"expected '=' in declaration");n->b=expr(p,0);want(p,FE_TOK_SEMI,"expected ';' after declaration");return n; } + if(is(p,FE_TOK_CONST)||is(p,FE_TOK_STATIC)||is(p,FE_TOK_VAR)) { FeTokKind kk=p->current.kind;next(p);n=toknode(p,kk==FE_TOK_CONST?FE_N_CONST:FE_N_GLOBAL,t);if(pub)n->flags|=FE_NODE_PUB;if(kk==FE_TOK_STATIC)n->flags|=FE_NODE_STATIC;if(shared)n->flags|=FE_NODE_SHARED;if(is_name(p)){next(p);n->text=fe_arena_strdup(&p->ast->arena,p->previous.begin,p->previous.length);}else error(p,"expected declaration name");if(eat(p,FE_TOK_COLON))n->a=type(p);want(p,FE_TOK_EQ,"expected '=' in declaration");n->b=expr(p,0);want(p,FE_TOK_SEMI,"expected ';' after declaration");return n; } error(p,"expected declaration"); before=p->current.kind; recover(p); if (p->current.kind==before && p->current.kind!=FE_TOK_EOF) next(p); return 0; diff --git a/fec/src/types.c b/fec/src/types.c index af2ff15..e3390cd 100644 --- a/fec/src/types.c +++ b/fec/src/types.c @@ -14,6 +14,7 @@ static FeType *new_type(FeTypeCtx *ctx, const char *name, FeTypeKind kind) t->name[i] = name[i]; t->name[i] = '\0'; t->kind = kind; + t->unit = 0; t->cname = 0; t->maker = 0; t->none_cname = 0; @@ -56,6 +57,28 @@ void fe_types_init(FeTypeCtx *ctx, FeArena *arena, unsigned pointer_bits) ctx->generated_serial = 0; } +/* Does this type answer to `name` for someone checking `unit`? A type with no + unit is shared by everyone; one with a unit answers only inside it. */ +static int type_visible_as(const FeType *t, const char *unit, const char *name) +{ + if (strcmp(t->name, name) != 0) return 0; + if (!t->unit) return 1; + return unit && strcmp(t->unit, unit) == 0; +} + +FeType *fe_type_intern_unit(FeTypeCtx *ctx, const char *unit, const char *name) +{ + FeType *t; + if (!name) name = ""; + if (!unit) return fe_type_intern(ctx, name); + for (t = ctx->types; t; t = t->next) + if (t->unit && strcmp(t->name, name) == 0 && + strcmp(t->unit, unit) == 0) return t; + t = new_type(ctx, name, FE_TYPE_UNKNOWN); + if (t) t->unit = unit; + return t; +} + FeType *fe_type_intern(FeTypeCtx *ctx, const char *name) { FeType *t; @@ -64,7 +87,7 @@ FeType *fe_type_intern(FeTypeCtx *ctx, const char *name) FeTypeKind kind = FE_TYPE_UNKNOWN; if (!name) name = ""; for (t = ctx->types; t; t = t->next) - if (strcmp(t->name, name) == 0) return t; + if (type_visible_as(t, ctx->unit_name, name)) return t; if (strcmp(name, "void") == 0) kind = FE_TYPE_VOID; else if (strcmp(name, "bool") == 0) kind = FE_TYPE_BOOL; else if (strcmp(name, "char") == 0) kind = FE_TYPE_CHAR; @@ -246,7 +269,7 @@ FeType *fe_type_declare_struct(FeTypeCtx *ctx, const FeNode *node, int packed) unsigned i = 0; char *cname; if (!node || !node->text) return 0; - t = fe_type_intern(ctx, node->text); + t = fe_type_intern_unit(ctx, ctx->unit_name, node->text); if (t->kind != FE_TYPE_UNKNOWN && t->kind != FE_TYPE_STRUCT) return t; if (t->kind == FE_TYPE_STRUCT) return t; t->kind = FE_TYPE_STRUCT; @@ -291,7 +314,7 @@ FeType *fe_type_declare_enum(FeTypeCtx *ctx, const FeNode *node) unsigned i = 0; char *cname; if (!node || !node->text) return 0; - t = fe_type_intern(ctx, node->text); + t = fe_type_intern_unit(ctx, ctx->unit_name, node->text); if (t->kind != FE_TYPE_UNKNOWN && t->kind != FE_TYPE_ENUM) return t; if (t->kind == FE_TYPE_ENUM) return t; t->kind = FE_TYPE_ENUM; @@ -568,7 +591,12 @@ FeType *fe_type_from_ast(FeTypeCtx *ctx, const FeNode *node) int fe_type_equal(const FeType *a, const FeType *b) { - return a == b || (a && b && strcmp(a->name, b->name) == 0); + if (a == b) return 1; + if (!a || !b) return 0; + if (strcmp(a->name, b->name) != 0) return 0; + /* The same spelling is not the same type across a unit boundary. */ + if (!a->unit || !b->unit) return a->unit == b->unit; + return strcmp(a->unit, b->unit) == 0; } int fe_type_is_integer(const FeType *t) diff --git a/fec/src/types.h b/fec/src/types.h index c5ddd88..c49d706 100644 --- a/fec/src/types.h +++ b/fec/src/types.h @@ -32,6 +32,10 @@ struct FeVariantType { struct FeType { FeTypeKind kind; char name[64]; + /* The unit that declared this type, for the nominal kinds. NULL for + builtins and for structural types like `[]u8`, which every unit + shares. Two units declaring the same name declare two types. */ + const char *unit; char *cname; char *maker; char *none_cname; @@ -76,6 +80,10 @@ typedef struct FeTypeCtx { void fe_types_init(FeTypeCtx *ctx, FeArena *arena, unsigned pointer_bits); FeType *fe_type_intern(FeTypeCtx *ctx, const char *name); +/* Intern a nominal type belonging to `unit` rather than to whichever unit + is being checked. Used to name a type across a unit boundary. */ +FeType *fe_type_intern_unit(FeTypeCtx *ctx, const char *unit, + const char *name); FeType *fe_type_from_ast(FeTypeCtx *ctx, const FeNode *node); FeType *fe_type_array(FeTypeCtx *ctx, unsigned long length, FeType *elem); FeType *fe_type_slice(FeTypeCtx *ctx, FeType *elem);