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