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:
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, "[")?;