commit c944388851200927212f4f113b53132881cbf3a9
parent 644e974b9969d2d0065bbf4ac6f2227db1f3f783
Author: Drew DeVault <sir@cmpwn.com>
Date: Sun, 10 Jan 2021 09:44:45 -0500
check: basic struct expression implementation
Missing a few things:
- Named struct types
-> Out-of-order initialization
-> Testing for exhaustive initialization
-> Autofill
- Embedded structs
Diffstat:
5 files changed, 96 insertions(+), 0 deletions(-)
diff --git a/include/expr.h b/include/expr.h
@@ -177,6 +177,12 @@ struct expression_return {
struct expression *value;
};
+struct expression_struct {
+ const struct type_struct_union *field;
+ struct expression *value;
+ struct expression_struct *next;
+};
+
enum unarithm_operator {
UN_ADDRESS, // &
UN_BNOT, // ~
@@ -209,6 +215,7 @@ struct expression {
struct expression_list list;
struct expression_measure measure;
struct expression_return _return;
+ struct expression_struct _struct;
struct expression_unarithm unarithm;
};
};
diff --git a/include/types.h b/include/types.h
@@ -104,6 +104,8 @@ struct type {
};
const struct type *type_dereference(const struct type *type);
+const struct type_struct_union *type_lookup_field(
+ const struct type *type, const char *name);
const char *type_storage_unparse(enum type_storage storage);
bool type_is_signed(const struct type *type);
diff --git a/src/check.c b/src/check.c
@@ -643,6 +643,70 @@ check_expr_return(struct context *ctx,
}
static void
+check_expr_struct(struct context *ctx,
+ const struct ast_expression *aexpr,
+ struct expression *expr)
+{
+ trenter(TR_CHECK, "struct");
+ assert(!aexpr->_struct.autofill); // TODO
+ assert(!aexpr->_struct.type.name); // TODO
+ expr->type = EXPR_STRUCT;
+
+ struct ast_type stype = {
+ .storage = TYPE_STORAGE_STRUCT,
+ .flags = TYPE_CONST,
+ };
+ struct ast_struct_union_type *tfield = &stype.struct_union;
+ struct ast_struct_union_type **tnext = &tfield->next;
+ struct expression_struct *sexpr = &expr->_struct;
+ struct expression_struct **snext = &sexpr->next;
+
+ struct ast_field_value *afield = aexpr->_struct.fields;
+ while (afield) {
+ assert(!afield->is_embedded); // TODO
+
+ tfield->member_type = MEMBER_TYPE_FIELD;
+ tfield->field.name = afield->field.name;
+ tfield->field.type = afield->field.type;
+ sexpr->value = xcalloc(1, sizeof(struct expression));
+ check_expression(ctx, afield->field.initializer, sexpr->value);
+
+ if (afield->next) {
+ *tnext = tfield = xcalloc(
+ 1, sizeof(struct ast_struct_union_type));
+ tnext = &tfield->next;
+ *snext = sexpr = xcalloc(
+ 1, sizeof(struct expression_struct));
+ snext = &sexpr->next;
+ }
+
+ afield = afield->next;
+ }
+
+ expr->result = type_store_lookup_atype(&ctx->store, &stype);
+
+ tfield = stype.struct_union.next;
+ sexpr = &expr->_struct;
+ while (tfield) {
+ const struct type_struct_union *field = type_lookup_field(
+ expr->result, tfield->field.name);
+ // TODO: Use more specific error location
+ expect(&aexpr->loc,
+ type_is_assignable(&ctx->store, field->type, sexpr->value->result),
+ "Cannot initialize struct field from value of this type");
+ sexpr->field = field;
+ sexpr->value = lower_implicit_cast(field->type, sexpr->value);
+
+ struct ast_struct_union_type *next = tfield->next;
+ free(tfield);
+ tfield = next;
+ sexpr = sexpr->next;
+ }
+
+ trleave(TR_CHECK, NULL);
+}
+
+static void
check_expr_unarithm(struct context *ctx,
const struct ast_expression *aexpr,
struct expression *expr)
@@ -753,7 +817,10 @@ check_expression(struct context *ctx,
check_expr_return(ctx, aexpr, expr);
break;
case EXPR_SLICE:
+ assert(0); // TODO
case EXPR_STRUCT:
+ check_expr_struct(ctx, aexpr, expr);
+ break;
case EXPR_SWITCH:
assert(0); // TODO
case EXPR_UNARITHM:
diff --git a/src/type_store.c b/src/type_store.c
@@ -646,6 +646,8 @@ type_init_from_type(struct type_store *store,
type_store_lookup_type(store, ofield->type);
field->offset = ofield->offset;
}
+ new->size = old->size;
+ new->align = old->align;
break;
case TYPE_STORAGE_TAGGED_UNION:
assert(0); // TODO
diff --git a/src/types.c b/src/types.c
@@ -1,5 +1,6 @@
#include <assert.h>
#include <stdbool.h>
+#include <string.h>
#include "types.h"
const struct type *
@@ -11,6 +12,23 @@ type_dereference(const struct type *type)
return type_dereference(type->pointer.referent);
}
+const struct type_struct_union *
+type_lookup_field(const struct type *type, const char *name)
+{
+ // TODO: We should consider lowering unions into structs with explicit
+ // offsets
+ assert(type->storage == TYPE_STORAGE_STRUCT
+ || type->storage == TYPE_STORAGE_UNION);
+ struct type_struct_union *typesu = type->struct_union;
+ while (typesu) {
+ if (strcmp(typesu->name, name) == 0) {
+ return typesu;
+ }
+ typesu = typesu->next;
+ }
+ return NULL;
+}
+
const char *
type_storage_unparse(enum type_storage storage)
{