hare

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

commit 81c073f632ef8a0cab0afa014c1984b1fe3f0a8c
parent 377af32d04fbeea786491a32d0aafce6ecd317e1
Author: Drew DeVault <sir@cmpwn.com>
Date:   Sat, 17 Apr 2021 08:56:41 -0400

hare::parse: implement tuple expressions

Diffstat:
Mhare/parse/+test/expr.ha | 14+++++++++++---
Mhare/parse/expr.ha | 30++++++++++++++++++++++++++++--
Mhare/unparse/expr.ha | 11++++++++++-
3 files changed, 49 insertions(+), 6 deletions(-)

diff --git a/hare/parse/+test/expr.ha b/hare/parse/+test/expr.ha @@ -18,9 +18,17 @@ }; @test fn constant() void = { - roundtrip("export fn main() void = 2 + -4 + void + true + \"hello\" + '?'; -export fn main() void = [1, 2, 3, 4]; -export fn main() void = [1, 2, 3, 4...]; + // XXX: nested-expression should probably be tested here, but it + // presents a problem for round tripping because it does not end up in + // the AST. We would need unparse to be able to tell that a given AST + // does not match the precedence requirements, and thus infer that + // parenthesis are needed to unparse it correctly. + roundtrip("export fn main() void = { + 2 + -4 + void + true + \"hello\" + '?'; + [1, 2, 3, 4]; + [1, 2, 3, 4...]; + (1, 2, 3); +}; "); }; diff --git a/hare/parse/expr.ha b/hare/parse/expr.ha @@ -258,10 +258,11 @@ fn plain_expression(lexer: *lex::lexer) (ast::expr | error) = { ltok::LBRACKET => plain_array(lexer)?, ltok::STRUCT => abort(), // TODO: Struct literal ltok::LPAREN => { - let ex = expression(lexer); + want(lexer, ltok::LPAREN)?; + let ex = expression(lexer)?; return switch (want(lexer, ltok::RPAREN, ltok::COMMA)?.0) { ltok::RPAREN => ex, - ltok::COMMA => abort(), // TODO: Tuple literal + ltok::COMMA => plain_tuple(lexer, ex)?, * => abort(), }; }, @@ -314,6 +315,31 @@ fn plain_array(lexer: *lex::lexer) (ast::expr | error) = { }; }; +fn plain_tuple(lexer: *lex::lexer, ex: ast::expr) (ast::expr | error) = { + let values: []*ast::expr = []; + append(values, alloc(ex)); + + for (true) { + match (try(lexer, ltok::RPAREN)?) { + lex::token => break, + void => void, + }; + + append(values, alloc(expression(lexer)?)); + + match (try(lexer, ltok::COMMA)?) { + void => { + want(lexer, ltok::RPAREN)?; + break; + }, + lex::token => void, + }; + }; + + // XXX: Why do we have to cast this twice? harec bug? + return values: ast::tuple_constant: ast::constant_expr; +}; + fn postfix(lexer: *lex::lexer, lvalue: (ast::expr | void)) (ast::expr | error) = { let lvalue = match (lvalue) { void => plain_expression(lexer)?, diff --git a/hare/unparse/expr.ha b/hare/unparse/expr.ha @@ -211,6 +211,15 @@ fn constant( if (ac.expand) "..." else "")?; }, ast::struct_constant => abort(), // TODO - ast::tuple_constant => abort(), // TODO + tu: ast::tuple_constant => { + let z = fmt::fprint(out, "(")?; + for (let i = 0z; i < len(tu); i += 1) { + z += expr(out, indent, *tu[i])?; + if (i + 1 < len(tu)) { + z += fmt::fprint(out, ", ")?; + }; + }; + z + fmt::fprint(out, ")")?; + }, }; };