commit b1f29e024d5c9efbe53ebe2d31153809bc9ec9af
parent 994a23184211b7f9b358e47f61886aa286d07d88
Author: Drew DeVault <sir@cmpwn.com>
Date: Sun, 17 Jan 2021 14:43:51 -0500
Implement array expansion
Diffstat:
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();
};