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:
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);