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:
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 != "") {