commit 41e9dd9515d5c5372382031708e73e219e913bf3
parent c95a5c1dd72d5714321f9e1682d56de760c1b17b
Author: Bor Grošelj Simić <bor.groseljsimic@telemach.net>
Date: Thu, 3 Mar 2022 02:59:55 +0100
adapt eval_struct for embedded structs
Signed-off-by: Bor Grošelj Simić <bor.groseljsimic@telemach.net>
Diffstat:
5 files changed, 93 insertions(+), 52 deletions(-)
diff --git a/include/expr.h b/include/expr.h
@@ -309,7 +309,7 @@ struct expr_struct_field {
};
struct expression_struct {
- struct expr_struct_field fields;
+ struct expr_struct_field *fields;
bool autofill;
};
diff --git a/src/check.c b/src/check.c
@@ -2417,8 +2417,7 @@ check_expr_struct(struct context *ctx,
};
struct ast_struct_union_type *tfield = &satype.struct_union;
struct ast_struct_union_type **tnext = &tfield->next;
- struct expr_struct_field *sexpr = &expr->_struct.fields;
- struct expr_struct_field **snext = &sexpr->next;
+ struct expr_struct_field *sexpr, **snext = &expr->_struct.fields;
expr->_struct.autofill = aexpr->_struct.autofill;
if (stype == NULL && expr->_struct.autofill) {
error(ctx, aexpr->loc, expr,
@@ -2429,6 +2428,9 @@ check_expr_struct(struct context *ctx,
struct ast_field_value *afield = aexpr->_struct.fields;
while (afield) {
const struct type *ftype;
+ *snext = sexpr = xcalloc(1, sizeof(struct expr_struct_field));
+ snext = &sexpr->next;
+ sexpr->value = xcalloc(1, sizeof(struct expression));
if (!stype) {
assert(afield->name); // TODO
if (!afield->type) {
@@ -2438,8 +2440,14 @@ check_expr_struct(struct context *ctx,
}
tfield->name = afield->name;
tfield->type = afield->type;
- ftype = type_store_lookup_atype(
- ctx->store, tfield->type);
+ ftype = type_store_lookup_atype(ctx->store, tfield->type);
+ check_expression(ctx, afield->initializer,
+ sexpr->value, ftype);
+ if (afield->next) {
+ *tnext = tfield = xcalloc(
+ 1, sizeof(struct ast_struct_union_type));
+ tnext = &tfield->next;
+ }
} else {
sexpr->field = type_get_field(type_dealias(stype),
afield->name);
@@ -2449,12 +2457,9 @@ check_expr_struct(struct context *ctx,
return;
}
ftype = sexpr->field->type;
- }
-
- sexpr->value = xcalloc(1, sizeof(struct expression));
- check_expression(ctx, afield->initializer, sexpr->value, ftype);
+ check_expression(ctx, afield->initializer,
+ sexpr->value, ftype);
- if (stype) {
if (!type_is_assignable(sexpr->field->type, sexpr->value->result)) {
error(ctx, afield->initializer->loc, expr,
"Initializer is not assignable to struct field");
@@ -2464,16 +2469,6 @@ check_expr_struct(struct context *ctx,
sexpr->field->type, sexpr->value);
}
- if (afield->next) {
- if (!stype) {
- *tnext = tfield = xcalloc(
- 1, sizeof(struct ast_struct_union_type));
- tnext = &tfield->next;
- }
- *snext = sexpr = xcalloc(1, sizeof(struct expr_struct_field));
- snext = &sexpr->next;
- }
-
afield = afield->next;
}
@@ -2486,7 +2481,7 @@ check_expr_struct(struct context *ctx,
expr->result = type_store_lookup_atype(ctx->store, &satype);
tfield = &satype.struct_union;
- sexpr = &expr->_struct.fields;
+ sexpr = expr->_struct.fields;
while (tfield) {
const struct struct_field *field = type_get_field(
expr->result, tfield->name);
diff --git a/src/eval.c b/src/eval.c
@@ -587,6 +587,53 @@ field_compar(const void *_a, const void *_b)
return (*a)->field->offset - (*b)->field->offset;
}
+static size_t
+count_struct_fields(const struct type *type)
+{
+ size_t n = 0;
+ 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) {
+ n += count_struct_fields(type_dealias(field->type));
+ } else {
+ ++n;
+ }
+ }
+ return n;
+}
+
+void
+autofill_struct(struct context *ctx, const struct type *type, struct struct_constant **fields)
+{
+ assert(type->storage == STORAGE_STRUCT || type->storage == STORAGE_UNION);
+ for (const struct struct_field *field = type->struct_union.fields;
+ field; field = field->next) {
+ size_t i = 0;
+ bool skip = false;
+ for (; fields[i]; ++i) {
+ if (!field->name) {
+ autofill_struct(ctx,
+ type_dealias(field->type), fields);
+ skip = true;
+ break;
+ }
+ if (!strcmp(field->name, fields[i]->field->name)) {
+ skip = true;
+ break;
+ }
+ }
+ if (!skip) {
+ fields[i] = xcalloc(1, sizeof(struct struct_constant));
+ fields[i]->field = field;
+ 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);
+ }
+ }
+}
+
enum eval_result
eval_struct(struct context *ctx, struct expression *in, struct expression *out)
{
@@ -595,42 +642,30 @@ eval_struct(struct context *ctx, struct expression *in, struct expression *out)
const struct type *type = type_dealias(in->result);
out->type = EXPR_CONSTANT;
- size_t n = 0;
- for (const struct struct_field *field = type->struct_union.fields;
- field; field = field->next) {
- ++n;
- }
+ size_t n = count_struct_fields(type);
assert(n > 0);
size_t i = 0;
struct struct_constant **fields =
xcalloc(n, sizeof(struct struct_constant *));
- 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;
- }
+ for (const struct expr_struct_field *field_in = in->_struct.fields;
+ field_in; field_in = field_in->next, ++i) {
+ const struct struct_field *field =
+ type_get_field(type, field_in->field->name);
+ fields[i] = xcalloc(1, sizeof(struct struct_constant));
+ fields[i]->field = field;
+ fields[i]->value = xcalloc(1, sizeof(struct expression));
+
+ enum eval_result r = eval_expr(ctx,
+ field_in->value, fields[i]->value);
+ if (r != EVAL_OK) {
+ return r;
}
+ }
+ assert(in->_struct.autofill || i == n);
- struct struct_constant *cfield = fields[i] =
- xcalloc(1, sizeof(struct struct_constant));
- cfield->field = field;
- cfield->value = xcalloc(1, sizeof(struct expression));
-
- 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;
- }
- }
+ if (in->_struct.autofill) {
+ autofill_struct(ctx, type, fields);
}
qsort(fields, n, sizeof(struct struct_constant *), field_compar);
diff --git a/src/gen.c b/src/gen.c
@@ -2492,7 +2492,7 @@ gen_expr_struct_at(struct gen_context *ctx,
}
struct gen_value ftemp = mktemp(ctx, &builtin_type_void, "field.%d");
- for (const struct expr_struct_field *field = &expr->_struct.fields;
+ for (const struct expr_struct_field *field = expr->_struct.fields;
field; field = field->next) {
if (!field->value) {
assert(expr->_struct.autofill);
diff --git a/tests/11-globals.ha b/tests/11-globals.ha
@@ -13,12 +13,21 @@ 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 su: coords = coords { y = 10, x = 20};
+let su_autofill: coords = coords { y = 10, x = 20, ... };
let au: coords = coords { ... };
type coords3 = struct { coords: coords, z: int };
let a3: coords3 = coords3 { ... };
+type embedded = struct { a: uint, b: u8 };
+type with_embedded = struct { embedded, c: int };
+let em: with_embedded = with_embedded {
+ a = 3,
+ b = 4,
+ c = 18,
+};
+
type aenum = enum u64 {
BIG_VALUE = 0x1234567887654321,
};
@@ -34,8 +43,10 @@ fn storage() void = {
assert(sl[0] == 1 && sl[1] == 2 && sl[2] == 3);
assert(len(st) == 6);
assert(su.x == 20 && su.y == 10);
+ assert(su_autofill.x == 20 && su_autofill.y == 10);
assert(au.x == 0 && au.y == 0);
assert(a3.coords.x == 0 && a3.coords.y == 0 && a3.z == 0);
+ assert(em.a == 3 && em.b == 4 && em.c == 18);
assert(big_value == 0x1234567887654321: aenum);
assert(float == 1234.5678);
assert(double == 1234.5678);