commit 21aa89bf1a4b9798995d96322d4abccd52a85bb0
parent c7a4513af88ba92af8cbf96cf178b332e6b288ba
Author: Drew DeVault <sir@cmpwn.com>
Date: Sun, 18 Apr 2021 13:25:18 -0400
hare::parse: implement append expressions
Diffstat:
4 files changed, 72 insertions(+), 8 deletions(-)
diff --git a/hare/ast/expr.ha b/hare/ast/expr.ha
@@ -32,7 +32,7 @@ export type alloc_expr = struct {
// append(foo, bar, (more), baz...)
export type append_expr = struct {
- expr: *expr,
+ object: *expr,
variadic: nullable *expr,
values: []*expr,
};
@@ -284,7 +284,7 @@ export fn expr_free(e: (expr | nullable *expr)) void = match (e) {
expr_free(a.capacity);
},
a: append_expr => {
- expr_free(a.expr);
+ expr_free(a.object);
match (a.variadic) {
null => void,
v: *expr => expr_free(v),
diff --git a/hare/parse/+test/expr.ha b/hare/parse/+test/expr.ha
@@ -35,6 +35,9 @@
roundtrip("export fn main() void = {
alloc(1234);
alloc(4321, 1234);
+ append(x, 10);
+ append(x, 10, 20, 30);
+ append(x, y, z, q...);
};
");
};
diff --git a/hare/parse/expr.ha b/hare/parse/expr.ha
@@ -95,6 +95,47 @@ fn alloc_expr(lexer: *lex::lexer) (ast::expr | error) = {
};
};
+fn append_expr(lexer: *lex::lexer) (ast::expr | error) = {
+ want(lexer, ltok::APPEND)?;
+ want(lexer, ltok::LPAREN)?;
+
+ const object =
+ if (try(lexer, ltok::TIMES)? is lex::token) unarithm(lexer)?
+ else objsel(lexer)?;
+ want(lexer, ltok::COMMA)?;
+
+ let variadic: nullable *ast::expr = null;
+ let values: []*ast::expr = [];
+ for (true) {
+ if (try(lexer, ltok::RPAREN)? is lex::token) break;
+
+ const expr = alloc(expression(lexer)?);
+ switch (want(lexer, ltok::COMMA, ltok::ELLIPSIS, ltok::RPAREN)?.0) {
+ ltok::COMMA => append(values, expr),
+ ltok::ELLIPSIS => {
+ variadic = expr;
+ try(lexer, ltok::COMMA)?;
+ want(lexer, ltok::RPAREN)?;
+ break;
+ },
+ ltok::RPAREN => {
+ append(values, expr);
+ break;
+ },
+ * => abort(),
+ };
+ };
+
+ synassert(mkloc(lexer), variadic != null || len(values) != 0,
+ "Expected values to append")?;
+
+ return ast::append_expr {
+ object = alloc(object),
+ variadic = variadic,
+ values = values,
+ };
+};
+
fn binarithm(
lexer: *lex::lexer,
lvalue: (ast::expr | void),
@@ -174,10 +215,10 @@ fn builtin(lexer: *lex::lexer) (ast::expr | error) = {
};
return switch (tok.0) {
ltok::ALLOC => alloc_expr(lexer)?,
- ltok::APPEND => abort(),
- ltok::DELETE => abort(),
- ltok::FREE => abort(),
- ltok::ASSERT => abort(),
+ ltok::APPEND => append_expr(lexer)?,
+ ltok::DELETE => abort(), // TODO
+ ltok::FREE => abort(), // TODO
+ ltok::ASSERT => abort(), // TODO
ltok::STATIC => {
want(lexer, ltok::STATIC)?;
let tok = match (peek(lexer, ltok::LET, ltok::CONST,
@@ -193,7 +234,7 @@ fn builtin(lexer: *lex::lexer) (ast::expr | error) = {
* => abort(),
};
},
- ltok::SIZE, ltok::LEN, ltok::OFFSET => abort(),
+ ltok::SIZE, ltok::LEN, ltok::OFFSET => abort(), // TODO
ltok::DEFER => {
want(lexer, ltok::DEFER)?;
alloc(expression(lexer)?): ast::defer_expr;
diff --git a/hare/unparse/expr.ha b/hare/unparse/expr.ha
@@ -46,7 +46,27 @@ export fn expr(
z += fmt::fprint(out, ")")?;
z;
},
- e: ast::append_expr => abort(),
+ e: ast::append_expr => {
+ let z = fmt::fprint(out, "append(")?;
+ z += expr(out, indent, *e.object)?;
+ z += fmt::fprint(out, ", ")?;
+ for (let i = 0z; i < len(e.values); i += 1) {
+ let val = e.values[i];
+ z += expr(out, indent, *val)?;
+ if (i + 1 < len(e.values)) {
+ z += fmt::fprint(out, ", ")?;
+ };
+ };
+ match (e.variadic) {
+ null => void,
+ e: *ast::expr => {
+ z += fmt::fprint(out, ", ")?;
+ z += expr(out, indent, *e)?;
+ z += fmt::fprint(out, "...")?;
+ },
+ };
+ z + fmt::fprint(out, ")")?;
+ },
e: ast::assert_expr => abort(),
e: ast::assign_expr => {
let z = 0z;