commit 7334dc8b3974528c231110ee190e3be17a3a85cc
parent 3f79921d1bfd6992ffa843e4b0be30eefd408098
Author: Sebastian <sebastian@sebsite.pw>
Date: Mon, 9 May 2022 18:38:50 -0400
parse: allow static bindings in for expression
This is required by the spec, since binding-list may have the static
form.
Fixes: https://todo.sr.ht/~sircmpwn/hare/677
Signed-off-by: Sebastian <sebastian@sebsite.pw>
Diffstat:
2 files changed, 62 insertions(+), 35 deletions(-)
diff --git a/src/parse.c b/src/parse.c
@@ -1384,6 +1384,38 @@ parse_slice_mutation(struct lexer *lexer, bool is_static)
}
static struct ast_expression *
+parse_static_expression(struct lexer *lexer, bool allowbinding)
+{
+ struct token tok = {0};
+ switch (lex(lexer, &tok)) {
+ case T_LET:
+ case T_CONST:
+ synassert(allowbinding, &tok, T_ABORT, T_ASSERT, T_APPEND,
+ T_INSERT, T_DELETE, T_EOF);
+ unlex(lexer, &tok);
+ return parse_binding_list(lexer, true);
+ case T_ABORT:
+ case T_ASSERT:
+ unlex(lexer, &tok);
+ return parse_assertion_expression(lexer, true);
+ case T_APPEND:
+ case T_INSERT:
+ case T_DELETE:
+ unlex(lexer, &tok);
+ return parse_slice_mutation(lexer, true);
+ default:
+ if (allowbinding) {
+ synassert(false, &tok, T_LET, T_CONST, T_ABORT,
+ T_ASSERT, T_APPEND, T_INSERT, T_DELETE, T_EOF);
+ } else {
+ synassert(false, &tok, T_ABORT, T_ASSERT, T_APPEND,
+ T_INSERT, T_DELETE, T_EOF);
+ }
+ }
+ assert(0); // Unreachable
+}
+
+static struct ast_expression *
parse_postfix_expression(struct lexer *lexer, struct ast_expression *lvalue)
{
if (lvalue == NULL) {
@@ -1518,21 +1550,7 @@ parse_builtin_expression(struct lexer *lexer)
unlex(lexer, &tok);
return parse_slice_mutation(lexer, false);
case T_STATIC:
- switch (lex(lexer, &tok)) {
- case T_ABORT:
- case T_ASSERT:
- unlex(lexer, &tok);
- return parse_assertion_expression(lexer, true);
- case T_APPEND:
- case T_DELETE:
- case T_INSERT:
- unlex(lexer, &tok);
- return parse_slice_mutation(lexer, true);
- default:
- synassert(false, &tok, T_ABORT, T_ASSERT,
- T_APPEND, T_DELETE, T_INSERT, T_EOF);
- };
- break;
+ return parse_static_expression(lexer, false);
case T_ABORT:
case T_ASSERT:
unlex(lexer, &tok);
@@ -1784,14 +1802,29 @@ parse_for_expression(struct lexer *lexer)
unlex(lexer, &tok);
exp->_for.bindings = parse_binding_list(lexer, false);
want(lexer, T_SEMICOLON, &tok);
+ exp->_for.cond = parse_expression(lexer);
+ break;
+ case T_STATIC:
+ switch (lex(lexer, &tok)) {
+ case T_LET:
+ case T_CONST:
+ unlex(lexer, &tok);
+ exp->_for.bindings = parse_binding_list(lexer, true);
+ want(lexer, T_SEMICOLON, &tok);
+ exp->_for.cond = parse_expression(lexer);
+ break;
+ default:
+ unlex(lexer, &tok);
+ exp->_for.cond = parse_static_expression(lexer, false);
+ break;
+ }
break;
default:
unlex(lexer, &tok);
+ exp->_for.cond = parse_expression(lexer);
break;
}
- exp->_for.cond = parse_expression(lexer);
-
switch (lex(lexer, &tok)) {
case T_SEMICOLON:
exp->_for.afterthought = parse_expression(lexer);
@@ -2210,24 +2243,7 @@ parse_expression(struct lexer *lexer)
unlex(lexer, &tok);
return parse_binding_list(lexer, false);
case T_STATIC:
- switch (lex(lexer, &tok)) {
- case T_LET:
- case T_CONST:
- unlex(lexer, &tok);
- return parse_binding_list(lexer, true);
- case T_ABORT:
- case T_ASSERT:
- unlex(lexer, &tok);
- return parse_assertion_expression(lexer, true);
- case T_APPEND:
- case T_INSERT:
- case T_DELETE:
- unlex(lexer, &tok);
- return parse_slice_mutation(lexer, true);
- default:
- synassert(false, &tok, T_LET, T_CONST, T_ABORT, T_ASSERT, T_EOF);
- }
- assert(0); // Unreachable
+ return parse_static_expression(lexer, true);
case T_BREAK:
case T_CONTINUE:
case T_RETURN:
diff --git a/tests/12-loops.ha b/tests/12-loops.ha
@@ -106,6 +106,16 @@ fn alias() void = {
abort("unreachable");
};
+fn _static() void = {
+ let count = 0z;
+ for (let i = 0z; i < 2; i += 1) {
+ for (static let j = 0z; j < 5; j += 1) {
+ count += 1;
+ };
+ };
+ assert(count == 5);
+};
+
export fn main() void = {
scope();
conditional();
@@ -115,4 +125,5 @@ export fn main() void = {
_continue();
label();
alias();
+ _static();
};