hare

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

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:
Mhare/ast/expr.ha | 4++--
Mhare/parse/+test/expr.ha | 3+++
Mhare/parse/expr.ha | 51++++++++++++++++++++++++++++++++++++++++++++++-----
Mhare/unparse/expr.ha | 22+++++++++++++++++++++-
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;