commit 689bdd02034adc68233d4e93dd233ead6d508108
parent 6f6cf46d0098afac20e5cae858129f2e53d6db68
Author: Drew DeVault <sir@cmpwn.com>
Date: Thu, 31 Dec 2020 10:37:05 -0500
gen: implement len()
Diffstat:
2 files changed, 27 insertions(+), 4 deletions(-)
diff --git a/src/check.c b/src/check.c
@@ -540,8 +540,10 @@ check_expr_measure(struct context *ctx,
expr->measure.value = xcalloc(1, sizeof(struct expression));
check_expression(ctx, aexpr->measure.value, expr->measure.value);
enum type_storage vstor = expr->measure.value->result->storage;
- expect(vstor == TYPE_STORAGE_ARRAY || vstor == TYPE_STORAGE_SLICE,
- "len argument must be of an array or slice type");
+ expect(vstor == TYPE_STORAGE_ARRAY
+ || vstor == TYPE_STORAGE_SLICE
+ || vstor == TYPE_STORAGE_STRING,
+ "len argument must be of an array, slice, or str type");
expect(expr->measure.value->result->size != SIZE_UNDEFINED,
"Cannot take length of array type with undefined length");
break;
diff --git a/src/gen.c b/src/gen.c
@@ -858,10 +858,31 @@ gen_expr_measure(struct gen_context *ctx,
const struct expression *expr,
const struct qbe_value *out)
{
- struct qbe_value temp = {0};
+ struct qbe_value temp = {0}, ptr = {0};
switch (expr->measure.op) {
case M_LEN:
- assert(0); // TODO
+ switch (expr->measure.value->result->storage) {
+ case TYPE_STORAGE_ARRAY:
+ gen_temp(ctx, &temp,
+ qtype_for_type(ctx, expr->result, false),
+ "len.%d");
+ constl(&temp, expr->measure.value->result->array.length);
+ gen_store(ctx, out, &temp);
+ break;
+ case TYPE_STORAGE_SLICE:
+ case TYPE_STORAGE_STRING:
+ gen_temp(ctx, &ptr, &qbe_long, "ptr.%d");
+ qval_address(&ptr);
+ gen_expression(ctx, expr->measure.value, &ptr);
+ constl(&temp, builtin_type_size.size);
+ pushi(ctx->current, &ptr, Q_ADD, &ptr, &temp, NULL);
+ qval_deref(&ptr);
+ gen_load(ctx, out, &ptr, false);
+ break;
+ default:
+ assert(0); // Invariant
+ }
+ break;
case M_SIZE:
gen_temp(ctx, &temp,
qtype_for_type(ctx, expr->result, false),