From bfc5846c4deaa1a3d24a75ee7bdc6f675ab569ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Motiejus=20Jak=C5=A1tys?= Date: Tue, 10 Feb 2026 14:05:41 +0000 Subject: [PATCH] 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) --- parser.c | 9 ++-- parser_test.zig | 130 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+), 3 deletions(-) diff --git a/parser.c b/parser.c index 0879cead97..d1f858b026 100644 --- a/parser.c +++ b/parser.c @@ -708,7 +708,7 @@ static AstNodeIndex parseSuffixExpr(Parser* p) { const uint32_t params_len = p->scratch.len - scratch_top.old_len; switch (params_len) { case 0: - return addNode( + res = addNode( &p->nodes, (AstNodeItem) { .tag = comma ? AST_NODE_CALL_ONE_COMMA : AST_NODE_CALL_ONE, @@ -718,8 +718,9 @@ static AstNodeIndex parseSuffixExpr(Parser* p) { .rhs = 0, }, }); + break; case 1: - return addNode( + res = addNode( &p->nodes, (AstNodeItem) { .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], }, }); + break; default:; const AstSubRange span = listToSpan( p, &p->scratch.arr[scratch_top.old_len], params_len); - return addNode( + res = addNode( &p->nodes, (AstNodeItem) { .tag = comma ? AST_NODE_CALL_COMMA : AST_NODE_CALL, @@ -745,6 +747,7 @@ static AstNodeIndex parseSuffixExpr(Parser* p) { }, 2), }, }); + break; } } } diff --git a/parser_test.zig b/parser_test.zig index df9d00fff0..1d88c2cc1c 100644 --- a/parser_test.zig +++ b/parser_test.zig @@ -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); + \\ } + \\} + \\ + ); +}