commit 72f020c5ee0b4e0e2de17f06fcf3ffb1c8c17c46
parent 2106aeb4546a4d143363f789a66d27a0114bba91
Author: Sebastian <sebastian@sebsite.pw>
Date: Mon, 16 Jan 2023 04:41:14 -0500
eval: default value for tuples
This also now correctly returns EVAL_INVALID when trying to get the
default value of a tagged union (the error message isn't very good,
though).
Signed-off-by: Sebastian <sebastian@sebsite.pw>
Diffstat:
3 files changed, 71 insertions(+), 27 deletions(-)
diff --git a/src/eval.c b/src/eval.c
@@ -403,20 +403,19 @@ eval_const(struct context *ctx, struct expression *in, struct expression *out)
if (storage == STORAGE_ENUM) {
storage = type_dealias(out->result)->alias.type->storage;
}
- struct array_constant **next;
switch (storage) {
case STORAGE_ALIAS:
case STORAGE_ENUM:
assert(0); // Handled above
- case STORAGE_ARRAY:
- next = &out->constant.array;
+ case STORAGE_ARRAY:;
+ struct array_constant **anext = &out->constant.array;
for (struct array_constant *arr = in->constant.array; arr;
arr = arr->next) {
- struct array_constant *aconst = *next =
+ struct array_constant *aconst = *anext =
xcalloc(sizeof(struct array_constant), 1);
aconst->value = xcalloc(sizeof(struct expression), 1);
eval_expr(ctx, arr->value, aconst->value);
- next = &aconst->next;
+ anext = &aconst->next;
}
break;
case STORAGE_FUNCTION:
@@ -436,8 +435,19 @@ eval_const(struct context *ctx, struct expression *in, struct expression *out)
out->constant.tagged.value);
case STORAGE_STRUCT:
case STORAGE_UNION:
- case STORAGE_TUPLE:
assert(0); // TODO
+ case STORAGE_TUPLE:;
+ struct tuple_constant **tnext = &out->constant.tuple;
+ for (struct tuple_constant *tuple = in->constant.tuple; tuple;
+ tuple = tuple->next) {
+ struct tuple_constant *tconst = *tnext =
+ xcalloc(1, sizeof(struct tuple_constant));
+ tconst->field = tuple->field;
+ tconst->value = xcalloc(1, sizeof(struct expression));
+ eval_expr(ctx, tuple->value, tconst->value);
+ tnext = &tconst->next;
+ }
+ break;
case STORAGE_BOOL:
case STORAGE_CHAR:
case STORAGE_ERROR:
@@ -693,7 +703,7 @@ eval_measurement(struct context *ctx, struct expression *in, struct expression *
assert(0);
}
-static void
+static enum eval_result
constant_default(struct context *ctx, struct expression *v)
{
struct expression b = {0};
@@ -742,11 +752,26 @@ constant_default(struct context *ctx, struct expression *v)
v->constant.array->value->type = EXPR_CONSTANT;
v->constant.array->value->result =
type_dealias(v->result)->array.members;
- constant_default(ctx, v->constant.array->value);
+ return constant_default(ctx, v->constant.array->value);
break;
case STORAGE_TAGGED:
- case STORAGE_TUPLE:
- assert(0); // TODO
+ return EVAL_INVALID;
+ case STORAGE_TUPLE:;
+ struct tuple_constant **c = &v->constant.tuple;
+ for (const struct type_tuple *t = &type_dealias(v->result)->tuple;
+ t != NULL; t = t->next) {
+ *c = xcalloc(1, sizeof(struct tuple_constant));
+ (*c)->field = t;
+ (*c)->value = xcalloc(1, sizeof(struct expression));
+ (*c)->value->type = EXPR_CONSTANT;
+ (*c)->value->result = t->type;
+ enum eval_result r = constant_default(ctx, (*c)->value);
+ if (r != EVAL_OK) {
+ return r;
+ }
+ c = &(*c)->next;
+ }
+ break;
case STORAGE_ALIAS:
case STORAGE_FUNCTION:
case STORAGE_VALIST:
@@ -754,6 +779,8 @@ constant_default(struct context *ctx, struct expression *v)
case STORAGE_VOID:
break; // no-op
}
+
+ return EVAL_OK;
}
static int
@@ -780,14 +807,18 @@ count_struct_fields(const struct type *type)
return n;
}
-static void
+static enum eval_result
autofill_struct(struct context *ctx, const struct type *type, struct struct_constant **fields)
{
+ enum eval_result r;
assert(type->storage == STORAGE_STRUCT || type->storage == STORAGE_UNION);
for (const struct struct_field *field = type->struct_union.fields;
field; field = field->next) {
if (!field->name) {
- autofill_struct(ctx, type_dealias(field->type), fields);
+ r = autofill_struct(ctx, type_dealias(field->type), fields);
+ if (r != EVAL_OK) {
+ return r;
+ }
continue;
}
size_t i = 0;
@@ -804,9 +835,16 @@ autofill_struct(struct context *ctx, const struct type *type, struct struct_cons
fields[i]->value = xcalloc(1, sizeof(struct expression));
fields[i]->value->type = EXPR_CONSTANT;
fields[i]->value->result = field->type;
- constant_default(ctx, fields[i]->value);
+ // TODO: there should probably be a better error message
+ // when this happens
+ r = constant_default(ctx, fields[i]->value);
+ if (r != EVAL_OK) {
+ return r;
+ }
}
}
+
+ return EVAL_OK;
}
static enum eval_result
@@ -839,7 +877,10 @@ eval_struct(struct context *ctx, struct expression *in, struct expression *out)
assert(in->_struct.autofill || i == n);
if (in->_struct.autofill) {
- autofill_struct(ctx, type, fields);
+ enum eval_result r = autofill_struct(ctx, type, fields);
+ if (r != EVAL_OK) {
+ return r;
+ }
}
qsort(fields, n, sizeof(struct struct_constant *), field_compar);
diff --git a/tests/06-structs.ha b/tests/06-structs.ha
@@ -115,7 +115,7 @@ type coords = struct { x: int, y: int };
type coords3 = struct { coords, z: int };
type embed = struct { a: uint, b: u8 };
// complex embedded hierarchy
-type me = struct { embed, coords3, f: int };
+type me = struct { embed, coords3, f: int, g: (int, str) };
let g1: me = me { b = 4, x = -1, y = -2, z = -3, f = 20, ... };
let g2: me = me { x = -1, y = -2, z = -3, f = 20, ... };
let g3: me = me { y = -2, z = -3, f = 20, ... };
@@ -132,12 +132,12 @@ fn autofill() void = {
let x = coords { x = 10, ... };
assert(x.x == 10 && x.y == 0);
- assert(g1.a == 0 && g1.b == 4 && g1.x == -1 && g1.y == -2 && g1.z == -3 && g1.f == 20);
- assert(g2.a == 0 && g2.b == 0 && g2.x == -1 && g2.y == -2 && g2.z == -3 && g2.f == 20);
- assert(g3.a == 0 && g3.b == 0 && g3.x == 0 && g3.y == -2 && g3.z == -3 && g3.f == 20);
- assert(g4.a == 0 && g4.b == 0 && g4.x == 0 && g4.y == 0 && g4.z == -3 && g4.f == 20);
- assert(g5.a == 0 && g5.b == 0 && g5.x == 0 && g5.y == 0 && g5.z == 0 && g5.f == 20);
- assert(g6.a == 0 && g6.b == 0 && g6.x == 0 && g6.y == 0 && g6.z == 0 && g6.f == 0 );
+ assert(g1.a == 0 && g1.b == 4 && g1.x == -1 && g1.y == -2 && g1.z == -3 && g1.f == 20 && g1.g.0 == 0 && g1.g.1 == "");
+ assert(g2.a == 0 && g2.b == 0 && g2.x == -1 && g2.y == -2 && g2.z == -3 && g2.f == 20 && g2.g.0 == 0 && g2.g.1 == "");
+ assert(g3.a == 0 && g3.b == 0 && g3.x == 0 && g3.y == -2 && g3.z == -3 && g3.f == 20 && g3.g.0 == 0 && g3.g.1 == "");
+ assert(g4.a == 0 && g4.b == 0 && g4.x == 0 && g4.y == 0 && g4.z == -3 && g4.f == 20 && g4.g.0 == 0 && g4.g.1 == "");
+ assert(g5.a == 0 && g5.b == 0 && g5.x == 0 && g5.y == 0 && g5.z == 0 && g5.f == 20 && g5.g.0 == 0 && g5.g.1 == "");
+ assert(g6.a == 0 && g6.b == 0 && g6.x == 0 && g6.y == 0 && g6.z == 0 && g6.f == 0 && g6.g.0 == 0 && g6.g.1 == "");
let l1: me = me { b = 4, x = -1, y = -2, z = -3, f = 20, ... };
let l2: me = me { x = -1, y = -2, z = -3, f = 20, ... };
@@ -146,12 +146,12 @@ fn autofill() void = {
let l5: me = me { f = 20, ... };
let l6: me = me { ... };
- assert(l1.a == 0 && l1.b == 4 && l1.x == -1 && l1.y == -2 && l1.z == -3 && l1.f == 20);
- assert(l2.a == 0 && l2.b == 0 && l2.x == -1 && l2.y == -2 && l2.z == -3 && l2.f == 20);
- assert(l3.a == 0 && l3.b == 0 && l3.x == 0 && l3.y == -2 && l3.z == -3 && l3.f == 20);
- assert(l4.a == 0 && l4.b == 0 && l4.x == 0 && l4.y == 0 && l4.z == -3 && l4.f == 20);
- assert(l5.a == 0 && l5.b == 0 && l5.x == 0 && l5.y == 0 && l5.z == 0 && l5.f == 20);
- assert(l6.a == 0 && l6.b == 0 && l6.x == 0 && l6.y == 0 && l6.z == 0 && l6.f == 0 );
+ assert(l1.a == 0 && l1.b == 4 && l1.x == -1 && l1.y == -2 && l1.z == -3 && l1.f == 20 && l1.g.0 == 0 && l1.g.1 == "");
+ assert(l2.a == 0 && l2.b == 0 && l2.x == -1 && l2.y == -2 && l2.z == -3 && l2.f == 20 && l2.g.0 == 0 && l2.g.1 == "");
+ assert(l3.a == 0 && l3.b == 0 && l3.x == 0 && l3.y == -2 && l3.z == -3 && l3.f == 20 && l3.g.0 == 0 && l3.g.1 == "");
+ assert(l4.a == 0 && l4.b == 0 && l4.x == 0 && l4.y == 0 && l4.z == -3 && l4.f == 20 && l4.g.0 == 0 && l4.g.1 == "");
+ assert(l5.a == 0 && l5.b == 0 && l5.x == 0 && l5.y == 0 && l5.z == 0 && l5.f == 20 && l5.g.0 == 0 && l5.g.1 == "");
+ assert(l6.a == 0 && l6.b == 0 && l6.x == 0 && l6.y == 0 && l6.z == 0 && l6.f == 0 && l6.g.0 == 0 && l6.g.1 == "");
};
fn invariants() void = {
diff --git a/tests/21-tuples.ha b/tests/21-tuples.ha
@@ -1,5 +1,7 @@
use rt::{compile, exited, EXIT_SUCCESS};
+def CONST: (int, str) = (15, "foo");
+
fn storage() void = {
let x: (int, size) = (42, 1337);
assert(size((int, size)) == size(size) * 2);
@@ -20,6 +22,7 @@ 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);
+ static assert(CONST.0 == 15 && CONST.1 == "foo");
};
fn eval_expr_tuple() void = {