hare

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

commit 3db5510b45e63de415152fd2c17e013581f0a37c
parent 487dc87f11de11cf66d49f95088099745c9cd1fc
Author: Drew DeVault <sir@cmpwn.com>
Date:   Sat, 17 Apr 2021 08:24:55 -0400

hare::parse: implement control expressions

Diffstat:
Mhare/ast/expr.ha | 2+-
Mhare/parse/+test/expr.ha | 20++++++++++++++++----
Mhare/parse/expr.ha | 16+++++++++++++++-
Mhare/unparse/expr.ha | 32+++++++++++++++++++++++++++++---
4 files changed, 61 insertions(+), 9 deletions(-)

diff --git a/hare/ast/expr.ha b/hare/ast/expr.ha @@ -201,7 +201,7 @@ export type offset_expr = void; // TODO export type propagate_expr = *expr; // return foo -export type return_expr = *expr; +export type return_expr = nullable *expr; // size(int) export type size_expr = *_type; diff --git a/hare/parse/+test/expr.ha b/hare/parse/+test/expr.ha @@ -2,10 +2,6 @@ roundtrip("export fn main() void = void + void * void / void;\n"); }; -@test fn constant() void = { - roundtrip("export fn main() void = 2 + -4 + void + true + \"hello\" + '?';\n"); -}; - @test fn call() void = { roundtrip("export fn main() void = test();\n" "export fn main() void = test(void, void, void);\n" @@ -21,6 +17,22 @@ "export fn main() void = void: int as uint: u16 is u8;\n"); }; +@test fn constant() void = { + roundtrip("export fn main() void = 2 + -4 + void + true + \"hello\" + '?';\n"); +}; + +@test fn control() void = { + roundtrip("export fn main() void = { + break; + break :foo; + continue; + continue :foo; + return; + return 2 + 2; +}; +"); +}; + @test fn list() void = { roundtrip("export fn main() void = { 2 + 2; diff --git a/hare/parse/expr.ha b/hare/parse/expr.ha @@ -158,7 +158,21 @@ fn constant(lexer: *lex::lexer) (ast::expr | error) = { }; fn control(lexer: *lex::lexer) (ast::expr | error) = { - abort(); // TODO + let tok = want(lexer, ltok::BREAK, ltok::CONTINUE, ltok::RETURN)?; + let label = if (tok.0 == ltok::BREAK || tok.0 == ltok::CONTINUE) { + match (try(lexer, ltok::LABEL)?) { + tok: lex::token => tok.1 as str, + void => "", + }; + } else ""; + return switch (tok.0) { + ltok::BREAK => label: ast::break_expr, + ltok::CONTINUE => label: ast::continue_expr, + ltok::RETURN => match (peek(lexer, ltok::COMMA, ltok::SEMICOLON)?) { + void => alloc(expression(lexer)?): ast::return_expr, + lex::token => null: ast::return_expr, + }, + }; }; fn expression_list(lexer: *lex::lexer) (ast::expr | error) = { diff --git a/hare/unparse/expr.ha b/hare/unparse/expr.ha @@ -59,7 +59,15 @@ export fn expr( z; }, e: []ast::binding_expr => abort(), - e: ast::break_expr => abort(), + e: ast::break_expr => { + let z = fmt::fprint(out, "break")?; + // TODO: https://todo.sr.ht/~sircmpwn/hare/380 + let l = e: ast::label: str; + if (l != "") { + z += fmt::fprintf(out, " :{}", l)?; + }; + z; + }, e: ast::call_expr => { let z = expr(out, indent, *e.lvalue)?; z += fmt::fprintf(out, "(")?; @@ -87,7 +95,15 @@ export fn expr( z; }, e: ast::constant_expr => constant(out, indent, e)?, - e: ast::continue_expr => abort(), + e: ast::continue_expr => { + let z = fmt::fprint(out, "continue")?; + // TODO: https://todo.sr.ht/~sircmpwn/hare/380 + let l = e: ast::label: str; + if (l != "") { + z += fmt::fprintf(out, " :{}", l)?; + }; + z; + }, e: ast::defer_expr => abort(), e: ast::delete_expr => abort(), e: ast::for_expr => abort(), @@ -112,7 +128,17 @@ export fn expr( let z = expr(out, indent, *e)?; z + fmt::fprintf(out, "?")?; }, - e: ast::return_expr => abort(), + e: ast::return_expr => { + let z = fmt::fprint(out, "return")?; + match (e) { + null => void, + e: *ast::expr => { + z += fmt::fprint(out, " ")?; + z += expr(out, indent, *e)?; + }, + }; + z; + }, e: ast::slice_expr => { let z = expr(out, indent, *e.object)?; z += fmt::fprint(out, "[")?;