commit fbbfbf01d15fa9423774975489d671995896313f
parent a99611ac5b1f6837b16004a99faa5a5eaa7b30f1
Author: Drew DeVault <sir@cmpwn.com>
Date: Sun, 24 Jan 2021 13:56:45 -0500
Implement recursive data structures
Diffstat:
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();
};