harec

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

commit 5ea0e291896fa9cf6b67af8c5089ada284f47b8c
parent 84edc0f7c3394bf46b59e52a7ee48f9a7605b9d6
Author: Bor Grošelj Simić <bgs@turminal.net>
Date:   Sat, 21 May 2022 03:03:06 +0200

implement enum aliases

Signed-off-by: Bor Grošelj Simić <bgs@turminal.net>

Diffstat:
Minclude/check.h | 1+
Minclude/types.h | 5+++--
Msrc/check.c | 113+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
Msrc/type_store.c | 3+--
Msrc/typedef.c | 4++--
Mtestmod/testmod.ha | 8++++++++
Mtests/15-enums.ha | 25+++++++++++++++++++++++++
7 files changed, 148 insertions(+), 11 deletions(-)

diff --git a/include/check.h b/include/check.h @@ -126,6 +126,7 @@ struct incomplete_declaration { struct { struct ast_decl decl; struct scope *enum_values; + struct identifiers *enum_aliases; }; struct incomplete_enum_field *field; }; diff --git a/include/types.h b/include/types.h @@ -72,7 +72,8 @@ struct type_enum_value { }; struct type_enum { - struct type_enum_value *values; + struct scope *values; + struct identifiers *aliases; }; enum variadism { @@ -156,7 +157,7 @@ struct type { union { struct { struct type_alias alias; - struct scope *enum_values; + struct type_enum _enum; }; struct type_array array; struct type_func func; diff --git a/src/check.c b/src/check.c @@ -3102,12 +3102,11 @@ check_type(struct context *ctx, decl->type = DECL_TYPE; const struct type *type = type_store_lookup_atype(ctx->store, adecl->type); - if (type->storage == STORAGE_ENUM) { + if (adecl->type->storage == STORAGE_ENUM) { decl->_type = type; } else { struct type _alias = { - .storage = type->storage == STORAGE_ENUM ? - STORAGE_ENUM : STORAGE_ALIAS, + .storage = STORAGE_ALIAS, .alias = { .ident = decl->ident, .name = adecl->ident, @@ -3462,17 +3461,111 @@ scan_enum_field(struct context *ctx, struct incomplete_declaration *idecl) } ctx->resolving_enum = NULL; + for (struct identifiers *id = type->_enum.aliases; id; id = id->next) { + const struct scope_object *obj = scope_lookup(ctx->scope, &id->ident); + if (obj->otype == O_SCAN) { + obj = scan_decl_finish(ctx, obj, NULL); + } + struct identifier alias_ident, alias_name = { + .name = name.name, + .ns = &id->ident, + }; + mkident(ctx, &alias_ident, &alias_name); + scope_insert(ctx->scope, O_CONST, &alias_ident, + &alias_name, obj->type, value); + } + scope_insert(idecl->field->enum_scope, O_CONST, &name, &localname, type, value); return scope_insert(ctx->scope, O_CONST, &ident, &name, type, value); } +void +enum_alias_list(struct context *ctx, const struct scope_object *obj, + struct identifiers *ids) +{ + struct incomplete_declaration *idecl; + const struct type *type; + switch (obj->otype) { + case O_SCAN: + idecl = (struct incomplete_declaration *)obj; + switch (idecl->type) { + case IDECL_ENUM_FLD: + return; + case IDECL_ENUM_TYPE: + if (!idecl->enum_aliases) { + idecl->enum_aliases = ids; + } else { + struct identifiers *id; + for (id = idecl->enum_aliases; + id->next; id = id->next); + id->next = ids; + } + return; + case IDECL_DECL: + if (idecl->decl.decl_type != AST_DECL_TYPE) { + return; + } + if (idecl->decl.type.type->storage != STORAGE_ALIAS) { + return; + } + struct identifiers *new = xcalloc(1, sizeof(struct identifiers)); + identifier_dup(&new->ident, &idecl->decl.type.ident); new->next = ids; + ids = new; + + struct scope *subunit = ctx->unit->parent; + ctx->unit->parent = idecl->imports; + obj = scope_lookup(ctx->scope, &idecl->decl.type.type->alias); + if (!obj) { + struct identifier *ident = + &idecl->decl.type.type->alias; + error(ctx, idecl->decl.loc, NULL, + "Unknown object '%s'", + identifier_unparse(ident)); + return; + } + ctx->unit->parent = subunit; + enum_alias_list(ctx, obj, ids); + break; + } + break; + case O_TYPE: + type = type_dealias(obj->type); + if (type->storage != STORAGE_ENUM) { + return; + } + for (; ids; ids = ids->next) { + const struct scope_object *alias = + scope_lookup(ctx->scope, &ids->ident); + if (alias->otype == O_SCAN) { + alias = scan_decl_finish(ctx, alias, NULL); + } + for (obj = type->_enum.values->objects; + obj; obj = obj->lnext) { + struct identifier ident, name = { + .name = obj->name.name, + .ns = &ids->ident, + }; + mkident(ctx, &ident, &name); + scope_insert(ctx->scope, O_CONST, &ident, &name, + alias->type, obj->value); + } + } + break; + case O_BIND: + case O_CONST: + case O_DECL: + return; + } +} + static const struct scope_object * scan_enum_type(struct context *ctx, struct incomplete_declaration *idecl) { assert(idecl->type == IDECL_ENUM_TYPE); struct type *type = (struct type *)type_store_lookup_atype(ctx->store, idecl->decl.type.type); - type->enum_values = idecl->enum_values; + type->_enum.values = idecl->enum_values; + type->_enum.aliases = idecl->enum_aliases; type->alias.exported = idecl->decl.exported; type_store_lookup_alias(ctx->store, type); return scope_insert(ctx->scope, O_TYPE, @@ -3505,7 +3598,6 @@ scan_type(struct context *ctx, struct ast_type_decl *decl, bool exported, scope_insert(ctx->scope, O_TYPE, &ident, &decl->ident, alias, NULL); ((struct type *)ret->type)->alias.type = type_store_lookup_atype(ctx->store, decl->type); - assert(alias->alias.type->storage != STORAGE_ENUM); return ret; } @@ -3852,6 +3944,17 @@ check_internal(struct type_store *ts, } 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) { + struct incomplete_declaration *idecl = + (struct incomplete_declaration *)obj; + if (idecl->type == IDECL_DECL + && idecl->decl.decl_type == AST_DECL_TYPE) { + enum_alias_list(&ctx, obj, NULL); + } + } + // Perform actual declaration resolution ctx.resolving_enum = NULL; for (const struct scope_object *obj = ctx.scope->objects; diff --git a/src/type_store.c b/src/type_store.c @@ -668,8 +668,7 @@ type_init_from_atype(struct type_store *store, type->storage = obj->type->storage; if (obj->type->storage == STORAGE_ENUM) { - assert(obj->type->enum_values); - type->enum_values = obj->type->enum_values; + type->_enum = obj->type->_enum; } else if (atype->unwrap) { *type = *type_dealias(obj->type); break; diff --git a/src/typedef.c b/src/typedef.c @@ -124,7 +124,7 @@ emit_const(const struct expression *expr, FILE *out) case STORAGE_ENUM: assert(expr->result->storage == STORAGE_ENUM); struct scope_object *ev = - type_dealias(expr->result)->enum_values->objects; + type_dealias(expr->result)->_enum.values->objects; for(; ev; ev = ev->lnext) { if (ev->otype == O_SCAN) { continue; @@ -413,7 +413,7 @@ emit_decl_type(struct declaration *decl, FILE *out) const struct type *type = decl->_type; fprintf(out, "enum %s { ", type_storage_unparse(type->alias.type->storage)); - for (const struct scope_object *ev = type->enum_values->objects; + for (const struct scope_object *ev = type->_enum.values->objects; ev; ev = ev->lnext) { if (ev->otype == O_SCAN) { continue; diff --git a/testmod/testmod.ha b/testmod/testmod.ha @@ -1,2 +1,10 @@ +export type _enum = enum { + ONE = 1, + TWO = 2, + THREE = 3, +}; + +export type enum_alias = _enum; + export fn testfunc1() void = void; export fn testfunc2() void = void; diff --git a/tests/15-enums.ha b/tests/15-enums.ha @@ -1,4 +1,5 @@ use rt; +use testmod; type implicit_values = enum { ZERO, @@ -84,10 +85,34 @@ fn interdependent() void = { assert(interdependent2::C == 5); }; +type alias = with_storage; + +type imported_alias = testmod::_enum; + +type imported_double_alias = testmod::enum_alias; + +fn aliases() void = { + assert(size(alias) == size(with_storage)); + assert(alias::CAFE == with_storage::CAFE); + assert(alias::BABE == with_storage::BABE); + assert(alias::DEAD == with_storage::DEAD); + assert(alias::BEEF == with_storage::BEEF); + + // test with alias of imported enum + assert(imported_alias::ONE == testmod::_enum::ONE); + assert(imported_alias::TWO == testmod::_enum::TWO); + assert(imported_alias::THREE == testmod::_enum::THREE); + + assert(imported_double_alias::ONE == testmod::_enum::ONE); + assert(imported_double_alias::TWO == testmod::_enum::TWO); + assert(imported_double_alias::THREE == testmod::_enum::THREE); +}; + export fn main() void = { implicit(); explicit(); storage(); reject(); interdependent(); + aliases(); };