hare

The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

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:
Mhare/types/+test.ha | 26++++++++++++++++++++++++++
Mhare/types/store.ha | 53++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mhare/types/types.ha | 2+-
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;