hare

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

commit 10c5e27f2f64f11a50bf994a18428ea8f9ea88a2
parent f4d83fe36175b6aadafedabe7c74f5f6be7133d8
Author: Eyal Sawady <ecs@d2evs.net>
Date:   Wed, 24 Mar 2021 01:30:01 -0400

hare::unparse: flesh out

Diffstat:
Mcmd/hare/schedule.ha | 5+++--
Dhare/ast/unparse.ha | 21---------------------
Mhare/module/manifest.ha | 3++-
Ahare/unparse/decl.ha | 192+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ahare/unparse/expr.ha | 14++++++++++++++
Ahare/unparse/ident.ha | 31+++++++++++++++++++++++++++++++
Ahare/unparse/import.ha | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Ahare/unparse/type.ha | 293+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ahare/unparse/unit.ha | 16++++++++++++++++
Ahare/unparse/util.ha | 12++++++++++++
Mscripts/gen-stdlib | 19++++++++++++++++---
Mstdlib.mk | 52++++++++++++++++++++++++++++++++++++++++++++--------
12 files changed, 675 insertions(+), 35 deletions(-)

diff --git a/cmd/hare/schedule.ha b/cmd/hare/schedule.ha @@ -2,6 +2,7 @@ use encoding::hex; use fmt; use hare::ast; use hare::module; +use hare::unparse; use hash::fnv; use hash; use os; @@ -32,7 +33,7 @@ fn sched_module(plan: *plan, ident: ast::ident, link: *[]*task) *task = { let ver = match (module::lookup(plan.context, ident)) { err: module::error => { - let ident = ast::ident_unparse_s(ident); + let ident = unparse::ident_s(ident); fmt::fatal("Error resolving {}: {}", ident, module::errstr(err)); }, @@ -156,7 +157,7 @@ fn sched_hare_object( let output = if (len(namespace) != 0) { // TODO: consult/update cache manifest let version = hex::encode(ver.hash); - let ns = ast::ident_unparse_s(namespace); + let ns = unparse::ident_s(namespace); let env = module::ident_underscore(namespace); defer free(env); diff --git a/hare/ast/unparse.ha b/hare/ast/unparse.ha @@ -1,21 +0,0 @@ -use fmt; -use io; -use strio; - -// Unparses an identifier. -export fn ident_unparse(out: *io::stream, ident: ident) (size | io::error) = { - let n = 0z; - for (let i = 0z; i < len(ident); i += 1) { - n += fmt::fprintf(out, "{}{}", ident[i], - if (i + 1 < len(ident)) "::" - else "")?; - }; - return n; -}; - -// Unparses an identifier into a string. The caller must free the return value. -export fn ident_unparse_s(ident: ident) str = { - let buf = strio::dynamic(); - ident_unparse(buf, ident); - return strio::finish(buf); -}; diff --git a/hare/module/manifest.ha b/hare/module/manifest.ha @@ -2,6 +2,7 @@ use encoding::hex; use fmt; use fs; use hare::ast; +use hare::unparse; use io; use path; use time; @@ -31,7 +32,7 @@ export fn manifest_write(ctx: *context, manifest: *manifest) (void | error) = { let fd = fs::create(ctx.fs, mpath, 0o644)?; defer io::close(fd); - let ident = ast::ident_unparse_s(manifest.ident); + let ident = unparse::ident_s(manifest.ident); defer free(ident); fmt::fprintfln(fd, "# {}", ident)?; fmt::fprintln(fd, "# This file is an internal Hare implementation detail.")?; diff --git a/hare/unparse/decl.ha b/hare/unparse/decl.ha @@ -0,0 +1,192 @@ +use io; +use fmt; +use hare::ast; +use hare::lex; +use strio; + +export fn decl(out: *io::stream, d: ast::decl) (size | io::error) = { + let n = 0z; + if (d.exported) { + n += fmt::fprint(out, "export ")?; + }; + match (d.decl) { + g: []ast::decl_global => { + n += fmt::fprint(out, + if (g[0].is_const) "def " else "let ")?; + for (let i = 0z; i < len(g); i += 1) { + if (len(g[i].symbol) != 0) { + n += fmt::fprintf(out, + "@symbol(\"{}\") ", g[i].symbol)?; + }; + n += ident(out, g[i].ident)?; + n += fmt::fprint(out, ": ")?; + n += _type(out, 0, g[i]._type)?; + n += fmt::fprint(out, " = ")?; + n += expr(out, 0, g[i].init)?; + if (i + 1 < len(g)) { + n += fmt::fprint(out, ", ")?; + }; + }; + }, + t: []ast::decl_type => { + n += fmt::fprint(out, "type ")?; + for (let i = 0z; i < len(t); i += 1) { + n += ident(out, t[i].ident)?; + n += fmt::fprint(out, " = ")?; + n += _type(out, 0, t[i]._type)?; + if (i + 1 < len(t)) { + n += fmt::fprint(out, ", ")?; + }; + }; + }, + f: ast::decl_func => { + n += fmt::fprint(out, switch (f.attrs) { + ast::fndecl_attrs::NONE => "", + ast::fndecl_attrs::FINI => "@fini ", + ast::fndecl_attrs::INIT => "@init ", + ast::fndecl_attrs::TEST => "@test ", + })?; + let p = f.prototype._type as ast::func_type; + if (p.attrs & ast::func_attrs::NORETURN != 0) { + n += fmt::fprint(out, "@noreturn ")?; + }; + if (len(f.symbol) != 0) { + n += fmt::fprintf(out, "@symbol(\"{}\") ", + f.symbol)?; + }; + n += fmt::fprint(out, "fn ")?; + n += ident(out, f.ident)?; + n += prototype(out, 0, + f.prototype._type as ast::func_type)?; + match (f.body) { + void => void, + e: ast::expr => { + n += fmt::fprint(out, " = ")?; + n += expr(out, 0, e)?; + }, + }; + }, + }; + n += fmt::fprint(out, ";")?; + return n; +}; + +fn decl_test(d: ast::decl, expected: str) bool = { + let buf = strio::dynamic(); + decl(buf, d) as size; + let s = strio::finish(buf); + defer free(s); + return s == expected; +}; + +@test fn decl() void = { + let loc = lex::location { + path = "<test>", + line = 0, + col = 0, + }; + let type_int = ast::_type { + loc = loc, + flags = 0, + _type = ast::builtin_type::INT, + }; + let type_fn = ast::_type { + loc = loc, + flags = ast::type_flags::CONST, + _type = ast::func_type { + result = &type_int, + attrs = ast::func_attrs::NORETURN, + variadism = ast::variadism::HARE, + params = [ + ast::func_param { + loc = loc, + name = "foo", + _type = &type_int, + }, + ast::func_param { + loc = loc, + name = "bar", + _type = &type_int, + }, + ], + }, + }; + let expr_void = void: ast::constant_expr: ast::expr; + + let d = ast::decl { + loc = loc, + exported = false, + decl = [ + ast::decl_global { + is_const = false, + symbol = "", + ident = ["foo", "bar"], + _type = type_int, + init = expr_void, + }, + ast::decl_global { + is_const = false, + symbol = "foobar", + ident = ["baz"], + _type = type_int, + init = expr_void, + }, + ], + }; + assert(decl_test(d, "let foo::bar: int = void, @symbol(\"foobar\") baz: int = void;")); + + d.exported = true; + d.decl = [ + ast::decl_global { + is_const = true, + ident = ["foo"], + _type = type_int, + init = expr_void, + ... + }, + ]; + assert(decl_test(d, "export def foo: int = void;")); + + d.exported = false; + d.decl = [ + ast::decl_type { + ident = ["foo"], + _type = type_int, + }, + ast::decl_type { + ident = ["bar"], + _type = type_int, + }, + ]; + assert(decl_test(d, "type foo = int, bar = int;")); + + d.decl = ast::decl_func { + symbol = "foo", + ident = ["foo"], + prototype = type_fn, + body = void, + attrs = ast::fndecl_attrs::FINI, + }; + assert(decl_test(d, "@fini @noreturn @symbol(\"foo\") fn foo(foo: int, bar: int...) int;")); + + type_fn._type = ast::func_type { + result = &type_int, + attrs = 0, + variadism = ast::variadism::NONE, + params = [ + ast::func_param { + loc = loc, + name = "", + _type = &type_int, + }, + ], + }; + d.decl = ast::decl_func { + symbol = "", + ident = ["foo"], + prototype = type_fn, + body = expr_void, + attrs = 0, + }; + assert(decl_test(d, "fn foo(_: int) int = void;")); +}; diff --git a/hare/unparse/expr.ha b/hare/unparse/expr.ha @@ -0,0 +1,14 @@ +use io; +use fmt; +use hare::ast; + +// TODO +export fn expr( + out: *io::stream, + indent: size, + t: ast::expr +) (size | io::error) = { + let e = t as ast::constant_expr; + assert(e is void); + return fmt::fprint(out, "void")?; +}; diff --git a/hare/unparse/ident.ha b/hare/unparse/ident.ha @@ -0,0 +1,31 @@ +use fmt; +use hare::ast; +use io; +use strio; + +// Unparses an identifier. +export fn ident(out: *io::stream, id: ast::ident) (size | io::error) = { + let n = 0z; + for (let i = 0z; i < len(id); i += 1) { + n += fmt::fprintf(out, "{}{}", id[i], + if (i + 1 < len(id)) "::" + else "")?; + }; + return n; +}; + +// Unparses an identifier into a string. The caller must free the return value. +export fn ident_s(id: ast::ident) str = { + let buf = strio::dynamic(); + ident(buf, id); + return strio::finish(buf); +}; + +@test fn ident() void = { + let s = ident_s(["foo", "bar", "baz"]); + assert(s == "foo::bar::baz"); + free(s); + s = ident_s(["foo"]); + assert(s == "foo"); + free(s); +}; diff --git a/hare/unparse/import.ha b/hare/unparse/import.ha @@ -0,0 +1,52 @@ +use fmt; +use io; +use hare::ast; +use strio; + +export fn import(out: *io::stream, i: ast::import) (size | io::error) = { + let n = 0z; + n += fmt::fprint(out, "use ")?; + match (i) { + m: ast::import_module => n += ident(out, m)?, + a: ast::import_alias => { + n += fmt::fprint(out, a.alias, "= ")?; + n += ident(out, a.ident)?; + }, + o: ast::import_objects => { + n += ident(out, o.ident)?; + n += fmt::fprint(out, "::{")?; + for (let i = 0z; i < len(o.objects); i += 1) { + n += fmt::fprintf(out, "{}{}", o.objects[i], + if (i + 1 < len(o.objects)) ", " + else "")?; + }; + n += fmt::fprint(out, "}")?; + }, + }; + n += fmt::fprint(out, ";")?; + return n; +}; + +@test fn import() void = { + let buf = strio::dynamic(); + import(buf, ["foo", "bar", "baz"]) as size; + let s = strio::finish(buf); + assert(s == "use foo::bar::baz;"); + free(s); + buf = strio::dynamic(); + import(buf, ast::import_alias { + ident = ["foo"], + alias = "bar", + }) as size; + s = strio::finish(buf); + assert(s == "use bar = foo;"); + free(s); + buf = strio::dynamic(); + import(buf, ast::import_objects { + ident = ["foo"], + objects = ["bar", "baz"], + }) as size; + s = strio::finish(buf); + assert(s == "use foo::{bar, baz};"); + free(s); +}; diff --git a/hare/unparse/type.ha b/hare/unparse/type.ha @@ -0,0 +1,293 @@ +use fmt; +use io; +use hare::ast; +use hare::lex; +use strio; + +fn builtin_type(b: ast::builtin_type) str = switch (b) { + ast::builtin_type::BOOL => "bool", + ast::builtin_type::CHAR => "char", + ast::builtin_type::F32 => "f32", + ast::builtin_type::F64 => "f64", + ast::builtin_type::FCONST => abort("FCONST has no lexical representation"), + ast::builtin_type::I16 => "i16", + ast::builtin_type::I32 => "i32", + ast::builtin_type::I64 => "i64", + ast::builtin_type::I8 => "i8", + ast::builtin_type::ICONST => abort("ICONST has no lexical representation"), + ast::builtin_type::INT => "int", + ast::builtin_type::NULL => "null", + ast::builtin_type::RUNE => "rune", + ast::builtin_type::SIZE => "size", + ast::builtin_type::STR => "str", + ast::builtin_type::U16 => "u16", + ast::builtin_type::U32 => "u32", + ast::builtin_type::U64 => "u64", + ast::builtin_type::U8 => "u8", + ast::builtin_type::UINT => "uint", + ast::builtin_type::UINTPTR => "uintptr", + ast::builtin_type::VOID => "void", +}; + +fn prototype( + out: *io::stream, + indent: size, + t: ast::func_type, +) (size | io::error) = { + let n = 0z; + n += fmt::fprint(out, "(")?; + for (let i = 0z; i < len(t.params); i += 1) { + let param = t.params[i]; + n += fmt::fprintf(out, "{}: ", + if (len(param.name) == 0) "_" else param.name)?; + n += _type(out, indent, *param._type)?; + if (i + 1 == len(t.params) + && t.variadism == ast::variadism::HARE) { + n += fmt::fprintf(out, "...")?; + }; + if (i + 1 < len(t.params)) { + n += fmt::fprint(out, ", ")?; + }; + }; + if (t.variadism == ast::variadism::C) { + n += fmt::fprint(out, ", ...")?; + }; + n += fmt::fprint(out, ") ")?; + n += _type(out, indent, *t.result)?; + return n; +}; + +export fn _type( + out: *io::stream, + indent: size, + t: ast::_type, +) (size | io::error) = { + let n = 0z; + if (t.flags & ast::type_flags::CONST != 0 + && !(t._type is ast::func_type)) { + n += fmt::fprint(out, "const ")?; + }; + match (t._type) { + a: ast::alias_type => { + if (a.unwrap) { + n += fmt::fprint(out, "...")?; + }; + n += ident(out, a.ident)?; + }, + b: ast::builtin_type => n += fmt::fprint(out, builtin_type(b))?, + e: ast::enum_type => { + n += fmt::fprint(out, "enum", + builtin_type(e.storage), "{")?; + indent += 1; + for (let i = 0z; i < len(e.values); i += 1) { + n += newline(out, indent)?; + let value = e.values[i]; + n += fmt::fprint(out, value.name)?; + match (value.value) { + null => void, + e: *ast::expr => { + n += fmt::fprint(out, ": ")?; + n += expr(out, indent, *e)?; + }, + }; + n += fmt::fprint(out, ",")?; + }; + indent -= 1; + n += newline(out, indent)?; + n += fmt::fprint(out, "}")?; + }, + f: ast::func_type => { + if (f.attrs & ast::func_attrs::NORETURN != 0) { + n += fmt::fprint(out, "@noreturn ")?; + }; + n += fmt::fprint(out, "fn")?; + n += prototype(out, indent, f)?; + }, + l: ast::list_type => { + n += fmt::fprint(out, "[")?; + n += match (l.length) { + ast::len_slice => 0, + ast::len_unbounded => fmt::fprint(out, "*")?, + ast::len_contextual => fmt::fprint(out, "_")?, + e: *ast::expr => expr(out, indent, *e)?, + }; + n += fmt::fprint(out, "]")?; + n += _type(out, indent, *l.members)?; + }, + p: ast::pointer_type => { + if (p.flags & ast::pointer_flags::NULLABLE != 0) { + n += fmt::fprint(out, "nullable ")?; + }; + n += fmt::fprint(out, "*")?; + n += _type(out, indent, *p.referent)?; + }, + s: []ast::struct_member => abort(), // TODO + t: ast::tagged_type => { + n += fmt::fprint(out, "(")?; + for (let i = 0z; i < len(t); i += 1) { + n += _type(out, indent, *t[i])?; + if (i + 1 < len(t)) { + n += fmt::fprint(out, " | ")?; + }; + }; + n += fmt::fprint(out, ")")?; + }, + t: ast::tuple_type => { + n += fmt::fprint(out, "(")?; + for (let i = 0z; i < len(t); i += 1) { + n += _type(out, indent, *t[i])?; + if (i + 1 < len(t)) { + n += fmt::fprint(out, ", ")?; + }; + }; + n += fmt::fprint(out, ")")?; + }, + }; + if (t.flags & ast::type_flags::ERROR != 0) { + n += fmt::fprint(out, "!")?; + }; + return n; +}; + +fn type_test(t: ast::_type, expected: str) bool = { + let buf = strio::dynamic(); + _type(buf, 0, t) as size; + let s = strio::finish(buf); + defer free(s); + return s == expected; +}; + +@test fn _type() void = { + let loc = lex::location { + path = "<test>", + line = 0, + col = 0, + }; + let t = ast::_type { + loc = loc, + flags = ast::type_flags::CONST, + _type = ast::alias_type { + unwrap = false, + ident = ["foo", "bar"], + }, + }; + let type_int = ast::_type { + loc = loc, + flags = 0, + _type = ast::builtin_type::INT, + }; + let expr_void = void: ast::constant_expr: ast::expr; + + assert(type_test(t, "const foo::bar")); + t.flags = 0; + t._type = ast::alias_type { + unwrap = true, + ident = ["baz"], + }; + assert(type_test(t, "...baz")); + + t.flags = ast::type_flags::ERROR; + t._type = ast::builtin_type::INT; + assert(type_test(t, "int!")); + + t.flags = ast::type_flags::CONST | ast::type_flags::ERROR; + t._type = ast::enum_type { + storage = ast::builtin_type::U32, + values = [ + ast::enum_field { + name = "FOO", + value = null, + }, + ast::enum_field { + name = "BAR", + value = &expr_void, + }, + ], + }; + assert(type_test(t, "const enum u32 {\n\tFOO,\n\tBAR: void,\n}!")); + + t.flags = 0; + + t._type = ast::func_type { + result = &type_int, + attrs = 0, + variadism = ast::variadism::NONE, + params = [], + }; + assert(type_test(t, "fn() int")); + t._type = ast::func_type { + result = &type_int, + attrs = ast::func_attrs::NORETURN, + variadism = ast::variadism::C, + params = [ + ast::func_param { + loc = loc, + name = "", + _type = &type_int, + }, + ], + }; + assert(type_test(t, "@noreturn fn(_: int, ...) int")); + t._type = ast::func_type { + result = &type_int, + attrs = 0, + variadism = ast::variadism::HARE, + params = [ + ast::func_param { + loc = loc, + name = "foo", + _type = &type_int, + }, + ast::func_param { + loc = loc, + name = "bar", + _type = &type_int, + }, + ], + }; + assert(type_test(t, "fn(foo: int, bar: int...) int")); + + t.flags = ast::type_flags::CONST; + assert(type_test(t, "fn(foo: int, bar: int...) int")); + + t.flags = 0; + t._type = ast::list_type { + length = ast::len_slice, + members = &type_int, + }; + assert(type_test(t, "[]int")); + t._type = ast::list_type { + length = ast::len_unbounded, + members = &type_int, + }; + assert(type_test(t, "[*]int")); + t._type = ast::list_type { + length = ast::len_contextual, + members = &type_int, + }; + assert(type_test(t, "[_]int")); + t._type = ast::list_type { + length = &expr_void, + members = &type_int, + }; + assert(type_test(t, "[void]int")); + + t._type = ast::pointer_type { + referent = &type_int, + flags = 0, + }; + assert(type_test(t, "*int")); + t._type = ast::pointer_type { + referent = &type_int, + flags = ast::pointer_flags::NULLABLE, + }; + assert(type_test(t, "nullable *int")); + + // TODO: struct_members + + t._type = [&type_int, &type_int]: ast::tagged_type; + assert(type_test(t, "(int | int)")); + + t._type = [&type_int, &type_int]: ast::tuple_type; + assert(type_test(t, "(int, int)")); +}; diff --git a/hare/unparse/unit.ha b/hare/unparse/unit.ha @@ -0,0 +1,16 @@ +use io; +use fmt; +use hare::ast; + +export fn subunit(out: *io::stream, s: ast::subunit) (size | io::error) = { + let n = 0z; + for (let i = 0z; i < len(s.imports); i += 1) { + n += import(out, s.imports[i])?; + n += fmt::fprintln(out)?; + }; + for (let i = 0z; i < len(s.decls); i += 1) { + n += decl(out, s.decls[i])?; + n += fmt::fprintln(out)?; + }; + return n; +}; diff --git a/hare/unparse/util.ha b/hare/unparse/util.ha @@ -0,0 +1,12 @@ +use io; +use fmt; + +fn newline(out: *io::stream, indent: size) (size | io::error) = { + let n = 0z; + n += fmt::fprint(out, "\n")?; + for (let i = 0z; i < indent; i += 1) { + n += fmt::fprint(out, "\t")?; + }; + return n; +}; + diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib @@ -249,9 +249,21 @@ hare_ast() { ident.ha \ import.ha \ type.ha \ + unit.ha + gen_ssa hare::ast hare::lex +} + +hare_unparse() { + printf '# hare::unparse\n' + gen_srcs hare::unparse \ + expr.ha \ + decl.ha \ + ident.ha \ + import.ha \ + type.ha \ unit.ha \ - unparse.ha - gen_ssa hare::ast hare::lex io fmt strio + util.ha + gen_ssa hare::unparse fmt io strio hare::ast } gensrcs_hare_lex() { @@ -281,7 +293,7 @@ hare_module() { scan.ha \ manifest.ha gen_ssa hare::module \ - hare::ast hare::lex hare::parse strio fs io strings hash \ + hare::ast hare::lex hare::parse hare::unparse strio fs io strings hash \ crypto::sha256 dirs bytes encoding::utf8 ascii fmt time } @@ -533,6 +545,7 @@ hare_ast hare_lex hare_module hare_parse +hare_unparse hash hash_fnv io diff --git a/stdlib.mk b/stdlib.mk @@ -125,6 +125,9 @@ hare_stdlib_deps+=$(stdlib_hare_module) stdlib_hare_parse=$(HARECACHE)/hare/parse/hare_parse.o hare_stdlib_deps+=$(stdlib_hare_parse) +stdlib_hare_unparse=$(HARECACHE)/hare/unparse/hare_unparse.o +hare_stdlib_deps+=$(stdlib_hare_unparse) + stdlib_hash=$(HARECACHE)/hash/hash.o hare_stdlib_deps+=$(stdlib_hash) @@ -354,10 +357,9 @@ stdlib_hare_ast_srcs= \ $(STDLIB)/hare/ast/ident.ha \ $(STDLIB)/hare/ast/import.ha \ $(STDLIB)/hare/ast/type.ha \ - $(STDLIB)/hare/ast/unit.ha \ - $(STDLIB)/hare/ast/unparse.ha + $(STDLIB)/hare/ast/unit.ha -$(HARECACHE)/hare/ast/hare_ast.ssa: $(stdlib_hare_ast_srcs) $(stdlib_rt) $(stdlib_hare_lex) $(stdlib_io) $(stdlib_fmt) $(stdlib_strio) +$(HARECACHE)/hare/ast/hare_ast.ssa: $(stdlib_hare_ast_srcs) $(stdlib_rt) $(stdlib_hare_lex) @printf 'HAREC \t$@\n' @mkdir -p $(HARECACHE)/hare/ast @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nhare::ast \ @@ -381,7 +383,7 @@ stdlib_hare_module_srcs= \ $(STDLIB)/hare/module/scan.ha \ $(STDLIB)/hare/module/manifest.ha -$(HARECACHE)/hare/module/hare_module.ssa: $(stdlib_hare_module_srcs) $(stdlib_rt) $(stdlib_hare_ast) $(stdlib_hare_lex) $(stdlib_hare_parse) $(stdlib_strio) $(stdlib_fs) $(stdlib_io) $(stdlib_strings) $(stdlib_hash) $(stdlib_crypto_sha256) $(stdlib_dirs) $(stdlib_bytes) $(stdlib_encoding_utf8) $(stdlib_ascii) $(stdlib_fmt) $(stdlib_time) +$(HARECACHE)/hare/module/hare_module.ssa: $(stdlib_hare_module_srcs) $(stdlib_rt) $(stdlib_hare_ast) $(stdlib_hare_lex) $(stdlib_hare_parse) $(stdlib_hare_unparse) $(stdlib_strio) $(stdlib_fs) $(stdlib_io) $(stdlib_strings) $(stdlib_hash) $(stdlib_crypto_sha256) $(stdlib_dirs) $(stdlib_bytes) $(stdlib_encoding_utf8) $(stdlib_ascii) $(stdlib_fmt) $(stdlib_time) @printf 'HAREC \t$@\n' @mkdir -p $(HARECACHE)/hare/module @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nhare::module \ @@ -399,6 +401,22 @@ $(HARECACHE)/hare/parse/hare_parse.ssa: $(stdlib_hare_parse_srcs) $(stdlib_rt) $ @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nhare::parse \ -t$(HARECACHE)/hare/parse/hare_parse.td $(stdlib_hare_parse_srcs) +# hare::unparse +stdlib_hare_unparse_srcs= \ + $(STDLIB)/hare/unparse/expr.ha \ + $(STDLIB)/hare/unparse/decl.ha \ + $(STDLIB)/hare/unparse/ident.ha \ + $(STDLIB)/hare/unparse/import.ha \ + $(STDLIB)/hare/unparse/type.ha \ + $(STDLIB)/hare/unparse/unit.ha \ + $(STDLIB)/hare/unparse/util.ha + +$(HARECACHE)/hare/unparse/hare_unparse.ssa: $(stdlib_hare_unparse_srcs) $(stdlib_rt) $(stdlib_fmt) $(stdlib_io) $(stdlib_strio) $(stdlib_hare_ast) + @printf 'HAREC \t$@\n' + @mkdir -p $(HARECACHE)/hare/unparse + @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nhare::unparse \ + -t$(HARECACHE)/hare/unparse/hare_unparse.td $(stdlib_hare_unparse_srcs) + # hash stdlib_hash_srcs= \ $(STDLIB)/hash/hash.ha @@ -751,6 +769,9 @@ hare_testlib_deps+=$(testlib_hare_module) testlib_hare_parse=$(TESTCACHE)/hare/parse/hare_parse.o hare_testlib_deps+=$(testlib_hare_parse) +testlib_hare_unparse=$(TESTCACHE)/hare/unparse/hare_unparse.o +hare_testlib_deps+=$(testlib_hare_unparse) + testlib_hash=$(TESTCACHE)/hash/hash.o hare_testlib_deps+=$(testlib_hash) @@ -982,10 +1003,9 @@ testlib_hare_ast_srcs= \ $(STDLIB)/hare/ast/ident.ha \ $(STDLIB)/hare/ast/import.ha \ $(STDLIB)/hare/ast/type.ha \ - $(STDLIB)/hare/ast/unit.ha \ - $(STDLIB)/hare/ast/unparse.ha + $(STDLIB)/hare/ast/unit.ha -$(TESTCACHE)/hare/ast/hare_ast.ssa: $(testlib_hare_ast_srcs) $(testlib_rt) $(testlib_hare_lex) $(testlib_io) $(testlib_fmt) $(testlib_strio) +$(TESTCACHE)/hare/ast/hare_ast.ssa: $(testlib_hare_ast_srcs) $(testlib_rt) $(testlib_hare_lex) @printf 'HAREC \t$@\n' @mkdir -p $(TESTCACHE)/hare/ast @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nhare::ast \ @@ -1010,7 +1030,7 @@ testlib_hare_module_srcs= \ $(STDLIB)/hare/module/scan.ha \ $(STDLIB)/hare/module/manifest.ha -$(TESTCACHE)/hare/module/hare_module.ssa: $(testlib_hare_module_srcs) $(testlib_rt) $(testlib_hare_ast) $(testlib_hare_lex) $(testlib_hare_parse) $(testlib_strio) $(testlib_fs) $(testlib_io) $(testlib_strings) $(testlib_hash) $(testlib_crypto_sha256) $(testlib_dirs) $(testlib_bytes) $(testlib_encoding_utf8) $(testlib_ascii) $(testlib_fmt) $(testlib_time) +$(TESTCACHE)/hare/module/hare_module.ssa: $(testlib_hare_module_srcs) $(testlib_rt) $(testlib_hare_ast) $(testlib_hare_lex) $(testlib_hare_parse) $(testlib_hare_unparse) $(testlib_strio) $(testlib_fs) $(testlib_io) $(testlib_strings) $(testlib_hash) $(testlib_crypto_sha256) $(testlib_dirs) $(testlib_bytes) $(testlib_encoding_utf8) $(testlib_ascii) $(testlib_fmt) $(testlib_time) @printf 'HAREC \t$@\n' @mkdir -p $(TESTCACHE)/hare/module @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nhare::module \ @@ -1029,6 +1049,22 @@ $(TESTCACHE)/hare/parse/hare_parse.ssa: $(testlib_hare_parse_srcs) $(testlib_rt) @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nhare::parse \ -t$(TESTCACHE)/hare/parse/hare_parse.td $(testlib_hare_parse_srcs) +# hare::unparse +testlib_hare_unparse_srcs= \ + $(STDLIB)/hare/unparse/expr.ha \ + $(STDLIB)/hare/unparse/decl.ha \ + $(STDLIB)/hare/unparse/ident.ha \ + $(STDLIB)/hare/unparse/import.ha \ + $(STDLIB)/hare/unparse/type.ha \ + $(STDLIB)/hare/unparse/unit.ha \ + $(STDLIB)/hare/unparse/util.ha + +$(TESTCACHE)/hare/unparse/hare_unparse.ssa: $(testlib_hare_unparse_srcs) $(testlib_rt) $(testlib_fmt) $(testlib_io) $(testlib_strio) $(testlib_hare_ast) + @printf 'HAREC \t$@\n' + @mkdir -p $(TESTCACHE)/hare/unparse + @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nhare::unparse \ + -t$(TESTCACHE)/hare/unparse/hare_unparse.td $(testlib_hare_unparse_srcs) + # hash testlib_hash_srcs= \ $(STDLIB)/hash/hash.ha