harec

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit fbbfbf01d15fa9423774975489d671995896313f
parent a99611ac5b1f6837b16004a99faa5a5eaa7b30f1
Author: Drew DeVault <sir@cmpwn.com>
Date:   Sun, 24 Jan 2021 13:56:45 -0500

Implement recursive data structures

Diffstat:
Msrc/check.c | 47++++++++++++++++++++++++++++++++++-------------
Msrc/type_store.c | 33+++++++++++++++++++++++++++++----
Msrc/types.c | 1+
Mtests/07-aliases.ha | 13+++++++++++++
4 files changed, 77 insertions(+), 17 deletions(-)

diff --git a/src/check.c b/src/check.c @@ -368,12 +368,44 @@ check_expr_binding(struct context *ctx, }; struct expression *initializer = xcalloc(1, sizeof(struct expression)); + + struct identifier gen = {0}; + if (abinding->is_static) { + // Generate a static declaration identifier + int n = snprintf(NULL, 0, "static.%d", ctx->id); + gen.name = xcalloc(n + 1, 1); + snprintf(gen.name, n + 1, "static.%d", ctx->id); + ++ctx->id; + } + + if (type) { + // If the type is defined in advance, we can insert the + // object into the scope early, which is required for + // self-referencing objects. + if (!abinding->is_static) { + binding->object = scope_insert(ctx->scope, + O_BIND, &ident, &ident, type, NULL); + } else { + binding->object = scope_insert(ctx->scope, + O_DECL, &gen, &ident, type, NULL); + } + } + check_expression(ctx, abinding->initializer, initializer, type); if (!type) { type = type_store_lookup_with_flags(ctx->store, initializer->result, abinding->flags); + + if (!abinding->is_static) { + binding->object = scope_insert(ctx->scope, + O_BIND, &ident, &ident, type, NULL); + } else { + binding->object = scope_insert(ctx->scope, + O_DECL, &gen, &ident, type, NULL); + } } + expect(&aexpr->loc, type->size != 0 && type->size != SIZE_UNDEFINED, "Cannot create binding for type of zero or undefined size"); @@ -383,25 +415,14 @@ check_expr_binding(struct context *ctx, binding->initializer = lower_implicit_cast(type, initializer); - if (!abinding->is_static) { - binding->object = scope_insert(ctx->scope, O_BIND, - &ident, &ident, type, NULL); - } else { + if (abinding->is_static) { struct expression *value = xcalloc(1, sizeof(struct expression)); enum eval_result r = eval_expr(ctx, initializer, value); expect(&abinding->initializer->loc, r == EVAL_OK, "Unable to evaluate static initializer at compile time"); // TODO: Free initializer - initializer = value; - - struct identifier gen = {0}; - int n = snprintf(NULL, 0, "static.%d", ctx->id); - gen.name = xcalloc(n + 1, 1); - snprintf(gen.name, n + 1, "static.%d", ctx->id); - ++ctx->id; - binding->object = scope_insert(ctx->scope, O_DECL, - &gen, &ident, type, NULL); + binding->initializer = value; } if (abinding->next) { diff --git a/src/type_store.c b/src/type_store.c @@ -586,6 +586,8 @@ type_init_from_atype(struct type_store *store, type->flags = atype->flags; const struct scope_object *obj; + const struct identifier *ident; + struct identifier temp; switch (type->storage) { case TYPE_STORAGE_BOOL: case TYPE_STORAGE_CHAR: @@ -609,13 +611,29 @@ type_init_from_atype(struct type_store *store, case TYPE_STORAGE_VOID: assert(0); // Invariant case TYPE_STORAGE_ALIAS: - obj = scope_lookup(store->check_context->scope, &atype->alias); - assert(obj && obj->otype == O_TYPE); // TODO: Bubble this up + ident = &atype->alias; + if (ident->ns == NULL) { + temp = *ident; + temp.ns = store->check_context->ns; + ident = &temp; + } + + obj = scope_lookup(store->check_context->scope, ident); + if (!obj) { + identifier_dup(&type->alias.ident, ident); + type->alias.type = NULL; + type->size = SIZE_UNDEFINED; + type->align = SIZE_UNDEFINED; + return; + } + + assert(obj->otype == O_TYPE); // TODO: Bubble this up if (atype->unwrap) { *type = *type_dealias(obj->type); break; } - identifier_dup(&type->alias.ident, &atype->alias); + + identifier_dup(&type->alias.ident, ident); type->alias.type = obj->type; type->size = type->alias.type->size; type->align = type->alias.type->align; @@ -835,5 +853,12 @@ type_store_lookup_alias(struct type_store *store, .size = secondary->size, .align = secondary->align, }; - return type_store_lookup_type(store, &alias); + struct type *type = (struct type *)type_store_lookup_type(store, &alias); + if (type->alias.type == NULL) { + // Finish filling in forward referenced type + type->alias.type = secondary; + type->size = secondary->size; + type->align = secondary->align; + } + return type; } diff --git a/src/types.c b/src/types.c @@ -24,6 +24,7 @@ const struct type * type_dealias(const struct type *type) { while (type->storage == TYPE_STORAGE_ALIAS) { + assert(type->alias.type != NULL); type = type->alias.type; } return type; diff --git a/tests/07-aliases.ha b/tests/07-aliases.ha @@ -88,6 +88,18 @@ fn alias_alias() void = { assert(a[2] == 3, "alias alias"); }; +type recur = struct { + self: *recur, +}; + +fn recursive() void = { + let x: recur = struct { + self: *recur = &x, + }; + x.self = &x; + assert(x.self == x.self.self); +}; + export fn main() void = { alias_builtin(); alias_array(); @@ -95,4 +107,5 @@ export fn main() void = { alias_struct(); alias_tagged(); alias_alias(); + recursive(); };