commit 2474bf28a6b828c08062b5e2ad211c2d9748ba45
parent 6c40c6cb64fb78f7f9c1a19bc1ecb441d3500fb6
Author: Drew DeVault <sir@cmpwn.com>
Date: Wed, 13 Jan 2021 13:42:22 -0500
gen: finish implementation of slicing expressions
Diffstat:
3 files changed, 35 insertions(+), 6 deletions(-)
diff --git a/src/gen.c b/src/gen.c
@@ -1089,6 +1089,10 @@ gen_expr_slice(struct gen_context *ctx,
gen_temp(ctx, &start, &qbe_long, "start.%d");
gen_temp(ctx, &end, &qbe_long, "end.%d");
+ struct qbe_value src = {0}, dest = {0}, temp = {0}, offset = {0};
+ gen_temp(ctx, &dest, &qbe_long, "dest.%d");
+ gen_temp(ctx, &offset, &qbe_long, "offset.%d");
+
if (expr->slice.start) {
gen_expression(ctx, expr->slice.start, &start);
} else {
@@ -1100,16 +1104,34 @@ gen_expr_slice(struct gen_context *ctx,
} else if (otype->storage == TYPE_STORAGE_ARRAY) {
constl(&end, otype->array.length);
} else {
- assert(0); // TODO: Read slice length into &end
+ pushc(ctx->current, "load length");
+ constl(&temp, 8); // XXX: ARCH
+ pushi(ctx->current, &offset, Q_ADD, &object, &temp, NULL);
+ pushi(ctx->current, &end, Q_LOADL, &offset, NULL);
}
// TODO: Bounds check
- struct qbe_value src = {0}, dest = {0}, temp = {0}, offset = {0};
- gen_temp(ctx, &dest, &qbe_long, "dest.%d");
- gen_temp(ctx, &offset, &qbe_long, "offset.%d");
pushi(ctx->current, &dest, Q_COPY, out, NULL);
if (otype->storage == TYPE_STORAGE_SLICE) {
- assert(0); // TODO
+ pushc(ctx->current, "load array");
+
+ gen_temp(ctx, &src, &qbe_long, "src.%d");
+ pushi(ctx->current, &src, Q_LOADL, &object, NULL);
+
+ pushc(ctx->current, "add offset");
+ constl(&temp, otype->array.members->size);
+ pushi(ctx->current, &offset, Q_MUL, &start, &temp, NULL);
+ pushi(ctx->current, &offset, Q_ADD, &src, &offset, NULL);
+ pushi(ctx->current, NULL, Q_STOREL, &offset, &dest, NULL);
+
+ pushc(ctx->current, "store length & capacity");
+ constl(&temp, 8); // XXX: ARCH
+ pushi(ctx->current, &offset, Q_SUB, &end, &start, NULL);
+ constl(&temp, 8); // XXX: ARCH
+ pushi(ctx->current, &dest, Q_ADD, &dest, &temp, NULL);
+ pushi(ctx->current, NULL, Q_STOREL, &offset, &dest, NULL);
+ pushi(ctx->current, &dest, Q_ADD, &dest, &temp, NULL);
+ pushi(ctx->current, NULL, Q_STOREL, &offset, &dest, NULL);
} else {
gen_temp(ctx, &src, &qbe_long, "length.%d");
diff --git a/src/parse.c b/src/parse.c
@@ -1118,6 +1118,8 @@ parse_index_slice_expression(struct lexer *lexer, struct ast_expression *lvalue)
exp->access.index = start;
trleave(TR_PARSE, "slice-index (index)");
return exp;
+ } else if (tok.token == T_RBRACKET) {
+ unlex(lexer, &tok);
}
switch (lex(lexer, &tok)) {
diff --git a/tests/08-slices.ha b/tests/08-slices.ha
@@ -73,11 +73,16 @@ fn assert_slice_eq(actual: []int, expected: []int) void = {
fn slicing() void = {
let a = [1, 2, 3, 4, 5];
+ assert_slice_eq(a[..], [1, 2, 3, 4, 5]);
assert_slice_eq(a[..3], [1, 2, 3]);
assert_slice_eq(a[1..3], [2, 3]);
assert_slice_eq(a[1..], [2, 3, 4, 5]);
- // TODO: Test slicing other slices
+ let b: []int = [1, 2, 3, 4, 5];
+ assert_slice_eq(b[..], [1, 2, 3, 4, 5]);
+ assert_slice_eq(b[..3], [1, 2, 3]);
+ assert_slice_eq(b[1..3], [2, 3]);
+ assert_slice_eq(b[1..], [2, 3, 4, 5]);
assert(rt::compile(
"fn test() void = { let x = \"test\"; x[1..3]; };"