commit e9acfa8ee777ea3290553af54079c79c8ff4e62e
parent 4d40b91c5b4fee2b07fe95b666392f3d03667011
Author: Drew DeVault <sir@cmpwn.com>
Date: Sun, 26 Sep 2021 10:18:45 +0200
gen: struct/union type info
Diffstat:
3 files changed, 140 insertions(+), 2 deletions(-)
diff --git a/src/gen.c b/src/gen.c
@@ -3605,9 +3605,104 @@ gen_type_info(struct gen_context *ctx,
item->value = constl(len);
break;
case STORAGE_STRUCT:
+ case STORAGE_UNION:
+ *repr_name = "struct_union";
+ item->value = constw(type_hash(&repr));
+ item->next = xcalloc(1, sizeof(struct qbe_data_item));
+ item = item->next;
+
+ item->type = QD_ZEROED;
+ item->zeroed = 4;
+ item->next = xcalloc(1, sizeof(struct qbe_data_item));
+ item = item->next;
+
+ item->type = QD_VALUE;
+ item->value = constw(type->storage == STORAGE_STRUCT ? 0 : 1);
+ item->value.type = &qbe_byte;
+ item->next = xcalloc(1, sizeof(struct qbe_data_item));
+ item = item->next;
+
+ item->type = QD_ZEROED;
+ item->zeroed = 7;
+ item->next = xcalloc(1, sizeof(struct qbe_data_item));
+ item = item->next;
+
+ def = xcalloc(1, sizeof(struct qbe_def));
+ def->name = gen_name(ctx, "sldata.%d");
+ def->kind = Q_DATA;
+ subitem = &def->data.items;
+ for (struct struct_field *field = type->struct_union.fields;
+ field; field = field->next) {
+ if (field->name) {
+ size_t l = strlen(field->name);
+ struct qbe_def *sdef = xcalloc(1, sizeof(struct qbe_def));
+ sdef->name = gen_name(ctx, "strdata.%d");
+ sdef->kind = Q_DATA;
+ sdef->data.items.type = QD_STRING;
+ sdef->data.items.str = xcalloc(1, l);
+ sdef->data.items.sz = l;
+ memcpy(sdef->data.items.str, field->name, l);
+ qbe_append_def(ctx->out, sdef);
+
+ subitem->value.kind = QV_GLOBAL;
+ subitem->value.type = &qbe_long;
+ subitem->value.name = strdup(sdef->name);
+ subitem->next = xcalloc(1, sizeof(struct qbe_data_item));
+ subitem = subitem->next;
+ subitem->type = QD_VALUE;
+ subitem->value = constl(l);
+ subitem->next = xcalloc(1, sizeof(struct qbe_data_item));
+ subitem = subitem->next;
+ subitem->type = QD_VALUE;
+ subitem->value = constl(l);
+ } else {
+ subitem->value = constl(0);
+ subitem->next = xcalloc(1, sizeof(struct qbe_data_item));
+ subitem = subitem->next;
+ subitem->type = QD_VALUE;
+ subitem->value = constl(0);
+ subitem->next = xcalloc(1, sizeof(struct qbe_data_item));
+ subitem = subitem->next;
+ subitem->type = QD_VALUE;
+ subitem->value = constl(0);
+ }
+
+ subitem->next = xcalloc(1, sizeof(struct qbe_data_item));
+ subitem = subitem->next;
+
+ subitem->type = QD_VALUE;
+ subitem->value = constl(field->offset);
+ subitem->next = xcalloc(1, sizeof(struct qbe_data_item));
+ subitem = subitem->next;
+
+ ref = mktyperef(ctx, field->type);
+ subitem->type = QD_VALUE;
+ subitem->value.kind = QV_GLOBAL;
+ subitem->value.type = &qbe_long;
+ subitem->value.name = ref.name;
+ if (field->next) {
+ subitem->next = xcalloc(1, sizeof(struct qbe_data_item));
+ subitem = subitem->next;
+ }
+ ++len;
+ }
+ qbe_append_def(ctx->out, def);
+
+ item->type = QD_VALUE;
+ item->value.kind = QV_GLOBAL;
+ item->value.type = &qbe_long;
+ item->value.name = strdup(def->name);
+ item->next = xcalloc(1, sizeof(struct qbe_data_item));
+ item = item->next;
+ item->type = QD_VALUE;
+ item->value = constl(len);
+ item->next = xcalloc(1, sizeof(struct qbe_data_item));
+ item = item->next;
+ item->type = QD_VALUE;
+ item->value = constl(len);
+ break;
case STORAGE_TAGGED:
case STORAGE_TUPLE:
- case STORAGE_UNION:
// XXX: Temporary code to make sure code in the wild builds
// while we flesh out these types
item->value = constw(0);
diff --git a/tests/34-reflect.ha b/tests/34-reflect.ha
@@ -124,6 +124,48 @@ fn functions() void = {
assert(func.flags == types::func_flags::NORETURN);
};
+fn struct_union() void = {
+ let ty = types::reflect(type(struct {
+ x: int,
+ y: int,
+ }));
+ assert(ty.sz == size(int) * 2);
+ assert(ty.al == size(int));
+ let su = ty.repr as types::struct_union;
+ assert(su.kind == types::struct_kind::STRUCT);
+ assert(len(su.fields) == 2);
+ assert(su.fields[0].name == "x");
+ assert(su.fields[0].offs == 0);
+ assert(su.fields[0].type_ == type(int));
+ assert(su.fields[1].name == "y");
+ assert(su.fields[1].offs == 4);
+ assert(su.fields[1].type_ == type(int));
+
+ let ty = types::reflect(type(union {
+ x: int,
+ y: int,
+ }));
+ let su = ty.repr as types::struct_union;
+ assert(su.kind == types::struct_kind::UNION);
+ assert(len(su.fields) == 2);
+ assert(su.fields[0].name == "x");
+ assert(su.fields[0].offs == 0);
+ assert(su.fields[1].name == "y");
+ assert(su.fields[1].offs == 0);
+
+ let ty = types::reflect(type(struct {
+ x: int,
+ y: int,
+ struct {
+ z: int,
+ },
+ }));
+ let su = ty.repr as types::struct_union;
+ assert(len(su.fields) == 3);
+ assert(su.fields[2].name == "");
+ assert(su.fields[2].offs == 8);
+};
+
export fn main() void = {
builtins();
aliases();
@@ -132,4 +174,5 @@ export fn main() void = {
slices();
pointers();
functions();
+ struct_union();
};
diff --git a/types/reflect.ha b/types/reflect.ha
@@ -99,7 +99,7 @@ export type pointer = struct {
export type slice_repr = type;
// Indicates if a [[_struct]] was declared as a struct or union type.
-export type struct_kind = enum {
+export type struct_kind = enum uint {
STRUCT,
UNION,
};