harec

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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:
Minclude/expr.h | 7+++++++
Msrc/check.c | 2+-
Msrc/eval.c | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/gen.c | 24+++++++++++++++++++++++-
Mtests/21-tuples.ha | 10++++++++++
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(); };