harec

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

commit c9d3c524809560d697095515b2622206269bdec1
parent 3eee6de3c91f8118d90f3671614d2786bbe93d4f
Author: Armin Weigl <tb46305@gmail.com>
Date:   Sat,  3 Dec 2022 09:52:00 +0100

resolve: complete incomplete_declarations inplace

Fixes: https://todo.sr.ht/~sircmpwn/hare/769
Signed-off-by: Armin Weigl <tb46305@gmail.com>

Diffstat:
Minclude/check.h | 12++++++------
Msrc/check.c | 136+++++++++++++++++++++++++++++++------------------------------------------------
Msrc/type_store.c | 5++---
Msrc/typedef.c | 4+---
4 files changed, 62 insertions(+), 95 deletions(-)

diff --git a/include/check.h b/include/check.h @@ -110,7 +110,7 @@ struct incomplete_enum_field { // Keeps track of context required to resolve a declaration or an enum field // Extends the scope_object struct so it can be inserted into a scope struct incomplete_declaration { - const struct scope_object obj; + struct scope_object obj; struct scope *imports; // the scope of this declaration's subunit enum idecl_type type; bool in_progress; @@ -123,19 +123,19 @@ struct incomplete_declaration { void mkident(struct context *ctx, struct identifier *out, const struct identifier *in, const char *symbol); -typedef const struct scope_object *(*resolvefn)(struct context *, +typedef void (*resolvefn)(struct context *, struct incomplete_declaration *idecl); -const struct scope_object *resolve_dimensions(struct context *ctx, +void resolve_dimensions(struct context *ctx, struct incomplete_declaration *idecl); -const struct scope_object *resolve_type(struct context *ctx, +void resolve_type(struct context *ctx, struct incomplete_declaration *idecl); -const struct scope_object *resolve_decl(struct context *ctx, +void resolve_decl(struct context *ctx, struct incomplete_declaration *idecl); -const struct scope_object *wrap_resolver(struct context *ctx, +void wrap_resolver(struct context *ctx, const struct scope_object *obj, resolvefn resolver); struct scope *check(struct type_store *ts, diff --git a/src/check.c b/src/check.c @@ -166,10 +166,7 @@ check_expr_access(struct context *ctx, "Unknown object '%s'", buf); return; } - if (obj->otype == O_SCAN) { - // complete the declaration first - obj = wrap_resolver(ctx, obj, resolve_decl); - } + wrap_resolver(ctx, obj, resolve_decl); switch (obj->otype) { case O_CONST: @@ -2548,22 +2545,14 @@ check_expr_struct(struct context *ctx, if (aexpr->_struct.type.name) { const struct scope_object *obj = scope_lookup(ctx->scope, &aexpr->_struct.type); + // resolve the unknown type + wrap_resolver(ctx, obj, resolve_type); if (!obj) { error(ctx, aexpr->loc, expr, "Unknown type alias"); return; } - if (obj->otype == O_SCAN) { - // resolve the unknown type - obj = wrap_resolver(ctx, obj, resolve_type); - if (!obj) { - error(ctx, aexpr->loc, expr, - "Unknown type"); - return; - } - } - if (obj->otype != O_TYPE) { error(ctx, aexpr->loc, expr, "Name does not refer to a type"); @@ -3542,15 +3531,15 @@ scan_types(struct context *ctx, struct scope *imp, struct ast_decl *decl) scan_enum_field(ctx, imp, type->_enum.values, type, t->type->_enum.values); type->_enum.values->parent = ctx->unit; - scope_insert(ctx->scope, O_TYPE, &with_ns, - &t->ident, type, NULL); + idecl->obj.otype = O_TYPE; + idecl->obj.type = type; } else { idecl->type = IDECL_DECL; } } } -const struct scope_object * +void resolve_const(struct context *ctx, struct incomplete_declaration *idecl) { const struct ast_global_decl *decl = &idecl->decl.global; @@ -3590,11 +3579,12 @@ resolve_const(struct context *ctx, struct incomplete_declaration *idecl) "Null is not a valid type for a constant"); free(initializer); - return scope_insert(ctx->unit, O_CONST, &idecl->obj.ident, - &idecl->obj.name, type, value); + idecl->obj.otype = O_CONST; + idecl->obj.type = type; + idecl->obj.value = value; } -const struct scope_object * +void resolve_function(struct context *ctx, struct incomplete_declaration *idecl) { const struct ast_function_decl *decl = &idecl->decl.function; @@ -3607,11 +3597,11 @@ resolve_function(struct context *ctx, struct incomplete_declaration *idecl) const struct type *fntype = type_store_lookup_atype( ctx->store, &fn_atype); - return scope_insert(ctx->unit, O_DECL, &idecl->obj.ident, - &idecl->obj.name, fntype, NULL); + idecl->obj.otype = O_DECL; + idecl->obj.type = fntype; } -const struct scope_object * +void resolve_global(struct context *ctx, struct incomplete_declaration *idecl) { const struct ast_global_decl *decl = &idecl->decl.global; @@ -3649,13 +3639,12 @@ resolve_global(struct context *ctx, struct incomplete_declaration *idecl) expect(ctx, &decl->init->loc, type->storage != STORAGE_NULL, "Null is not a valid type for a global"); - struct scope_object *global = scope_insert(ctx->unit, O_DECL, - &idecl->obj.ident, &idecl->obj.name, type, NULL); - global->threadlocal = decl->threadlocal; - return global; + idecl->obj.otype = O_DECL; + idecl->obj.type = type; + idecl->obj.threadlocal = decl->threadlocal; } -const struct scope_object * +void resolve_enum_field(struct context *ctx, struct incomplete_declaration *idecl) { assert(idecl->type == IDECL_ENUM_FLD); @@ -3669,17 +3658,12 @@ resolve_enum_field(struct context *ctx, struct incomplete_declaration *idecl) const struct scope_object *new = scope_lookup(idecl->field->enum_scope, &localname); if (new != &idecl->obj) { - if (new->otype == O_SCAN) { - new = wrap_resolver(ctx, new, resolve_enum_field); - } + wrap_resolver(ctx, new, resolve_enum_field); assert(new->otype == O_CONST); - const struct scope_object *obj = scope_lookup(ctx->scope, - &idecl->obj.name); - if (obj->otype == O_SCAN) { - return scope_insert(ctx->scope, O_CONST, &obj->ident, - &obj->name, type, new->value); - } - return obj; + idecl->obj.otype = O_CONST; + idecl->obj.type = type; + idecl->obj.value = new->value; + return; } ctx->scope = idecl->field->enum_scope; @@ -3707,12 +3691,7 @@ resolve_enum_field(struct context *ctx, struct incomplete_declaration *idecl) } else { // implicit value const struct scope_object *obj = idecl->obj.lnext; // find previous enum value - if (obj && obj->otype == O_SCAN) { - // complete previous value first - obj = wrap_resolver(ctx, obj, resolve_enum_field); - } else { - obj = NULL; - } + wrap_resolver(ctx, obj, resolve_enum_field); value->type = EXPR_CONSTANT; if (type_is_signed(type_dealias(type))) { if (obj == NULL) { @@ -3729,8 +3708,9 @@ resolve_enum_field(struct context *ctx, struct incomplete_declaration *idecl) } } - return scope_insert(idecl->field->enum_scope, O_CONST, - &idecl->obj.ident, &idecl->obj.name, type, value); + idecl->obj.otype = O_CONST; + idecl->obj.type = type; + idecl->obj.value = value; } const struct type * @@ -3754,8 +3734,7 @@ lookup_enum_type(struct context *ctx, const struct scope_object *obj) } if (idecl->decl.type.type->storage == STORAGE_ENUM) { - enum_type = scope_lookup(ctx->scope, - &obj->name)->type; + assert(false); } else if (idecl->decl.type.type->storage == STORAGE_ALIAS) { ctx->scope->parent = idecl->imports; const struct identifier *alias = @@ -3800,13 +3779,10 @@ scan_enum_field_aliases(struct context *ctx, const struct scope_object *obj) // orig->type is (perhaps transitively) an alias of a resolved enum // type, which means its dependency graph is a linear chain of // resolved types ending with that enum, so we can immediately resolve it - obj = wrap_resolver(ctx, obj, resolve_type); + wrap_resolver(ctx, obj, resolve_type); for (const struct scope_object *val = enum_type->_enum.values->objects; val; val = val->lnext) { - if (val->otype != O_SCAN) { - continue; - } struct identifier name = { .name = val->name.name, .ns = (struct identifier *)&obj->name, @@ -3839,7 +3815,7 @@ scan_enum_field_aliases(struct context *ctx, const struct scope_object *obj) }; } -const struct scope_object * +void resolve_dimensions(struct context *ctx, struct incomplete_declaration *idecl) { if (idecl->type != IDECL_DECL || idecl->decl.decl_type != AST_DECL_TYPE) { @@ -3855,15 +3831,14 @@ resolve_dimensions(struct context *ctx, struct incomplete_declaration *idecl) } struct dimensions dim = type_store_lookup_dimensions(ctx->store, idecl->decl.type.type); - ((struct scope_object *)&idecl->obj)->type = xcalloc(1, sizeof(struct type)); + idecl->obj.type = xcalloc(1, sizeof(struct type)); *(struct type *)idecl->obj.type = (struct type){ .size = dim.size, .align = dim.align, }; - return &idecl->obj; } -const struct scope_object * +void resolve_type(struct context *ctx, struct incomplete_declaration *idecl) { if (idecl->type != IDECL_DECL || idecl->decl.decl_type != AST_DECL_TYPE) { @@ -3900,12 +3875,10 @@ resolve_type(struct context *ctx, struct incomplete_declaration *idecl) }; const struct type *alias = type_store_lookup_alias(ctx->store, &_alias); - const struct scope_object *ret = - scope_insert(ctx->scope, O_TYPE, &idecl->obj.ident, - &idecl->obj.name, alias, NULL); - ((struct type *)ret->type)->alias.type = + idecl->obj.otype = O_TYPE; + idecl->obj.type = alias; + ((struct type *)alias)->alias.type = type_store_lookup_atype(ctx->store, idecl->decl.type.type); - return ret; } static struct incomplete_declaration * @@ -3980,30 +3953,35 @@ scan_decl(struct context *ctx, struct scope *imports, struct ast_decl *decl) } } -const struct scope_object * +void resolve_decl(struct context *ctx, struct incomplete_declaration *idecl) { switch (idecl->type) { case IDECL_ENUM_FLD: - return resolve_enum_field(ctx, idecl); + resolve_enum_field(ctx, idecl); + return; case IDECL_DECL: break; } switch (idecl->decl.decl_type) { case AST_DECL_CONST: - return resolve_const(ctx, idecl); + resolve_const(ctx, idecl); + return; case AST_DECL_GLOBAL: - return resolve_global(ctx, idecl); + resolve_global(ctx, idecl); + return; case AST_DECL_FUNC: - return resolve_function(ctx, idecl); + resolve_function(ctx, idecl); + return; case AST_DECL_TYPE: - return resolve_type(ctx, idecl); + resolve_type(ctx, idecl); + return; } abort(); } -const struct scope_object * +void wrap_resolver(struct context *ctx, const struct scope_object *obj, resolvefn resolver) { @@ -4013,12 +3991,12 @@ wrap_resolver(struct context *ctx, const struct scope_object *obj, ctx->unit->parent = NULL; // ensure this declaration wasn't already scanned - struct incomplete_declaration *idecl = (struct incomplete_declaration *)obj; - obj = scope_lookup(ctx->scope, &idecl->obj.name); - if (obj && obj->otype != O_SCAN) { + if (!obj || obj->otype != O_SCAN) { goto exit; } + struct incomplete_declaration *idecl = (struct incomplete_declaration *)obj; + // load this declaration's subunit context ctx->scope = ctx->unit; ctx->unit->parent = idecl->imports; @@ -4037,13 +4015,13 @@ wrap_resolver(struct context *ctx, const struct scope_object *obj, } idecl->in_progress = true; - obj = resolver(ctx, idecl); + resolver(ctx, idecl); + + idecl->in_progress = false; exit: // load stored context ctx->unit->parent = subunit; ctx->scope = scope; - idecl->in_progress = false; - return obj; } static void @@ -4109,9 +4087,7 @@ load_import(struct context *ctx, struct ast_global_decl *defines, } else { for (struct scope_object *obj = mod->objects; obj; obj = obj->lnext) { - if (obj->otype == O_SCAN) { - continue; - } + assert(obj->otype != O_SCAN); struct scope_object *new; if (!(import->mode & AST_IMPORT_ALIAS) @@ -4243,18 +4219,12 @@ check_internal(struct type_store *ts, // Find enum aliases and store them in incomplete enum value declarations for (const struct scope_object *obj = ctx.scope->objects; obj; obj = obj->lnext) { - if (obj->otype != O_SCAN) { - continue; - } scan_enum_field_aliases(&ctx, obj); } // Perform actual declaration resolution for (const struct scope_object *obj = ctx.scope->objects; obj; obj = obj->lnext) { - if (obj->otype != O_SCAN) { - continue; - } wrap_resolver(&ctx, obj, resolve_decl); } diff --git a/src/type_store.c b/src/type_store.c @@ -695,15 +695,14 @@ type_init_from_atype(struct type_store *store, struct incomplete_declaration *idecl = (struct incomplete_declaration *)obj; if (size_only && idecl->type == IDECL_DECL) { - obj = wrap_resolver(store->check_context, obj, + wrap_resolver(store->check_context, obj, resolve_dimensions); type->size = obj->type->size; type->align = obj->type->align; break; } // complete it first and then proceed normally - obj = wrap_resolver(store->check_context, - obj, resolve_type); + wrap_resolver(store->check_context, obj, resolve_type); } if (obj->otype != O_TYPE) { diff --git a/src/typedef.c b/src/typedef.c @@ -437,9 +437,7 @@ emit_decl_type(struct declaration *decl, FILE *out) type_storage_unparse(type->alias.type->storage)); for (const struct scope_object *ev = type->_enum.values->objects; ev; ev = ev->lnext) { - if (ev->otype == O_SCAN) { - continue; - } + assert(ev->otype != O_SCAN); fprintf(out, "%s = ", ev->name.name); emit_const(ev->value, out); fprintf(out, ", ");