commit 559b994e6474c8b6a3f688ed8edcf587dac625f8
parent 3db5510b45e63de415152fd2c17e013581f0a37c
Author: Drew DeVault <sir@cmpwn.com>
Date: Sat, 17 Apr 2021 08:36:05 -0400
hare::parse: implement if expressions
Diffstat:
4 files changed, 48 insertions(+), 6 deletions(-)
diff --git a/hare/ast/expr.ha b/hare/ast/expr.ha
@@ -168,8 +168,8 @@ export type free_expr = *expr;
// if (foo) bar else baz
export type if_expr = struct {
cond: *expr,
- true_branch: nullable *expr,
- false_branch: nullable *expr,
+ tbranch: *expr,
+ fbranch: nullable *expr,
};
// :label. The ":" character is not included.
@@ -363,8 +363,8 @@ export fn expr_free(e: (expr | nullable *expr)) void = match (e) {
f: free_expr => expr_free(f: *expr),
i: if_expr => {
expr_free(i.cond);
- expr_free(i.true_branch);
- expr_free(i.false_branch);
+ expr_free(i.tbranch);
+ expr_free(i.fbranch);
},
l: len_expr => expr_free(l: *expr),
l: list_expr => {
diff --git a/hare/parse/+test/expr.ha b/hare/parse/+test/expr.ha
@@ -33,6 +33,18 @@
");
};
+@test fn if_expr() void = {
+ roundtrip("export fn main() void = {
+ if (x == y) {
+ z;
+ };
+ if (y == x) z;
+ if (z == q) r else p;
+ if (a == b) c else if (d == e) f else g;
+};
+");
+};
+
@test fn list() void = {
roundtrip("export fn main() void = {
2 + 2;
diff --git a/hare/parse/expr.ha b/hare/parse/expr.ha
@@ -15,7 +15,7 @@ export fn expression(lexer: *lex::lexer) (ast::expr | error) = {
ltok::LBRACE => expression_list(lexer),
ltok::MATCH => abort(), // TODO
ltok::SWITCH => abort(), // TODO
- ltok::IF => abort(), // TODO
+ ltok::IF => if_expr(lexer),
ltok::FOR => abort(), // TODO
ltok::BREAK, ltok::CONTINUE, ltok::RETURN => control(lexer),
ltok::LET, ltok::CONST => abort(), // TODO
@@ -192,6 +192,23 @@ fn expression_list(lexer: *lex::lexer) (ast::expr | error) = {
return items;
};
+fn if_expr(lexer: *lex::lexer) (ast::expr | error) = {
+ want(lexer, ltok::IF)?;
+ want(lexer, ltok::LPAREN)?;
+ const cond = alloc(expression(lexer)?);
+ want(lexer, ltok::RPAREN)?;
+ const tbranch = alloc(expression(lexer)?);
+ const fbranch: nullable *ast::expr = match (try(lexer, ltok::ELSE)?) {
+ void => null,
+ lex::token => alloc(expression(lexer)?),
+ };
+ return ast::if_expr {
+ cond = cond,
+ tbranch = tbranch,
+ fbranch = fbranch,
+ };
+};
+
fn indexing(lexer: *lex::lexer, lvalue: ast::expr) (ast::expr | error) = {
let is_slice = false;
let start: nullable *ast::expr = null, end: nullable *ast::expr = null;
diff --git a/hare/unparse/expr.ha b/hare/unparse/expr.ha
@@ -108,7 +108,20 @@ export fn expr(
e: ast::delete_expr => abort(),
e: ast::for_expr => abort(),
e: ast::free_expr => abort(),
- e: ast::if_expr => abort(),
+ e: ast::if_expr => {
+ let z = fmt::fprint(out, "if (")?;
+ z += expr(out, indent, *e.cond)?;
+ z += fmt::fprint(out, ") ")?;
+ z += expr(out, indent, *e.tbranch)?;
+ match (e.fbranch) {
+ null => void,
+ e: *ast::expr => {
+ z += fmt::fprint(out, " else ")?;
+ z += expr(out, indent, *e)?;
+ },
+ };
+ z;
+ },
e: ast::list_expr => {
let z = fmt::fprintf(out, "{{")?;
for (let i = 0z; i < len(e); i += 1) {