commit a89b9593e653ae6af309adbeea204aecd5938f95
parent d1aaddfaf1df5dd19a2781095fc4911b4707f51f
Author: Bor Grošelj Simić <bor.groseljsimic@telemach.net>
Date: Thu, 4 Mar 2021 23:41:15 +0100
implement compile-time evaluation of tuples
Diffstat:
5 files changed, 94 insertions(+), 4 deletions(-)
diff --git a/include/expr.h b/include/expr.h
@@ -161,6 +161,12 @@ struct struct_constant {
struct struct_constant *next;
};
+struct tuple_constant {
+ const struct type_tuple *field;
+ struct expression *value;
+ struct tuple_constant *next;
+};
+
struct expression_constant {
// If non-null, ival is an offset from this object's address
const struct scope_object *object;
@@ -176,6 +182,7 @@ struct expression_constant {
} string;
struct array_constant *array;
struct struct_constant *_struct;
+ struct tuple_constant *tuple;
};
};
diff --git a/src/check.c b/src/check.c
@@ -360,7 +360,7 @@ check_expr_assert(struct context *ctx,
assert(out.result->storage == STORAGE_BOOL);
cond = out.constant.bval;
} else {
- cond = false;
+ cond = false;
}
if (aexpr->assert.message != NULL) {
expect(&aexpr->assert.cond->loc, cond,
diff --git a/src/eval.c b/src/eval.c
@@ -28,7 +28,23 @@ eval_access(struct context *ctx, struct expression *in, struct expression *out)
case ACCESS_FIELD:
assert(0); // TODO
case ACCESS_TUPLE:
- assert(0); // TODO
+ out->type = EXPR_CONSTANT;
+ struct expression tmp = {0};
+ enum eval_result r = eval_expr(ctx, in->access.value, &tmp);
+ if (r != EVAL_OK) {
+ return r;
+ }
+ size_t i = tmp.constant.uval;
+ // ensure the entire tuple is known at compile time
+ r = eval_expr(ctx, in->access.tuple, &tmp);
+ if (r != EVAL_OK) {
+ return r;
+ }
+ const struct tuple_constant *tuple = tmp.constant.tuple;
+ for (; i > 0; --i) {
+ tuple = tuple->next;
+ }
+ return eval_expr(ctx, tuple->value, out);
}
return EVAL_OK;
@@ -536,6 +552,40 @@ eval_struct(struct context *ctx, struct expression *in, struct expression *out)
}
static enum eval_result
+eval_tuple(struct context *ctx, struct expression *in, struct expression *out)
+{
+ assert(in->type == EXPR_TUPLE);
+ const struct type *type = type_dealias(in->result);
+ out->type = EXPR_CONSTANT;
+
+
+ struct tuple_constant *out_tuple_start, *out_tuple;
+ out_tuple_start = out_tuple = xcalloc(1, sizeof(struct tuple_constant));
+ const struct expression_tuple *in_tuple = &in->tuple;
+ for (const struct type_tuple *field_type = &type->tuple; field_type;
+ field_type = field_type->next) {
+ out_tuple->value = xcalloc(1, sizeof(struct expression));
+ enum eval_result r =
+ eval_expr(ctx, in_tuple->value, out_tuple->value);
+ if (r != EVAL_OK) {
+ return r;
+ }
+ out_tuple->field = field_type;
+ if (in_tuple->next) {
+ in_tuple = in_tuple->next;
+ out_tuple->next =
+ xcalloc(1, sizeof(struct tuple_constant));
+ out_tuple = out_tuple->next;
+ }
+ }
+
+ out->constant.tuple = out_tuple_start;
+ out->result = in->result;
+ return EVAL_OK;
+}
+
+
+static enum eval_result
eval_unarithm(struct context *ctx, struct expression *in, struct expression *out)
{
struct expression lvalue = {0};
@@ -581,8 +631,9 @@ eval_expr(struct context *ctx, struct expression *in, struct expression *out)
case EXPR_STRUCT:
return eval_struct(ctx, in, out);
case EXPR_SLICE:
- case EXPR_TUPLE:
assert(0); // TODO
+ case EXPR_TUPLE:
+ return eval_tuple(ctx, in, out);
case EXPR_UNARITHM:
return eval_unarithm(ctx, in, out);
case EXPR_ALLOC:
diff --git a/src/gen.c b/src/gen.c
@@ -2782,8 +2782,30 @@ gen_data_item(struct gen_context *ctx, struct expression *expr,
assert(0);
}
break;
- case STORAGE_TAGGED:
case STORAGE_TUPLE:
+ for (const struct tuple_constant *tuple = constant->tuple;
+ tuple; tuple = tuple->next) {
+ item = gen_data_item(ctx, tuple->value, item);
+ if (tuple->next) {
+ const struct type_tuple *f1 = tuple->field;
+ const struct type_tuple *f2 = tuple->next->field;
+ if (f2->offset != f1->offset + f1->type->size) {
+ item->next = xcalloc(1,
+ sizeof(struct qbe_data_item));
+ item = item->next;
+ item->type = QD_ZEROED;
+ item->zeroed = f2->offset -
+ (f1->offset + f1->type->size);
+ }
+
+
+ item->next = xcalloc(1,
+ sizeof(struct qbe_data_item));
+ item = item->next;
+ }
+ }
+ break;
+ case STORAGE_TAGGED:
case STORAGE_UNION:
assert(0); // TODO
case STORAGE_ALIAS:
diff --git a/tests/21-tuples.ha b/tests/21-tuples.ha
@@ -12,6 +12,14 @@ fn indexing() void = {
fn func(in: (int, size)) (int, size) = (in.0 + 1, in.1 + 1);
+fn eval_expr_access() void = {
+ static assert ((42, 0).0 == 42 && (42, 0).1 == 0);
+};
+
+fn eval_expr_tuple() void = {
+ static let t = (42, 8);
+};
+
fn funcs() void = {
let x = func((41, 1336));
assert(x.0 == 42 && x.1 == 1337);
@@ -21,4 +29,6 @@ export fn main() void = {
storage();
indexing();
funcs();
+ eval_expr_tuple();
+ eval_expr_access();
};