commit da96a44882f7fa364273245be61783fbb4748df1
parent 4730e0d18cbcc0bdab83c38f1ec9b4e1c8ca3b32
Author: Drew DeVault <sir@cmpwn.com>
Date: Fri, 16 Apr 2021 08:26:39 -0400
hare::parse: implement call expressions
Diffstat:
3 files changed, 69 insertions(+), 4 deletions(-)
diff --git a/hare/parse/+test/expr.ha b/hare/parse/+test/expr.ha
@@ -6,6 +6,14 @@
roundtrip("export fn main() void = 2 + -4 + void + true + \"hello\" + '?';\n");
};
+@test fn call() void = {
+ roundtrip("export fn main() void = test();
+export fn main() void = test(void, void, void);
+export fn main() void = test(void, void, void...);
+export fn main() void = test()()(void);
+");
+};
+
@test fn cast() void = {
roundtrip("export fn main() void = void: int;\n"
"export fn main() void = void as int;\n"
diff --git a/hare/parse/expr.ha b/hare/parse/expr.ha
@@ -59,6 +59,44 @@ fn builtin(lexer: *lex::lexer) (ast::expr | error) = {
return postfix(lexer, void);
};
+fn call(lexer: *lex::lexer, lvalue: ast::expr) (ast::expr | error) = {
+ let args: []*ast::expr = [];
+ let variadic = false;
+
+ for (true) {
+ match (try(lexer, ltok::RPAREN)?) {
+ lex::token => break,
+ void => void,
+ };
+
+ append(args, alloc(expression(lexer)?));
+
+ match (try(lexer, ltok::ELLIPSIS)?) {
+ lex::token => {
+ variadic = true;
+ try(lexer, ltok::COMMA)?;
+ want(lexer, ltok::RPAREN)?;
+ break;
+ },
+ void => void,
+ };
+
+ match (try(lexer, ltok::COMMA)?) {
+ lex::token => void,
+ void => {
+ want(lexer, ltok::RPAREN)?;
+ break;
+ },
+ };
+ };
+
+ return ast::call_expr {
+ lvalue = alloc(lvalue),
+ variadic = variadic,
+ args = args,
+ };
+};
+
fn cast(lexer: *lex::lexer, lvalue: (ast::expr | void)) (ast::expr | error) = {
const lvalue = match (lvalue) {
void => unarithm(lexer)?,
@@ -169,10 +207,10 @@ fn postfix(lexer: *lex::lexer, lvalue: (ast::expr | void)) (ast::expr | error) =
ex: ast::expr => ex,
};
- match (try(lexer, ltok::LPAREN, ltok::DOT, ltok::LBRACKET,
+ lvalue = match (try(lexer, ltok::LPAREN, ltok::DOT, ltok::LBRACKET,
ltok::QUESTION)) {
tok: lex::token => switch (tok.0) {
- ltok::LPAREN => abort(), // TODO: Calls
+ ltok::LPAREN => call(lexer, lvalue)?,
ltok::DOT => abort(), // TODO: Field access
ltok::LBRACKET => abort(), // TODO: Indexing
ltok::QUESTION => abort(), // TODO: Propagation
diff --git a/hare/unparse/expr.ha b/hare/unparse/expr.ha
@@ -9,7 +9,12 @@ export fn expr(
t: ast::expr
) (size | io::error) = {
return match (t) {
- e: ast::access_expr => abort(),
+ e: ast::access_expr => match (e) {
+ id: ast::access_identifier => ident(out, id),
+ ix: ast::access_index => abort(),
+ fl: ast::access_field => abort(),
+ tp: ast::access_tuple => abort(),
+ },
e: ast::alloc_expr => abort(),
e: ast::append_expr => abort(),
e: ast::assert_expr => abort(),
@@ -42,7 +47,21 @@ export fn expr(
},
e: []ast::binding_expr => abort(),
e: ast::break_expr => abort(),
- e: ast::call_expr => abort(),
+ e: ast::call_expr => {
+ let z = expr(out, indent, *e.lvalue)?;
+ z += fmt::fprintf(out, "(")?;
+ for (let i = 0z; i < len(e.args); i += 1) {
+ z += expr(out, indent, *e.args[i])?;
+ if (i + 1 < len(e.args)) {
+ z += fmt::fprintf(out, ", ")?;
+ };
+ };
+ if (e.variadic) {
+ z += fmt::fprintf(out, "...")?;
+ };
+ z += fmt::fprintf(out, ")")?;
+ z;
+ },
e: ast::cast_expr => {
let z = expr(out, indent, *e.value)?;
const op = switch (e.kind) {