harec

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

commit 716dad41aebc0dc43aaead5e091a811c2b7081f0
parent c1adb055de5d65842866e689754e16a2eae4d386
Author: Drew DeVault <sir@cmpwn.com>
Date:   Sun, 25 Jul 2021 09:35:55 +0200

gen: fix non-access field/index expressions

Signed-off-by: Drew DeVault <sir@cmpwn.com>

Diffstat:
Msrc/gen.c | 28+++++++++++++++++++++++-----
Mtests/903-postfix.ha | 36++++++++++++++++++++++++++++++++++++
2 files changed, 59 insertions(+), 5 deletions(-)

diff --git a/src/gen.c b/src/gen.c @@ -220,16 +220,26 @@ gen_address_field(struct gen_context *ctx, struct gen_temp *temp, assert(access->type == ACCESS_FIELD); const struct expression *object = access->_struct; - assert(object->type == EXPR_ACCESS); // TODO: Other cases? + // XXX: If gen_temp had an "allocate before use" flag, we might be able + // to avoid allocating it here. It remains to be seen if this would be + // useful; other expressions will tell (such as len() or casts). struct gen_temp base = {0}; - struct qbe_value qbase = {0}, field = {0}, offset = {0}; - gen_access_address(ctx, &base, object); + if (object->type == EXPR_ACCESS) { + gen_access_address(ctx, &base, object); + } else { + alloc_temp(ctx, &base, object->result, "fieldtemp.%d"); + gen_expr(ctx, object, &base); + } + gen_auto_deref(ctx, &base); + + struct qbe_value qbase = {0}, field = {0}, offset = {0}; qval_temp(ctx, &qbase, &base); gen_qtemp(ctx, &field, ctx->arch.ptr, "field.%d"); constl(&offset, access->field->offset); pushi(ctx->current, &field, Q_ADD, &qbase, &offset, NULL); + temp->name = field.name; temp->type = access->field->type; temp->indirect = true; @@ -244,10 +254,18 @@ gen_address_index(struct gen_context *ctx, struct gen_temp *temp, const struct type *atype = type_dereference(access->array->result); assert(atype->storage == STORAGE_ARRAY); const struct expression *object = access->array; - assert(object->type == EXPR_ACCESS); // TODO: Other cases? + // XXX: If gen_temp had an "allocate before use" flag, we might be able + // to avoid allocating it here. It remains to be seen if this would be + // useful; other expressions will tell (such as len() or casts). struct gen_temp base = {0}; - gen_access_address(ctx, &base, object); + if (object->type == EXPR_ACCESS) { + gen_access_address(ctx, &base, object); + } else { + alloc_temp(ctx, &base, object->result, "indextemp.%d"); + gen_expr(ctx, object, &base); + } + gen_auto_deref(ctx, &base); struct gen_temp index = {0}; diff --git a/tests/903-postfix.ha b/tests/903-postfix.ha @@ -1,10 +1,44 @@ type coords = struct { x: size, y: size }; +type coords3 = struct { _2: coords, z: size }; fn foo() size = 2; fn equal(x: int, y: int) bool = x == y; fn aggregate(c: coords) coords = c; fn not(x: bool) bool = x == false; +fn nested() void = { + let c = coords3 { + _2 = coords { + x = 10, + y = 20, + }, + z = 30, + }; + assert(c._2.x == 10); + assert(c._2.y == 20); + assert(c.z == 30); + + let x = coords { x = 10, y = 20 }; + let a = [x, x, x, x]; + assert(a[0].x == 10); + assert(a[0].y == 20); + assert(a[1].x == 10); + assert(a[1].y == 20); + assert(a[2].x == 10); + assert(a[2].y == 20); + assert(a[3].x == 10); + assert(a[3].y == 20); +}; + +fn nonaccess() void = { + let c = coords { x = 10, y = 20 }; + assert(aggregate(coords { x = 10, y = 20 }).x == 10); + assert(aggregate(c).y == 20); + assert(coords { x = 10, y = 20 }.x == 10); + assert(coords { x = 10, y = 20 }.y == 20); + assert([1, 2, 3, 4][2] == 3); +}; + fn deref() void = { let a = coords { x = 10, y = 20 }; let b = &a; @@ -54,6 +88,8 @@ fn calls() void = { }; export fn main() int = { + nested(); + nonaccess(); deref(); calls(); return 0;