From fdefdc98c2dd66ad170cdb5442a752902b6bb50b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Motiejus=20Jak=C5=A1tys?= Date: Wed, 11 Feb 2026 11:40:38 +0000 Subject: [PATCH] parser: sync tests with upstream, fix tokenizer and parser Sync parser_test.zig test section with upstream, adding ~40 new tests (testError, testCanonical, testTransform). Remove extra blank lines between tests to match upstream formatting. Fix tokenizer keyword lookup bug: getKeyword() returned TOKEN_INVALID when input was longer than a keyword prefix (e.g., "orelse" matched "or" prefix then bailed out instead of continuing to find "orelse"). Fix parser to handle if/for/while expressions in type position (e.g., function return types like `fn foo() if (cond) i32 else void`). Add labeled block support in parsePrimaryTypeExpr. Replace assert for chained comparison operators with longjmp error. 365/381 tests pass. Remaining 16 failures are parser limitations for specific syntax patterns and error recovery. Co-Authored-By: Claude Opus 4.6 (1M context) --- parser.c | 133 ++++- parser_test.zig | 1238 +++++++++++++++++++++++++++++++++++------------ tokenizer.c | 4 +- 3 files changed, 1062 insertions(+), 313 deletions(-) diff --git a/parser.c b/parser.c index d86931ffc8..8a9a5b2a93 100644 --- a/parser.c +++ b/parser.c @@ -42,6 +42,8 @@ static AstNodeIndex parseSwitchExpr(Parser*); static AstNodeIndex parseForExpr(Parser*); static AstNodeIndex parseAsmExpr(Parser*); static AstNodeIndex parseIfExpr(Parser*); +static uint32_t forPrefix(Parser*); +static AstNodeIndex parseLabeledStatement(Parser*); typedef struct { enum { FIELD_STATE_NONE, FIELD_STATE_SEEN, FIELD_STATE_END } tag; @@ -521,6 +523,22 @@ static AstNodeIndex parsePrimaryTypeExpr(Parser* p) { }); } case TOKEN_IDENTIFIER: + if (p->token_tags[p->tok_i + 1] == TOKEN_COLON) { + switch (p->token_tags[p->tok_i + 2]) { + case TOKEN_L_BRACE: { + // Labeled block: label: { ... } + nextToken(p); // consume label + nextToken(p); // consume ':' + return parseBlock(p); + } + case TOKEN_KEYWORD_WHILE: + return parseLabeledStatement(p); + case TOKEN_KEYWORD_FOR: + return parseLabeledStatement(p); + default: + break; + } + } return addNode(&p->nodes, (AstNodeItem) { .tag = AST_NODE_IDENTIFIER, @@ -1018,6 +1036,116 @@ static AstNodeIndex parseTypeExpr(Parser* p) { }, }); } + case TOKEN_KEYWORD_IF: { + // if-type-expr: uses parseTypeExpr for branches instead of parseExpr + const AstTokenIndex if_token = nextToken(p); + expectToken(p, TOKEN_L_PAREN); + const AstNodeIndex condition = expectExpr(p); + expectToken(p, TOKEN_R_PAREN); + parsePtrPayload(p); + const AstNodeIndex then_expr = parseTypeExpr(p); + if (eatToken(p, TOKEN_KEYWORD_ELSE) == null_token) + return addNode(&p->nodes, + (AstNodeItem) { + .tag = AST_NODE_IF_SIMPLE, + .main_token = if_token, + .data = { .lhs = condition, .rhs = then_expr }, + }); + parsePayload(p); + const AstNodeIndex else_expr = parseTypeExpr(p); + return addNode(&p->nodes, + (AstNodeItem) { + .tag = AST_NODE_IF, + .main_token = if_token, + .data = { + .lhs = condition, + .rhs = addExtra(p, + (AstNodeIndex[]) { then_expr, else_expr }, 2), + }, + }); + } + case TOKEN_KEYWORD_FOR: { + // for-type-expr: uses parseTypeExpr for body instead of parseExpr + const AstTokenIndex for_token = nextToken(p); + const uint32_t scratch_top2 = p->scratch.len; + const uint32_t inputs = forPrefix(p); + const AstNodeIndex body = parseTypeExpr(p); + if (eatToken(p, TOKEN_KEYWORD_ELSE) != null_token) { + parsePayload(p); + SLICE_APPEND(AstNodeIndex, &p->scratch, body); + const AstNodeIndex else_expr = parseTypeExpr(p); + SLICE_APPEND(AstNodeIndex, &p->scratch, else_expr); + const uint32_t total = p->scratch.len - scratch_top2; + const AstSubRange span + = listToSpan(p, &p->scratch.arr[scratch_top2], total); + p->scratch.len = scratch_top2; + return addNode(&p->nodes, + (AstNodeItem) { + .tag = AST_NODE_FOR, + .main_token = for_token, + .data = { + .lhs = span.start, + .rhs = ((uint32_t)inputs & 0x7FFFFFFF) | (1u << 31), + }, + }); + } + SLICE_APPEND(AstNodeIndex, &p->scratch, body); + const uint32_t total = p->scratch.len - scratch_top2; + const AstSubRange span + = listToSpan(p, &p->scratch.arr[scratch_top2], total); + p->scratch.len = scratch_top2; + return addNode(&p->nodes, + (AstNodeItem) { + .tag = AST_NODE_FOR, + .main_token = for_token, + .data = { + .lhs = span.start, + .rhs = (uint32_t)inputs & 0x7FFFFFFF, + }, + }); + } + case TOKEN_KEYWORD_WHILE: { + // while-type-expr: uses parseTypeExpr for body instead of parseExpr + const AstTokenIndex while_token = nextToken(p); + expectToken(p, TOKEN_L_PAREN); + const AstNodeIndex condition = expectExpr(p); + expectToken(p, TOKEN_R_PAREN); + parsePtrPayload(p); + const AstNodeIndex cont_expr + = eatToken(p, TOKEN_COLON) != null_token ? expectExpr(p) : 0; + const AstNodeIndex body = parseTypeExpr(p); + if (eatToken(p, TOKEN_KEYWORD_ELSE) != null_token) { + parsePayload(p); + const AstNodeIndex else_expr = parseTypeExpr(p); + return addNode(&p->nodes, + (AstNodeItem) { + .tag = AST_NODE_WHILE, + .main_token = while_token, + .data = { + .lhs = condition, + .rhs = addExtra(p, + (AstNodeIndex[]) { cont_expr, body, else_expr }, 3), + }, + }); + } + if (cont_expr != 0) + return addNode(&p->nodes, + (AstNodeItem) { + .tag = AST_NODE_WHILE_CONT, + .main_token = while_token, + .data = { + .lhs = condition, + .rhs = addExtra(p, + (AstNodeIndex[]) { cont_expr, body }, 2), + }, + }); + return addNode(&p->nodes, + (AstNodeItem) { + .tag = AST_NODE_WHILE_SIMPLE, + .main_token = while_token, + .data = { .lhs = condition, .rhs = body }, + }); + } default: return parseErrorUnionExpr(p); } @@ -1899,7 +2027,10 @@ static AstNodeIndex parseExprPrecedence(Parser* p, int32_t min_prec) { if (info.prec < min_prec) break; - assert(info.prec != banned_prec); + if (info.prec == banned_prec) { + fprintf(stderr, "chained comparison operators\n"); + longjmp(p->error_jmp, 1); + } const AstTokenIndex oper_token = nextToken(p); if (tok_tag == TOKEN_KEYWORD_CATCH) diff --git a/parser_test.zig b/parser_test.zig index 164829eac0..19493cf088 100644 --- a/parser_test.zig +++ b/parser_test.zig @@ -4,7 +4,6 @@ const print = std.debug.print; const io = std.io; const maxInt = std.math.maxInt; - test "zig fmt: remove extra whitespace at start and end of file with comment between" { try testTransform( \\ @@ -18,7 +17,6 @@ test "zig fmt: remove extra whitespace at start and end of file with comment bet ); } - test "zig fmt: tuple struct" { try testCanonical( \\const T = struct { @@ -33,7 +31,6 @@ test "zig fmt: tuple struct" { ); } - test "zig fmt: preserves clobbers in inline asm with stray comma" { try testTransform( \\fn foo() void { @@ -66,7 +63,6 @@ test "zig fmt: preserves clobbers in inline asm with stray comma" { ); } - test "zig fmt: remove trailing comma at the end of assembly clobber" { try testTransform( \\fn foo() void { @@ -89,7 +85,6 @@ test "zig fmt: remove trailing comma at the end of assembly clobber" { ); } - test "zig fmt: respect line breaks in struct field value declaration" { try testCanonical( \\const Foo = struct { @@ -115,7 +110,6 @@ test "zig fmt: respect line breaks in struct field value declaration" { ); } - test "zig fmt: respect line breaks before functions" { try testCanonical( \\const std = @import("std"); @@ -133,7 +127,6 @@ test "zig fmt: respect line breaks before functions" { ); } - test "zig fmt: rewrite callconv(.@\"inline\") to the inline keyword" { try testTransform( \\fn foo() callconv(.@"inline") void {} @@ -148,7 +141,6 @@ test "zig fmt: rewrite callconv(.@\"inline\") to the inline keyword" { ); } - test "zig fmt: simple top level comptime block" { try testCanonical( \\// line comment @@ -157,7 +149,6 @@ test "zig fmt: simple top level comptime block" { ); } - test "zig fmt: two spaced line comments before decl" { try testCanonical( \\// line comment @@ -168,7 +159,6 @@ test "zig fmt: two spaced line comments before decl" { ); } - test "zig fmt: respect line breaks after var declarations" { try testCanonical( \\const crc = @@ -184,7 +174,6 @@ test "zig fmt: respect line breaks after var declarations" { ); } - test "zig fmt: multiline string mixed with comments" { try testCanonical( \\const s1 = @@ -215,14 +204,12 @@ test "zig fmt: multiline string mixed with comments" { ); } - test "zig fmt: empty file" { try testCanonical( \\ ); } - test "zig fmt: file ends in comment" { try testTransform( \\ //foobar @@ -232,7 +219,6 @@ test "zig fmt: file ends in comment" { ); } - test "zig fmt: file ends in multi line comment" { try testTransform( \\ \\foobar @@ -242,7 +228,6 @@ test "zig fmt: file ends in multi line comment" { ); } - test "zig fmt: file ends in comment after var decl" { try testTransform( \\const x = 42; @@ -254,7 +239,6 @@ test "zig fmt: file ends in comment after var decl" { ); } - test "zig fmt: if statement" { try testCanonical( \\test "" { @@ -265,7 +249,6 @@ test "zig fmt: if statement" { ); } - test "zig fmt: top-level fields" { try testCanonical( \\a: did_you_know, @@ -275,7 +258,6 @@ test "zig fmt: top-level fields" { ); } - test "zig fmt: top-level tuple function call type" { try testCanonical( \\foo() @@ -283,7 +265,6 @@ test "zig fmt: top-level tuple function call type" { ); } - test "zig fmt: top-level enum missing 'const name ='" { try testError( \\enum(u32) @@ -291,7 +272,6 @@ test "zig fmt: top-level enum missing 'const name ='" { , &[_]Error{.expected_token}); } - test "zig fmt: top-level for/while loop" { try testCanonical( \\for (foo) |_| foo @@ -303,7 +283,6 @@ test "zig fmt: top-level for/while loop" { ); } - test "zig fmt: top-level bare asterisk+identifier" { try testCanonical( \\*x @@ -311,7 +290,6 @@ test "zig fmt: top-level bare asterisk+identifier" { ); } - test "zig fmt: top-level bare asterisk+asterisk+identifier" { try testCanonical( \\**x @@ -319,6 +297,45 @@ test "zig fmt: top-level bare asterisk+asterisk+identifier" { ); } +test "zig fmt: C style containers" { + try testError( + \\struct Foo { + \\ a: u32, + \\}; + , &[_]Error{ + .c_style_container, + .zig_style_container, + }); + try testError( + \\test { + \\ struct Foo { + \\ a: u32, + \\ }; + \\} + , &[_]Error{ + .c_style_container, + .zig_style_container, + }); +} + +test "zig fmt: decl between fields" { + try testError( + \\const S = struct { + \\ const foo = 2; + \\ const bar = 2; + \\ const baz = 2; + \\ a: usize, + \\ const foo1 = 2; + \\ const bar1 = 2; + \\ const baz1 = 2; + \\ b: usize, + \\}; + , &[_]Error{ + .decl_between_fields, + .previous_field, + .next_field, + }); +} test "zig fmt: errdefer with payload" { try testCanonical( @@ -333,7 +350,6 @@ test "zig fmt: errdefer with payload" { ); } - test "zig fmt: nosuspend block" { try testCanonical( \\pub fn main() anyerror!void { @@ -345,7 +361,6 @@ test "zig fmt: nosuspend block" { ); } - test "zig fmt: container declaration, single line" { try testCanonical( \\const X = struct { foo: i32 }; @@ -357,7 +372,6 @@ test "zig fmt: container declaration, single line" { ); } - test "zig fmt: container declaration, one item, multi line trailing comma" { try testCanonical( \\test "" { @@ -371,7 +385,6 @@ test "zig fmt: container declaration, one item, multi line trailing comma" { ); } - test "zig fmt: container declaration, no trailing comma on separate line" { try testTransform( \\test "" { @@ -392,7 +405,6 @@ test "zig fmt: container declaration, no trailing comma on separate line" { ); } - test "zig fmt: container declaration, line break, no trailing comma" { try testTransform( \\const X = struct { @@ -403,7 +415,6 @@ test "zig fmt: container declaration, line break, no trailing comma" { ); } - test "zig fmt: container declaration, transform trailing comma" { try testTransform( \\const X = struct { @@ -417,7 +428,6 @@ test "zig fmt: container declaration, transform trailing comma" { ); } - test "zig fmt: container declaration, comment, add trailing comma" { try testTransform( \\const X = struct { @@ -443,7 +453,6 @@ test "zig fmt: container declaration, comment, add trailing comma" { ); } - test "zig fmt: container declaration, multiline string, add trailing comma" { try testTransform( \\const X = struct { @@ -463,7 +472,6 @@ test "zig fmt: container declaration, multiline string, add trailing comma" { ); } - test "zig fmt: container declaration, doc comment on member, add trailing comma" { try testTransform( \\pub const Pos = struct { @@ -483,7 +491,6 @@ test "zig fmt: container declaration, doc comment on member, add trailing comma" ); } - test "zig fmt: remove empty lines at start/end of container decl" { try testTransform( \\const X = struct { @@ -504,7 +511,6 @@ test "zig fmt: remove empty lines at start/end of container decl" { ); } - test "zig fmt: remove empty lines at start/end of block" { try testTransform( \\test { @@ -525,7 +531,6 @@ test "zig fmt: remove empty lines at start/end of block" { ); } - test "zig fmt: allow empty line before comment at start of block" { try testCanonical( \\test { @@ -537,7 +542,6 @@ test "zig fmt: allow empty line before comment at start of block" { ); } - test "zig fmt: trailing comma in fn parameter list" { try testCanonical( \\pub fn f( @@ -580,7 +584,6 @@ test "zig fmt: trailing comma in fn parameter list" { ); } - test "zig fmt: comptime struct field" { try testCanonical( \\const Foo = struct { @@ -591,7 +594,6 @@ test "zig fmt: comptime struct field" { ); } - test "zig fmt: break from block" { try testCanonical( \\const a = blk: { @@ -610,7 +612,6 @@ test "zig fmt: break from block" { ); } - test "zig fmt: grouped expressions (parentheses)" { try testCanonical( \\const r = (x + y) * (a + b); @@ -618,7 +619,6 @@ test "zig fmt: grouped expressions (parentheses)" { ); } - test "zig fmt: c pointer type" { try testCanonical( \\pub extern fn repro() [*c]const u8; @@ -626,7 +626,6 @@ test "zig fmt: c pointer type" { ); } - test "zig fmt: builtin call with trailing comma" { try testCanonical( \\pub fn main() void { @@ -642,7 +641,6 @@ test "zig fmt: builtin call with trailing comma" { ); } - test "zig fmt: asm expression with comptime content" { try testTransform( \\comptime { @@ -687,7 +685,6 @@ test "zig fmt: asm expression with comptime content" { ); } - test "zig fmt: array types last token" { try testCanonical( \\test { @@ -701,7 +698,6 @@ test "zig fmt: array types last token" { ); } - test "zig fmt: sentinel-terminated array type" { try testCanonical( \\pub fn cStrToPrefixedFileW(s: [*:0]const u8) ![PATH_MAX_WIDE:0]u16 { @@ -711,7 +707,6 @@ test "zig fmt: sentinel-terminated array type" { ); } - test "zig fmt: sentinel-terminated slice type" { try testCanonical( \\pub fn toSlice(self: Buffer) [:0]u8 { @@ -721,7 +716,6 @@ test "zig fmt: sentinel-terminated slice type" { ); } - test "zig fmt: pointer-to-one with modifiers" { try testCanonical( \\const x: *u32 = undefined; @@ -731,7 +725,6 @@ test "zig fmt: pointer-to-one with modifiers" { ); } - test "zig fmt: pointer-to-many with modifiers" { try testCanonical( \\const x: [*]u32 = undefined; @@ -741,7 +734,6 @@ test "zig fmt: pointer-to-many with modifiers" { ); } - test "zig fmt: sentinel pointer with modifiers" { try testCanonical( \\const x: [*:42]u32 = undefined; @@ -751,7 +743,6 @@ test "zig fmt: sentinel pointer with modifiers" { ); } - test "zig fmt: c pointer with modifiers" { try testCanonical( \\const x: [*c]u32 = undefined; @@ -761,7 +752,6 @@ test "zig fmt: c pointer with modifiers" { ); } - test "zig fmt: slice with modifiers" { try testCanonical( \\const x: []u32 = undefined; @@ -770,7 +760,6 @@ test "zig fmt: slice with modifiers" { ); } - test "zig fmt: sentinel slice with modifiers" { try testCanonical( \\const x: [:42]u32 = undefined; @@ -779,7 +768,6 @@ test "zig fmt: sentinel slice with modifiers" { ); } - test "zig fmt: anon literal in array" { try testCanonical( \\var arr: [2]Foo = .{ @@ -790,7 +778,6 @@ test "zig fmt: anon literal in array" { ); } - test "zig fmt: alignment in anonymous literal" { try testTransform( \\const a = .{ @@ -809,7 +796,6 @@ test "zig fmt: alignment in anonymous literal" { ); } - test "zig fmt: anon struct literal 0 element" { try testCanonical( \\test { @@ -819,7 +805,6 @@ test "zig fmt: anon struct literal 0 element" { ); } - test "zig fmt: anon struct literal 1 element" { try testCanonical( \\test { @@ -829,7 +814,6 @@ test "zig fmt: anon struct literal 1 element" { ); } - test "zig fmt: anon struct literal 1 element comma" { try testCanonical( \\test { @@ -841,7 +825,6 @@ test "zig fmt: anon struct literal 1 element comma" { ); } - test "zig fmt: anon struct literal 2 element" { try testCanonical( \\test { @@ -851,7 +834,6 @@ test "zig fmt: anon struct literal 2 element" { ); } - test "zig fmt: anon struct literal 2 element comma" { try testCanonical( \\test { @@ -864,7 +846,6 @@ test "zig fmt: anon struct literal 2 element comma" { ); } - test "zig fmt: anon struct literal 3 element" { try testCanonical( \\test { @@ -874,7 +855,6 @@ test "zig fmt: anon struct literal 3 element" { ); } - test "zig fmt: anon struct literal 3 element comma" { try testCanonical( \\test { @@ -888,7 +868,6 @@ test "zig fmt: anon struct literal 3 element comma" { ); } - test "zig fmt: struct literal 0 element" { try testCanonical( \\test { @@ -898,7 +877,6 @@ test "zig fmt: struct literal 0 element" { ); } - test "zig fmt: struct literal 1 element" { try testCanonical( \\test { @@ -908,7 +886,6 @@ test "zig fmt: struct literal 1 element" { ); } - test "zig fmt: Unicode code point literal larger than u8" { try testCanonical( \\test { @@ -920,7 +897,6 @@ test "zig fmt: Unicode code point literal larger than u8" { ); } - test "zig fmt: struct literal 2 element" { try testCanonical( \\test { @@ -930,7 +906,6 @@ test "zig fmt: struct literal 2 element" { ); } - test "zig fmt: struct literal 2 element comma" { try testCanonical( \\test { @@ -943,7 +918,6 @@ test "zig fmt: struct literal 2 element comma" { ); } - test "zig fmt: struct literal 3 element" { try testCanonical( \\test { @@ -953,7 +927,6 @@ test "zig fmt: struct literal 3 element" { ); } - test "zig fmt: struct literal 3 element comma" { try testCanonical( \\test { @@ -967,7 +940,6 @@ test "zig fmt: struct literal 3 element comma" { ); } - test "zig fmt: anon list literal 1 element" { try testCanonical( \\test { @@ -977,7 +949,6 @@ test "zig fmt: anon list literal 1 element" { ); } - test "zig fmt: anon list literal 1 element comma" { try testCanonical( \\test { @@ -989,7 +960,6 @@ test "zig fmt: anon list literal 1 element comma" { ); } - test "zig fmt: anon list literal 2 element" { try testCanonical( \\test { @@ -999,7 +969,6 @@ test "zig fmt: anon list literal 2 element" { ); } - test "zig fmt: anon list literal 2 element comma" { try testCanonical( \\test { @@ -1012,7 +981,6 @@ test "zig fmt: anon list literal 2 element comma" { ); } - test "zig fmt: anon list literal 3 element" { try testCanonical( \\test { @@ -1022,7 +990,6 @@ test "zig fmt: anon list literal 3 element" { ); } - test "zig fmt: anon list literal 3 element comma" { try testCanonical( \\test { @@ -1038,7 +1005,6 @@ test "zig fmt: anon list literal 3 element comma" { ); } - test "zig fmt: array literal 0 element" { try testCanonical( \\test { @@ -1048,7 +1014,6 @@ test "zig fmt: array literal 0 element" { ); } - test "zig fmt: array literal 1 element" { try testCanonical( \\test { @@ -1058,7 +1023,6 @@ test "zig fmt: array literal 1 element" { ); } - test "zig fmt: array literal 1 element comma" { try testCanonical( \\test { @@ -1070,7 +1034,6 @@ test "zig fmt: array literal 1 element comma" { ); } - test "zig fmt: array literal 2 element" { try testCanonical( \\test { @@ -1080,7 +1043,6 @@ test "zig fmt: array literal 2 element" { ); } - test "zig fmt: array literal 2 element comma" { try testCanonical( \\test { @@ -1093,7 +1055,6 @@ test "zig fmt: array literal 2 element comma" { ); } - test "zig fmt: array literal 3 element" { try testCanonical( \\test { @@ -1103,7 +1064,6 @@ test "zig fmt: array literal 3 element" { ); } - test "zig fmt: array literal 3 element comma" { try testCanonical( \\test { @@ -1117,7 +1077,6 @@ test "zig fmt: array literal 3 element comma" { ); } - test "zig fmt: sentinel array literal 1 element" { try testCanonical( \\test { @@ -1127,7 +1086,6 @@ test "zig fmt: sentinel array literal 1 element" { ); } - test "zig fmt: slices" { try testCanonical( \\const a = b[0..]; @@ -1138,7 +1096,6 @@ test "zig fmt: slices" { ); } - test "zig fmt: slices with spaces in bounds" { try testCanonical( \\const a = b[0 + 0 ..]; @@ -1149,7 +1106,6 @@ test "zig fmt: slices with spaces in bounds" { ); } - test "zig fmt: block in slice expression" { try testCanonical( \\const a = b[{ @@ -1168,7 +1124,6 @@ test "zig fmt: block in slice expression" { ); } - test "zig fmt: whitespace fixes" { try testTransform("test \"\" {\r\n\tconst hi = x;\r\n}\n// zig fmt: off\ntest \"\"{\r\n\tconst a = b;}\r\n", \\test "" { @@ -1181,7 +1136,6 @@ test "zig fmt: whitespace fixes" { ); } - test "zig fmt: while else err prong with no block" { try testCanonical( \\test "" { @@ -1194,7 +1148,6 @@ test "zig fmt: while else err prong with no block" { ); } - test "zig fmt: tagged union with enum values" { try testCanonical( \\const MultipleChoice2 = union(enum(u32)) { @@ -1212,7 +1165,6 @@ test "zig fmt: tagged union with enum values" { ); } - test "zig fmt: tagged union enum tag last token" { try testCanonical( \\test { @@ -1232,7 +1184,6 @@ test "zig fmt: tagged union enum tag last token" { ); } - test "zig fmt: allowzero pointer" { try testCanonical( \\const T = [*]allowzero const u8; @@ -1240,7 +1191,6 @@ test "zig fmt: allowzero pointer" { ); } - test "zig fmt: empty enum decls" { try testCanonical( \\const A = enum {}; @@ -1251,7 +1201,6 @@ test "zig fmt: empty enum decls" { ); } - test "zig fmt: empty union decls" { try testCanonical( \\const A = union {}; @@ -1263,7 +1212,6 @@ test "zig fmt: empty union decls" { ); } - test "zig fmt: enum literal" { try testCanonical( \\const x = .hi; @@ -1271,7 +1219,6 @@ test "zig fmt: enum literal" { ); } - test "zig fmt: enum literal inside array literal" { try testCanonical( \\test "enums in arrays" { @@ -1287,7 +1234,6 @@ test "zig fmt: enum literal inside array literal" { ); } - test "zig fmt: character literal larger than u8" { try testCanonical( \\const x = '\u{01f4a9}'; @@ -1295,7 +1241,6 @@ test "zig fmt: character literal larger than u8" { ); } - test "zig fmt: infix operator and then multiline string literal" { try testCanonical( \\const x = "" ++ @@ -1305,7 +1250,6 @@ test "zig fmt: infix operator and then multiline string literal" { ); } - test "zig fmt: infix operator and then multiline string literal over multiple lines" { try testCanonical( \\const x = "" ++ @@ -1317,7 +1261,6 @@ test "zig fmt: infix operator and then multiline string literal over multiple li ); } - test "zig fmt: C pointers" { try testCanonical( \\const Ptr = [*c]i32; @@ -1325,7 +1268,6 @@ test "zig fmt: C pointers" { ); } - test "zig fmt: threadlocal" { try testCanonical( \\threadlocal var x: i32 = 1234; @@ -1333,7 +1275,6 @@ test "zig fmt: threadlocal" { ); } - test "zig fmt: linksection" { try testCanonical( \\export var aoeu: u64 linksection(".text.derp") = 1234; @@ -1342,7 +1283,6 @@ test "zig fmt: linksection" { ); } - test "zig fmt: addrspace" { try testCanonical( \\export var python_length: u64 align(1) addrspace(.generic); @@ -1353,7 +1293,6 @@ test "zig fmt: addrspace" { ); } - test "zig fmt: correctly space struct fields with doc comments" { try testTransform( \\pub const S = struct { @@ -1383,7 +1322,6 @@ test "zig fmt: correctly space struct fields with doc comments" { ); } - test "zig fmt: doc comments on param decl" { try testCanonical( \\pub const Allocator = struct { @@ -1405,7 +1343,6 @@ test "zig fmt: doc comments on param decl" { ); } - test "zig fmt: aligned struct field" { try testCanonical( \\pub const S = struct { @@ -1421,7 +1358,6 @@ test "zig fmt: aligned struct field" { ); } - test "zig fmt: comment to disable/enable zig fmt first" { try testCanonical( \\// Test trailing comma syntax @@ -1431,7 +1367,6 @@ test "zig fmt: comment to disable/enable zig fmt first" { ); } - test "zig fmt: 'zig fmt: (off|on)' can be surrounded by arbitrary whitespace" { try testTransform( \\// Test trailing comma syntax @@ -1451,7 +1386,6 @@ test "zig fmt: 'zig fmt: (off|on)' can be surrounded by arbitrary whitespace" { ); } - test "zig fmt: comment to disable/enable zig fmt" { try testTransform( \\const a = b; @@ -1469,7 +1403,6 @@ test "zig fmt: comment to disable/enable zig fmt" { ); } - test "zig fmt: line comment following 'zig fmt: off'" { try testCanonical( \\// zig fmt: off @@ -1478,7 +1411,6 @@ test "zig fmt: line comment following 'zig fmt: off'" { ); } - test "zig fmt: doc comment following 'zig fmt: off'" { try testCanonical( \\// zig fmt: off @@ -1487,7 +1419,6 @@ test "zig fmt: doc comment following 'zig fmt: off'" { ); } - test "zig fmt: line and doc comment following 'zig fmt: off'" { try testCanonical( \\// zig fmt: off @@ -1497,7 +1428,6 @@ test "zig fmt: line and doc comment following 'zig fmt: off'" { ); } - test "zig fmt: doc and line comment following 'zig fmt: off'" { try testCanonical( \\// zig fmt: off @@ -1507,7 +1437,6 @@ test "zig fmt: doc and line comment following 'zig fmt: off'" { ); } - test "zig fmt: alternating 'zig fmt: off' and 'zig fmt: on'" { try testCanonical( \\// zig fmt: off @@ -1525,7 +1454,6 @@ test "zig fmt: alternating 'zig fmt: off' and 'zig fmt: on'" { ); } - test "zig fmt: line comment following 'zig fmt: on'" { try testCanonical( \\// zig fmt: off @@ -1537,7 +1465,6 @@ test "zig fmt: line comment following 'zig fmt: on'" { ); } - test "zig fmt: doc comment following 'zig fmt: on'" { try testCanonical( \\// zig fmt: off @@ -1549,7 +1476,6 @@ test "zig fmt: doc comment following 'zig fmt: on'" { ); } - test "zig fmt: line and doc comment following 'zig fmt: on'" { try testCanonical( \\// zig fmt: off @@ -1562,7 +1488,6 @@ test "zig fmt: line and doc comment following 'zig fmt: on'" { ); } - test "zig fmt: doc and line comment following 'zig fmt: on'" { try testCanonical( \\// zig fmt: off @@ -1575,7 +1500,6 @@ test "zig fmt: doc and line comment following 'zig fmt: on'" { ); } - test "zig fmt: 'zig fmt: (off|on)' works in the middle of code" { try testTransform( \\test "" { @@ -1602,7 +1526,6 @@ test "zig fmt: 'zig fmt: (off|on)' works in the middle of code" { ); } - test "zig fmt: 'zig fmt: on' indentation is unchanged" { try testCanonical( \\fn initOptionsAndLayouts(output: *Output, context: *Context) !void { @@ -1624,7 +1547,6 @@ test "zig fmt: 'zig fmt: on' indentation is unchanged" { ); } - test "zig fmt: pointer of unknown length" { try testCanonical( \\fn foo(ptr: [*]u8) void {} @@ -1632,7 +1554,6 @@ test "zig fmt: pointer of unknown length" { ); } - test "zig fmt: spaces around slice operator" { try testCanonical( \\var a = b[c..d]; @@ -1647,7 +1568,6 @@ test "zig fmt: spaces around slice operator" { ); } - test "zig fmt: 2nd arg multiline string" { try testCanonical( \\comptime { @@ -1676,7 +1596,6 @@ test "zig fmt: 2nd arg multiline string" { ); } - test "zig fmt: 2nd arg multiline string many args" { try testCanonical( \\comptime { @@ -1688,7 +1607,6 @@ test "zig fmt: 2nd arg multiline string many args" { ); } - test "zig fmt: final arg multiline string" { try testCanonical( \\comptime { @@ -1700,7 +1618,6 @@ test "zig fmt: final arg multiline string" { ); } - test "zig fmt: if condition wraps" { try testTransform( \\comptime { @@ -1782,7 +1699,6 @@ test "zig fmt: if condition wraps" { ); } - test "zig fmt: if condition has line break but must not wrap" { try testCanonical( \\comptime { @@ -1807,7 +1723,6 @@ test "zig fmt: if condition has line break but must not wrap" { ); } - test "zig fmt: if condition has line break but must not wrap (no fn call comma)" { try testCanonical( \\comptime { @@ -1829,7 +1744,6 @@ test "zig fmt: if condition has line break but must not wrap (no fn call comma)" ); } - test "zig fmt: function call with multiline argument" { try testCanonical( \\comptime { @@ -1842,7 +1756,6 @@ test "zig fmt: function call with multiline argument" { ); } - test "zig fmt: if-else with comment before else" { try testCanonical( \\comptime { @@ -1861,7 +1774,6 @@ test "zig fmt: if-else with comment before else" { ); } - test "zig fmt: if nested" { try testCanonical( \\pub fn foo() void { @@ -1885,7 +1797,6 @@ test "zig fmt: if nested" { ); } - test "zig fmt: respect line breaks in if-else" { try testCanonical( \\comptime { @@ -1905,7 +1816,6 @@ test "zig fmt: respect line breaks in if-else" { ); } - test "zig fmt: respect line breaks after infix operators" { try testCanonical( \\comptime { @@ -1923,7 +1833,6 @@ test "zig fmt: respect line breaks after infix operators" { ); } - test "zig fmt: fn decl with trailing comma" { try testTransform( \\fn foo(a: i32, b: i32,) void {} @@ -1936,7 +1845,6 @@ test "zig fmt: fn decl with trailing comma" { ); } - test "zig fmt: enum decl with no trailing comma" { try testTransform( \\const StrLitKind = enum {Normal, C}; @@ -1946,7 +1854,6 @@ test "zig fmt: enum decl with no trailing comma" { ); } - test "zig fmt: switch comment before prong" { try testCanonical( \\comptime { @@ -1959,7 +1866,6 @@ test "zig fmt: switch comment before prong" { ); } - test "zig fmt: switch comment after prong" { try testCanonical( \\comptime { @@ -1973,7 +1879,6 @@ test "zig fmt: switch comment after prong" { ); } - test "zig fmt: struct literal no trailing comma" { try testTransform( \\const a = foo{ .x = 1, .y = 2 }; @@ -1992,7 +1897,6 @@ test "zig fmt: struct literal no trailing comma" { ); } - test "zig fmt: struct literal containing a multiline expression" { try testTransform( \\const a = A{ .x = if (f1()) 10 else 20 }; @@ -2054,7 +1958,6 @@ test "zig fmt: struct literal containing a multiline expression" { ); } - test "zig fmt: array literal with hint" { try testTransform( \\const a = []u8{ @@ -2132,7 +2035,6 @@ test "zig fmt: array literal with hint" { ); } - test "zig fmt: array literal vertical column alignment" { try testTransform( \\const a = []u8{ @@ -2180,7 +2082,6 @@ test "zig fmt: array literal vertical column alignment" { ); } - test "zig fmt: multiline string with backslash at end of line" { try testCanonical( \\comptime { @@ -2192,7 +2093,6 @@ test "zig fmt: multiline string with backslash at end of line" { ); } - test "zig fmt: multiline string parameter in fn call with trailing comma" { try testCanonical( \\fn foo() void { @@ -2211,7 +2111,6 @@ test "zig fmt: multiline string parameter in fn call with trailing comma" { ); } - test "zig fmt: trailing comma on fn call" { try testCanonical( \\comptime { @@ -2225,7 +2124,6 @@ test "zig fmt: trailing comma on fn call" { ); } - test "zig fmt: multi line arguments without last comma" { try testTransform( \\pub fn foo( @@ -2245,7 +2143,6 @@ test "zig fmt: multi line arguments without last comma" { ); } - test "zig fmt: empty block with only comment" { try testCanonical( \\comptime { @@ -2257,7 +2154,6 @@ test "zig fmt: empty block with only comment" { ); } - test "zig fmt: trailing commas on struct decl" { try testTransform( \\const RoundParam = struct { @@ -2277,7 +2173,6 @@ test "zig fmt: trailing commas on struct decl" { ); } - test "zig fmt: extra newlines at the end" { try testTransform( \\const a = b; @@ -2290,7 +2185,6 @@ test "zig fmt: extra newlines at the end" { ); } - test "zig fmt: simple asm" { try testTransform( \\comptime { @@ -2328,7 +2222,6 @@ test "zig fmt: simple asm" { ); } - test "zig fmt: nested struct literal with one item" { try testCanonical( \\const a = foo{ @@ -2338,7 +2231,6 @@ test "zig fmt: nested struct literal with one item" { ); } - test "zig fmt: switch cases trailing comma" { try testTransform( \\test "switch cases trailing comma"{ @@ -2373,7 +2265,6 @@ test "zig fmt: switch cases trailing comma" { ); } - test "zig fmt: slice align" { try testCanonical( \\const A = struct { @@ -2383,7 +2274,6 @@ test "zig fmt: slice align" { ); } - test "zig fmt: add trailing comma to array literal" { try testTransform( \\comptime { @@ -2405,7 +2295,6 @@ test "zig fmt: add trailing comma to array literal" { ); } - test "zig fmt: first thing in file is line comment" { try testCanonical( \\// Introspection and determination of system libraries needed by zig. @@ -2417,7 +2306,6 @@ test "zig fmt: first thing in file is line comment" { ); } - test "zig fmt: line comment after doc comment" { try testCanonical( \\/// doc comment @@ -2427,7 +2315,6 @@ test "zig fmt: line comment after doc comment" { ); } - test "zig fmt: bit field alignment" { try testCanonical( \\test { @@ -2437,7 +2324,6 @@ test "zig fmt: bit field alignment" { ); } - test "zig fmt: nested switch" { try testCanonical( \\test { @@ -2452,7 +2338,6 @@ test "zig fmt: nested switch" { ); } - test "zig fmt: float literal with exponent" { try testCanonical( \\pub const f64_true_min = 4.94065645841246544177e-324; @@ -2461,7 +2346,6 @@ test "zig fmt: float literal with exponent" { ); } - test "zig fmt: if-else end of comptime" { try testCanonical( \\comptime { @@ -2475,7 +2359,6 @@ test "zig fmt: if-else end of comptime" { ); } - test "zig fmt: nested blocks" { try testCanonical( \\comptime { @@ -2491,7 +2374,6 @@ test "zig fmt: nested blocks" { ); } - test "zig fmt: block with same line comment after end brace" { try testCanonical( \\comptime { @@ -2503,7 +2385,6 @@ test "zig fmt: block with same line comment after end brace" { ); } - test "zig fmt: statements with comment between" { try testCanonical( \\comptime { @@ -2515,7 +2396,6 @@ test "zig fmt: statements with comment between" { ); } - test "zig fmt: statements with empty line between" { try testCanonical( \\comptime { @@ -2527,7 +2407,6 @@ test "zig fmt: statements with empty line between" { ); } - test "zig fmt: ptr deref operator and unwrap optional operator" { try testCanonical( \\const a = b.*; @@ -2536,7 +2415,6 @@ test "zig fmt: ptr deref operator and unwrap optional operator" { ); } - test "zig fmt: comment after if before another if" { try testCanonical( \\test "aoeu" { @@ -2559,7 +2437,6 @@ test "zig fmt: comment after if before another if" { ); } - test "zig fmt: line comment between if block and else keyword" { try testCanonical( \\test "aoeu" { @@ -2581,7 +2458,6 @@ test "zig fmt: line comment between if block and else keyword" { ); } - test "zig fmt: same line comments in expression" { try testCanonical( \\test "aoeu" { @@ -2593,7 +2469,6 @@ test "zig fmt: same line comments in expression" { ); } - test "zig fmt: add comma on last switch prong" { try testTransform( \\test "aoeu" { @@ -2623,7 +2498,6 @@ test "zig fmt: add comma on last switch prong" { ); } - test "zig fmt: same-line comment after a statement" { try testCanonical( \\test "" { @@ -2635,7 +2509,6 @@ test "zig fmt: same-line comment after a statement" { ); } - test "zig fmt: same-line comment after var decl in struct" { try testCanonical( \\pub const vfs_cap_data = extern struct { @@ -2645,7 +2518,6 @@ test "zig fmt: same-line comment after var decl in struct" { ); } - test "zig fmt: same-line comment after field decl" { try testCanonical( \\pub const dirent = extern struct { @@ -2659,7 +2531,6 @@ test "zig fmt: same-line comment after field decl" { ); } - test "zig fmt: same-line comment after switch prong" { try testCanonical( \\test "" { @@ -2672,7 +2543,6 @@ test "zig fmt: same-line comment after switch prong" { ); } - test "zig fmt: same-line comment after non-block if expression" { try testCanonical( \\comptime { @@ -2683,7 +2553,6 @@ test "zig fmt: same-line comment after non-block if expression" { ); } - test "zig fmt: same-line comment on comptime expression" { try testCanonical( \\test "" { @@ -2693,7 +2562,6 @@ test "zig fmt: same-line comment on comptime expression" { ); } - test "zig fmt: switch with empty body" { try testCanonical( \\test "" { @@ -2703,7 +2571,6 @@ test "zig fmt: switch with empty body" { ); } - test "zig fmt: line comments in struct initializer" { try testCanonical( \\fn foo() void { @@ -2726,7 +2593,6 @@ test "zig fmt: line comments in struct initializer" { ); } - test "zig fmt: first line comment in struct initializer" { try testCanonical( \\pub fn acquire(self: *Self) HeldLock { @@ -2740,7 +2606,6 @@ test "zig fmt: first line comment in struct initializer" { ); } - test "zig fmt: doc comments before struct field" { try testCanonical( \\pub const Allocator = struct { @@ -2752,7 +2617,6 @@ test "zig fmt: doc comments before struct field" { ); } - test "zig fmt: error set declaration" { try testCanonical( \\const E = error{ @@ -2785,7 +2649,6 @@ test "zig fmt: error set declaration" { ); } - test "zig fmt: union(enum(u32)) with assigned enum values" { try testCanonical( \\const MultipleChoice = union(enum(u32)) { @@ -2798,7 +2661,6 @@ test "zig fmt: union(enum(u32)) with assigned enum values" { ); } - test "zig fmt: resume from suspend block" { try testCanonical( \\fn foo() void { @@ -2810,7 +2672,6 @@ test "zig fmt: resume from suspend block" { ); } - test "zig fmt: comments before error set decl" { try testCanonical( \\const UnexpectedError = error{ @@ -2827,7 +2688,6 @@ test "zig fmt: comments before error set decl" { ); } - test "zig fmt: comments before switch prong" { try testCanonical( \\test "" { @@ -2845,7 +2705,6 @@ test "zig fmt: comments before switch prong" { ); } - test "zig fmt: comments before var decl in struct" { try testCanonical( \\pub const vfs_cap_data = extern struct { @@ -2871,7 +2730,6 @@ test "zig fmt: comments before var decl in struct" { ); } - test "zig fmt: array literal with 1 item on 1 line" { try testCanonical( \\var s = []const u64{0} ** 25; @@ -2879,7 +2737,6 @@ test "zig fmt: array literal with 1 item on 1 line" { ); } - test "zig fmt: comments before global variables" { try testCanonical( \\/// Foo copies keys and values before they go into the map, and @@ -2889,7 +2746,6 @@ test "zig fmt: comments before global variables" { ); } - test "zig fmt: comments in statements" { try testCanonical( \\test "std" { @@ -2905,7 +2761,6 @@ test "zig fmt: comments in statements" { ); } - test "zig fmt: comments before test decl" { try testCanonical( \\// top level normal comment @@ -2918,7 +2773,6 @@ test "zig fmt: comments before test decl" { ); } - test "zig fmt: preserve spacing" { try testCanonical( \\const std = @import("std"); @@ -2934,7 +2788,6 @@ test "zig fmt: preserve spacing" { ); } - test "zig fmt: return types" { try testCanonical( \\pub fn main() !void {} @@ -2944,7 +2797,6 @@ test "zig fmt: return types" { ); } - test "zig fmt: imports" { try testCanonical( \\const std = @import("std"); @@ -2953,7 +2805,6 @@ test "zig fmt: imports" { ); } - test "zig fmt: global declarations" { try testCanonical( \\const a = b; @@ -2976,7 +2827,6 @@ test "zig fmt: global declarations" { ); } - test "zig fmt: extern declaration" { try testCanonical( \\extern var foo: c_int; @@ -2984,7 +2834,6 @@ test "zig fmt: extern declaration" { ); } - test "zig fmt: alignment" { try testCanonical( \\var foo: c_int align(1); @@ -2992,7 +2841,6 @@ test "zig fmt: alignment" { ); } - test "zig fmt: C main" { try testCanonical( \\fn main(argc: c_int, argv: **u8) c_int { @@ -3002,7 +2850,6 @@ test "zig fmt: C main" { ); } - test "zig fmt: return" { try testCanonical( \\fn foo(argc: c_int, argv: **u8) c_int { @@ -3016,7 +2863,6 @@ test "zig fmt: return" { ); } - test "zig fmt: function attributes" { try testCanonical( \\export fn foo() void {} @@ -3031,7 +2877,6 @@ test "zig fmt: function attributes" { ); } - test "zig fmt: nested pointers with ** tokens" { try testCanonical( \\const x: *u32 = undefined; @@ -3045,7 +2890,6 @@ test "zig fmt: nested pointers with ** tokens" { ); } - test "zig fmt: pointer attributes" { try testCanonical( \\extern fn f1(s: *align(*u8) u8) c_int; @@ -3057,7 +2901,6 @@ test "zig fmt: pointer attributes" { ); } - test "zig fmt: slice attributes" { try testCanonical( \\extern fn f1(s: []align(*u8) u8) c_int; @@ -3069,7 +2912,6 @@ test "zig fmt: slice attributes" { ); } - test "zig fmt: test declaration" { try testCanonical( \\test "test name" { @@ -3080,7 +2922,6 @@ test "zig fmt: test declaration" { ); } - test "zig fmt: destructure" { try testCanonical( \\comptime { @@ -3100,7 +2941,6 @@ test "zig fmt: destructure" { ); } - test "zig fmt: infix operators" { try testCanonical( \\test { @@ -3128,12 +2968,31 @@ test "zig fmt: infix operators" { \\ _ = i!i; \\ _ = i ** i; \\ _ = i ++ i; + \\ _ = i orelse i; + \\ _ = i % i; + \\ _ = i / i; + \\ _ = i *% i; + \\ _ = i * i; + \\ _ = i -% i; + \\ _ = i - i; + \\ _ = i +% i; + \\ _ = i + i; + \\ _ = i << i; + \\ _ = i >> i; + \\ _ = i & i; + \\ _ = i ^ i; + \\ _ = i | i; + \\ _ = i >= i; + \\ _ = i <= i; + \\ _ = i > i; + \\ _ = i < i; + \\ _ = i and i; + \\ _ = i or i; \\} \\ ); } - test "zig fmt: precedence" { try testCanonical( \\test "precedence" { @@ -3166,7 +3025,6 @@ test "zig fmt: precedence" { ); } - test "zig fmt: prefix operators" { try testCanonical( \\test "prefix operators" { @@ -3176,7 +3034,6 @@ test "zig fmt: prefix operators" { ); } - test "zig fmt: call expression" { try testCanonical( \\test "test calls" { @@ -3189,7 +3046,6 @@ test "zig fmt: call expression" { ); } - test "zig fmt: anytype type" { try testCanonical( \\fn print(args: anytype) @This() {} @@ -3197,7 +3053,6 @@ test "zig fmt: anytype type" { ); } - test "zig fmt: functions" { try testCanonical( \\extern fn puts(s: *const u8) c_int; @@ -3222,7 +3077,6 @@ test "zig fmt: functions" { ); } - test "zig fmt: multiline string" { try testCanonical( \\test "" { @@ -3241,7 +3095,6 @@ test "zig fmt: multiline string" { ); } - test "zig fmt: multiline string with CRLF line endings" { try testTransform("" ++ "const s =\r\n" ++ @@ -3258,7 +3111,6 @@ test "zig fmt: multiline string with CRLF line endings" { ); } - test "zig fmt: values" { try testCanonical( \\test "values" { @@ -3278,7 +3130,6 @@ test "zig fmt: values" { ); } - test "zig fmt: indexing" { try testCanonical( \\test "test index" { @@ -3299,7 +3150,6 @@ test "zig fmt: indexing" { ); } - test "zig fmt: struct declaration" { try testCanonical( \\const S = struct { @@ -3338,7 +3188,6 @@ test "zig fmt: struct declaration" { ); } - test "zig fmt: enum declaration" { try testCanonical( \\const E = enum { @@ -3367,7 +3216,6 @@ test "zig fmt: enum declaration" { ); } - test "zig fmt: union declaration" { try testCanonical( \\const U = union { @@ -3408,7 +3256,6 @@ test "zig fmt: union declaration" { ); } - test "zig fmt: arrays" { try testCanonical( \\test "test array" { @@ -3427,7 +3274,6 @@ test "zig fmt: arrays" { ); } - test "zig fmt: container initializers" { try testCanonical( \\const a0 = []u8{}; @@ -3448,7 +3294,6 @@ test "zig fmt: container initializers" { ); } - test "zig fmt: catch" { try testCanonical( \\test "catch" { @@ -3464,7 +3309,6 @@ test "zig fmt: catch" { ); } - test "zig fmt: blocks" { try testCanonical( \\test "blocks" { @@ -3487,7 +3331,6 @@ test "zig fmt: blocks" { ); } - test "zig fmt: switch" { try testCanonical( \\test "switch" { @@ -3543,7 +3386,6 @@ test "zig fmt: switch" { ); } - test "zig fmt: switch multiline string" { try testCanonical( \\test "switch multiline string" { @@ -3575,7 +3417,6 @@ test "zig fmt: switch multiline string" { ); } - test "zig fmt: while" { try testCanonical( \\test "while" { @@ -3651,7 +3492,6 @@ test "zig fmt: while" { ); } - test "zig fmt: for" { try testCanonical( \\test "for" { @@ -3753,7 +3593,6 @@ test "zig fmt: for" { ); } - test "zig fmt: for if" { try testCanonical( \\test { @@ -3779,7 +3618,6 @@ test "zig fmt: for if" { ); } - test "zig fmt: if for" { try testCanonical( \\test { @@ -3805,7 +3643,6 @@ test "zig fmt: if for" { ); } - test "zig fmt: while if" { try testCanonical( \\test { @@ -3831,7 +3668,6 @@ test "zig fmt: while if" { ); } - test "zig fmt: if while" { try testCanonical( \\test { @@ -3857,7 +3693,6 @@ test "zig fmt: if while" { ); } - test "zig fmt: while for" { try testCanonical( \\test { @@ -3883,7 +3718,6 @@ test "zig fmt: while for" { ); } - test "zig fmt: for while" { try testCanonical( \\test { @@ -3909,7 +3743,6 @@ test "zig fmt: for while" { ); } - test "zig fmt: if" { try testCanonical( \\test "if" { @@ -3959,7 +3792,6 @@ test "zig fmt: if" { ); } - test "zig fmt: fix single statement if/for/while line breaks" { try testTransform( \\test { @@ -4012,6 +3844,29 @@ test "zig fmt: fix single statement if/for/while line breaks" { ); } +test "zig fmt: anon struct/array literal in if" { + try testCanonical( + \\test { + \\ const a = if (cond) .{ + \\ 1, 2, + \\ 3, 4, + \\ } else .{ + \\ 1, + \\ 2, + \\ 3, + \\ }; + \\ + \\ const rl_and_tag: struct { rl: ResultLoc, tag: zir.Inst.Tag } = if (any_payload_is_ref) .{ + \\ .rl = .ref, + \\ .tag = .switchbr_ref, + \\ } else .{ + \\ .rl = .none, + \\ .tag = .switchbr, + \\ }; + \\} + \\ + ); +} test "zig fmt: defer" { try testCanonical( @@ -4033,7 +3888,6 @@ test "zig fmt: defer" { ); } - test "zig fmt: comptime" { try testCanonical( \\fn a() u8 { @@ -4073,7 +3927,6 @@ test "zig fmt: comptime" { ); } - test "zig fmt: fn type" { try testCanonical( \\fn a(i: u8) u8 { @@ -4087,7 +3940,6 @@ test "zig fmt: fn type" { ); } - test "zig fmt: inline asm" { try testTransform( \\pub fn syscall1(number: usize, arg1: usize) usize { @@ -4112,7 +3964,6 @@ test "zig fmt: inline asm" { ); } - test "zig fmt: nosuspend" { try testCanonical( \\const a = nosuspend foo(); @@ -4120,7 +3971,6 @@ test "zig fmt: nosuspend" { ); } - test "zig fmt: Block after if" { try testCanonical( \\test { @@ -4136,7 +3986,6 @@ test "zig fmt: Block after if" { ); } - test "zig fmt: string identifier" { try testCanonical( \\const @"a b" = @"c d".@"e f"; @@ -4145,7 +3994,6 @@ test "zig fmt: string identifier" { ); } - test "zig fmt: error return" { try testCanonical( \\fn err() anyerror { @@ -4156,7 +4004,6 @@ test "zig fmt: error return" { ); } - test "zig fmt: comptime block in container" { try testCanonical( \\pub fn container() type { @@ -4172,7 +4019,6 @@ test "zig fmt: comptime block in container" { ); } - test "zig fmt: inline asm parameter alignment" { try testCanonical( \\pub fn main() void { @@ -4210,7 +4056,6 @@ test "zig fmt: inline asm parameter alignment" { ); } - test "zig fmt: multiline string in array" { try testCanonical( \\const Foo = [][]const u8{ @@ -4236,7 +4081,17 @@ test "zig fmt: multiline string in array" { ); } - +test "zig fmt: if type expr" { + try testCanonical( + \\const mycond = true; + \\pub fn foo() if (mycond) i32 else void { + \\ if (mycond) { + \\ return 42; + \\ } + \\} + \\ + ); +} test "zig fmt: file ends with struct field" { try testCanonical( \\a: bool @@ -4244,7 +4099,6 @@ test "zig fmt: file ends with struct field" { ); } - test "zig fmt: comment after empty comment" { try testCanonical( \\const x = true; // @@ -4255,7 +4109,6 @@ test "zig fmt: comment after empty comment" { ); } - test "zig fmt: line comment in array" { try testTransform( \\test "a" { @@ -4288,7 +4141,6 @@ test "zig fmt: line comment in array" { ); } - test "zig fmt: comment after params" { try testTransform( \\fn a( @@ -4315,7 +4167,6 @@ test "zig fmt: comment after params" { ); } - test "zig fmt: comment in array initializer/access" { try testCanonical( \\test "a" { @@ -4352,7 +4203,6 @@ test "zig fmt: comment in array initializer/access" { ); } - test "zig fmt: comments at several places in struct init" { try testTransform( \\var bar = Bar{ @@ -4380,7 +4230,6 @@ test "zig fmt: comments at several places in struct init" { ); } - test "zig fmt: container doc comments" { try testCanonical( \\//! tld 1 @@ -4437,7 +4286,6 @@ test "zig fmt: container doc comments" { ); } - test "zig fmt: remove newlines surrounding doc comment" { try testTransform( \\ @@ -4454,7 +4302,6 @@ test "zig fmt: remove newlines surrounding doc comment" { ); } - test "zig fmt: remove newlines surrounding doc comment between members" { try testTransform( \\f1: i32, @@ -4473,7 +4320,6 @@ test "zig fmt: remove newlines surrounding doc comment between members" { ); } - test "zig fmt: remove newlines surrounding doc comment between members within container decl (1)" { try testTransform( \\const Foo = struct { @@ -4497,7 +4343,6 @@ test "zig fmt: remove newlines surrounding doc comment between members within co ); } - test "zig fmt: remove newlines surrounding doc comment between members within container decl (2)" { try testTransform( \\const Foo = struct { @@ -4520,7 +4365,6 @@ test "zig fmt: remove newlines surrounding doc comment between members within co ); } - test "zig fmt: remove newlines surrounding doc comment within container decl" { try testTransform( \\const Foo = struct { @@ -4540,6 +4384,29 @@ test "zig fmt: remove newlines surrounding doc comment within container decl" { ); } +test "zig fmt: comptime before comptime field" { + try testError( + \\const Foo = struct { + \\ a: i32, + \\ comptime comptime b: i32 = 1234, + \\}; + \\ + , &[_]Error{ + .expected_comma_after_field, + }); +} + +test "zig fmt: invalid doc comments on comptime and test blocks" { + try testError( + \\/// This is a doc comment for a comptime block. + \\comptime {} + \\/// This is a doc comment for a test + \\test "This is my test" {} + , &[_]Error{ + .comptime_doc_comment, + .test_doc_comment, + }); +} test "zig fmt: comments with CRLF line endings" { try testTransform("" ++ @@ -4563,7 +4430,6 @@ test "zig fmt: comments with CRLF line endings" { ); } - test "zig fmt: else comptime expr" { try testCanonical( \\comptime { @@ -4579,6 +4445,73 @@ test "zig fmt: else comptime expr" { ); } +test "zig fmt: invalid else branch statement" { + try testError( + \\comptime { + \\ if (true) {} else var a = 0; + \\ if (true) {} else defer {} + \\} + \\comptime { + \\ while (true) {} else var a = 0; + \\ while (true) {} else defer {} + \\} + \\comptime { + \\ for ("") |_| {} else var a = 0; + \\ for ("") |_| {} else defer {} + \\} + , &[_]Error{ + .expected_expr_or_assignment, + .expected_expr_or_assignment, + .expected_expr_or_assignment, + .expected_expr_or_assignment, + .expected_expr_or_assignment, + .expected_expr_or_assignment, + }); +} + +test "zig fmt: anytype struct field" { + try testError( + \\pub const Pointer = struct { + \\ sentinel: anytype, + \\}; + \\ + , &[_]Error{ + .expected_type_expr, + }); +} + +test "zig fmt: extern without container keyword returns error" { + try testError( + \\const container = extern {}; + \\ + , &[_]Error{ + .expected_container, + }); +} + +test "zig fmt: same line doc comment returns error" { + try testError( + \\const Foo = struct{ + \\ bar: u32, /// comment + \\ foo: u32, /// comment + \\ /// comment + \\}; + \\ + \\const a = 42; /// comment + \\ + \\extern fn foo() void; /// comment + \\ + \\/// comment + \\ + , &[_]Error{ + .same_line_doc_comment, + .same_line_doc_comment, + .unattached_doc_comment, + .same_line_doc_comment, + .same_line_doc_comment, + .unattached_doc_comment, + }); +} test "zig fmt: integer literals with underscore separators" { try testTransform( @@ -4593,7 +4526,6 @@ test "zig fmt: integer literals with underscore separators" { ); } - test "zig fmt: hex literals with underscore separators" { try testTransform( \\pub fn orMask(a: [ 1_000 ]u64, b: [ 1_000] u64) [1_000]u64 { @@ -4617,7 +4549,6 @@ test "zig fmt: hex literals with underscore separators" { ); } - test "zig fmt: decimal float literals with underscore separators" { try testTransform( \\pub fn main() void { @@ -4635,7 +4566,6 @@ test "zig fmt: decimal float literals with underscore separators" { ); } - test "zig fmt: hexadecimal float literals with underscore separators" { try testTransform( \\pub fn main() void { @@ -4653,7 +4583,6 @@ test "zig fmt: hexadecimal float literals with underscore separators" { ); } - test "zig fmt: C var args" { try testCanonical( \\pub extern "c" fn printf(format: [*:0]const u8, ...) c_int; @@ -4661,7 +4590,6 @@ test "zig fmt: C var args" { ); } - test "zig fmt: Only indent multiline string literals in function calls" { try testCanonical( \\test "zig fmt:" { @@ -4679,7 +4607,6 @@ test "zig fmt: Only indent multiline string literals in function calls" { ); } - test "zig fmt: Don't add extra newline after if" { try testCanonical( \\pub fn atomicSymLink(allocator: Allocator, existing_path: []const u8, new_path: []const u8) !void { @@ -4691,7 +4618,6 @@ test "zig fmt: Don't add extra newline after if" { ); } - test "zig fmt: comments in ternary ifs" { try testCanonical( \\const x = if (true) { @@ -4711,7 +4637,6 @@ test "zig fmt: comments in ternary ifs" { ); } - test "zig fmt: while statement in blockless if" { try testCanonical( \\pub fn main() void { @@ -4726,7 +4651,6 @@ test "zig fmt: while statement in blockless if" { ); } - test "zig fmt: test comments in field access chain" { try testCanonical( \\pub const str = struct { @@ -4762,7 +4686,6 @@ test "zig fmt: test comments in field access chain" { ); } - test "zig fmt: allow line break before field access" { try testCanonical( \\test { @@ -4811,7 +4734,6 @@ test "zig fmt: allow line break before field access" { ); } - test "zig fmt: Indent comma correctly after multiline string literals in arg list (trailing comma)" { try testCanonical( \\fn foo() void { @@ -4837,6 +4759,40 @@ test "zig fmt: Indent comma correctly after multiline string literals in arg lis ); } +test "zig fmt: Control flow statement as body of blockless if" { + try testCanonical( + \\pub fn main() void { + \\ const zoom_node = if (focused_node == layout_first) + \\ if (it.next()) { + \\ if (!node.view.pending.float and !node.view.pending.fullscreen) break node; + \\ } else null + \\ else + \\ focused_node; + \\ + \\ const zoom_node = if (focused_node == layout_first) while (it.next()) |node| { + \\ if (!node.view.pending.float and !node.view.pending.fullscreen) break node; + \\ } else null else focused_node; + \\ + \\ const zoom_node = if (focused_node == layout_first) + \\ if (it.next()) { + \\ if (!node.view.pending.float and !node.view.pending.fullscreen) break node; + \\ } else null; + \\ + \\ const zoom_node = if (focused_node == layout_first) while (it.next()) |node| { + \\ if (!node.view.pending.float and !node.view.pending.fullscreen) break node; + \\ }; + \\ + \\ const zoom_node = if (focused_node == layout_first) for (nodes) |node| { + \\ break node; + \\ }; + \\ + \\ const zoom_node = if (focused_node == layout_first) switch (nodes) { + \\ 0 => 0, + \\ } else focused_node; + \\} + \\ + ); +} test "zig fmt: regression test for #5722" { try testCanonical( @@ -4853,7 +4809,6 @@ test "zig fmt: regression test for #5722" { ); } - test "zig fmt: regression test for #8974" { try testCanonical( \\pub const VARIABLE; @@ -4861,7 +4816,6 @@ test "zig fmt: regression test for #8974" { ); } - test "zig fmt: allow trailing line comments to do manual array formatting" { try testCanonical( \\fn foo() void { @@ -4900,7 +4854,6 @@ test "zig fmt: allow trailing line comments to do manual array formatting" { ); } - test "zig fmt: multiline string literals should play nice with array initializers" { try testCanonical( \\fn main() void { @@ -4967,7 +4920,6 @@ test "zig fmt: multiline string literals should play nice with array initializer ); } - test "zig fmt: use of comments and multiline string literals may force the parameters over multiple lines" { try testCanonical( \\pub fn makeMemUndefined(qzz: []u8) i1 { @@ -5008,7 +4960,6 @@ test "zig fmt: use of comments and multiline string literals may force the param ); } - test "zig fmt: single argument trailing commas in @builtins()" { try testCanonical( \\pub fn foo(qzz: []u8) i1 { @@ -5027,7 +4978,6 @@ test "zig fmt: single argument trailing commas in @builtins()" { ); } - test "zig fmt: trailing comma should force multiline 1 column" { try testTransform( \\pub const UUID_NULL: uuid_t = [16]u8{0,0,0,0,}; @@ -5043,7 +4993,6 @@ test "zig fmt: trailing comma should force multiline 1 column" { ); } - test "zig fmt: function params should align nicely" { try testCanonical( \\pub fn foo() void { @@ -5060,7 +5009,6 @@ test "zig fmt: function params should align nicely" { ); } - test "zig fmt: fn proto end with anytype and comma" { try testCanonical( \\pub fn format( @@ -5070,7 +5018,6 @@ test "zig fmt: fn proto end with anytype and comma" { ); } - test "zig fmt: space after top level doc comment" { try testCanonical( \\//! top level doc comment @@ -5080,7 +5027,6 @@ test "zig fmt: space after top level doc comment" { ); } - test "zig fmt: remove trailing whitespace after container doc comment" { try testTransform( \\//! top level doc comment @@ -5091,7 +5037,6 @@ test "zig fmt: remove trailing whitespace after container doc comment" { ); } - test "zig fmt: remove trailing whitespace after doc comment" { try testTransform( \\/// doc comment @@ -5104,7 +5049,6 @@ test "zig fmt: remove trailing whitespace after doc comment" { ); } - test "zig fmt: for loop with ptr payload and index" { try testCanonical( \\test { @@ -5117,7 +5061,6 @@ test "zig fmt: for loop with ptr payload and index" { ); } - test "zig fmt: proper indent line comment after multi-line single expr while loop" { try testCanonical( \\test { @@ -5131,6 +5074,16 @@ test "zig fmt: proper indent line comment after multi-line single expr while loo ); } +test "zig fmt: function with labeled block as return type" { + try testCanonical( + \\fn foo() t: { + \\ break :t bar; + \\} { + \\ baz(); + \\} + \\ + ); +} test "zig fmt: extern function with missing param name" { try testCanonical( @@ -5143,6 +5096,37 @@ test "zig fmt: extern function with missing param name" { ); } +test "zig fmt: line comment after multiline single expr if statement with multiline string" { + try testCanonical( + \\test { + \\ if (foo) + \\ x = + \\ \\hello + \\ \\hello + \\ \\ + \\ ; + \\ + \\ // bar + \\ baz(); + \\ + \\ if (foo) + \\ x = + \\ \\hello + \\ \\hello + \\ \\ + \\ else + \\ y = + \\ \\hello + \\ \\hello + \\ \\ + \\ ; + \\ + \\ // bar + \\ baz(); + \\} + \\ + ); +} test "zig fmt: respect extra newline between switch items" { try testCanonical( @@ -5157,7 +5141,6 @@ test "zig fmt: respect extra newline between switch items" { ); } - test "zig fmt: assignment with inline for and inline while" { try testCanonical( \\const tmp = inline for (items) |item| {}; @@ -5170,7 +5153,6 @@ test "zig fmt: assignment with inline for and inline while" { ); } - test "zig fmt: saturating arithmetic" { try testCanonical( \\test { @@ -5191,7 +5173,6 @@ test "zig fmt: saturating arithmetic" { ); } - test "zig fmt: insert trailing comma if there are comments between switch values" { try testTransform( \\const a = switch (b) { @@ -5223,7 +5204,6 @@ test "zig fmt: insert trailing comma if there are comments between switch values ); } - test "zig fmt: insert trailing comma if comments in array init" { try testTransform( \\var a = .{ @@ -5261,7 +5241,6 @@ test "zig fmt: insert trailing comma if comments in array init" { ); } - test "zig fmt: make single-line if no trailing comma" { try testTransform( \\test "function call no trailing comma" { @@ -5309,7 +5288,6 @@ test "zig fmt: make single-line if no trailing comma" { ); } - test "zig fmt: preserve container doc comment in container without trailing comma" { try testTransform( \\const A = enum(u32) { @@ -5325,6 +5303,141 @@ test "zig fmt: preserve container doc comment in container without trailing comm ); } +test "zig fmt: make single-line if no trailing comma, fmt: off" { + try testCanonical( + \\// Test trailing comma syntax + \\// zig fmt: off + \\ + \\extern var a: c_int; + \\extern "c" var b: c_int; + \\export var c: c_int = 0; + \\threadlocal var d: c_int = 0; + \\extern threadlocal var e: c_int; + \\extern "c" threadlocal var f: c_int; + \\export threadlocal var g: c_int = 0; + \\ + \\const struct_trailing_comma = struct { x: i32, y: i32, }; + \\const struct_no_comma = struct { x: i32, y: i32 }; + \\const struct_fn_no_comma = struct { fn m() void {} y: i32 }; + \\ + \\const enum_no_comma = enum { A, B }; + \\ + \\fn container_init() void { + \\ const S = struct { x: i32, y: i32 }; + \\ _ = S { .x = 1, .y = 2 }; + \\ _ = S { .x = 1, .y = 2, }; + \\} + \\ + \\fn type_expr_return1() if (true) A {} + \\fn type_expr_return2() for (true) |_| A {} + \\fn type_expr_return3() while (true) A {} + \\ + \\fn switch_cases(x: i32) void { + \\ switch (x) { + \\ 1,2,3 => {}, + \\ 4,5, => {}, + \\ 6...8, => {}, + \\ else => {}, + \\ } + \\} + \\ + \\fn switch_prongs(x: i32) void { + \\ switch (x) { + \\ 0 => {}, + \\ else => {}, + \\ } + \\ switch (x) { + \\ 0 => {}, + \\ else => {} + \\ } + \\} + \\ + \\const fn_no_comma = fn (i32, i32) void; + \\const fn_trailing_comma = fn (i32, i32,) void; + \\ + \\fn fn_calls() void { + \\ fn add(x: i32, y: i32,) i32 { x + y }; + \\ _ = add(1, 2); + \\ _ = add(1, 2,); + \\} + \\ + \\fn asm_lists() void { + \\ if (false) { // Build AST but don't analyze + \\ asm ("not real assembly" + \\ :[a] "x" (x),); + \\ asm ("not real assembly" + \\ :[a] "x" (->i32),:[a] "x" (1),); + \\ asm volatile ("still not real assembly" + \\ :::.{.a = true,.b = true,}); + \\ } + \\} + ); +} + +test "zig fmt: variable initialized with ==" { + try testError( + \\comptime { + \\ var z: u32 == 12 + 1; + \\} + , &.{.wrong_equal_var_decl}); +} + +test "zig fmt: missing const/var before local variable in comptime block" { + try testError( + \\comptime { + \\ z: u32; + \\} + \\comptime { + \\ z: u32 align(1); + \\} + \\comptime { + \\ z: u32 addrspace(.generic); + \\} + \\comptime { + \\ z: u32 linksection("foo"); + \\} + \\comptime { + \\ z: u32 = 1; + \\} + , &.{ + .expected_labelable, + .expected_var_const, + .expected_var_const, + .expected_var_const, + .expected_var_const, + }); +} + +test "zig fmt: missing const/var before local variable" { + try testError( + \\std = foo, + \\std = foo; + \\*u32 = foo; + , &.{ + .expected_comma_after_field, + .var_const_decl, + .expected_comma_after_field, + }); +} + +test "zig fmt: while continue expr" { + try testCanonical( + \\test { + \\ while (i > 0) + \\ (i * 2); + \\} + \\ + ); + try testError( + \\test { + \\ while (i > 0) (i -= 1) { + \\ print("test123", .{}); + \\ } + \\} + , &[_]Error{ + .expected_continue_expr, + }); +} test "zig fmt: canonicalize symbols (simple)" { try testTransform( @@ -5474,8 +5587,114 @@ test "zig fmt: canonicalize symbols (simple)" { ); } - - +// Contextually unescape when shadowing primitive types and values. +test "zig fmt: canonicalize symbols (primitive types)" { + try testTransform( + \\const @"anyopaque" = struct { + \\ @"u8": @"type" = true, + \\ @"_": @"false" = @"true", + \\ const @"type" = bool; + \\ const @"false" = bool; + \\ const @"true" = false; + \\}; + \\ + \\const U = union(@"null") { + \\ @"type", + \\ const @"null" = enum { + \\ @"type", + \\ }; + \\}; + \\ + \\test { + \\ const E = enum { @"anyopaque" }; + \\ _ = U{ .@"type" = {} }; + \\ _ = U.@"type"; + \\ _ = E.@"anyopaque"; + \\} + \\ + \\fn @"i10"(@"void": @"anyopaque", @"type": @"anyopaque".@"type") error{@"null"}!void { + \\ var @"f32" = @"void"; + \\ @"f32".@"u8" = false; + \\ _ = @"type"; + \\ _ = type; + \\ if (@"f32".@"u8") { + \\ return @"i10"(.{ .@"u8" = true, .@"_" = false }, false); + \\ } else { + \\ return error.@"null"; + \\ } + \\} + \\ + \\test @"i10" { + \\ try @"i10"(.{}, true); + \\ _ = @"void": while (null) |@"u3"| { + \\ break :@"void" @"u3"; + \\ }; + \\ _ = @"void": { + \\ break :@"void"; + \\ }; + \\ for ("hi", 0..) |@"u3", @"i4"| { + \\ _ = @"u3"; + \\ _ = @"i4"; + \\ } + \\ if (false) {} else |@"bool"| { + \\ _ = @"bool"; + \\ } + \\} + \\ + , + \\const @"anyopaque" = struct { + \\ u8: @"type" = true, + \\ _: @"false" = @"true", + \\ const @"type" = bool; + \\ const @"false" = bool; + \\ const @"true" = false; + \\}; + \\ + \\const U = union(@"null") { + \\ type, + \\ const @"null" = enum { + \\ type, + \\ }; + \\}; + \\ + \\test { + \\ const E = enum { anyopaque }; + \\ _ = U{ .type = {} }; + \\ _ = U.type; + \\ _ = E.anyopaque; + \\} + \\ + \\fn @"i10"(@"void": @"anyopaque", @"type": @"anyopaque".type) error{null}!void { + \\ var @"f32" = @"void"; + \\ @"f32".u8 = false; + \\ _ = @"type"; + \\ _ = type; + \\ if (@"f32".u8) { + \\ return @"i10"(.{ .u8 = true, ._ = false }, false); + \\ } else { + \\ return error.null; + \\ } + \\} + \\ + \\test @"i10" { + \\ try @"i10"(.{}, true); + \\ _ = void: while (null) |@"u3"| { + \\ break :void @"u3"; + \\ }; + \\ _ = void: { + \\ break :void; + \\ }; + \\ for ("hi", 0..) |@"u3", @"i4"| { + \\ _ = @"u3"; + \\ _ = @"i4"; + \\ } + \\ if (false) {} else |@"bool"| { + \\ _ = @"bool"; + \\ } + \\} + \\ + ); +} test "zig fmt: no space before newline before multiline string" { try testCanonical( @@ -5506,7 +5725,7 @@ test "zig fmt: no space before newline before multiline string" { ); } - +// Normalize \xNN and \u{NN} escapes and unicode inside @"" escapes. test "zig fmt: canonicalize symbols (character escapes)" { try testTransform( \\const @"\x46\x6f\x6f\x64" = struct { @@ -5549,8 +5768,6 @@ test "zig fmt: canonicalize symbols (character escapes)" { ); } - - test "zig fmt: canonicalize symbols (asm)" { try testTransform( \\test "asm" { @@ -5599,8 +5816,6 @@ test "zig fmt: canonicalize symbols (asm)" { ); } - - test "zig fmt: don't canonicalize _ in enums" { try testTransform( \\const A = enum { @@ -5657,6 +5872,35 @@ test "zig fmt: don't canonicalize _ in enums" { ); } +test "zig fmt: error for missing sentinel value in sentinel slice" { + try testError( + \\const foo = foo[0..:]; + , &[_]Error{ + .expected_expr, + }); +} + +test "zig fmt: error for invalid bit range" { + try testError( + \\var x: []align(0:0:0)u8 = bar; + , &[_]Error{ + .invalid_bit_range, + }); +} + +test "zig fmt: error for ptr mod on array child type" { + try testError( + \\var a: [10]align(10) u8 = e; + \\var b: [10]const u8 = f; + \\var c: [10]volatile u8 = g; + \\var d: [10]allowzero u8 = h; + , &[_]Error{ + .ptr_mod_on_array_child_type, + .ptr_mod_on_array_child_type, + .ptr_mod_on_array_child_type, + .ptr_mod_on_array_child_type, + }); +} test "zig fmt: pointer type syntax to index" { try testCanonical( @@ -5667,7 +5911,6 @@ test "zig fmt: pointer type syntax to index" { ); } - test "zig fmt: binop indentation in if statement" { try testCanonical( \\test { @@ -5684,6 +5927,79 @@ test "zig fmt: binop indentation in if statement" { ); } +test "zig fmt: test indentation after equals sign" { + try testCanonical( + \\test { + \\ const foo = + \\ if (1 == 2) + \\ 1 + \\ else if (3 > 4) + \\ 2 + \\ else + \\ 0; + \\ + \\ const foo, const bar = + \\ if (1 == 2) + \\ .{ 0, 0 } + \\ else if (3 > 4) + \\ .{ 1, 1 } + \\ else + \\ .{ 2, 2 }; + \\ + \\ while (foo) if (bar) + \\ f(x); + \\ + \\ foobar = + \\ if (true) + \\ 1 + \\ else + \\ 0; + \\ + \\ const foo = if (1 == 2) + \\ 1 + \\ else if (3 > 4) + \\ 2 + \\ else + \\ 0; + \\ + \\ const foo, const bar = if (1 == 2) + \\ .{ 0, 0 } + \\ else if (3 > 4) + \\ .{ 1, 1 } + \\ else + \\ .{ 2, 2 }; + \\ + \\ foobar = if (true) + \\ 1 + \\ else + \\ 0; + \\ + \\ const is_alphanum = + \\ (ch >= 'a' and ch <= 'z') or + \\ (ch >= 'A' and ch <= 'Z') or + \\ (ch >= '0' and ch <= '9'); + \\ + \\ const bar = 100 + calculate( + \\ 200, + \\ 300, + \\ ); + \\ + \\ const gcc_pragma = std.meta.stringToEnum(Directive, pp.expandedSlice(directive_tok)) orelse + \\ return pp.comp.addDiagnostic(.{ + \\ .tag = .unknown_gcc_pragma, + \\ .loc = directive_tok.loc, + \\ }, pp.expansionSlice(start_idx + 1)); + \\ + \\ const vec4s = + \\ [_][4]i32{ + \\ [_]i32{ 0, 1, 0, 0 }, + \\ [_]i32{ 0, -1, 0, 0 }, + \\ [_]i32{ 2, 1, 2, 0 }, + \\ }; + \\} + \\ + ); +} test "zig fmt: test indentation of if expressions" { try testCanonical( @@ -5721,6 +6037,24 @@ test "zig fmt: test indentation of if expressions" { ); } +test "zig fmt: indentation of comments within catch, else, orelse" { + try testCanonical( + \\comptime { + \\ _ = foo() catch + \\ // + \\ bar(); + \\ + \\ _ = if (foo) bar() else + \\ // + \\ qux(); + \\ + \\ _ = foo() orelse + \\ // + \\ qux(); + \\} + \\ + ); +} test "zig fmt: canonicalize cast builtins" { try testTransform( @@ -5734,8 +6068,6 @@ test "zig fmt: canonicalize cast builtins" { ); } - - test "zig fmt: do not canonicalize invalid cast builtins" { try testCanonical( \\const foo = @alignCast(@volatileCast(@ptrCast(@alignCast(bar)))); @@ -5743,38 +6075,322 @@ test "zig fmt: do not canonicalize invalid cast builtins" { ); } +test "recovery: top level" { + try testError( + \\test "" {inline} + \\test "" {inline} + , &[_]Error{ + .expected_inlinable, + .expected_inlinable, + }); +} -test "Ast header smoke test" { - try std.testing.expectEqual(zigNode(c.AST_NODE_IF), Ast.Node.Tag.@"if"); +test "recovery: block statements" { + try testError( + \\test "" { + \\ foo + +; + \\ inline; + \\} + , &[_]Error{ + .expected_expr, + .expected_semi_after_stmt, + .expected_statement, + .expected_inlinable, + }); +} + +test "recovery: missing comma" { + try testError( + \\test "" { + \\ switch (foo) { + \\ 2 => {} + \\ 3 => {} + \\ else => { + \\ foo & bar +; + \\ } + \\ } + \\} + , &[_]Error{ + .expected_comma_after_switch_prong, + .expected_comma_after_switch_prong, + .expected_expr, + }); +} + +test "recovery: non-associative operators" { + try testError( + \\const x = a == b == c; + \\const x = a == b != c; + , &[_]Error{ + .chained_comparison_operators, + .chained_comparison_operators, + }); +} + +test "recovery: extra qualifier" { + try testError( + \\const a: *const const u8; + \\test "" + , &[_]Error{ + .extra_const_qualifier, + .expected_block, + }); +} + +test "recovery: missing return type" { + try testError( + \\fn foo() { + \\ a & b; + \\} + \\test "" + , &[_]Error{ + .expected_return_type, + .expected_block, + }); +} + +test "recovery: invalid extern/inline" { + try testError( + \\inline test "" { a & b; } + , &[_]Error{ + .expected_fn, + }); + try testError( + \\extern "" test "" { a & b; } + , &[_]Error{ + .expected_var_decl_or_fn, + }); +} + +test "recovery: missing semicolon" { + try testError( + \\test "" { + \\ comptime a & b + \\ c & d + \\ @foo + \\} + , &[_]Error{ + .expected_semi_after_stmt, + .expected_semi_after_stmt, + .expected_param_list, + .expected_semi_after_stmt, + }); +} + +// TODO after https://github.com/ziglang/zig/issues/35 is implemented, +// we should be able to recover from this *at any indentation level*, +// reporting a parse error and yet also parsing all the decls even +// inside structs. +test "recovery: extra '}' at top level" { + try testError( + \\}}} + \\test "" { + \\ a & b; + \\} + , &[_]Error{ + .expected_token, + }); +} + +test "recovery: mismatched bracket at top level" { + try testError( + \\const S = struct { + \\ arr: 128]?G + \\}; + , &[_]Error{ + .expected_comma_after_field, + }); +} + +test "recovery: invalid global error set access" { + try testError( + \\test "" { + \\ error & foo; + \\} + , &[_]Error{ + .expected_token, + }); +} + +test "recovery: invalid asterisk after pointer dereference" { + try testError( + \\test "" { + \\ var sequence = "repeat".*** 10; + \\} + , &[_]Error{ + .asterisk_after_ptr_deref, + .mismatched_binary_op_whitespace, + }); + try testError( + \\test "" { + \\ var sequence = "repeat".** 10&a; + \\} + , &[_]Error{ + .asterisk_after_ptr_deref, + .mismatched_binary_op_whitespace, + }); +} + +test "recovery: missing semicolon after if, for, while stmt" { + try testError( + \\test "" { + \\ if (foo) bar + \\ for (foo) |a| bar + \\ while (foo) bar + \\ a & b; + \\} + , &[_]Error{ + .expected_semi_or_else, + .expected_semi_or_else, + .expected_semi_or_else, + }); +} + +test "recovery: invalid comptime" { + try testError( + \\comptime + , &[_]Error{ + .expected_type_expr, + }); +} + +test "recovery: missing block after suspend" { + try testError( + \\fn foo() void { + \\ suspend; + \\ nosuspend; + \\} + , &[_]Error{ + .expected_block_or_expr, + .expected_block_or_expr, + }); +} + +test "recovery: missing block after for/while loops" { + try testError( + \\test "" { while (foo) } + , &[_]Error{ + .expected_block_or_assignment, + }); + try testError( + \\test "" { for (foo) |bar| } + , &[_]Error{ + .expected_block_or_assignment, + }); +} + +test "recovery: missing for payload" { + try testError( + \\comptime { + \\ const a = for(a) {}; + \\ const a: for(a) blk: {} = {}; + \\ for(a) {} + \\} + , &[_]Error{ + .expected_loop_payload, + .expected_loop_payload, + .expected_loop_payload, + }); +} + +test "recovery: missing comma in params" { + try testError( + \\fn foo(comptime bool what what) void { } + \\fn bar(a: i32, b: i32 c) void { } + \\ + , &[_]Error{ + .expected_comma_after_param, + .expected_comma_after_param, + .expected_comma_after_param, + }); +} + +test "recovery: missing while rbrace" { + try testError( + \\fn a() b { + \\ while (d) { + \\} + , &[_]Error{ + .expected_statement, + }); +} + +test "recovery: nonfinal varargs" { + try testError( + \\extern fn f(a: u32, ..., b: u32) void; + \\extern fn g(a: u32, ..., b: anytype) void; + \\extern fn h(a: u32, ..., ...) void; + , &[_]Error{ + .varargs_nonfinal, + .varargs_nonfinal, + .varargs_nonfinal, + }); +} + +test "recovery: eof in c pointer" { + try testError( + \\const Ptr = [*c + , &[_]Error{ + .expected_token, + }); +} + +test "matching whitespace on minus op" { + try testError( + \\ _ = 2 -1, + \\ _ = 2- 1, + \\ _ = 2- + \\ 2, + \\ _ = 2 + \\ -2, + , &[_]Error{ + .mismatched_binary_op_whitespace, + .mismatched_binary_op_whitespace, + .mismatched_binary_op_whitespace, + .mismatched_binary_op_whitespace, + }); + + try testError( + \\ _ = - 1, + \\ _ = -1, + \\ _ = 2 - -1, + \\ _ = 2 - 1, + \\ _ = 2-1, + \\ _ = 2 - + \\1, + \\ _ = 2 + \\ - 1, + , &[_]Error{}); +} + +test "ampersand" { + try testError( + \\ _ = bar && foo, + \\ _ = bar&&foo, + \\ _ = bar& & foo, + \\ _ = bar& &foo, + , &.{ + .invalid_ampersand_ampersand, + .invalid_ampersand_ampersand, + .mismatched_binary_op_whitespace, + .mismatched_binary_op_whitespace, + }); + + try testError( + \\ _ = bar & &foo, + \\ _ = bar & &&foo, + \\ _ = &&foo, + , &.{}); } var fixed_buffer_mem: [100 * 1024]u8 = undefined; fn testParse(source: [:0]const u8, allocator: mem.Allocator, anything_changed: *bool) ![]u8 { - var stderr_buf: [4096]u8 = undefined; - var stderr_file_writer = std.fs.File.stderr().writer(&stderr_buf); - const stderr = &stderr_file_writer.interface; - - //var tree = try std.zig.Ast.parse(allocator, source, .zig); var c_tree = c.astParse(source, @intCast(source.len)); defer c.astDeinit(&c_tree); var tree = try zigAst(allocator, c_tree); defer tree.deinit(allocator); - for (tree.errors) |parse_error| { - const loc = tree.tokenLocation(0, parse_error.token); - try stderr.print("(memory buffer):{d}:{d}: error: ", .{ loc.line + 1, loc.column + 1 }); - try tree.renderError(parse_error, stderr); - try stderr.print("\n{s}\n", .{source[loc.line_start..loc.line_end]}); - { - var i: usize = 0; - while (i < loc.column) : (i += 1) { - try stderr.writeAll(" "); - } - try stderr.writeAll("^"); - } - try stderr.writeAll("\n"); - } if (tree.errors.len != 0) { return error.ParseError; } diff --git a/tokenizer.c b/tokenizer.c index 3607118524..2fde2e9ce6 100644 --- a/tokenizer.c +++ b/tokenizer.c @@ -82,9 +82,11 @@ static TokenizerTag getKeyword(const char* bytes, const uint32_t len) { if (cmp == 0) { if (len == klen) { return keywords[i].tag; - } else { + } else if (len < klen) { return TOKEN_INVALID; } + // len > klen: input is longer than keyword (e.g., "orelse" vs + // "or"), continue searching. } else if (cmp < 0) { return TOKEN_INVALID; }