harec

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

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:
Minclude/expr.h | 2+-
Msrc/check.c | 35+++++++++++++++--------------------
Msrc/eval.c | 93++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Msrc/gen.c | 2+-
Mtests/11-globals.ha | 13++++++++++++-
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);