harec

[hare] Hare compiler, written in C11 for POSIX OSs
Log | Files | Refs | README | LICENSE

commit 61e9b7d075b831d998a94e196413b361b7472493
parent 33cacc01ae09d2bdc744fc0e8dedf32a425e1618
Author: Armin Weigl <tb46305@gmail.com>
Date:   Tue,  7 Feb 2023 05:32:02 +0100

check: keep defines in their own scope

This has multiple effects:
	- All objects in SCOPE_UNIT are now guaranteed to be
	  incomplete_declarations, which is a prerequisite for a later
	  patch.
	- Defines are no longer (redundantly) imported from
	  type definitions.

Signed-off-by: Armin Weigl <tb46305@gmail.com>

Diffstat:
Mdocs/declaration_solver.txt | 2+-
Minclude/check.h | 1+
Minclude/scope.h | 1+
Msrc/check.c | 34+++++++++++-----------------------
Mtests/36-defines.ha | 2+-
5 files changed, 15 insertions(+), 25 deletions(-)

diff --git a/docs/declaration_solver.txt b/docs/declaration_solver.txt @@ -20,7 +20,7 @@ in this algorithm. Enum types never have dependencies and can be completed on the spot. Enum values are put into a special scope that is created for each enum type and marked incomplete. -At this point the defines can be copied from the dedicated scope into the unit +At this point the dedicated scope for defines is reparented on the unit scope, shadowing the declarations from the source files. Next, aliases of enum types are detected and taken care of. Because an enum diff --git a/include/check.h b/include/check.h @@ -33,6 +33,7 @@ struct context { bool is_test; struct scope *unit; struct scope *scope; + struct scope *defines; bool deferring; int id; struct errors *errors; diff --git a/include/scope.h b/include/scope.h @@ -35,6 +35,7 @@ enum scope_class { SCOPE_MATCH, SCOPE_SUBUNIT, SCOPE_UNIT, + SCOPE_DEFINES, }; struct expression; diff --git a/src/check.c b/src/check.c @@ -3320,7 +3320,7 @@ check_const(struct context *ctx, } struct declaration *decl = xcalloc(1, sizeof(struct declaration)); const struct scope_object *obj = scope_lookup( - ctx->unit, &adecl->ident); + ctx->defines, &adecl->ident); decl->type = DECL_CONST; decl->constant.type = type; decl->constant.value = obj->value; @@ -3683,7 +3683,7 @@ scan_types(struct context *ctx, struct scope *imp, struct ast_decl *decl) scope_push((struct scope **)&type->_enum.values, SCOPE_ENUM); scan_enum_field(ctx, imp, type->_enum.values, type, t->type->_enum.values); - type->_enum.values->parent = ctx->unit; + type->_enum.values->parent = ctx->defines; idecl->obj.otype = O_TYPE; idecl->obj.type = type; } else { @@ -4171,7 +4171,7 @@ wrap_resolver(struct context *ctx, const struct scope_object *obj, struct incomplete_declaration *idecl = (struct incomplete_declaration *)obj; // load this declaration's subunit context - ctx->scope = ctx->unit; + ctx->scope = ctx->defines; ctx->unit->parent = idecl->imports; // resolving a declaration that is already in progress -> cycle @@ -4323,15 +4323,15 @@ check_internal(struct type_store *ts, // Put defines into a temporary scope (-D on the command line) ctx.scope = NULL; - ctx.unit = scope_push(&ctx.scope, SCOPE_UNIT); + ctx.unit = scope_push(&ctx.scope, SCOPE_DEFINES); for (struct ast_global_decl *def = defines; def; def = def->next) { struct incomplete_declaration *idecl = scan_const(&ctx, NULL, false , defineloc, def); resolve_const(&ctx, idecl); } - struct scope *def_scope = ctx.scope; + ctx.defines = ctx.scope; ctx.scope = NULL; - ctx.unit = scope_push(&ctx.scope, SCOPE_UNIT); + ctx.defines->parent = ctx.unit = scope_push(&ctx.scope, SCOPE_UNIT); // Populate the imports and put declarations into a scope. // Each declaration holds a reference to its subunit's imports @@ -4374,29 +4374,17 @@ check_internal(struct type_store *ts, next = &(*next)->next; } - // Put defines into unit scope - // We have to insert them *after* declarations, because this way they - // shadow declarations, not the other way around - // - // XXX: shadowed declarations are not checked for consistency - for (const struct scope_object *obj = def_scope->objects; - obj; obj = obj->lnext) { - if (obj->otype == O_SCAN) { - continue; - } - scope_insert(ctx.unit, O_CONST, &obj->ident, &obj->name, - obj->type, obj->value); - } - scope_free(def_scope); - // Find enum aliases and store them in incomplete enum value declarations for (const struct scope_object *obj = ctx.scope->objects; obj; obj = obj->lnext) { scan_enum_field_aliases(&ctx, obj); } + // XXX: shadowed declarations are not checked for consistency + ctx.scope = ctx.defines; + // Perform actual declaration resolution - for (const struct scope_object *obj = ctx.scope->objects; + for (const struct scope_object *obj = ctx.unit->objects; obj; obj = obj->lnext) { wrap_resolver(&ctx, obj, resolve_decl); } @@ -4415,7 +4403,7 @@ check_internal(struct type_store *ts, for (const struct ast_subunit *su = &aunit->subunits; su; su = su->next) { // subunit scope has to be *behind* unit scope - ctx.scope->parent = scope->scope; + ctx.unit->parent = scope->scope; next_decl = check_declarations(&ctx, su->decls, next_decl); scope = scope->next; } diff --git a/tests/36-defines.ha b/tests/36-defines.ha @@ -44,7 +44,7 @@ fn compatibility() void = { }; export fn main() void = { - // TODO: import(); + import(); mandatory(); optional(); // TODO: compatibility();