hare

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

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:
Mhare/parse/+test/expr.ha | 8++++++++
Mhare/parse/expr.ha | 45++++++++++++++++++++++++++++++++++++++++++---
Mhare/unparse/expr.ha | 27++++++++++++++++++++++++++-
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) {