parser: port full "while" and "for" tests
Port tests: - "while" (full test with all variants) - "for" (full test with all variants including testTransform) Fix in parser.c: - comptime var decl: don't wrap in comptime node (renderer detects comptime from token positions) - forPrefix: handle trailing comma in input list and capture list Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
19
parser.c
19
parser.c
@@ -1335,6 +1335,8 @@ static uint32_t forPrefix(Parser* p) {
|
|||||||
SLICE_APPEND(AstNodeIndex, &p->scratch, input);
|
SLICE_APPEND(AstNodeIndex, &p->scratch, input);
|
||||||
if (p->token_tags[p->tok_i] == TOKEN_COMMA) {
|
if (p->token_tags[p->tok_i] == TOKEN_COMMA) {
|
||||||
p->tok_i++;
|
p->tok_i++;
|
||||||
|
if (eatToken(p, TOKEN_R_PAREN) != null_token)
|
||||||
|
break;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
expectToken(p, TOKEN_R_PAREN);
|
expectToken(p, TOKEN_R_PAREN);
|
||||||
@@ -1349,6 +1351,8 @@ static uint32_t forPrefix(Parser* p) {
|
|||||||
expectToken(p, TOKEN_IDENTIFIER);
|
expectToken(p, TOKEN_IDENTIFIER);
|
||||||
if (p->token_tags[p->tok_i] == TOKEN_COMMA) {
|
if (p->token_tags[p->tok_i] == TOKEN_COMMA) {
|
||||||
p->tok_i++;
|
p->tok_i++;
|
||||||
|
if (eatToken(p, TOKEN_PIPE) != null_token)
|
||||||
|
break;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
expectToken(p, TOKEN_PIPE);
|
expectToken(p, TOKEN_PIPE);
|
||||||
@@ -2660,10 +2664,21 @@ static AstNodeIndex expectStatement(Parser* p, bool allow_defer_var) {
|
|||||||
.data = { .lhs = block, .rhs = 0 },
|
.data = { .lhs = block, .rhs = 0 },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// comptime var decl or expression — the result needs to be
|
// comptime var decl or expression
|
||||||
// wrapped in a comptime node
|
|
||||||
if (allow_defer_var) {
|
if (allow_defer_var) {
|
||||||
|
// Pass through to expectVarDeclExprStatement.
|
||||||
|
// For var decls, the comptime prefix is detected from token
|
||||||
|
// positions by the renderer (no wrapping needed).
|
||||||
|
// For expressions, the result is wrapped in a comptime node.
|
||||||
const AstNodeIndex inner = expectVarDeclExprStatement(p);
|
const AstNodeIndex inner = expectVarDeclExprStatement(p);
|
||||||
|
const AstNodeTag inner_tag = p->nodes.tags[inner];
|
||||||
|
if (inner_tag == AST_NODE_SIMPLE_VAR_DECL
|
||||||
|
|| inner_tag == AST_NODE_ALIGNED_VAR_DECL
|
||||||
|
|| inner_tag == AST_NODE_LOCAL_VAR_DECL
|
||||||
|
|| inner_tag == AST_NODE_GLOBAL_VAR_DECL
|
||||||
|
|| inner_tag == AST_NODE_ASSIGN_DESTRUCTURE) {
|
||||||
|
return inner;
|
||||||
|
}
|
||||||
return addNode(&p->nodes,
|
return addNode(&p->nodes,
|
||||||
(AstNodeItem) {
|
(AstNodeItem) {
|
||||||
.tag = AST_NODE_COMPTIME,
|
.tag = AST_NODE_COMPTIME,
|
||||||
|
|||||||
188
parser_test.zig
188
parser_test.zig
@@ -3778,6 +3778,194 @@ test "zig fmt: switch" {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "zig fmt: while" {
|
||||||
|
try testCanonical(
|
||||||
|
\\test "while" {
|
||||||
|
\\ while (10 < 1) unreachable;
|
||||||
|
\\
|
||||||
|
\\ while (10 < 1) unreachable else unreachable;
|
||||||
|
\\
|
||||||
|
\\ while (10 < 1) {
|
||||||
|
\\ unreachable;
|
||||||
|
\\ }
|
||||||
|
\\
|
||||||
|
\\ while (10 < 1)
|
||||||
|
\\ unreachable;
|
||||||
|
\\
|
||||||
|
\\ var i: usize = 0;
|
||||||
|
\\ while (i < 10) : (i += 1) {
|
||||||
|
\\ continue;
|
||||||
|
\\ }
|
||||||
|
\\
|
||||||
|
\\ i = 0;
|
||||||
|
\\ while (i < 10) : (i += 1)
|
||||||
|
\\ continue;
|
||||||
|
\\
|
||||||
|
\\ i = 0;
|
||||||
|
\\ var j: usize = 0;
|
||||||
|
\\ while (i < 10) : ({
|
||||||
|
\\ i += 1;
|
||||||
|
\\ j += 1;
|
||||||
|
\\ }) continue;
|
||||||
|
\\
|
||||||
|
\\ while (i < 10) : ({
|
||||||
|
\\ i += 1;
|
||||||
|
\\ j += 1;
|
||||||
|
\\ }) {
|
||||||
|
\\ continue;
|
||||||
|
\\ }
|
||||||
|
\\
|
||||||
|
\\ var a: ?u8 = 2;
|
||||||
|
\\ while (a) |v| : (a = null) {
|
||||||
|
\\ continue;
|
||||||
|
\\ }
|
||||||
|
\\
|
||||||
|
\\ while (a) |v| : (a = null)
|
||||||
|
\\ continue;
|
||||||
|
\\
|
||||||
|
\\ while (a) |v| : (a = null)
|
||||||
|
\\ continue
|
||||||
|
\\ else
|
||||||
|
\\ unreachable;
|
||||||
|
\\
|
||||||
|
\\ for (&[_]u8{}) |v| {
|
||||||
|
\\ continue;
|
||||||
|
\\ }
|
||||||
|
\\
|
||||||
|
\\ while (a) |v| : (a = null)
|
||||||
|
\\ unreachable;
|
||||||
|
\\
|
||||||
|
\\ label: while (10 < 0) {
|
||||||
|
\\ unreachable;
|
||||||
|
\\ }
|
||||||
|
\\
|
||||||
|
\\ const res = while (0 < 10) {
|
||||||
|
\\ break 7;
|
||||||
|
\\ } else {
|
||||||
|
\\ unreachable;
|
||||||
|
\\ };
|
||||||
|
\\
|
||||||
|
\\ const res = while (0 < 10)
|
||||||
|
\\ break 7
|
||||||
|
\\ else
|
||||||
|
\\ unreachable;
|
||||||
|
\\
|
||||||
|
\\ var a: anyerror!u8 = 0;
|
||||||
|
\\ while (a) |v| {
|
||||||
|
\\ a = error.Err;
|
||||||
|
\\ } else |err| {
|
||||||
|
\\ i = 1;
|
||||||
|
\\ }
|
||||||
|
\\
|
||||||
|
\\ comptime var k: usize = 0;
|
||||||
|
\\ inline while (i < 10) : (i += 1)
|
||||||
|
\\ j += 2;
|
||||||
|
\\}
|
||||||
|
\\
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "zig fmt: for" {
|
||||||
|
try testCanonical(
|
||||||
|
\\test "for" {
|
||||||
|
\\ for (a) |v| {
|
||||||
|
\\ continue;
|
||||||
|
\\ }
|
||||||
|
\\
|
||||||
|
\\ for (a) |v| continue;
|
||||||
|
\\
|
||||||
|
\\ for (a) |v| continue else return;
|
||||||
|
\\
|
||||||
|
\\ for (a) |v| {
|
||||||
|
\\ continue;
|
||||||
|
\\ } else return;
|
||||||
|
\\
|
||||||
|
\\ for (a) |v| continue else {
|
||||||
|
\\ return;
|
||||||
|
\\ }
|
||||||
|
\\
|
||||||
|
\\ for (a) |v|
|
||||||
|
\\ continue
|
||||||
|
\\ else
|
||||||
|
\\ return;
|
||||||
|
\\
|
||||||
|
\\ for (a) |v|
|
||||||
|
\\ continue;
|
||||||
|
\\
|
||||||
|
\\ for (a) |*v|
|
||||||
|
\\ continue;
|
||||||
|
\\
|
||||||
|
\\ for (a, 0..) |v, i| {
|
||||||
|
\\ continue;
|
||||||
|
\\ }
|
||||||
|
\\
|
||||||
|
\\ for (a, 0..) |v, i|
|
||||||
|
\\ continue;
|
||||||
|
\\
|
||||||
|
\\ for (a) |b| switch (b) {
|
||||||
|
\\ c => {},
|
||||||
|
\\ d => {},
|
||||||
|
\\ };
|
||||||
|
\\
|
||||||
|
\\ const res = for (a, 0..) |v, i| {
|
||||||
|
\\ break v;
|
||||||
|
\\ } else {
|
||||||
|
\\ unreachable;
|
||||||
|
\\ };
|
||||||
|
\\
|
||||||
|
\\ var num: usize = 0;
|
||||||
|
\\ inline for (a, 0..1) |v, i| {
|
||||||
|
\\ num += v;
|
||||||
|
\\ num += i;
|
||||||
|
\\ }
|
||||||
|
\\
|
||||||
|
\\ for (a, b) |
|
||||||
|
\\ long_name,
|
||||||
|
\\ another_long_name,
|
||||||
|
\\ | {
|
||||||
|
\\ continue;
|
||||||
|
\\ }
|
||||||
|
\\}
|
||||||
|
\\
|
||||||
|
);
|
||||||
|
|
||||||
|
try testTransform(
|
||||||
|
\\test "fix for" {
|
||||||
|
\\ for (a) |x|
|
||||||
|
\\ f(x) else continue;
|
||||||
|
\\}
|
||||||
|
\\
|
||||||
|
,
|
||||||
|
\\test "fix for" {
|
||||||
|
\\ for (a) |x|
|
||||||
|
\\ f(x)
|
||||||
|
\\ else
|
||||||
|
\\ continue;
|
||||||
|
\\}
|
||||||
|
\\
|
||||||
|
);
|
||||||
|
|
||||||
|
try testTransform(
|
||||||
|
\\test "fix for" {
|
||||||
|
\\ for (a, b, c,) |long, another, third,| {}
|
||||||
|
\\}
|
||||||
|
\\
|
||||||
|
,
|
||||||
|
\\test "fix for" {
|
||||||
|
\\ for (
|
||||||
|
\\ a,
|
||||||
|
\\ b,
|
||||||
|
\\ c,
|
||||||
|
\\ ) |
|
||||||
|
\\ long,
|
||||||
|
\\ another,
|
||||||
|
\\ third,
|
||||||
|
\\ | {}
|
||||||
|
\\}
|
||||||
|
\\
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
test "zig fmt: for if" {
|
test "zig fmt: for if" {
|
||||||
try testCanonical(
|
try testCanonical(
|
||||||
\\test {
|
\\test {
|
||||||
|
|||||||
Reference in New Issue
Block a user