commit eb3cf2adb9481baa6a304eda1412e9780e3f1935
parent d7a5971a23cf972ea102e11284db8421426428ed
Author: Eyal Sawady <ecs@d2evs.net>
Date: Sun, 9 May 2021 12:38:35 -0400
hare::types: implement tagged union lookup
Signed-off-by: Eyal Sawady <ecs@d2evs.net>
Diffstat:
3 files changed, 79 insertions(+), 2 deletions(-)
diff --git a/hare/types/+test.ha b/hare/types/+test.ha
@@ -300,3 +300,29 @@ fn resolve(
assert(f.params[0]._type as builtin == builtin::INT);
assert(f.params[1]._type as builtin == builtin::STR);
};
+
+@test fn tagged() void = {
+ let st = store(x86_64, &resolve, null);
+ defer store_free(st);
+
+ let atype = parse_type("(int | int | void)");
+ defer ast::type_free(atype);
+ let htype = lookup(st, &atype)!;
+ assert(htype.sz == st.arch._int * 2);
+ assert(htype.align == st.arch._int);
+ let t = htype._type as tagged;
+ assert(len(t) == 2);
+ assert(t[0]._type as builtin == builtin::INT);
+ assert(t[1]._type as builtin == builtin::VOID);
+
+ let atype = parse_type("(int | (int | str | void))");
+ defer ast::type_free(atype);
+ let htype = lookup(st, &atype)!;
+ assert(htype.sz == 32);
+ assert(htype.align == 8);
+ let t = htype._type as tagged;
+ assert(len(t) == 3);
+ assert(t[0]._type as builtin == builtin::INT);
+ assert(t[1]._type as builtin == builtin::VOID);
+ assert(t[2]._type as builtin == builtin::STR);
+};
diff --git a/hare/types/store.ha b/hare/types/store.ha
@@ -223,6 +223,23 @@ fn fromast(store: *typestore, atype: *ast::_type) (_type | deferred | error) = {
};
st;
},
+ ta: ast::tagged_type => {
+ let ta = tagged_from_ast(store, ta)?;
+ sz = 0; align = 0;
+ for (let i = 0z; i < len(ta); i += 1) {
+ if (ta[i].sz > sz) {
+ sz = ta[i].sz;
+ };
+ if (ta[i].align > align) {
+ align = ta[i].align;
+ };
+ };
+ if (store.arch._int > align) {
+ align = store.arch._int;
+ };
+ sz += store.arch._int % align + store.arch._int;
+ ta;
+ },
tu: ast::tuple_type => {
let tu = tuple_from_ast(store, tu)?;
sz = 0; align = 0;
@@ -243,7 +260,6 @@ fn fromast(store: *typestore, atype: *ast::_type) (_type | deferred | error) = {
align = r.1;
r.2;
},
- ta: ast::tagged_type => abort(), // TODO
et: ast::enum_type => abort(), // TODO
};
return _type {
@@ -398,6 +414,41 @@ fn struct_from_ast(
};
};
+fn tagged_collect(
+ store: *typestore,
+ atype: ast::tagged_type,
+ types: *[]const *_type,
+) (void | deferred | error) = {
+ for (let i = 0z; i < len(atype); i += 1) match (atype[i]._type) {
+ ta: ast::tagged_type => tagged_collect(store, ta, types)?,
+ * => append(*types, lookup(store, atype[i])?),
+ };
+};
+
+fn tagged_cmp(a: const *void, b: const *void) int = {
+ const a = a: const **_type, b = b: const **_type;
+ return if (a.id < b.id) -1 else if (a.id == b.id) 0 else 1;
+};
+
+fn tagged_from_ast(
+ store: *typestore,
+ atype: ast::tagged_type,
+) (tagged | deferred | error) = {
+ let types: []const *_type = [];
+ //defer! free(types);
+ tagged_collect(store, atype, &types)?;
+ sort::sort(types, size(const *_type), &tagged_cmp);
+ for (let i = 1z; i < len(types); i += 1) {
+ if (types[i].id == types[i - 1].id) {
+ delete(types[i]);
+ i -= 1;
+ };
+ };
+ // TODO: Handle this gracefully
+ assert(len(types) > 1);
+ return types;
+};
+
fn tuple_from_ast(
store: *typestore,
membs: ast::tuple_type,
diff --git a/hare/types/types.ha b/hare/types/types.ha
@@ -87,7 +87,7 @@ export type struct_field = struct {
};
// A tagged union type, e.g. (int | uint | void).
-export type tagged = []*_type;
+export type tagged = []const *_type;
// A tuple type, e.g. (a, b, c)
export type tuple = []tuple_value;