commit a8f7752df0f0c42e2311ec85240dde16491d808b
parent dc46d6f9206a2f6c11a89a13f66b2c6513839a12
Author: Drew DeVault <sir@cmpwn.com>
Date: Tue, 2 Feb 2021 21:36:08 -0500
eval: fix struct autofill
Diffstat:
2 files changed, 84 insertions(+), 12 deletions(-)
diff --git a/src/eval.c b/src/eval.c
@@ -373,6 +373,56 @@ eval_measurement(struct context *ctx, struct expression *in, struct expression *
assert(0);
}
+static void
+constant_default(struct context *ctx, struct expression *v)
+{
+ struct expression b = {0};
+ switch (type_dealias(v->result)->storage) {
+ case TYPE_STORAGE_POINTER:
+ case TYPE_STORAGE_I16:
+ case TYPE_STORAGE_I32:
+ case TYPE_STORAGE_I64:
+ case TYPE_STORAGE_I8:
+ case TYPE_STORAGE_INT:
+ case TYPE_STORAGE_U16:
+ case TYPE_STORAGE_U32:
+ case TYPE_STORAGE_U64:
+ case TYPE_STORAGE_U8:
+ case TYPE_STORAGE_UINT:
+ case TYPE_STORAGE_UINTPTR:
+ case TYPE_STORAGE_SIZE:
+ case TYPE_STORAGE_F32:
+ case TYPE_STORAGE_F64:
+ case TYPE_STORAGE_CHAR:
+ case TYPE_STORAGE_ENUM:
+ case TYPE_STORAGE_NULL:
+ case TYPE_STORAGE_RUNE:
+ case TYPE_STORAGE_BOOL:
+ break; // calloc does this for us
+ case TYPE_STORAGE_STRUCT:
+ case TYPE_STORAGE_UNION:
+ b.type = EXPR_STRUCT;
+ b.result = v->result;
+ b._struct.autofill = true;
+ enum eval_result r = eval_expr(ctx, &b, v);
+ assert(r == EVAL_OK);
+ break;
+ case TYPE_STORAGE_STRING:
+ v->constant.string.value = strdup("");
+ v->constant.string.len = 0;
+ break;
+ case TYPE_STORAGE_TAGGED:
+ case TYPE_STORAGE_ARRAY:
+ case TYPE_STORAGE_SLICE:
+ assert(0); // TODO
+ case TYPE_STORAGE_ALIAS:
+ case TYPE_STORAGE_FUNCTION:
+ assert(0); // Invariant
+ case TYPE_STORAGE_VOID:
+ break; // no-op
+ }
+}
+
static int
field_compar(const void *_a, const void *_b)
{
@@ -386,30 +436,45 @@ eval_struct(struct context *ctx, struct expression *in, struct expression *out)
{
assert(in->type == EXPR_STRUCT);
assert(type_dealias(in->result)->storage != TYPE_STORAGE_UNION); // TODO
+ const struct type *type = type_dealias(in->result);
out->type = EXPR_CONSTANT;
size_t n = 0;
- for (const struct expr_struct_field *field = &in->_struct.fields;
+ for (const struct struct_field *field = type->struct_union.fields;
field; field = field->next) {
++n;
}
assert(n > 0);
+ size_t i = 0;
struct struct_constant **fields =
xcalloc(n, sizeof(struct struct_constant *));
- n = 0;
- for (const struct expr_struct_field *field = &in->_struct.fields;
- field; field = field->next) {
- struct struct_constant *cfield = fields[n] =
+ for (const struct struct_field *field = type->struct_union.fields;
+ field; field = field->next, ++i) {
+ const struct expr_struct_field *field_in = NULL;
+ for (field_in = &in->_struct.fields; field_in; field_in = field_in->next) {
+ if (field_in->field == field) {
+ break;
+ }
+ }
+
+ struct struct_constant *cfield = fields[i] =
xcalloc(1, sizeof(struct struct_constant));
- cfield->field = field->field;
+ cfield->field = field;
cfield->value = xcalloc(1, sizeof(struct expression));
- enum eval_result r = eval_expr(ctx,
- field->value, cfield->value);
- if (r != EVAL_OK) {
- return r;
+
+ if (!field_in) {
+ assert(in->_struct.autofill);
+ cfield->value->type = EXPR_CONSTANT;
+ cfield->value->result = field->type;
+ constant_default(ctx, cfield->value);
+ } else {
+ enum eval_result r = eval_expr(ctx,
+ field_in->value, cfield->value);
+ if (r != EVAL_OK) {
+ return r;
+ }
}
- ++n;
}
qsort(fields, n, sizeof(struct struct_constant *), field_compar);
diff --git a/tests/11-globals.ha b/tests/11-globals.ha
@@ -8,11 +8,16 @@ fn write() void = {
assert(x == 1337);
};
-type coords = struct { x: int, y: int };
let ar: [3]int = [1, 2, 3];
let sl: []int = [1, 2, 3];
let st: str = "Hello!";
+
+type coords = struct { x: int, y: int };
let su: coords = coords { y = 10, x = 20 };
+let au: coords = coords { ... };
+
+type coords3 = struct { coords: coords, z: int };
+let a3: coords3 = coords3 { ... };
fn storage() void = {
assert(len(ar) == 3z);
@@ -21,6 +26,8 @@ fn storage() void = {
assert(sl[0] == 1 && sl[1] == 2 && sl[2] == 3);
assert(len(st) == 6z);
assert(su.x == 20 && su.y == 10);
+ assert(au.x == 0 && au.y == 0);
+ assert(a3.coords.x == 0 && a3.coords.y == 0 && a3.z == 0);
};
fn invariants() void = {