hare

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

commit 413d17a737d263a696e620eb3d44077ecb58af58
parent c24c4f5921738cd6bc76cad7803b429ccb59e72d
Author: Eyal Sawady <ecs@d2evs.net>
Date:   Thu,  2 Sep 2021 04:44:44 +0000

hare::parse: implement insert

Also implement static slice mutations

Signed-off-by: Eyal Sawady <ecs@d2evs.net>

Diffstat:
Mhare/ast/expr.ha | 35++++++++++++++++++++++++++++++-----
Mhare/lex/token.ha | 2++
Mhare/parse/+test/expr.ha | 7+++++++
Mhare/parse/expr.ha | 51++++++++++++++++++++++++++++++++++++---------------
Mhare/unparse/expr.ha | 50++++++++++++++++++++++++++++++++++++++++++--------
5 files changed, 117 insertions(+), 28 deletions(-)

diff --git a/hare/ast/expr.ha b/hare/ast/expr.ha @@ -48,6 +48,7 @@ export type append_expr = struct { object: *expr, variadic: nullable *expr, values: []*expr, + is_static: bool, }; // An assertion expression. @@ -220,7 +221,10 @@ export type defer_expr = *expr; // // delete(foo[10]) // delete(foo[4..42]) -export type delete_expr = *expr; +export type delete_expr = struct { + object: *expr, + is_static: bool, +}; // A for loop. The label is set to empty string if absent. // @@ -246,6 +250,16 @@ export type if_expr = struct { fbranch: nullable *expr, }; +// An insert expression. +// +// insert(foo[0], bar, (more), baz...) +export type insert_expr = struct { + object: *expr, + variadic: nullable *expr, + values: []*expr, + is_static: bool, +}; + // :label. The ":" character is not included. export type label = str; @@ -355,9 +369,9 @@ export type expr = struct { assign_expr | binarithm_expr | binding_expr | break_expr | call_expr | cast_expr | constant_expr | continue_expr | defer_expr | delete_expr | for_expr | free_expr | if_expr | - compound_expr | match_expr | len_expr | size_expr | offset_expr | - propagate_expr | return_expr | slice_expr | switch_expr | - unarithm_expr | yield_expr), + insert_expr | compound_expr | match_expr | len_expr | + size_expr | offset_expr | propagate_expr | return_expr | + slice_expr | switch_expr | unarithm_expr | yield_expr), }; // Frees resources associated with a Hare [[expr]]ession. @@ -471,7 +485,7 @@ export fn expr_free(e: (expr | nullable *expr)) void = match (e) { }, c: continue_expr => free(c), d: defer_expr => expr_free(d: *expr), - d: delete_expr => expr_free(d: *expr), + d: delete_expr => expr_free(d.object), f: for_expr => { expr_free(f.bindings); expr_free(f.cond); @@ -484,6 +498,17 @@ export fn expr_free(e: (expr | nullable *expr)) void = match (e) { expr_free(i.tbranch); expr_free(i.fbranch); }, + e: insert_expr => { + expr_free(e.object); + match (e.variadic) { + null => void, + v: *expr => expr_free(v), + }; + for (let i = 0z; i < len(e.values); i += 1) { + expr_free(e.values[i]); + }; + free(e.values); + }, l: len_expr => expr_free(l: *expr), m: match_expr => { expr_free(m.value); diff --git a/hare/lex/token.ha b/hare/lex/token.ha @@ -39,6 +39,7 @@ export type ltok = enum uint { I64, I8, IF, + INSERT, INT, IS, LEN, @@ -183,6 +184,7 @@ const bmap: [_]str = [ "i64", "i8", "if", + "insert", "int", "is", "len", diff --git a/hare/parse/+test/expr.ha b/hare/parse/+test/expr.ha @@ -40,8 +40,10 @@ alloc(1234); alloc(4321, 1234); append(x, 10); + append(x, 10...); append(x, 10, 20, 30); append(x, y, z, q...); + static append(x, 10); abort(); abort(\"surprize\"); static abort(); @@ -54,7 +56,12 @@ delete(x[10..20]); delete(x[..]); delete(x.y.z[..]); + static delete(x[10]); free(x); + insert(x[0], foo); + insert(x[0], foo...); + insert(x[0], foo, bar...); + static insert(x[0], foo); len([1, 2, 3, 4]); size(u32); }; diff --git a/hare/parse/expr.ha b/hare/parse/expr.ha @@ -158,11 +158,16 @@ fn alloc_expr(lexer: *lex::lexer) (ast::expr | error) = { }; }; -fn append_expr(lexer: *lex::lexer) (ast::expr | error) = { - const tok = want(lexer, ltok::APPEND)?; +fn append_insert_expr( + lexer: *lex::lexer, + is_static: bool, +) (ast::expr | error) = { + const tok = want(lexer, ltok::APPEND, ltok::INSERT)?; want(lexer, ltok::LPAREN)?; - const object = objsel(lexer)?; + const object = if (tok.0 == ltok::APPEND) objsel(lexer)? + else postfix(lexer, void)?; + // TODO: Assert that this was an indexing expression want(lexer, ltok::COMMA)?; let variadic: nullable *ast::expr = null; @@ -189,15 +194,23 @@ fn append_expr(lexer: *lex::lexer) (ast::expr | error) = { synassert(lex::mkloc(lexer), variadic != null || len(values) != 0, "Expected values to append")?; + + const expr = if (tok.0 == ltok::APPEND) ast::append_expr { + object = alloc(object), + variadic = variadic, + values = values, + is_static = is_static, + } else ast::insert_expr { + object = alloc(object), + variadic = variadic, + values = values, + is_static = is_static, + }; return ast::expr { start = tok.2, end = lex::prevloc(lexer), - expr = ast::append_expr { - object = alloc(object), - variadic = variadic, - values = values, - }, + expr = expr, }; }; @@ -309,21 +322,23 @@ fn binding(lexer: *lex::lexer, is_static: bool) (ast::expr | error) = { fn builtin(lexer: *lex::lexer) (ast::expr | error) = { const tok = match (peek(lexer, ltok::ALLOC, ltok::APPEND, ltok::FREE, - ltok::DELETE, ltok::ABORT, ltok::ASSERT, ltok::STATIC, - ltok::SIZE, ltok::LEN, ltok::OFFSET, ltok::DEFER)?) { + ltok::DELETE, ltok::ABORT, ltok::ASSERT, ltok::INSERT, + ltok::STATIC, ltok::SIZE, ltok::LEN, ltok::OFFSET, + ltok::DEFER)?) { tok: lex::token => tok, void => return postfix(lexer, void), }; return switch (tok.0) { ltok::ALLOC => alloc_expr(lexer), - ltok::APPEND => append_expr(lexer), - ltok::DELETE => delete_expr(lexer), + ltok::APPEND, ltok::INSERT => append_insert_expr(lexer, false), + ltok::DELETE => delete_expr(lexer, false), ltok::FREE => free_expr(lexer), ltok::ABORT, ltok::ASSERT => assert_expr(lexer, false), ltok::STATIC => { want(lexer, ltok::STATIC)?; let tok = match (peek(lexer, ltok::LET, ltok::CONST, - ltok::ABORT, ltok::ASSERT)?) { + ltok::ABORT, ltok::ASSERT, ltok::APPEND, + ltok::INSERT, ltok::DELETE)?) { tok: lex::token => tok, // TODO: The following is lame void => return syntaxerr(tok.2, @@ -333,6 +348,9 @@ fn builtin(lexer: *lex::lexer) (ast::expr | error) = { ltok::LET, ltok::CONST => binding(lexer, true), ltok::ABORT, ltok::ASSERT => assert_expr(lexer, true), + ltok::APPEND, + ltok::INSERT => append_insert_expr(lexer, true), + ltok::DELETE => delete_expr(lexer, true), * => abort(), }; }, @@ -461,7 +479,7 @@ fn control(lexer: *lex::lexer) (ast::expr | error) = { }; }; -fn delete_expr(lexer: *lex::lexer) (ast::expr | error) = { +fn delete_expr(lexer: *lex::lexer, is_static: bool) (ast::expr | error) = { const start = want(lexer, ltok::DELETE)?; want(lexer, ltok::LPAREN)?; const expr = alloc(postfix(lexer, void)?); @@ -470,7 +488,10 @@ fn delete_expr(lexer: *lex::lexer) (ast::expr | error) = { return ast::expr { start = start.2, end = lex::prevloc(lexer), - expr = expr: ast::delete_expr, + expr = ast::delete_expr { + object = expr, + is_static = is_static, + }, }; }; diff --git a/hare/unparse/expr.ha b/hare/unparse/expr.ha @@ -49,7 +49,9 @@ export fn expr( yield z; }, e: ast::append_expr => { - let z = fmt::fprint(out, "append(")?; + let z = if (e.is_static) fmt::fprint(out, "static ")? + else 0z; + 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) { @@ -61,9 +63,11 @@ export fn expr( }; match (e.variadic) { null => void, - e: *ast::expr => { - z += fmt::fprint(out, ", ")?; - z += expr(out, indent, *e)?; + v: *ast::expr => { + if (len(e.values) != 0) { + z += fmt::fprint(out, ", ")?; + }; + z += expr(out, indent, *v)?; z += fmt::fprint(out, "...")?; }, }; @@ -220,10 +224,14 @@ export fn expr( }, e: ast::defer_expr => fmt::fprint(out, "defer ")? + expr(out, indent, *e)?, - e: ast::delete_expr => - fmt::fprint(out, "delete(")? - + expr(out, indent, *e)? - + fmt::fprint(out, ")")?, + e: ast::delete_expr => { + let z = if (e.is_static) fmt::fprint(out, "static ")? + else 0z; + z += fmt::fprint(out, "delete(")?; + z += expr(out, indent, *e.object)?; + z += fmt::fprint(out, ")")?; + yield z; + }, e: ast::for_expr => for_expr(out, indent, e)?, e: ast::free_expr => fmt::fprint(out, "free(")? @@ -243,6 +251,32 @@ export fn expr( }; yield z; }, + e: ast::insert_expr => { + let z = if (e.is_static) fmt::fprint(out, "static ")? + else 0z; + z += fmt::fprint(out, "insert(")?; + 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, + v: *ast::expr => { + if (len(e.values) != 0) { + z += fmt::fprint(out, ", ")?; + }; + z += expr(out, indent, *v)?; + z += fmt::fprint(out, "...")?; + }, + }; + z += fmt::fprint(out, ")")?; + yield z; + }, e: ast::compound_expr => { let z = 0z; if (e.label != "") {