From 96e05aba5b1ae849e3f6f4523c0d84226b129030 Mon Sep 17 00:00:00 2001 From: Sebastian Jeong Date: Mon, 17 Aug 2026 05:00:31 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20=EB=B9=8C=EB=93=9C=20=EC=A0=84?= =?UTF-8?q?=EC=B2=B4=EB=A5=BC=20=ED=95=98=EB=82=98=EC=9D=98=20=EA=B2=80?= =?UTF-8?q?=EC=82=AC=EA=B8=B0=EB=A1=9C=20=EB=B3=B8=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 유닛마다 FeCheck 를 새로 만들면 타입 문맥도 유닛마다 따로 생겨서 유닛 경계를 넘는 이름을 볼 수가 없었다. 검사기가 빌드 전체를 맡고, 모든 유닛의 선언을 등록한 뒤에 어느 본문이든 보기 시작한다. 스코프와 심볼과 타입은 현재 유닛보다 오래 살아야 하므로 AST 아레나가 아니라 검사기 자신의 아레나에서 잡는다. 이름이 같아도 유닛이 다르면 다른 타입이므로 nominal 타입은 선언한 유닛으로도 구분한다. pub 은 파서가 버리고 있었다. 이제 FE_NODE_PUB 으로 남긴다. --- fec/src/ast.h | 6 +++ fec/src/check.c | 131 +++++++++++++++++++++++++++++++---------------- fec/src/check.h | 19 +++++-- fec/src/driver.c | 8 ++- fec/src/parser.c | 16 +++--- fec/src/types.c | 36 +++++++++++-- fec/src/types.h | 8 +++ 7 files changed, 161 insertions(+), 63 deletions(-) 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);