harec

[hare] Hare compiler, written in C11 for POSIX OSs
Log | Files | Refs | README | LICENSE

commit 20c786e75ade06281a003645740915edce78688c
parent 4a97bd2bafbd6e89f692c18477a08d8112dbd6e1
Author: Sebastian <sebastian@sebsite.pw>
Date:   Fri,  6 May 2022 22:45:42 -0400

Allow literal arrays to be copied by alloc()

alloc([1, 2, 3]...) now works.

Signed-off-by: Sebastian <sebastian@sebsite.pw>

Diffstat:
Msrc/check.c | 28+++++++++++++++++++++-------
Msrc/gen.c | 32+++++++++++++++++++++++---------
Mtests/17-alloc.ha | 7+++++++
3 files changed, 51 insertions(+), 16 deletions(-)

diff --git a/src/check.c b/src/check.c @@ -293,6 +293,9 @@ check_expr_alloc_init(struct context *ctx, case STORAGE_SLICE: inithint = hint; break; + case STORAGE_TAGGED: + // TODO + break; default: // The user's code is wrong here, but we'll let it fail // later. @@ -375,17 +378,28 @@ check_expr_alloc_copy(struct context *ctx, // alloc(init...) case check_expression(ctx, aexpr->alloc.init, expr->alloc.init, hint); - const struct type *result = expr->alloc.init->result; - if (hint && result != hint) { - // TODO: We might be able to be less strict on this. We could - // copy slices of types which differ only based on the flag, or - // copy an array into a new slice. + const struct type *result = type_dealias(expr->alloc.init->result); + if (result->storage != STORAGE_ARRAY + && result->storage != STORAGE_SLICE) { error(ctx, aexpr->alloc.init->loc, expr, - "Cannot copy a slice to a slice of another type"); + "Slice initializer must be of slice or array type, not %s", + type_storage_unparse(result->storage)); return; } + if (hint) { + const struct type *htype = type_dealias(hint); + if (htype->storage != STORAGE_SLICE + && htype->storage != STORAGE_TAGGED) { + error(ctx, aexpr->alloc.init->loc, expr, + "Hint must be a slice type, not %s", + type_storage_unparse(htype->storage)); + return; + } + } - expr->result = result; + check_expression(ctx, aexpr->alloc.init, expr->alloc.init, hint); + result = type_dealias(expr->alloc.init->result); + expr->result = type_store_lookup_slice(ctx->store, result->array.members); } static void diff --git a/src/gen.c b/src/gen.c @@ -553,6 +553,8 @@ gen_expr_alloc_copy_with(struct gen_context *ctx, const struct expression *expr, struct gen_value *out) { // alloc(init...) case + assert(expr->alloc.cap == NULL); + struct gen_value ret = gv_void; if (out == NULL) { ret = mkgtemp(ctx, expr->result, "object.%d"); @@ -568,15 +570,27 @@ gen_expr_alloc_copy_with(struct gen_context *ctx, enum qbe_instr store = store_for_type(ctx, &builtin_type_size); struct gen_value src = gen_expr(ctx, expr->alloc.init); - struct qbe_value sbase = mkcopy(ctx, &src, ".%d"); struct qbe_value dbase = mkcopy(ctx, out, ".%d"); - struct qbe_value srcdata = mkqtmp(ctx, ctx->arch.sz, ".%d"); - pushi(ctx->current, &srcdata, load, &sbase, NULL); struct qbe_value offs = constl(builtin_type_size.size); - pushi(ctx->current, &sbase, Q_ADD, &sbase, &offs, NULL); - struct qbe_value length = mkqtmp(ctx, ctx->arch.sz, ".%d"); - pushi(ctx->current, &length, load, &sbase, NULL); + const struct type *initres = type_dealias(expr->alloc.init->result); + struct qbe_value srcdata; + struct qbe_value length; + if (initres->storage == STORAGE_SLICE) { + assert(initres->array.length == SIZE_UNDEFINED); + srcdata = mkqtmp(ctx, ctx->arch.sz, ".%d"); + struct qbe_value sbase = mkcopy(ctx, &src, ".%d"); + pushi(ctx->current, &srcdata, load, &sbase, NULL); + pushi(ctx->current, &sbase, Q_ADD, &sbase, &offs, NULL); + length = mkqtmp(ctx, ctx->arch.sz, ".%d"); + pushi(ctx->current, &length, load, &sbase, NULL); + } else if (initres->storage == STORAGE_ARRAY) { + assert(initres->array.length != SIZE_UNDEFINED); + srcdata = mkcopy(ctx, &src, ".%d"); // TODO: object.%d + length = constl(initres->array.length); + } else { + abort(); + } struct qbe_statement linvalid, lvalid, lalloc; struct qbe_value balloc = mklabel(ctx, &lalloc, ".%d"); @@ -589,10 +603,10 @@ gen_expr_alloc_copy_with(struct gen_context *ctx, pushi(ctx->current, NULL, Q_JNZ, &length, &balloc, &bvalid, NULL); push(&ctx->current->body, &lalloc); - const struct type *membtype = - type_dealias(expr->alloc.init->result)->array.members; + const struct type *result = type_dealias(expr->result); + assert(result->storage == STORAGE_SLICE); struct qbe_value sz = mkqtmp(ctx, ctx->arch.sz, ".%d"); - struct qbe_value membsz = constl(membtype->size); + struct qbe_value membsz = constl(result->array.members->size); pushi(ctx->current, &sz, Q_MUL, &membsz, &length, NULL); struct qbe_value rtfunc = mkrtfunc(ctx, "rt.malloc"); diff --git a/tests/17-alloc.ha b/tests/17-alloc.ha @@ -106,6 +106,13 @@ fn slice_copy() void = { let q: *[]int = alloc(x); defer free(q); assert((*q): *[*]int == x: *[*]int); + + let r: []int = alloc([1, 2, 3]...); + defer free(r); + assert(len(x) == len(r)); + for (let i = 0z; i < len(x); i += 1) { + assert(x[i] == r[i]); + }; }; fn string() void = {