harec

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

commit 10060824bc60fb02d532cffdf8fb0a989aff391a
parent 553c994eadc52936d2a65f367c522de9646643c8
Author: Drew DeVault <sir@cmpwn.com>
Date:   Sun, 31 Jan 2021 16:06:00 -0500

Implement context-defined array lengths

Diffstat:
Minclude/ast.h | 1+
Minclude/lex.h | 1+
Minclude/types.h | 2+-
Mrt/abort.ha | 2+-
Msrc/check.c | 40++++++++++++++++++++++++++++++++++++----
Msrc/lex.c | 1+
Msrc/parse.c | 7+++++++
7 files changed, 48 insertions(+), 6 deletions(-)

diff --git a/include/ast.h b/include/ast.h @@ -27,6 +27,7 @@ struct ast_imports { struct ast_list_type { struct ast_expression *length; // NULL for slices and unbounded arrays struct ast_type *members; + bool contextual; }; struct ast_enum_field { diff --git a/include/lex.h b/include/lex.h @@ -11,6 +11,7 @@ enum lexical_token { T_ATTR_NORETURN, T_ATTR_SYMBOL, T_ATTR_TEST, + T_UNDERSCORE, T_ABORT, T_ALLOC, T_APPEND, diff --git a/include/types.h b/include/types.h @@ -49,7 +49,7 @@ struct type_alias { }; struct type_array { - size_t length; // SIZE_UNDEFINED for [*] or slices + size_t length; // SIZE_UNDEFINED for [*] and slices const struct type *members; }; diff --git a/rt/abort.ha b/rt/abort.ha @@ -7,7 +7,7 @@ export @noreturn @symbol("rt.abort") fn _abort(msg: str) void = { }; // See include/gen.h -const reasons: [3]str = [ +const reasons: [_]str = [ "slice or array access out of bounds", // 0 "type assertion failed", // 1 "allocation failed", // 2 diff --git a/src/check.c b/src/check.c @@ -376,7 +376,10 @@ check_expr_binding(struct context *ctx, ++ctx->id; } - if (type) { + bool context = abinding->type + && abinding->type->storage == TYPE_STORAGE_ARRAY + && abinding->type->array.contextual; + if (type && !context) { // If the type is defined in advance, we can insert the // object into the scope early, which is required for // self-referencing objects. @@ -391,9 +394,21 @@ check_expr_binding(struct context *ctx, check_expression(ctx, abinding->initializer, initializer, type); - if (!type) { - type = type_store_lookup_with_flags(ctx->store, - initializer->result, abinding->flags); + if (context) { + expect(&aexpr->loc, + initializer->result->storage == TYPE_STORAGE_ARRAY, + "Cannot infer array length from non-array type"); + expect(&aexpr->loc, + initializer->result->array.members == type->array.members, + "Initializer is not assignable to binding type"); + type = initializer->result; + } + + if (context || !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, @@ -1581,12 +1596,29 @@ check_global(struct context *ctx, const struct type *type = type_store_lookup_atype( ctx->store, agdecl->type); + bool context = agdecl->type->storage == TYPE_STORAGE_ARRAY + && agdecl->type->array.contextual; // TODO: Free initialier struct expression *initializer = xcalloc(1, sizeof(struct expression)); check_expression(ctx, agdecl->init, initializer, type); + if (context) { + expect(&agdecl->init->loc, + initializer->result->storage == TYPE_STORAGE_ARRAY, + "Cannot infer array length from non-array type"); + expect(&agdecl->init->loc, + initializer->result->array.members == type->array.members, + "Initializer is not assignable to binding type"); + type = initializer->result; + + // Update type of object (drops const, hack!) + struct scope_object *obj = (struct scope_object *)scope_lookup( + ctx->scope, &agdecl->ident); + obj->type = type; + } + expect(&agdecl->init->loc, type_is_assignable(type, initializer->result), "Constant type is not assignable from initializer type"); diff --git a/src/lex.c b/src/lex.c @@ -20,6 +20,7 @@ static const char *tokens[] = { [T_ATTR_NORETURN] = "@noreturn", [T_ATTR_SYMBOL] = "@symbol", [T_ATTR_TEST] = "@test", + [T_UNDERSCORE] = "_", [T_ABORT] = "abort", [T_ALLOC] = "alloc", [T_APPEND] = "append", diff --git a/src/parse.c b/src/parse.c @@ -631,6 +631,13 @@ parse_type(struct lexer *lexer) want(lexer, T_RBRACKET, NULL); type->array.members = parse_type(lexer); break; + case T_UNDERSCORE: + type->storage = TYPE_STORAGE_ARRAY; + type->array.length = NULL; + type->array.contextual = true; + want(lexer, T_RBRACKET, NULL); + type->array.members = parse_type(lexer); + break; default: type->storage = TYPE_STORAGE_ARRAY; unlex(lexer, &tok);