harec

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

commit b1f29e024d5c9efbe53ebe2d31153809bc9ec9af
parent 994a23184211b7f9b358e47f61886aa286d07d88
Author: Drew DeVault <sir@cmpwn.com>
Date:   Sun, 17 Jan 2021 14:43:51 -0500

Implement array expansion

Diffstat:
Minclude/type_store.h | 2+-
Minclude/types.h | 1-
Msrc/check.c | 17++++++++++++++---
Msrc/gen.c | 21+++++++++++++++++++--
Msrc/type_store.c | 3+--
Mtests/01-arrays.ha | 22++++++++++++++++++++++
6 files changed, 57 insertions(+), 9 deletions(-)

diff --git a/include/type_store.h b/include/type_store.h @@ -36,7 +36,7 @@ const struct type *type_store_lookup_pointer(struct type_store *store, const struct type *referent, unsigned int ptrflags); const struct type *type_store_lookup_array(struct type_store *store, - const struct type *members, size_t len, bool expandable); + const struct type *members, size_t len); const struct type *type_store_lookup_slice(struct type_store *store, const struct type *members); diff --git a/include/types.h b/include/types.h @@ -51,7 +51,6 @@ struct type_alias { struct type_array { size_t length; // SIZE_UNDEFINED for [*] or slices const struct type *members; - bool expandable; }; enum variadism { diff --git a/src/check.c b/src/check.c @@ -369,7 +369,7 @@ lower_vaargs(struct context *ctx, // XXX: This error handling is minimum-effort and bad const struct type *hint = type_store_lookup_array( - &ctx->store, type, SIZE_UNDEFINED, false); + &ctx->store, type, SIZE_UNDEFINED); check_expression(ctx, &val, vaargs, hint); assert(vaargs->result->storage == TYPE_STORAGE_ARRAY); expect(&val.loc, vaargs->result->array.members == type, @@ -521,7 +521,7 @@ check_expr_array(struct context *ctx, if (item->expand) { expandable = true; - cur->expand = true; + expr->constant.array->expand = true; assert(!item->next); } @@ -530,7 +530,18 @@ check_expr_array(struct context *ctx, ++len; } - expr->result = type_store_lookup_array(&ctx->store, type, len, expandable); + if (expandable) { + expect(&aexpr->loc, hint != NULL, + "Cannot expand array for inferred type"); + expect(&aexpr->loc, hint->storage == TYPE_STORAGE_ARRAY + && hint->array.length != SIZE_UNDEFINED + && hint->array.length >= len, + "Cannot expand array into destination type"); + expr->result = type_store_lookup_array(&ctx->store, + type, hint->array.length); + } else { + expr->result = type_store_lookup_array(&ctx->store, type, len); + } } static void diff --git a/src/gen.c b/src/gen.c @@ -992,7 +992,6 @@ gen_array(struct gen_context *ctx, const struct qbe_value *out) { const struct type *type = expr->result; - assert(!type->array.expandable); // Invariant // XXX: ARCH struct qbe_value ptr = {0}; @@ -1003,14 +1002,32 @@ gen_array(struct gen_context *ctx, struct qbe_value size = {0}; constl(&size, type->array.members->size); + size_t n = 0; struct array_constant *item = expr->constant.array; while (item) { gen_expression(ctx, item->value, &ptr); + ++n; if (item->next) { pushi(ctx->current, &ptr, Q_ADD, &ptr, &size, NULL); } item = item->next; } + + if (!expr->constant.array->expand) { + return; + } + + pushc(ctx->current, "expanding array to length %zd", type->array.length); + struct qbe_value last = {0}; + gen_loadtemp(ctx, &last, &ptr, + qtype_for_type(ctx, type->array.members, false), "expand.%d"); + if (type_is_aggregate(type->array.members)) { + ptr.type = last.type; + } + for (; n < type->array.length; ++n) { + pushi(ctx->current, &ptr, Q_ADD, &ptr, &size, NULL); + gen_store(ctx, &ptr, &last); + } } static void @@ -1751,7 +1768,7 @@ gen_data_item(struct gen_context *ctx, struct expression *expr, break; case TYPE_STORAGE_ARRAY: assert(type->array.length != SIZE_UNDEFINED); - assert(!type->array.expandable); // TODO + assert(!constant->array->expand); // TODO for (struct array_constant *c = constant->array; c; c = c->next) { gen_data_item(ctx, c->value, item); if (c->next) { diff --git a/src/type_store.c b/src/type_store.c @@ -744,14 +744,13 @@ type_store_lookup_pointer(struct type_store *store, const struct type * type_store_lookup_array(struct type_store *store, - const struct type *members, size_t len, bool expandable) + const struct type *members, size_t len) { struct type array = { .storage = TYPE_STORAGE_ARRAY, .array = { .members = members, .length = len, - .expandable = expandable, }, .size = len == SIZE_UNDEFINED ? SIZE_UNDEFINED : members->size * len, diff --git a/tests/01-arrays.ha b/tests/01-arrays.ha @@ -63,6 +63,27 @@ fn nested() void = { assert(x[1][0] == 5 && x[1][1] == 6); }; +fn expanded() void = { + let a: [5]int = [1337...]; + for (let i = 0z; i < len(a); i += 1z) { + assert(a[i] == 1337); + }; + + let b: [5]struct { x: int, y: int } = [struct { + x: int = 10, + y: int = 20, + }...]; + for (let i = 0z; i < len(b); i += 1z) { + assert(b[i].x == 10 && b[i].y == 20); + }; + + let c: [5]int = [1, 2, 3...]; + let expected = [1, 2, 3, 3, 3]; + for (let i = 0z; i < len(c); i += 1z) { + assert(c[i] == expected[i]); + }; +}; + export fn main() void = { indexing(); measurements(); @@ -71,4 +92,5 @@ export fn main() void = { assignment(); param([1, 2, 3]); nested(); + expanded(); };