harec

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

commit 19e55ef41c885c9e21d9b869d0c5f60aca8a55c2
parent a5d269eb7ca97a40903ee5f6993035909131538a
Author: Drew DeVault <sir@cmpwn.com>
Date:   Wed, 28 Apr 2021 11:40:46 -0400

gen: implement variadic insert

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

Diffstat:
Msrc/check.c | 12++++++------
Msrc/gen.c | 36++++++++++++++++++++++++++++++++++--
Mtests/28-insert.ha | 16+++++++++++++++-
3 files changed, 55 insertions(+), 9 deletions(-)

diff --git a/src/check.c b/src/check.c @@ -1633,16 +1633,16 @@ check_expr_insert(struct context *ctx, next = &value->next; } if (aexpr->insert.variadic != NULL) { - const struct type *type = expr->insert.expr->result; expr->insert.variadic = xcalloc(sizeof(struct expression), 1); errors = check_expression(ctx, aexpr->insert.variadic, - expr->insert.variadic, type, errors); - if (!type_is_assignable(type, expr->insert.variadic->result)) { + expr->insert.variadic, sltype, errors); + if (!type_is_assignable(sltype, expr->insert.variadic->result)) { return error(aexpr->insert.variadic->loc, expr, errors, - "inserted slice must be assignable to slice type"); + "inserted slice type %s must be assignable to slice type", + type_storage_unparse(expr->insert.variadic->result->storage)); } - expr->insert.variadic = - lower_implicit_cast(type, expr->insert.variadic); + expr->insert.variadic = lower_implicit_cast( + sltype, expr->insert.variadic); } return errors; } diff --git a/src/gen.c b/src/gen.c @@ -1921,7 +1921,6 @@ gen_expr_insert(struct gen_context *ctx, const struct qbe_value *out) { assert(expr->type == EXPR_INSERT); - assert(!expr->insert.variadic); // TODO struct qbe_value val = {0}, temp = {0}; gen_temp(ctx, &val, &qbe_long, "insert.val.%d"); @@ -1951,13 +1950,34 @@ gen_expr_insert(struct gen_context *ctx, pushi(ctx->current, &lenptr, Q_ADD, &lenptr, &temp, NULL); qval_deref(&lenptr); gen_loadtemp(ctx, &len, &lenptr, &qbe_long, false); + + struct qbe_value variadic = {0}, vptr = {0}, vlen = {0}; + pushi(ctx->current, &newlen, Q_COPY, &len, NULL); + size_t args = 0; for (struct append_values *value = expr->insert.values; value; value = value->next) { args++; } constl(&nadd, args); - pushi(ctx->current, &newlen, Q_ADD, &len, &nadd, NULL); + pushi(ctx->current, &newlen, Q_ADD, &newlen, &nadd, NULL); + + if (expr->insert.variadic) { + struct qbe_value vlenptr = {0}; + alloc_temp(ctx, &variadic, + expr->insert.variadic->result, "insert.variadic.%d"); + gen_expression(ctx, expr->insert.variadic, &variadic); + qval_deref(&variadic); + gen_loadtemp(ctx, &vptr, &variadic, &qbe_long, false); + qval_deref(&vptr); + gen_temp(ctx, &vlenptr, &qbe_long, "insert.vlenptr.%d"); + constl(&temp, builtin_type_size.size); + pushi(ctx->current, &vlenptr, Q_ADD, &vptr, &temp, NULL); + qval_deref(&vlenptr); + gen_loadtemp(ctx, &vlen, &vlenptr, &qbe_long, false); + pushi(ctx->current, &newlen, Q_ADD, &newlen, &vlen, NULL); + } + gen_store(ctx, &lenptr, &newlen); struct qbe_value rtfunc = {0}, membsz = {0}; @@ -1984,6 +2004,10 @@ gen_expr_insert(struct gen_context *ctx, pushi(ctx->current, &ncopy, Q_MUL, &len, &membsz, NULL); pushi(ctx->current, &ncopy, Q_SUB, &ncopy, &index, NULL); pushi(ctx->current, &nbytes, Q_MUL, &nadd, &membsz, NULL); + if (expr->insert.variadic) { + pushi(ctx->current, &vlen, Q_MUL, &vlen, &membsz, NULL); + pushi(ctx->current, &nbytes, Q_ADD, &nbytes, &vlen, NULL); + } pushi(ctx->current, &dest, Q_ADD, &dest, &nbytes, NULL); rtfunc.name = strdup("rt.memmove"); pushi(ctx->current, NULL, Q_CALL, &rtfunc, &dest, &ptr, &ncopy, NULL); @@ -2000,6 +2024,14 @@ gen_expr_insert(struct gen_context *ctx, ptr.type = &qbe_long; pushi(ctx->current, &ptr, Q_ADD, &ptr, &membsz, NULL); } + if (expr->append.variadic) { + struct qbe_value rtmemcpy = {0}, v = {0}; + gen_loadtemp(ctx, &v, &vptr, &qbe_long, false); + rtmemcpy.kind = QV_GLOBAL; + rtmemcpy.name = strdup("rt.memcpy"); + rtmemcpy.type = &qbe_long; + pushi(ctx->current, NULL, Q_CALL, &rtmemcpy, &ptr, &v, &vlen, NULL); + } } static void diff --git a/tests/28-insert.ha b/tests/28-insert.ha @@ -24,7 +24,21 @@ fn basics() void = { assert(sleq(x, [1, 2, 7, 8, 9, 3, 4, 5, 6])); }; +fn variadic() void = { + let x: []int = []; + defer free(x); + append(x, 1, 2, 3, 4, 5, 6); + insert(x[2], [7, 8, 9]...); + assert(sleq(x, [1, 2, 7, 8, 9, 3, 4, 5, 6])); + + let x: []int = []; + defer free(x); + append(x, 1, 2, 3, 4, 5, 6); + insert(x[2], 7, 8, 9, [10, 11, 12]...); + assert(sleq(x, [1, 2, 7, 8, 9, 10, 11, 12, 3, 4, 5, 6])); +}; + export fn main() void = { basics(); - // TODO: Variadic insert + variadic(); };