commit f8e1221decb4bad55bf5b8feb41e0af56ce74b7a
parent 3fd05e229b728a739001d0b3faadfcc99eee11b7
Author: Alexey Yerin <yyp@disroot.org>
Date: Sun, 18 Apr 2021 23:25:08 +0300
hare/parse,unparse: add assertion expressions
Diffstat:
3 files changed, 76 insertions(+), 4 deletions(-)
diff --git a/hare/parse/+test/expr.ha b/hare/parse/+test/expr.ha
@@ -38,6 +38,14 @@
append(x, 10);
append(x, 10, 20, 30);
append(x, y, z, q...);
+ abort();
+ abort(\"surprize\");
+ static abort();
+ static abort(\"surprize\");
+ assert(x == 12);
+ assert(x == 12, \"number mismatch\");
+ static assert(x == 12);
+ static assert(x == 12, \"number mismatch\");
delete(x[10]);
delete(x[10..20]);
delete(x[..]);
diff --git a/hare/parse/expr.ha b/hare/parse/expr.ha
@@ -77,6 +77,44 @@ export fn expression(lexer: *lex::lexer) (ast::expr | error) = {
};
};
+fn assert_expr(lexer: *lex::lexer, is_static: bool) (ast::expr | error) = {
+ let tok = want(lexer, ltok::ABORT, ltok::ASSERT)?;
+
+ return switch (tok.0) {
+ ltok::ABORT => {
+ want(lexer, ltok::LPAREN)?;
+ const msg: nullable *ast::expr =
+ if (peek(lexer, ltok::RPAREN)? is lex::token) {
+ null;
+ } else alloc(expression(lexer)?);
+ want(lexer, ltok::RPAREN)?;
+
+ ast::assert_expr {
+ cond = null,
+ message = msg,
+ is_static = is_static,
+ };
+ },
+ ltok::ASSERT => {
+ want(lexer, ltok::LPAREN)?;
+ const cond: nullable *ast::expr =
+ alloc(expression(lexer)?);
+ const msg: nullable *ast::expr =
+ if (try(lexer, ltok::COMMA)? is lex::token) {
+ alloc(expression(lexer)?);
+ } else null;
+ want(lexer, ltok::RPAREN)?;
+
+ ast::assert_expr {
+ cond = cond,
+ message = msg,
+ is_static = is_static,
+ };
+ },
+ * => abort(), // unreachable
+ };
+};
+
fn alloc_expr(lexer: *lex::lexer) (ast::expr | error) = {
want(lexer, ltok::ALLOC)?;
want(lexer, ltok::LPAREN)?;
@@ -240,11 +278,11 @@ fn builtin(lexer: *lex::lexer) (ast::expr | error) = {
ltok::APPEND => append_expr(lexer)?,
ltok::DELETE => delete_expr(lexer)?,
ltok::FREE => free_expr(lexer)?,
- ltok::ASSERT => abort(), // TODO
+ ltok::ABORT, ltok::ASSERT => assert_expr(lexer, false),
ltok::STATIC => {
want(lexer, ltok::STATIC)?;
let tok = match (peek(lexer, ltok::LET, ltok::CONST,
- ltok::ASSERT)?) {
+ ltok::ABORT, ltok::ASSERT)?) {
tok: lex::token => tok,
// TODO: The following is lame
void => return syntaxerr(tok.2,
@@ -252,7 +290,8 @@ fn builtin(lexer: *lex::lexer) (ast::expr | error) = {
};
switch (tok.0) {
ltok::LET, ltok::CONST => binding(lexer, true),
- ltok::ASSERT => abort(), // TODO
+ ltok::ABORT,
+ ltok::ASSERT => assert_expr(lexer, true),
* => abort(),
};
},
diff --git a/hare/unparse/expr.ha b/hare/unparse/expr.ha
@@ -67,7 +67,32 @@ export fn expr(
};
z + fmt::fprint(out, ")")?;
},
- e: ast::assert_expr => abort(),
+ e: ast::assert_expr => {
+ let z = fmt::fprint(
+ out, if (e.is_static) "static " else "")?;
+ // assert without a condition = abort
+ z += match (e.cond) {
+ e: *ast::expr => {
+ fmt::fprint(out, "assert(")? +
+ expr(out, indent, *e)?;
+ },
+ null => fmt::fprint(out, "abort(")?,
+ };
+ z += match (e.message) {
+ m: *ast::expr => {
+ let z = 0z;
+ match (e.cond) {
+ *ast::expr => {
+ z += fmt::fprint(out, ", ")?;
+ },
+ null => void,
+ };
+ z + expr(out, indent, *m)?;
+ },
+ null => 0,
+ };
+ z + fmt::fprint(out, ")")?;
+ },
e: ast::assign_expr => {
let z = 0z;
if (e.indirect) {