commit 880dea36a4dcda574262dc70349b4baa08c9f4b8
parent 8b17d5954c0c53b8d57e5f9c1598408f99af6621
Author: Drew DeVault <sir@cmpwn.com>
Date: Sun, 10 Jan 2021 11:34:38 -0500
gen: implement struct expressions
Diffstat:
3 files changed, 43 insertions(+), 4 deletions(-)
diff --git a/src/check.c b/src/check.c
@@ -685,12 +685,13 @@ check_expr_struct(struct context *ctx,
expr->result = type_store_lookup_atype(&ctx->store, &stype);
- tfield = stype.struct_union.next;
+ tfield = &stype.struct_union;
sexpr = &expr->_struct;
while (tfield) {
const struct struct_field *field = type_lookup_field(
expr->result, tfield->field.name);
// TODO: Use more specific error location
+ expect(&aexpr->loc, field, "No field by this name exists for this type");
expect(&aexpr->loc,
type_is_assignable(&ctx->store, field->type, sexpr->value->result),
"Cannot initialize struct field from value of this type");
@@ -698,7 +699,9 @@ check_expr_struct(struct context *ctx,
sexpr->value = lower_implicit_cast(field->type, sexpr->value);
struct ast_struct_union_type *next = tfield->next;
- free(tfield);
+ if (tfield != &stype.struct_union) {
+ free(tfield);
+ }
tfield = next;
sexpr = sexpr->next;
}
diff --git a/src/gen.c b/src/gen.c
@@ -959,6 +959,27 @@ gen_expr_return(struct gen_context *ctx,
}
static void
+gen_expr_struct(struct gen_context *ctx,
+ const struct expression *expr,
+ const struct qbe_value *out)
+{
+ // XXX: ARCH
+ struct qbe_value base = {0}, ptr = {0}, offset = {0};
+ gen_temp(ctx, &base, &qbe_long, "base.%d");
+ gen_temp(ctx, &ptr, &qbe_long, "ptr.%d");
+ pushi(ctx->current, &base, Q_COPY, out, NULL);
+
+ const struct expression_struct *field = &expr->_struct;
+ while (field) {
+ constl(&offset, field->field->offset);
+ pushi(ctx->current, &ptr, Q_ADD, &base, &offset, NULL);
+ ptr.indirect = !type_is_aggregate(field->field->type);
+ gen_expression(ctx, field->value, &ptr);
+ field = field->next;
+ }
+}
+
+static void
gen_expr_address(struct gen_context *ctx,
const struct expression *expr,
const struct qbe_value *out)
@@ -1072,7 +1093,10 @@ gen_expression(struct gen_context *ctx,
gen_expr_return(ctx, expr, out);
break;
case EXPR_SLICE:
+ assert(0); // TODO
case EXPR_STRUCT:
+ gen_expr_struct(ctx, expr, out);
+ break;
case EXPR_SWITCH:
assert(0); // TODO
case EXPR_UNARITHM:
diff --git a/src/qtype.c b/src/qtype.c
@@ -130,11 +130,23 @@ lookup_aggregate(struct gen_context *ctx, const struct type *type)
field->type = &qbe_long; // XXX: ARCH
field->count = 3;
break;
+ case TYPE_STORAGE_STRUCT:
+ case TYPE_STORAGE_UNION:
+ assert(type->struct_union.c_compat); // TODO
+ for (struct struct_field *tfield = type->struct_union.fields;
+ tfield; tfield = tfield->next) {
+ field->type = qtype_for_type(ctx, tfield->type, true);
+ field->count = 1;
+
+ if (tfield->next) {
+ field->next = xcalloc(1, sizeof(struct qbe_field));
+ field = field->next;
+ }
+ }
+ break;
case TYPE_STORAGE_ENUM:
case TYPE_STORAGE_SLICE:
- case TYPE_STORAGE_STRUCT:
case TYPE_STORAGE_TAGGED_UNION:
- case TYPE_STORAGE_UNION:
assert(0); // TODO
case TYPE_STORAGE_ARRAY:
case TYPE_STORAGE_ALIAS: