harec

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

commit 2b53ab23f3270c51d93b4b3ff300c65843a2a0a1
parent a53c0817a301913ec8242a2f472fad7968c9ee95
Author: Eyal Sawady <ecs@d2evs.net>
Date:   Sun, 14 Feb 2021 14:17:01 -0500

Implement slice assignment

Diffstat:
Msrc/check.c | 5+++++
Msrc/gen.c | 53++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mtests/08-slices.ha | 15+++++++++++++++
3 files changed, 72 insertions(+), 1 deletion(-)

diff --git a/src/check.c b/src/check.c @@ -374,6 +374,11 @@ check_expr_assign(struct context *ctx, check_expression(ctx, aexpr->assign.value, value, object->result); assert(object->type == EXPR_ACCESS || object->type == EXPR_SLICE); // Invariant + if (object->type == EXPR_SLICE) { + expect(&aexpr->assign.object->loc, + expr->assign.op == BIN_LEQUAL, + "Slice assignments may not have a binop"); + } expect(&aexpr->loc, !(object->result->flags & TYPE_CONST), "Cannot assign to const object"); expect(&aexpr->loc, diff --git a/src/gen.c b/src/gen.c @@ -750,7 +750,58 @@ gen_expr_assign_slice(struct gen_context *ctx, const struct expression *expr, const struct qbe_value *out) { - assert(0); // TODO + struct qbe_value obj = {0}, val = {0}, temp = {0}; + assert(expr->assign.op == BIN_LEQUAL && !expr->assign.indirect); + constl(&temp, builtin_type_size.size); + alloc_temp(ctx, &obj, expr->assign.object->result, "assign.object.%d"); + alloc_temp(ctx, &val,expr->assign.value->result, "assign.value.%d"); + gen_expression(ctx, expr->assign.object, &obj); + gen_expression(ctx, expr->assign.value, &val); + + struct qbe_value ptr = {0}, olen = {0}, vlen = {0}; + gen_temp(ctx, &ptr, &qbe_long, "assign.lenptr.%d"); + gen_temp(ctx, &olen, &qbe_long, "assign.olen.%d"); + gen_temp(ctx, &vlen, &qbe_long, "assign.vlen.%d"); + + qval_deref(&obj); + qval_deref(&val); + pushi(ctx->current, &ptr, Q_COPY, &obj, NULL); + pushi(ctx->current, &ptr, Q_ADD, &ptr, &temp, NULL); + pushi(ctx->current, &olen, Q_LOADL, &ptr, NULL); + pushi(ctx->current, &ptr, Q_COPY, &val, NULL); + pushi(ctx->current, &ptr, Q_ADD, &ptr, &temp, NULL); + pushi(ctx->current, &vlen, Q_LOADL, &ptr, NULL); + + struct qbe_statement equall = {0}, diffl = {0}; + struct qbe_value bequal = {0}, bdiff = {0}; + bequal.kind = QV_LABEL; + bequal.name = strdup(genl(&equall, &ctx->id, "equal.%d")); + bdiff.kind = QV_LABEL; + bdiff.name = strdup(genl(&diffl, &ctx->id, "diff.%d")); + gen_temp(ctx, &temp, &qbe_long, "assign.equal.%d"); + pushi(ctx->current, &temp, Q_SUB, &olen, &vlen, NULL); + pushi(ctx->current, NULL, Q_JNZ, &temp, &bdiff, &bequal, NULL); + push(&ctx->current->body, &diffl); + + struct qbe_value rtabort = {0}; + rtabort.kind = QV_GLOBAL; + rtabort.name = strdup("rt.abort_fixed"); + rtabort.type = &qbe_long; + constl(&temp, 0); + pushi(ctx->current, NULL, Q_CALL, &rtabort, &temp, NULL); + push(&ctx->current->body, &equall); + + struct qbe_value rtmemcpy = {0}, optr = {0}, vptr = {0}; + rtmemcpy.kind = QV_GLOBAL; + rtmemcpy.name = strdup("rt.memcpy"); + rtmemcpy.type = &qbe_long; + gen_temp(ctx, &optr, &qbe_long, "assign.optr.%d"); + pushi(ctx->current, &optr, Q_LOADL, &obj, NULL); + gen_temp(ctx, &vptr, &qbe_long, "assign.vptr.%d"); + pushi(ctx->current, &vptr, Q_LOADL, &val, NULL); + constl(&temp, expr->assign.object->result->array.members->size); + pushi(ctx->current, &olen, Q_MUL, &olen, &temp, NULL); + pushi(ctx->current, NULL, Q_CALL, &rtmemcpy, &optr, &vptr, &olen, NULL); } static void diff --git a/tests/08-slices.ha b/tests/08-slices.ha @@ -55,6 +55,10 @@ fn indexing() void = { ) != 0, "indexing non-array, non-slice object"); }; +fn zero3(s: []int) void = { + s[..] = [0, 0, 0]; +}; + fn assignment() void = { let source = [1, 2, 3]; let x: []int = source; @@ -70,6 +74,17 @@ fn assignment() void = { x[2] = 9; assert(x[0] == 7 && x[1] == 8 && x[2] == 9); assert(source[0] == 4 && source[1] == 5 && source[2] == 6); + + zero3(y); + assert(y[0] == 0 && y[1] == 0 && y[2] == 0); + let z: []int = [1, 2, 3, 4, 5]; + z[1..4] = [42, 69, 1337]; + assert(z[0] == 1 && z[1] == 42 && z[2] == 69 && z[3] == 1337 && z[4] == 5); + z[2..5] = y; + assert(z[0] == 1 && z[1] == 42 && z[2] == 0 && z[3] == 0 && z[4] == 0); + assert(rt::compile( + "export fn main() void = { let a: []int = [1]; a[..] += a; };" + ) != 0, "binop slice assignment"); }; fn assert_slice_eq(actual: []int, expected: []int) void = {