hare

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

commit 696aefd5b69e84fef0dd837a3aa2aece46c7044f
parent df58525ba5493bd23d74902555a2cb25257b5105
Author: Sebastian <sebastian@sebsite.pw>
Date:   Sun,  1 Oct 2023 00:57:30 -0400

hare::ast: pass around pointers

We won't see much benefit from this until matching on pointers is
implemented, but this at least updates the interface.

References: https://todo.sr.ht/~sircmpwn/hare/378
Signed-off-by: Sebastian <sebastian@sebsite.pw>

Diffstat:
Mcmd/hare/build/types.ha | 2++
Mcmd/haretype/main.ha | 2+-
Mhare/ast/decl.ha | 14+++++++++++---
Mhare/ast/expr.ha | 92++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
Mhare/ast/type.ha | 119+++++++++++++++++++++++++++++++++++++------------------------------------------
Mhare/parse/+test/loc.ha | 6+++---
Mhare/types/+test.ha | 44++++++++++++++++++++++----------------------
7 files changed, 167 insertions(+), 112 deletions(-)

diff --git a/cmd/hare/build/types.ha b/cmd/hare/build/types.ha @@ -95,7 +95,9 @@ export fn ctx_finish(ctx: *context) void = { for (let i = 0z; i < len(ctx.defines); i += 1) { ast::ident_free(ctx.defines[i].ident); ast::type_finish(ctx.defines[i]._type); + free(ctx.defines[i]._type); ast::expr_finish(ctx.defines[i].init); + free(ctx.defines[i].init); }; free(ctx.defines); free(ctx.libdirs); diff --git a/cmd/haretype/main.ha b/cmd/haretype/main.ha @@ -27,7 +27,7 @@ fn typeinfo( const lexer = lex::init(&stream, "-"); defer lex::finish(&lexer); const atype = parse::_type(&lexer)?; - defer ast::type_finish(atype); + defer ast::type_finish(&atype); const typ = types::lookup(store, &atype)?; unparse::_type(os::stdout, &unparse::syn_nowrap, atype)?; fmt::println()?; diff --git a/hare/ast/decl.ha b/hare/ast/decl.ha @@ -72,25 +72,33 @@ export fn decl_finish(d: decl) void = { free(g[i].symbol); ident_free(g[i].ident); type_finish(g[i]._type); + free(g[i]._type); expr_finish(g[i].init); + free(g[i].init); }; free(g); case let t: []decl_type => for (let i = 0z; i < len(t); i += 1) { ident_free(t[i].ident); - type_finish(t[i]._type); + type_finish(&t[i]._type); }; free(t); case let f: decl_func => free(f.symbol); ident_free(f.ident); - type_finish(f.prototype); - if (f.body is expr) expr_finish(f.body as expr); + type_finish(&f.prototype); + match (f.body) { + case let e: expr => + expr_finish(&e); + case void => void; + }; case let c: []decl_const => for (let i = 0z; i < len(c); i += 1) { ident_free(c[i].ident); type_finish(c[i]._type); + free(c[i]._type); expr_finish(c[i].init); + free(c[i].init); }; free(c); }; diff --git a/hare/ast/expr.ha b/hare/ast/expr.ha @@ -433,15 +433,9 @@ export type expr = struct { }; // Frees resources associated with a Hare [[expr]]ession. -export fn expr_finish(e: (expr | nullable *expr)) void = match (e) { -case let e: nullable *expr => - match (e) { - case null => void; - case let e: *expr => - expr_finish(*e); - free(e); - }; -case let e: expr => +export fn expr_finish(e: nullable *expr) void = match (e) { +case null => void; +case let e: *expr => match (e.expr) { case let a: access_expr => match (a) { @@ -449,32 +443,49 @@ case let e: expr => ident_free(i); case let i: access_index => expr_finish(i.object); + free(i.object); expr_finish(i.index); + free(i.index); case let f: access_field => expr_finish(f.object); + free(f.object); free(f.field); case let t: access_tuple => expr_finish(t.object); + free(t.object); expr_finish(t.value); + free(t.value); }; case let a: align_expr => - type_finish(a: *_type); + type_finish(a); + free(a); case let a: alloc_expr => expr_finish(a.init); + free(a.init); expr_finish(a.capacity); + free(a.capacity); case let a: append_expr => expr_finish(a.object); + free(a.object); expr_finish(a.value); + free(a.value); expr_finish(a.length); + free(a.length); case let a: assert_expr => expr_finish(a.cond); + free(a.cond); expr_finish(a.message); + free(a.message); case let a: assign_expr => expr_finish(a.object); + free(a.object); expr_finish(a.value); + free(a.value); case let b: binarithm_expr => expr_finish(b.lvalue); + free(b.lvalue); expr_finish(b.rvalue); + free(b.rvalue); case let b: binding_expr => for (let i = 0z; i < len(b.bindings); i += 1) { match (b.bindings[i].name) { @@ -491,23 +502,30 @@ case let e: expr => free(u); }; type_finish(b.bindings[i]._type); + free(b.bindings[i]._type); expr_finish(b.bindings[i].init); + free(b.bindings[i].init); }; free(b.bindings); case let b: break_expr => free(b); case let c: call_expr => expr_finish(c.lvalue); + free(c.lvalue); for (let i = 0z; i < len(c.args); i += 1) { expr_finish(c.args[i]); + free(c.args[i]); }; free(c.args); case let c: cast_expr => expr_finish(c.value); + free(c.value); type_finish(c._type); + free(c._type); case let c: compound_expr => for (let i = 0z; i < len(c.exprs); i += 1) { expr_finish(c.exprs[i]); + free(c.exprs[i]); }; free(c.exprs); free(c.label); @@ -516,13 +534,15 @@ case let e: expr => case let a: array_constant => for (let i = 0z; i < len(a.values); i += 1) { expr_finish(a.values[i]); + free(a.values[i]); }; free(a.values); case let s: struct_constant => - struct_constant_finish(s); + struct_constant_finish(&s); case let t: tuple_constant => for (let i = 0z; i < len(t); i += 1) { expr_finish(t[i]); + free(t[i]); }; free(t); case (value | number_constant) => void; @@ -530,94 +550,128 @@ case let e: expr => case let c: continue_expr => free(c); case let d: defer_expr => - expr_finish(d: *expr); + expr_finish(d); + free(d); case let d: delete_expr => expr_finish(d.object); + free(d.object); case let e: error_assert_expr => expr_finish(e); + free(e); case let f: for_expr => expr_finish(f.bindings); + free(f.bindings); expr_finish(f.cond); + free(f.cond); expr_finish(f.afterthought); + free(f.afterthought); expr_finish(f.body); + free(f.body); case let f: free_expr => - expr_finish(f: *expr); + expr_finish(f); + free(f); case let i: if_expr => expr_finish(i.cond); + free(i.cond); expr_finish(i.tbranch); + free(i.tbranch); expr_finish(i.fbranch); + free(i.fbranch); case let e: insert_expr => expr_finish(e.object); + free(e.object); expr_finish(e.value); + free(e.value); expr_finish(e.length); + free(e.length); case let l: len_expr => - expr_finish(l: *expr); + expr_finish(l); + free(l); case let m: match_expr => expr_finish(m.value); + free(m.value); for (let i = 0z; i < len(m.cases); i += 1) { free(m.cases[i].name); type_finish(m.cases[i]._type); + free(m.cases[i]._type); const exprs = m.cases[i].exprs; for (let i = 0z; i < len(exprs); i += 1) { expr_finish(exprs[i]); + free(exprs[i]); }; free(exprs); }; free(m.cases); case let o: offset_expr => - expr_finish(o: *expr); + expr_finish(o); + free(o); case let p: propagate_expr => expr_finish(p); + free(p); case let r: return_expr => - expr_finish(r: *expr); + expr_finish(r); + free(r); case let s: size_expr => - type_finish(s: *_type); + type_finish(s); + free(s); case let s: slice_expr => expr_finish(s.object); + free(s.object); expr_finish(s.start); + free(s.start); expr_finish(s.end); + free(s.end); case let s: switch_expr => expr_finish(s.value); + free(s.value); for (let i = 0z; i < len(s.cases); i += 1) { let opts = s.cases[i].options; for (let j = 0z; j < len(opts); j += 1) { expr_finish(opts[j]); + free(opts[j]); }; free(opts); let exprs = s.cases[i].exprs; for (let j = 0z; j < len(exprs); j += 1) { expr_finish(exprs[j]); + free(exprs[j]); }; free(exprs); }; free(s.cases); case let u: unarithm_expr => expr_finish(u.operand); + free(u.operand); case let v: variadic_expr => match (v) { case vastart_expr => void; case let v: vaarg_expr => expr_finish(v); + free(v); case let v: vaend_expr => expr_finish(v); + free(v); }; case let y: yield_expr => free(y.label); expr_finish(y.value); + free(y.value); }; }; -fn struct_constant_finish(s: struct_constant) void = { +fn struct_constant_finish(s: *struct_constant) void = { ident_free(s.alias); for (let i = 0z; i < len(s.fields); i += 1) { match (s.fields[i]) { case let v: struct_value => free(v.name); type_finish(v._type); + free(v._type); expr_finish(v.init); + free(v.init); case let c: *struct_constant => - struct_constant_finish(*c); + struct_constant_finish(c); free(c); }; }; diff --git a/hare/ast/type.ha b/hare/ast/type.ha @@ -133,26 +133,19 @@ export type _type = struct { tagged_type | tuple_type), }; -fn struct_type_finish(t: (struct_type | union_type)) void = { - let membs = match (t) { - case let s: struct_type => - yield s.members: []struct_member; - case let u: union_type => - yield u: []struct_member; - }; +fn struct_members_free(membs: []struct_member) void = { for (let i = 0z; i < len(membs); i += 1) { free(membs[i].docs); - match (membs[i]._offset) { - case null => void; - case let e: *expr => - expr_finish(e); - }; + expr_finish(membs[i]._offset); + free(membs[i]._offset); match (membs[i].member) { case let f: struct_field => free(f.name); type_finish(f._type); + free(f._type); case let e: struct_embedded => - type_finish(e: *_type); + type_finish(e); + free(e); case let a: struct_alias => ident_free(a); }; @@ -161,58 +154,56 @@ fn struct_type_finish(t: (struct_type | union_type)) void = { }; // Frees resources associated with a [[_type]]. -export fn type_finish(t: (_type | nullable *_type)) void = { - match (t) { - case let t: nullable *_type => - match (t) { - case null => void; - case let t: *_type => - type_finish(*t); - free(t); +export fn type_finish(t: nullable *_type) void = match (t) { +case null => void; +case let t: *_type => + match (t.repr) { + case let a: alias_type => + ident_free(a.ident); + case builtin_type => void; + case let e: enum_type => + for (let i = 0z; i < len(e.values); i += 1) { + free(e.values[i].name); + expr_finish(e.values[i].value); + free(e.values[i].value); }; - case let t: _type => - match (t.repr) { - case let a: alias_type => - ident_free(a.ident); - case builtin_type => void; - case let e: enum_type => - for (let i = 0z; i < len(e.values); i += 1) { - free(e.values[i].name); - match (e.values[i].value) { - case null => void; - case let v: *expr => - expr_finish(v); - }; - }; - free(e.values); - case let f: func_type => - type_finish(f.result); - for (let i = 0z; i < len(f.params); i += 1) { - free(f.params[i].name); - type_finish(f.params[i]._type); - }; - free(f.params); - case let l: list_type => - match (l.length) { - case let e: *expr => - expr_finish(e); - case => void; - }; - type_finish(l.members); - case let p: pointer_type => - type_finish(p.referent); - case let s: (struct_type | union_type) => - struct_type_finish(s); - case let t: tagged_type => - for (let i = 0z; i < len(t); i += 1) { - type_finish(t[i]); - }; - free(t); - case let t: tuple_type => - for (let i = 0z; i < len(t); i += 1) { - type_finish(t[i]); - }; - free(t); + free(e.values); + case let f: func_type => + type_finish(f.result); + free(f.result); + for (let i = 0z; i < len(f.params); i += 1) { + free(f.params[i].name); + type_finish(f.params[i]._type); + free(f.params[i]._type); }; + free(f.params); + case let l: list_type => + match (l.length) { + case let e: *expr => + expr_finish(e); + free(e); + case => void; + }; + type_finish(l.members); + free(l.members); + case let p: pointer_type => + type_finish(p.referent); + free(p.referent); + case let s: struct_type => + struct_members_free(s.members); + case let t: tagged_type => + for (let i = 0z; i < len(t); i += 1) { + type_finish(t[i]); + free(t[i]); + }; + free(t); + case let t: tuple_type => + for (let i = 0z; i < len(t); i += 1) { + type_finish(t[i]); + free(t[i]); + }; + free(t); + case let u: union_type => + struct_members_free(u); }; }; diff --git a/hare/parse/+test/loc.ha b/hare/parse/+test/loc.ha @@ -21,7 +21,7 @@ fn expr_testloc(srcs: str...) void = for (let i = 0z; i < len(srcs); i += 1) { fmt::errorfln("{}: {}", srcs[i], strerror(err))!; abort(); }; - defer ast::expr_finish(exp); + defer ast::expr_finish(&exp); let runes = 0z; let d = utf8::decode(srcs[i]); for (true) match (utf8::next(&d)!) { @@ -86,7 +86,7 @@ fn expr_testloc(srcs: str...) void = for (let i = 0z; i < len(srcs); i += 1) { fmt::errorln(strerror(err))!; abort(); }; - defer ast::expr_finish(exp); + defer ast::expr_finish(&exp); assert(exp.start.line == 1 && exp.start.col == 1); assert(exp.end.line == 1 && exp.end.col == 13); let c = exp.expr as ast::cast_expr; @@ -110,7 +110,7 @@ fn type_testloc(srcs: str...) void = for (let i = 0z; i < len(srcs); i += 1) { fmt::errorln(strerror(err))!; abort(); }; - defer ast::type_finish(typ); + defer ast::type_finish(&typ); let runes = 0z; let d = utf8::decode(srcs[i]); for (true) match (utf8::next(&d)!) { diff --git a/hare/types/+test.ha b/hare/types/+test.ha @@ -21,7 +21,7 @@ fn parse_type(in: str) ast::_type = { defer store_free(st); let atype = parse_type("int"); - defer ast::type_finish(atype); + defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.repr as builtin == builtin::INT); assert(htype.sz == x86_64._int && htype._align == x86_64._int); @@ -30,7 +30,7 @@ fn parse_type(in: str) ast::_type = { assert(htype == type2, "types should be singletons"); let atype = parse_type("*int"); - defer ast::type_finish(atype); + defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.sz == x86_64._pointer && htype._align == x86_64._pointer); let htype = htype.repr as pointer; @@ -55,7 +55,7 @@ fn resolve( // Basic struct let atype = parse_type("struct { x: int, y: int }"); - defer ast::type_finish(atype); + defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.sz == 8); assert(htype._align == 4); @@ -75,7 +75,7 @@ fn resolve( // Basic union let atype = parse_type("union { x: int, y: int }"); - defer ast::type_finish(atype); + defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.sz == 4); assert(htype._align == 4); @@ -95,7 +95,7 @@ fn resolve( // Padding let atype = parse_type("struct { w: u8, x: u32, y: u8, z: u64 }"); - defer ast::type_finish(atype); + defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.sz == 24); assert(htype._align == 8); @@ -112,13 +112,13 @@ fn resolve( assert(z.offs == 16); let atype = parse_type("struct { x: u8, y: size, z: u8 }"); - defer ast::type_finish(atype); + defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.sz == 24); // Sort order let atype = parse_type("struct { z: u8, y: u8, x: u8, q: u8 }"); - defer ast::type_finish(atype); + defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; let stype = htype.repr as _struct; assert(stype.fields[0].name == "q"); @@ -136,7 +136,7 @@ fn resolve( }, p: int, }"); - defer ast::type_finish(atype); + defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.sz == 20); assert(htype._align == 4); @@ -162,7 +162,7 @@ fn resolve( }, p: int, }"); - defer ast::type_finish(atype); + defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.sz == 16); assert(htype._align == 4); @@ -190,7 +190,7 @@ fn resolve( @offset(16) y: int, @offset(32) z: int, }"); - defer ast::type_finish(atype); + defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.sz == 36); assert(htype._align == 4); @@ -209,7 +209,7 @@ fn resolve( // Basic case let atype = parse_type("(int, int)"); - defer ast::type_finish(atype); + defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.sz == 8); assert(htype._align == 4); @@ -223,7 +223,7 @@ fn resolve( // Padding let atype = parse_type("(i8, i32, i8, i64)"); - defer ast::type_finish(atype); + defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.sz == 24); assert(htype._align == 8); @@ -241,7 +241,7 @@ fn resolve( // Slice let atype = parse_type("[]int"); - defer ast::type_finish(atype); + defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.sz == 24); assert(htype._align == 8); @@ -250,7 +250,7 @@ fn resolve( // Normal array let atype = parse_type("[5]i32"); - defer ast::type_finish(atype); + defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.sz == 4 * 5); assert(htype._align == 4); @@ -260,7 +260,7 @@ fn resolve( // Unbounded array let atype = parse_type("[*]i32"); - defer ast::type_finish(atype); + defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.sz == SIZE_UNDEFINED); assert(htype._align == 4); @@ -270,7 +270,7 @@ fn resolve( // Contextual array (equivalent to unbounded at this compilation stage) let atype = parse_type("[_]i32"); - defer ast::type_finish(atype); + defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.sz == SIZE_UNDEFINED); assert(htype._align == 4); @@ -284,7 +284,7 @@ fn resolve( defer store_free(st); let atype = parse_type("fn() never"); - defer ast::type_finish(atype); + defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.sz == SIZE_UNDEFINED); assert(htype._align == SIZE_UNDEFINED); @@ -294,7 +294,7 @@ fn resolve( assert(len(f.params) == 0); let atype = parse_type("fn(foo: int, bar: str...) int"); - defer ast::type_finish(atype); + defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.sz == SIZE_UNDEFINED); assert(htype._align == SIZE_UNDEFINED); @@ -311,7 +311,7 @@ fn resolve( defer store_free(st); let atype = parse_type("(int | int | void)"); - defer ast::type_finish(atype); + defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.sz == st.arch._int * 2); assert(htype._align == st.arch._int); @@ -321,7 +321,7 @@ fn resolve( assert(t[1].repr as builtin == builtin::VOID); let atype = parse_type("(int | (int | str | void))"); - defer ast::type_finish(atype); + defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.sz == 32); assert(htype._align == 8); @@ -344,7 +344,7 @@ fn resolve( assert((al.repr as alias).secondary == of); const atype = parse_type("myalias"); - defer ast::type_finish(atype); + defer ast::type_finish(&atype); const htype = lookup(st, &atype)!; assert(htype == al); }; @@ -354,7 +354,7 @@ fn resolve( defer store_free(st); const atype = parse_type("myalias"); - defer ast::type_finish(atype); + defer ast::type_finish(&atype); const htype = lookup(st, &atype)!; assert((htype.repr as alias).secondary == null);