commit c2ce6392f471292486baa50e0e632226f716f990
parent 210acb6ab94480735b7ec54c1abbbf4789e5aa45
Author: Drew DeVault <sir@cmpwn.com>
Date: Wed, 28 Apr 2021 13:04:28 -0400
all: implement static append/insert
Signed-off-by: Drew DeVault <sir@cmpwn.com>
Diffstat:
5 files changed, 89 insertions(+), 9 deletions(-)
diff --git a/include/expr.h b/include/expr.h
@@ -80,6 +80,8 @@ struct expression_append {
struct expression *expr;
struct expression *variadic;
struct append_values *values;
+ struct location loc;
+ bool is_static;
};
struct expression_assert {
@@ -222,6 +224,8 @@ struct expression_insert {
struct expression *expr;
struct expression *variadic;
struct append_values *values;
+ struct location loc;
+ bool is_static;
};
struct expressions {
diff --git a/src/check.c b/src/check.c
@@ -331,9 +331,10 @@ check_expr_append(struct context *ctx,
struct errors *errors)
{
assert(aexpr->type == EXPR_APPEND);
- assert(!aexpr->append.is_static); // TODO
expr->type = EXPR_APPEND;
expr->result = &builtin_type_void;
+ expr->append.is_static = aexpr->append.is_static;
+ expr->insert.loc = aexpr->loc;
expr->append.expr = xcalloc(sizeof(struct expression), 1);
errors = check_expression(ctx, aexpr->append.expr, expr->append.expr,
NULL, errors);
@@ -1596,9 +1597,10 @@ check_expr_insert(struct context *ctx,
struct errors *errors)
{
assert(aexpr->type == EXPR_INSERT);
- assert(!aexpr->insert.is_static); // TODO
expr->type = EXPR_INSERT;
expr->result = &builtin_type_void;
+ expr->insert.is_static = aexpr->insert.is_static;
+ expr->insert.loc = aexpr->loc;
expr->insert.expr = xcalloc(sizeof(struct expression), 1);
errors = check_expression(ctx, aexpr->insert.expr,
expr->insert.expr, NULL, errors);
diff --git a/src/gen.c b/src/gen.c
@@ -702,12 +702,39 @@ gen_expr_append(struct gen_context *ctx,
const struct type *mtype =
type_dealias(expr->append.expr->result)->array.members;
- struct qbe_value rtfunc = {0}, membsz = {0};
+ struct qbe_value membsz = {0};
constl(&membsz, mtype->size);
- rtfunc.kind = QV_GLOBAL;
- rtfunc.name = strdup("rt.ensure");
- rtfunc.type = &qbe_long;
- pushi(ctx->current, NULL, Q_CALL, &rtfunc, &val, &membsz, NULL);
+ if (!expr->append.is_static) {
+ struct qbe_value rtfunc = {0};
+ rtfunc.kind = QV_GLOBAL;
+ rtfunc.name = strdup("rt.ensure");
+ rtfunc.type = &qbe_long;
+ pushi(ctx->current, NULL, Q_CALL, &rtfunc, &val, &membsz, NULL);
+ } else {
+ struct qbe_value capptr = {0}, cap = {0};
+ gen_temp(ctx, &capptr, &qbe_long, "append.capptr.%d");
+ constl(&temp, builtin_type_size.size);
+ pushi(ctx->current, &capptr, Q_ADD, &lenptr, &temp, NULL);
+ qval_deref(&capptr);
+ gen_loadtemp(ctx, &cap, &capptr, &qbe_long, false);
+
+ struct qbe_statement validl = {0}, invalidl = {0};
+ struct qbe_value bvalid = {0}, binvalid = {0};
+ bvalid.kind = QV_LABEL;
+ bvalid.name = strdup(genl(&validl, &ctx->id, "bounds.valid.%d"));
+ binvalid.kind = QV_LABEL;
+ binvalid.name = strdup(genl(&invalidl, &ctx->id, "bounds.invalid.%d"));
+
+ struct qbe_value valid = {0};
+ gen_temp(ctx, &valid, &qbe_word, "valid.%d");
+ pushi(ctx->current, &valid, Q_CULEL, &newlen, &cap, NULL);
+ pushi(ctx->current, NULL, Q_JNZ, &valid, &bvalid, &binvalid, NULL);
+ push(&ctx->current->body, &invalidl);
+
+ gen_fixed_abort(ctx, expr->loc, ABORT_OOB);
+
+ push(&ctx->current->body, &validl);
+ }
struct qbe_value ptr = {0};
const struct qbe_type *type = qtype_for_type(ctx, mtype, true);
@@ -1983,9 +2010,36 @@ gen_expr_insert(struct gen_context *ctx,
struct qbe_value rtfunc = {0}, membsz = {0};
constl(&membsz, mtype->size);
rtfunc.kind = QV_GLOBAL;
- rtfunc.name = strdup("rt.ensure");
rtfunc.type = &qbe_long;
- pushi(ctx->current, NULL, Q_CALL, &rtfunc, &val, &membsz, NULL);
+
+ if (!expr->insert.is_static) {
+ rtfunc.name = strdup("rt.ensure");
+ pushi(ctx->current, NULL, Q_CALL, &rtfunc, &val, &membsz, NULL);
+ } else {
+ struct qbe_value capptr = {0}, cap = {0};
+ gen_temp(ctx, &capptr, &qbe_long, "append.capptr.%d");
+ constl(&temp, builtin_type_size.size);
+ pushi(ctx->current, &capptr, Q_ADD, &lenptr, &temp, NULL);
+ qval_deref(&capptr);
+ gen_loadtemp(ctx, &cap, &capptr, &qbe_long, false);
+
+ struct qbe_statement validl = {0}, invalidl = {0};
+ struct qbe_value bvalid = {0}, binvalid = {0};
+ bvalid.kind = QV_LABEL;
+ bvalid.name = strdup(genl(&validl, &ctx->id, "bounds.valid.%d"));
+ binvalid.kind = QV_LABEL;
+ binvalid.name = strdup(genl(&invalidl, &ctx->id, "bounds.invalid.%d"));
+
+ struct qbe_value valid = {0};
+ gen_temp(ctx, &valid, &qbe_word, "valid.%d");
+ pushi(ctx->current, &valid, Q_CULEL, &newlen, &cap, NULL);
+ pushi(ctx->current, NULL, Q_JNZ, &valid, &bvalid, &binvalid, NULL);
+ push(&ctx->current->body, &invalidl);
+
+ gen_fixed_abort(ctx, expr->loc, ABORT_OOB);
+
+ push(&ctx->current->body, &validl);
+ }
struct qbe_value ptr = {0};
const struct qbe_type *type = qtype_for_type(ctx, mtype, true);
diff --git a/tests/19-append.ha b/tests/19-append.ha
@@ -42,9 +42,19 @@ fn variadic() void = {
free(y);
};
+fn static_append() void = {
+ let buf: [4]int = [0...];
+ let x = buf[..0];
+ static append(x, 1, 2);
+ static append(x, [3, 4]...);
+ assert(x[0] == 1 && x[1] == 2 && x[2] == 3 && x[3] == 4);
+ assert(buf[0] == 1 && buf[1] == 2 && buf[2] == 3 && buf[3] == 4);
+};
+
export fn main() void = {
simple();
variadic();
+ static_append();
assert(rt::compile("fn test() void = append([1], 2);") != 0);
assert(rt::compile("fn test() void = { let x: []int = alloc([1], 1z); append(x[..], 2); };") != 0);
diff --git a/tests/28-insert.ha b/tests/28-insert.ha
@@ -38,7 +38,17 @@ fn variadic() void = {
assert(sleq(x, [1, 2, 7, 8, 9, 10, 11, 12, 3, 4, 5, 6]));
};
+fn static_insert() void = {
+ let buf: [4]int = [0...];
+ let x = buf[..0];
+ static insert(x[0], 1, 2);
+ static insert(x[1], [3, 4]...);
+ assert(x[0] == 1 && x[1] == 3 && x[2] == 4 && x[3] == 2);
+ assert(buf[0] == 1 && buf[1] == 3 && buf[2] == 4 && buf[3] == 2);
+};
+
export fn main() void = {
basics();
variadic();
+ static_insert();
};