hare

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

commit a6e0ba6a4a067a88ff4e3c0a5ded65045c74b85b
parent c6fbfa5519948400676271027e801400732d7bdd
Author: Drew DeVault <sir@cmpwn.com>
Date:   Mon,  5 Apr 2021 19:02:00 -0400

hare::parse: implement cast-expression

Diffstat:
Mhare/parse/+test.ha | 49+++++++++++++++++++++++--------------------------
Mhare/parse/expr.ha | 30+++++++++++++++++++++++++-----
Mhare/unparse/expr.ha | 12+++++++++++-
3 files changed, 59 insertions(+), 32 deletions(-)

diff --git a/hare/parse/+test.ha b/hare/parse/+test.ha @@ -168,16 +168,8 @@ use strio; }; }; -@test fn decls() void = { - const in = "export type foo::bar = *int, baz = const void;\n" - "type foo = ...bar;\n" - "type foo = nullable *fn(x: rune, _: int) void;\n" - "export let @symbol(\"_\") foo::bar: int = void, baz: int = void;\n" - "def foo::bar: int = void;\n" - "@symbol(\".f9$oo\") fn foo(bar: int, baz: int...) void;\n" - "@test fn foo(_: int, ...) void;\n" - "export fn main() void = void;\n"; - let buf = bufio::fixed(strings::toutf8(in), mode::READ); +fn roundtrip(src: str) void = { + let buf = bufio::fixed(strings::toutf8(src), mode::READ); let lexer = lex::init(buf, "<test>"); let u = ast::subunit { imports = [], @@ -186,23 +178,28 @@ use strio; defer ast::subunit_free(u); let out = strio::dynamic(); unparse::subunit(out, u) as size; - let s = strio::finish(out); - defer free(s); - assert(s == in); + let unsrc = strio::finish(out); + defer free(unsrc); + assert(unsrc == src); +}; + +@test fn decls() void = { + roundtrip("export type foo::bar = *int, baz = const void;\n" + "type foo = ...bar;\n" + "type foo = nullable *fn(x: rune, _: int) void;\n" + "export let @symbol(\"_\") foo::bar: int = void, baz: int = void;\n" + "def foo::bar: int = void;\n" + "@symbol(\".f9$oo\") fn foo(bar: int, baz: int...) void;\n" + "@test fn foo(_: int, ...) void;\n" + "export fn main() void = void;\n"); }; @test fn binarithm() void = { - const in = "export fn main() void = void + void * void / void;\n"; - let buf = bufio::fixed(strings::toutf8(in), mode::READ); - let lexer = lex::init(buf, "<test>"); - let u = ast::subunit { - imports = [], - decls = decls(&lexer) as []ast::decl, - }; - defer ast::subunit_free(u); - let out = strio::dynamic(); - unparse::subunit(out, u) as size; - let s = strio::finish(out); - defer free(s); - assert(s == in); + roundtrip("export fn main() void = void + void * void / void;\n"); +}; + +@test fn cast() void = { + roundtrip("export fn main() void = void: int;\n" + "export fn main() void = void as int;\n" + "export fn main() void = void is int;\n"); }; diff --git a/hare/parse/expr.ha b/hare/parse/expr.ha @@ -2,11 +2,6 @@ use hare::ast; use hare::lex; use hare::lex::{btoken}; -fn cast(lexer: *lex::lexer) (ast::expr | error) = { - want_btoken(lexer, btoken::VOID)?; // TODO - return void; -}; - fn binarithm( lexer: *lex::lexer, lvalue: (ast::expr | void), @@ -59,6 +54,31 @@ fn binarithm( return lvalue; }; +fn cast(lexer: *lex::lexer) (ast::expr | error) = { + let lvalue = unarithm(lexer)?; + const tok = match (try_btoken(lexer, btoken::COLON, + btoken::AS, btoken::IS)?) { + void => return lvalue, + tok: btoken => tok, + }; + const kind = switch (tok) { + btoken::COLON => ast::cast_kind::CAST, + btoken::AS => ast::cast_kind::ASSERTION, + btoken::IS => ast::cast_kind::TEST, + * => abort(), + }; + return ast::cast_expr { + kind = kind, + value = alloc(lvalue), + _type = alloc(_type(lexer)?), + }; +}; + +fn unarithm(lexer: *lex::lexer) (ast::expr | error) = { + want_btoken(lexer, btoken::VOID)?; // TODO + return void; +}; + fn binop_for_tok(tok: (lex::token, lex::location)) ast::binarithm_op = { let tok = match (tok.0) { b: btoken => b, diff --git a/hare/unparse/expr.ha b/hare/unparse/expr.ha @@ -43,7 +43,17 @@ export fn expr( e: []ast::binding_expr => abort(), e: ast::break_expr => abort(), e: ast::call_expr => abort(), - e: ast::cast_expr => abort(), + e: ast::cast_expr => { + let z = expr(out, indent, *e.value)?; + const op = switch (e.kind) { + ast::cast_kind::CAST => ": ", + ast::cast_kind::ASSERTION => " as ", + ast::cast_kind::TEST => " is ", + }; + z += fmt::fprintf(out, "{}", op)?; + z += _type(out, indent, *e._type)?; + z; + }, e: ast::constant_expr => { assert(e is void); fmt::fprint(out, "void")?;