hare

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

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:
Mhare/ast/expr.ha | 8++++----
Mhare/parse/+test/expr.ha | 12++++++++++++
Mhare/parse/expr.ha | 19++++++++++++++++++-
Mhare/unparse/expr.ha | 15++++++++++++++-
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) {