hare

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

commit 746bf5fbf39a71158ce936ad8434df61cfde55a4
parent f3cba36f7dd88255d3a0730de472522fb6ef54ba
Author: Drew DeVault <sir@cmpwn.com>
Date:   Sun, 30 Apr 2023 11:55:37 +0200

hare::ast, hare::parse: def/let/const w/o type

This implements AST and parse support for:

	def x = 10;
	let x = 10;
	const x = 10;

i.e. without a type. Also updates haredoc accordingly.

Signed-off-by: Drew DeVault <sir@cmpwn.com>

Diffstat:
Mcmd/haredoc/hare.ha | 17++++++++++++++---
Mcmd/haredoc/html.ha | 36++++++++++++++++++++++++++++--------
Mcmd/haredoc/tty.ha | 21++++++++++++++++-----
Mhare/ast/decl.ha | 4++--
Mhare/parse/+test/unit.ha | 3++-
Mhare/parse/decl.ha | 18++++++++++++++----
Mhare/unparse/decl.ha | 26++++++++++++++++++--------
7 files changed, 94 insertions(+), 31 deletions(-)

diff --git a/cmd/haredoc/hare.ha b/cmd/haredoc/hare.ha @@ -135,8 +135,13 @@ fn unparse_hare(out: io::handle, d: ast::decl) (size | io::error) = { "@symbol(\"{}\") ", g[i].symbol)?; }; n += unparse::ident(out, g[i].ident)?; - n += fmt::fprint(out, ": ")?; - n += unparse::_type(out, 0, g[i]._type)?; + match (g[i]._type) { + case null => + yield; + case let ty: *ast::_type => + n += fmt::fprint(out, ": ")?; + n += unparse::_type(out, 0, *ty)?; + }; if (i + 1 < len(g)) { n += fmt::fprint(out, ", ")?; }; @@ -156,7 +161,13 @@ fn unparse_hare(out: io::handle, d: ast::decl) (size | io::error) = { for (let i = 0z; i < len(c); i += 1) { n += unparse::ident(out, c[i].ident)?; n += fmt::fprint(out, ": ")?; - n += unparse::_type(out, 0, c[i]._type)?; + match (c[i]._type) { + case null => + yield; + case let ty: *ast::_type => + n += fmt::fprint(out, ": ")?; + n += unparse::_type(out, 0, *ty)?; + }; if (i + 1 < len(c)) { n += fmt::fprint(out, ", ")?; }; diff --git a/cmd/haredoc/html.ha b/cmd/haredoc/html.ha @@ -271,12 +271,22 @@ fn tocentry(out: io::handle, decl: ast::decl) (void | error) = { case let t: []ast::decl_type => void; case let g: []ast::decl_global => let g = g[0]; - fmt::fprint(out, ": ")?; - type_html(out, 0, g._type, true)?; + match (g._type) { + case null => + yield; + case let ty: *ast::_type => + fmt::fprint(out, ": ")?; + type_html(out, 0, *ty, true)?; + }; case let c: []ast::decl_const => let c = c[0]; - fmt::fprint(out, ": ")?; - type_html(out, 0, c._type, true)?; + match (c._type) { + case null => + yield; + case let ty: *ast::_type => + fmt::fprint(out, ": ")?; + type_html(out, 0, *ty, true)?; + }; case let f: ast::decl_func => prototype_html(out, 0, f.prototype.repr as ast::func_type, @@ -444,8 +454,13 @@ fn unparse_html(out: io::handle, d: ast::decl) (size | io::error) = { n += fmt::fprintf(out, "<span class='keyword'>def</span> ")?; for (let i = 0z; i < len(c); i += 1) { n += unparse::ident(out, c[i].ident)?; - n += fmt::fprint(out, ": ")?; - n += type_html(out, 0, c[i]._type, false)?; + match (c[i]._type) { + case null => + yield; + case let ty: *ast::_type => + n += fmt::fprint(out, ": ")?; + n += type_html(out, 0, *ty, false)?; + }; if (i + 1 < len(c)) { n += fmt::fprint(out, ", ")?; }; @@ -455,8 +470,13 @@ fn unparse_html(out: io::handle, d: ast::decl) (size | io::error) = { if (g[0].is_const) "const " else "let ")?; for (let i = 0z; i < len(g); i += 1) { n += unparse::ident(out, g[i].ident)?; - n += fmt::fprint(out, ": ")?; - n += type_html(out, 0, g[i]._type, false)?; + match (g[i]._type) { + case null => + yield; + case let ty: *ast::_type => + n += fmt::fprint(out, ": ")?; + n += type_html(out, 0, *ty, false)?; + }; if (i + 1 < len(g)) { n += fmt::fprint(out, ", ")?; }; diff --git a/cmd/haredoc/tty.ha b/cmd/haredoc/tty.ha @@ -159,9 +159,14 @@ fn unparse_tty(out: io::handle, d: ast::decl) (size | io::error) = { }; n += render(out, syn::GLOBAL)?; n += unparse::ident(out, g[i].ident)?; - n += render(out, syn::PUNCTUATION)?; - n += fmt::fprint(out, ": ")?; - n += type_tty(out, 0, g[i]._type)?; + match (g[i]._type) { + case null => + yield; + case let ty: *ast::_type => + n += render(out, syn::PUNCTUATION)?; + n += fmt::fprint(out, ": ")?; + n += type_html(out, 0, *ty, false)?; + }; if (i + 1 < len(g)) { n += render(out, syn::PUNCTUATION)?; n += fmt::fprint(out, ", ")?; @@ -175,8 +180,14 @@ fn unparse_tty(out: io::handle, d: ast::decl) (size | io::error) = { n += render(out, syn::CONSTANT)?; n += unparse::ident(out, c[i].ident)?; n += render(out, syn::PUNCTUATION)?; - n += fmt::fprint(out, ": ")?; - n += type_tty(out, 0, c[i]._type)?; + match (c[i]._type) { + case null => + yield; + case let ty: *ast::_type => + n += render(out, syn::PUNCTUATION)?; + n += fmt::fprint(out, ": ")?; + n += type_html(out, 0, *ty, false)?; + }; if (i + 1 < len(c)) { n += render(out, syn::PUNCTUATION)?; n += fmt::fprint(out, ", ")?; diff --git a/hare/ast/decl.ha b/hare/ast/decl.ha @@ -8,7 +8,7 @@ use hare::lex; // def foo: int = 0; export type decl_const = struct { ident: ident, - _type: _type, + _type: nullable *_type, init: *expr, }; @@ -21,7 +21,7 @@ export type decl_global = struct { is_threadlocal: bool, symbol: str, ident: ident, - _type: _type, + _type: nullable *_type, init: nullable *expr, }; diff --git a/hare/parse/+test/unit.ha b/hare/parse/+test/unit.ha @@ -121,8 +121,9 @@ fn tup_to_import(tup: import_tuple) ast::import = ast::import { roundtrip("export type foo::bar = *int, baz = const void;\n\n" "type foo = ...bar;\n\n" "type foo = nullable *fn(x: rune, _: int) void;\n\n" - "export let @symbol(\"_\") foo::bar: int = void, baz: int = void;\n\n" + "export let @symbol(\"_\") foo::bar: int = void, baz: int = void, bat = void;\n\n" "def foo::bar: int = void;\n\n" + "def foo::bar = void;\n\n" "@symbol(\".f9$oo\") fn foo(bar: int, baz: int...) void;\n\n" "@test fn foo(_: int, ...) void;\n\n" "export fn main() void = void;\n\n" diff --git a/hare/parse/decl.ha b/hare/parse/decl.ha @@ -36,8 +36,13 @@ fn decl_const( let decl: []ast::decl_const = []; for (true) { const ident = ident(lexer)?; - want(lexer, ltok::COLON)?; - const _type = _type(lexer)?; + const _type: nullable *ast::_type = + match (try(lexer, ltok::COLON)?) { + case lex::token => + yield alloc(_type(lexer)?); + case void => + yield null; + }; want(lexer, ltok::EQUAL)?; const init: *ast::expr = alloc(expr(lexer)?); append(decl, ast::decl_const { @@ -72,8 +77,13 @@ fn decl_global( }; }; const ident = ident(lexer)?; - want(lexer, ltok::COLON)?; - const _type = _type(lexer)?; + const _type: nullable *ast::_type = + match (try(lexer, ltok::COLON)?) { + case lex::token => + yield alloc(_type(lexer)?); + case void => + yield null; + }; const init: nullable *ast::expr = match (try(lexer, ltok::EQUAL)?) { case lex::token => diff --git a/hare/unparse/decl.ha b/hare/unparse/decl.ha @@ -24,8 +24,13 @@ export fn decl(out: io::handle, d: ast::decl) (size | io::error) = { n += fmt::fprint(out, "def ")?; for (let i = 0z; i < len(c); i += 1) { n += ident(out, c[i].ident)?; - n += fmt::fprint(out, ": ")?; - n += _type(out, 0, c[i]._type)?; + match (c[i]._type) { + case null => + yield; + case let ty: *ast::_type => + n += fmt::fprint(out, ": ")?; + n += _type(out, 0, *ty)?; + }; n += fmt::fprint(out, " = ")?; n += expr(out, 0, *c[i].init)?; if (i + 1 < len(c)) { @@ -43,8 +48,13 @@ export fn decl(out: io::handle, d: ast::decl) (size | io::error) = { n += fmt::fprintf(out, "@threadlocal ")?; }; n += ident(out, g[i].ident)?; - n += fmt::fprint(out, ": ")?; - n += _type(out, 0, g[i]._type)?; + match (g[i]._type) { + case null => + yield; + case let ty: *ast::_type => + n += fmt::fprint(out, ": ")?; + n += _type(out, 0, *ty)?; + }; match (g[i].init) { case null => void; case let ex: *ast::expr => @@ -171,7 +181,7 @@ fn decl_test(d: ast::decl, expected: str) bool = { is_threadlocal = false, symbol = "", ident = ["foo", "bar"], - _type = type_int, + _type = &type_int, init = alloc(expr_void), }, ast::decl_global { @@ -179,7 +189,7 @@ fn decl_test(d: ast::decl, expected: str) bool = { is_threadlocal = true, symbol = "", ident = ["boo"], - _type = type_int, + _type = &type_int, init = alloc(expr_void), }, ast::decl_global { @@ -187,7 +197,7 @@ fn decl_test(d: ast::decl, expected: str) bool = { is_threadlocal = false, symbol = "foobar", ident = ["baz"], - _type = type_int, + _type = &type_int, init = alloc(expr_void), }, ], @@ -199,7 +209,7 @@ fn decl_test(d: ast::decl, expected: str) bool = { d.decl = [ ast::decl_const { ident = ["foo"], - _type = type_int, + _type = &type_int, init = alloc(expr_void), }, ];