parser: add multiline string, fn call, struct, if-else tests

Port tests from upstream parser_test.zig:
- "multiline string with backslash at end of line"
- "multiline string parameter in fn call with trailing comma"
- "trailing comma on fn call"
- "multi line arguments without last comma"
- "empty block with only comment"
- "trailing commas on struct decl"
- "extra newlines at the end"
- "nested struct literal with one item"
- "if-else with comment before else"

Fix parseSuffixExpr: continue suffix loop after call parsing
instead of returning, enabling method chains like a.b().c().

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-02-10 14:05:41 +00:00
parent bf632b9d6b
commit bfc5846c4d
2 changed files with 136 additions and 3 deletions

View File

@@ -708,7 +708,7 @@ static AstNodeIndex parseSuffixExpr(Parser* p) {
const uint32_t params_len = p->scratch.len - scratch_top.old_len; const uint32_t params_len = p->scratch.len - scratch_top.old_len;
switch (params_len) { switch (params_len) {
case 0: case 0:
return addNode( res = addNode(
&p->nodes, &p->nodes,
(AstNodeItem) { (AstNodeItem) {
.tag = comma ? AST_NODE_CALL_ONE_COMMA : AST_NODE_CALL_ONE, .tag = comma ? AST_NODE_CALL_ONE_COMMA : AST_NODE_CALL_ONE,
@@ -718,8 +718,9 @@ static AstNodeIndex parseSuffixExpr(Parser* p) {
.rhs = 0, .rhs = 0,
}, },
}); });
break;
case 1: case 1:
return addNode( res = addNode(
&p->nodes, &p->nodes,
(AstNodeItem) { (AstNodeItem) {
.tag = comma ? AST_NODE_CALL_ONE_COMMA : AST_NODE_CALL_ONE, .tag = comma ? AST_NODE_CALL_ONE_COMMA : AST_NODE_CALL_ONE,
@@ -729,10 +730,11 @@ static AstNodeIndex parseSuffixExpr(Parser* p) {
.rhs = p->scratch.arr[scratch_top.old_len], .rhs = p->scratch.arr[scratch_top.old_len],
}, },
}); });
break;
default:; default:;
const AstSubRange span = listToSpan( const AstSubRange span = listToSpan(
p, &p->scratch.arr[scratch_top.old_len], params_len); p, &p->scratch.arr[scratch_top.old_len], params_len);
return addNode( res = addNode(
&p->nodes, &p->nodes,
(AstNodeItem) { (AstNodeItem) {
.tag = comma ? AST_NODE_CALL_COMMA : AST_NODE_CALL, .tag = comma ? AST_NODE_CALL_COMMA : AST_NODE_CALL,
@@ -745,6 +747,7 @@ static AstNodeIndex parseSuffixExpr(Parser* p) {
}, 2), }, 2),
}, },
}); });
break;
} }
} }
} }

View File

@@ -1668,3 +1668,133 @@ test "zig fmt: remove empty lines at start/end of block" {
\\ \\
); );
} }
test "zig fmt: multiline string with backslash at end of line" {
try testCanonical(
\\comptime {
\\ err(
\\ \\\
\\ );
\\}
\\
);
}
test "zig fmt: multiline string parameter in fn call with trailing comma" {
try testCanonical(
\\fn foo() void {
\\ try stdout.print(
\\ \\ZIG_CMAKE_BINARY_DIR {s}
\\ \\ZIG_C_HEADER_FILES {s}
\\ \\ZIG_DIA_GUIDS_LIB {s}
\\ \\
\\ ,
\\ std.mem.sliceTo(c.ZIG_CMAKE_BINARY_DIR, 0),
\\ std.mem.sliceTo(c.ZIG_CXX_COMPILER, 0),
\\ std.mem.sliceTo(c.ZIG_DIA_GUIDS_LIB, 0),
\\ );
\\}
\\
);
}
test "zig fmt: trailing comma on fn call" {
try testCanonical(
\\comptime {
\\ var module = try Module.create(
\\ allocator,
\\ zig_lib_dir,
\\ full_cache_dir,
\\ );
\\}
\\
);
}
test "zig fmt: multi line arguments without last comma" {
try testTransform(
\\pub fn foo(
\\ a: usize,
\\ b: usize,
\\ c: usize,
\\ d: usize
\\) usize {
\\ return a + b + c + d;
\\}
\\
,
\\pub fn foo(a: usize, b: usize, c: usize, d: usize) usize {
\\ return a + b + c + d;
\\}
\\
);
}
test "zig fmt: empty block with only comment" {
try testCanonical(
\\comptime {
\\ {
\\ // comment
\\ }
\\}
\\
);
}
test "zig fmt: trailing commas on struct decl" {
try testTransform(
\\const RoundParam = struct {
\\ k: usize, s: u32, t: u32
\\};
\\const RoundParam = struct {
\\ k: usize, s: u32, t: u32,
\\};
,
\\const RoundParam = struct { k: usize, s: u32, t: u32 };
\\const RoundParam = struct {
\\ k: usize,
\\ s: u32,
\\ t: u32,
\\};
\\
);
}
test "zig fmt: extra newlines at the end" {
try testTransform(
\\const a = b;
\\
\\
\\
,
\\const a = b;
\\
);
}
test "zig fmt: nested struct literal with one item" {
try testCanonical(
\\const a = foo{
\\ .item = bar{ .a = b },
\\};
\\
);
}
test "zig fmt: if-else with comment before else" {
try testCanonical(
\\comptime {
\\ // cexp(finite|nan +- i inf|nan) = nan + i nan
\\ if ((hx & 0x7fffffff) != 0x7f800000) {
\\ return Complex(f32).init(y - y, y - y);
\\ } // cexp(-inf +- i inf|nan) = 0 + i0
\\ else if (hx & 0x80000000 != 0) {
\\ return Complex(f32).init(0, 0);
\\ } // cexp(+inf +- i inf|nan) = inf + i nan
\\ else {
\\ return Complex(f32).init(x, y - y);
\\ }
\\}
\\
);
}