diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2021-02-01 17:23:49 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2021-02-01 17:23:49 -0700 |
| commit | 20554d32c0a9e8adeb311645797e0d6873f4bbc0 (patch) | |
| tree | 1080a2c4700156e8b1283ddbadad64e1f4520063 /lib/std | |
| parent | bf8fafc37d4182196d108c773ae36c33a109d703 (diff) | |
| download | zig-20554d32c0a9e8adeb311645797e0d6873f4bbc0.tar.gz zig-20554d32c0a9e8adeb311645797e0d6873f4bbc0.zip | |
zig fmt: start reworking with new memory layout
* start implementation of ast.Tree.firstToken and lastToken
* clarify some ast.Node doc comments
* reimplement renderToken
Diffstat (limited to 'lib/std')
| -rw-r--r-- | lib/std/zig/ast.zig | 300 | ||||
| -rw-r--r-- | lib/std/zig/parse.zig | 2 | ||||
| -rw-r--r-- | lib/std/zig/parser_test.zig | 7425 | ||||
| -rw-r--r-- | lib/std/zig/render.zig | 4443 | ||||
| -rw-r--r-- | lib/std/zig/tokenizer.zig | 31 |
5 files changed, 6121 insertions, 6080 deletions
diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig index 823e0312cd..3fd34cd03c 100644 --- a/lib/std/zig/ast.zig +++ b/lib/std/zig/ast.zig @@ -185,24 +185,293 @@ pub const Tree = struct { } } - /// Skips over comments. - pub fn prevToken(self: *const Tree, token_index: TokenIndex) TokenIndex { - const token_tags = self.tokens.items(.tag); - var index = token_index - 1; - while (token_tags[index] == .LineComment) { - index -= 1; + pub fn firstToken(tree: Tree, node: Node.Index) TokenIndex { + const tags = tree.nodes.items(.tag); + const datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); + switch (tags[node]) { + .Root => return 0, + + .UsingNamespace, + .TestDecl, + .ErrDefer, + .Defer, + .BoolNot, + .Negation, + .BitNot, + .NegationWrap, + .AddressOf, + .Try, + .Await, + .OptionalType, + .ArrayInitDotTwo, + .ArrayInitDot, + .StructInitDotTwo, + .StructInitDot, + .Switch, + .IfSimple, + .IfSimpleOptional, + .If, + .IfOptional, + .IfError, + .Suspend, + .Resume, + .Continue, + .Break, + .Return, + .AnyFrameType, + .OneToken, + .Identifier, + .EnumLiteral, + .MultilineStringLiteral, + .GroupedExpression, + .BuiltinCallTwo, + .BuiltinCall, + .ErrorSetDecl, + .AnyType, + .Comptime, + .Nosuspend, + .Block, + .AsmSimple, + .Asm, + => return main_tokens[node], + + .Catch, + .FieldAccess, + .UnwrapOptional, + .EqualEqual, + .BangEqual, + .LessThan, + .GreaterThan, + .LessOrEqual, + .GreaterOrEqual, + .AssignMul, + .AssignDiv, + .AssignMod, + .AssignAdd, + .AssignSub, + .AssignBitShiftLeft, + .AssignBitShiftRight, + .AssignBitAnd, + .AssignBitXor, + .AssignBitOr, + .AssignMulWrap, + .AssignAddWrap, + .AssignSubWrap, + .Assign, + .MergeErrorSets, + .Mul, + .Div, + .Mod, + .ArrayMult, + .MulWrap, + .Add, + .Sub, + .ArrayCat, + .AddWrap, + .SubWrap, + .BitShiftLeft, + .BitShiftRight, + .BitAnd, + .BitXor, + .BitOr, + .OrElse, + .BoolAnd, + .BoolOr, + .SliceOpen, + .Slice, + .Deref, + .ArrayAccess, + .ArrayInitOne, + .ArrayInit, + .StructInitOne, + .CallOne, + .Call, + .SwitchCaseOne, + .SwitchRange, + .FnDecl, + => return tree.firstToken(datas[node].lhs), + + .GlobalVarDecl, + .LocalVarDecl, + .SimpleVarDecl, + .AlignedVarDecl, + .ArrayType, + .ArrayTypeSentinel, + .PtrTypeAligned, + .PtrTypeSentinel, + .PtrType, + .SliceType, + .StructInit, + .SwitchCaseMulti, + .WhileSimple, + .WhileSimpleOptional, + .WhileCont, + .WhileContOptional, + .While, + .WhileOptional, + .WhileError, + .ForSimple, + .For, + .FnProtoSimple, + .FnProtoSimpleMulti, + .FnProtoOne, + .FnProto, + .ContainerDecl, + .ContainerDeclArg, + .TaggedUnion, + .TaggedUnionEnumTag, + .ContainerFieldInit, + .ContainerFieldAlign, + .ContainerField, + .AsmOutput, + .AsmInput, + .ErrorValue, + .ErrorUnion, + => @panic("TODO finish implementing firstToken"), } - return index; } - /// Skips over comments. - pub fn nextToken(self: *const Tree, token_index: TokenIndex) TokenIndex { - const token_tags = self.tokens.items(.tag); - var index = token_index + 1; - while (token_tags[index] == .LineComment) { - index += 1; + pub fn lastToken(tree: Tree, node: Node.Index) TokenIndex { + const tags = tree.nodes.items(.tag); + const datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); + switch (tags[node]) { + .Root, + .UsingNamespace, + .TestDecl, + .ErrDefer, + .Defer, + .BoolNot, + .Negation, + .BitNot, + .NegationWrap, + .AddressOf, + .Try, + .Await, + .OptionalType, + .ArrayInitDotTwo, + .ArrayInitDot, + .StructInitDotTwo, + .StructInitDot, + .Switch, + .IfSimple, + .IfSimpleOptional, + .If, + .IfOptional, + .IfError, + .Suspend, + .Resume, + .Continue, + .Break, + .Return, + .AnyFrameType, + .OneToken, + .Identifier, + .EnumLiteral, + .MultilineStringLiteral, + .GroupedExpression, + .BuiltinCallTwo, + .BuiltinCall, + .ErrorSetDecl, + .AnyType, + .Comptime, + .Nosuspend, + .Block, + .AsmSimple, + .Asm, + .Catch, + .FieldAccess, + .UnwrapOptional, + .EqualEqual, + .BangEqual, + .LessThan, + .GreaterThan, + .LessOrEqual, + .GreaterOrEqual, + .AssignMul, + .AssignDiv, + .AssignMod, + .AssignAdd, + .AssignSub, + .AssignBitShiftLeft, + .AssignBitShiftRight, + .AssignBitAnd, + .AssignBitXor, + .AssignBitOr, + .AssignMulWrap, + .AssignAddWrap, + .AssignSubWrap, + .Assign, + .MergeErrorSets, + .Mul, + .Div, + .Mod, + .ArrayMult, + .MulWrap, + .Add, + .Sub, + .ArrayCat, + .AddWrap, + .SubWrap, + .BitShiftLeft, + .BitShiftRight, + .BitAnd, + .BitXor, + .BitOr, + .OrElse, + .BoolAnd, + .BoolOr, + .SliceOpen, + .Slice, + .Deref, + .ArrayAccess, + .ArrayInitOne, + .ArrayInit, + .StructInitOne, + .CallOne, + .Call, + .SwitchCaseOne, + .SwitchRange, + .FnDecl, + .GlobalVarDecl, + .LocalVarDecl, + .SimpleVarDecl, + .AlignedVarDecl, + .ArrayType, + .ArrayTypeSentinel, + .PtrTypeAligned, + .PtrTypeSentinel, + .PtrType, + .SliceType, + .StructInit, + .SwitchCaseMulti, + .WhileSimple, + .WhileSimpleOptional, + .WhileCont, + .WhileContOptional, + .While, + .WhileOptional, + .WhileError, + .ForSimple, + .For, + .FnProtoSimple, + .FnProtoSimpleMulti, + .FnProtoOne, + .FnProto, + .ContainerDecl, + .ContainerDeclArg, + .TaggedUnion, + .TaggedUnionEnumTag, + .ContainerFieldInit, + .ContainerFieldAlign, + .ContainerField, + .AsmOutput, + .AsmInput, + .ErrorValue, + .ErrorUnion, + => @panic("TODO finish implementing lastToken"), } - return index; } }; @@ -454,7 +723,7 @@ pub const Node = struct { /// lhs is test name token (must be string literal), if any. /// rhs is the body node. TestDecl, - /// lhs is the index into global_var_decl_list. + /// lhs is the index into extra_data. /// rhs is the initialization expression, if any. GlobalVarDecl, /// `var a: x align(y) = rhs` @@ -732,6 +1001,7 @@ pub const Node = struct { /// `nosuspend lhs`. rhs unused. Nosuspend, /// `{}`. `sub_list[lhs..rhs]`. + /// main_token points at the `{`. Block, /// `asm(lhs)`. rhs unused. AsmSimple, diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig index 04c44f5c9c..05efea7fe1 100644 --- a/lib/std/zig/parse.zig +++ b/lib/std/zig/parse.zig @@ -594,7 +594,7 @@ const Parser = struct { p.eatToken(.Keyword_var) orelse return null_node; - const name_token = try p.expectToken(.Identifier); + _ = try p.expectToken(.Identifier); const type_node: Node.Index = if (p.eatToken(.Colon) == null) 0 else try p.expectTypeExpr(); const align_node = try p.parseByteAlign(); const section_node = try p.parseLinkSection(); diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index 279402d71b..d4a01da0d0 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -3,3727 +3,3704 @@ // This file is part of [zig](https://ziglang.org/), which is MIT licensed. // The MIT license requires this copyright notice to be included in all copies // and substantial portions of the software. -test "zig fmt: convert var to anytype" { - // TODO remove in next release cycle - try testTransform( - \\pub fn main( - \\ a: var, - \\ bar: var, - \\) void {} - , - \\pub fn main( - \\ a: anytype, - \\ bar: anytype, - \\) void {} - \\ - ); -} - -test "zig fmt: noasync to nosuspend" { - // TODO: remove this - try testTransform( - \\pub fn main() void { - \\ noasync call(); - \\} - , - \\pub fn main() void { - \\ nosuspend call(); - \\} - \\ - ); -} - -test "recovery: top level" { - try testError( - \\test "" {inline} - \\test "" {inline} - , &[_]Error{ - .ExpectedInlinable, - .ExpectedInlinable, - }); -} - -test "recovery: block statements" { - try testError( - \\test "" { - \\ foo + +; - \\ inline; - \\} - , &[_]Error{ - .InvalidToken, - .ExpectedInlinable, - }); -} - -test "recovery: missing comma" { - try testError( - \\test "" { - \\ switch (foo) { - \\ 2 => {} - \\ 3 => {} - \\ else => { - \\ foo && bar +; - \\ } - \\ } - \\} - , &[_]Error{ - .ExpectedToken, - .ExpectedToken, - .InvalidAnd, - .InvalidToken, - }); -} - -test "recovery: extra qualifier" { - try testError( - \\const a: *const const u8; - \\test "" - , &[_]Error{ - .ExtraConstQualifier, - .ExpectedLBrace, - }); -} - -test "recovery: missing return type" { - try testError( - \\fn foo() { - \\ a && b; - \\} - \\test "" - , &[_]Error{ - .ExpectedReturnType, - .InvalidAnd, - .ExpectedLBrace, - }); -} - -test "recovery: continue after invalid decl" { - try testError( - \\fn foo { - \\ inline; - \\} - \\pub test "" { - \\ async a && b; - \\} - , &[_]Error{ - .ExpectedToken, - .ExpectedPubItem, - .ExpectedParamList, - .InvalidAnd, - }); - try testError( - \\threadlocal test "" { - \\ @a && b; - \\} - , &[_]Error{ - .ExpectedVarDecl, - .ExpectedParamList, - .InvalidAnd, - }); -} - -test "recovery: invalid extern/inline" { - try testError( - \\inline test "" { a && b; } - , &[_]Error{ - .ExpectedFn, - .InvalidAnd, - }); - try testError( - \\extern "" test "" { a && b; } - , &[_]Error{ - .ExpectedVarDeclOrFn, - .InvalidAnd, - }); -} - -test "recovery: missing semicolon" { - try testError( - \\test "" { - \\ comptime a && b - \\ c && d - \\ @foo - \\} - , &[_]Error{ - .InvalidAnd, - .ExpectedToken, - .InvalidAnd, - .ExpectedToken, - .ExpectedParamList, - .ExpectedToken, - }); -} - -test "recovery: invalid container members" { - try testError( - \\usingnamespace; - \\foo+ - \\bar@, - \\while (a == 2) { test "" {}} - \\test "" { - \\ a && b - \\} - , &[_]Error{ - .ExpectedExpr, - .ExpectedToken, - .ExpectedToken, - .ExpectedContainerMembers, - .InvalidAnd, - .ExpectedToken, - }); -} - -test "recovery: invalid parameter" { - try testError( - \\fn main() void { - \\ a(comptime T: type) - \\} - , &[_]Error{ - .ExpectedToken, - }); -} - -test "recovery: extra '}' at top level" { - try testError( - \\}}} - \\test "" { - \\ a && b; - \\} - , &[_]Error{ - .ExpectedContainerMembers, - .ExpectedContainerMembers, - .ExpectedContainerMembers, - .InvalidAnd, - }); -} - -test "recovery: mismatched bracket at top level" { - try testError( - \\const S = struct { - \\ arr: 128]?G - \\}; - , &[_]Error{ - .ExpectedToken, - }); -} - -test "recovery: invalid global error set access" { - try testError( - \\test "" { - \\ error && foo; - \\} - , &[_]Error{ - .ExpectedToken, - .ExpectedIdentifier, - .InvalidAnd, - }); -} - -test "recovery: invalid asterisk after pointer dereference" { - try testError( - \\test "" { - \\ var sequence = "repeat".*** 10; - \\} - , &[_]Error{ - .AsteriskAfterPointerDereference, - }); - try testError( - \\test "" { - \\ var sequence = "repeat".** 10&&a; - \\} - , &[_]Error{ - .AsteriskAfterPointerDereference, - .InvalidAnd, - }); -} - -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{ - .ExpectedSemiOrElse, - .ExpectedSemiOrElse, - .ExpectedSemiOrElse, - .InvalidAnd, - }); -} - -test "recovery: invalid comptime" { - try testError( - \\comptime - , &[_]Error{ - .ExpectedBlockOrField, - }); -} - -test "recovery: missing block after for/while loops" { - try testError( - \\test "" { while (foo) } - , &[_]Error{ - .ExpectedBlockOrAssignment, - }); - try testError( - \\test "" { for (foo) |bar| } - , &[_]Error{ - .ExpectedBlockOrAssignment, - }); -} - -test "zig fmt: respect line breaks after var declarations" { - try testCanonical( - \\const crc = - \\ lookup_tables[0][p[7]] ^ - \\ lookup_tables[1][p[6]] ^ - \\ lookup_tables[2][p[5]] ^ - \\ lookup_tables[3][p[4]] ^ - \\ lookup_tables[4][@truncate(u8, self.crc >> 24)] ^ - \\ lookup_tables[5][@truncate(u8, self.crc >> 16)] ^ - \\ lookup_tables[6][@truncate(u8, self.crc >> 8)] ^ - \\ lookup_tables[7][@truncate(u8, self.crc >> 0)]; - \\ - ); -} - -test "zig fmt: multiline string mixed with comments" { - try testCanonical( - \\const s1 = - \\ //\\one - \\ \\two) - \\ \\three - \\; - \\const s2 = - \\ \\one - \\ \\two) - \\ //\\three - \\; - \\const s3 = - \\ \\one - \\ //\\two) - \\ \\three - \\; - \\const s4 = - \\ \\one - \\ //\\two - \\ \\three - \\ //\\four - \\ \\five - \\; - \\const a = - \\ 1; - \\ - ); -} - -test "zig fmt: empty file" { - try testCanonical( - \\ - ); -} - -test "zig fmt: if statment" { - try testCanonical( - \\test "" { - \\ if (optional()) |some| - \\ bar = some.foo(); - \\} - \\ - ); -} - -test "zig fmt: top-level fields" { - try testCanonical( - \\a: did_you_know, - \\b: all_files_are, - \\structs: ?x, - \\ - ); -} - -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{ - .DeclBetweenFields, - }); -} - -test "zig fmt: eof after missing comma" { - try testError( - \\foo() - , &[_]Error{ - .ExpectedToken, - }); -} - -test "zig fmt: errdefer with payload" { - try testCanonical( - \\pub fn main() anyerror!void { - \\ errdefer |a| x += 1; - \\ errdefer |a| {} - \\ errdefer |a| { - \\ x += 1; - \\ } - \\} - \\ - ); -} - -test "zig fmt: nosuspend block" { - try testCanonical( - \\pub fn main() anyerror!void { - \\ nosuspend { - \\ var foo: Foo = .{ .bar = 42 }; - \\ } - \\} - \\ - ); -} - -test "zig fmt: nosuspend await" { - try testCanonical( - \\fn foo() void { - \\ x = nosuspend await y; - \\} - \\ - ); -} - -test "zig fmt: trailing comma in container declaration" { - try testCanonical( - \\const X = struct { foo: i32 }; - \\const X = struct { foo: i32, bar: i32 }; - \\const X = struct { foo: i32 = 1, bar: i32 = 2 }; - \\const X = struct { foo: i32 align(4), bar: i32 align(4) }; - \\const X = struct { foo: i32 align(4) = 1, bar: i32 align(4) = 2 }; - \\ - ); - try testCanonical( - \\test "" { - \\ comptime { - \\ const X = struct { - \\ x: i32 - \\ }; - \\ } - \\} - \\ - ); - try testTransform( - \\const X = struct { - \\ foo: i32, bar: i8 }; - , - \\const X = struct { - \\ foo: i32, bar: i8 - \\}; - \\ - ); -} - -test "zig fmt: trailing comma in fn parameter list" { - try testCanonical( - \\pub fn f( - \\ a: i32, - \\ b: i32, - \\) i32 {} - \\pub fn f( - \\ a: i32, - \\ b: i32, - \\) align(8) i32 {} - \\pub fn f( - \\ a: i32, - \\ b: i32, - \\) linksection(".text") i32 {} - \\pub fn f( - \\ a: i32, - \\ b: i32, - \\) callconv(.C) i32 {} - \\pub fn f( - \\ a: i32, - \\ b: i32, - \\) align(8) linksection(".text") i32 {} - \\pub fn f( - \\ a: i32, - \\ b: i32, - \\) align(8) callconv(.C) i32 {} - \\pub fn f( - \\ a: i32, - \\ b: i32, - \\) align(8) linksection(".text") callconv(.C) i32 {} - \\pub fn f( - \\ a: i32, - \\ b: i32, - \\) linksection(".text") callconv(.C) i32 {} - \\ - ); -} - -test "zig fmt: comptime struct field" { - try testCanonical( - \\const Foo = struct { - \\ a: i32, - \\ comptime b: i32 = 1234, - \\}; - \\ - ); -} - -test "zig fmt: c pointer type" { - try testCanonical( - \\pub extern fn repro() [*c]const u8; - \\ - ); -} - -test "zig fmt: builtin call with trailing comma" { - try testCanonical( - \\pub fn main() void { - \\ @breakpoint(); - \\ _ = @boolToInt(a); - \\ _ = @call( - \\ a, - \\ b, - \\ c, - \\ ); - \\} - \\ - ); -} - -test "zig fmt: asm expression with comptime content" { - try testCanonical( - \\comptime { - \\ asm ("foo" ++ "bar"); - \\} - \\pub fn main() void { - \\ asm volatile ("foo" ++ "bar"); - \\ asm volatile ("foo" ++ "bar" - \\ : [_] "" (x) - \\ ); - \\ asm volatile ("foo" ++ "bar" - \\ : [_] "" (x) - \\ : [_] "" (y) - \\ ); - \\ asm volatile ("foo" ++ "bar" - \\ : [_] "" (x) - \\ : [_] "" (y) - \\ : "h", "e", "l", "l", "o" - \\ ); - \\} - \\ - ); -} - -test "zig fmt: anytype struct field" { - try testCanonical( - \\pub const Pointer = struct { - \\ sentinel: anytype, - \\}; - \\ - ); -} - -test "zig fmt: sentinel-terminated array type" { - try testCanonical( - \\pub fn cStrToPrefixedFileW(s: [*:0]const u8) ![PATH_MAX_WIDE:0]u16 { - \\ return sliceToPrefixedFileW(mem.toSliceConst(u8, s)); - \\} - \\ - ); -} - -test "zig fmt: sentinel-terminated slice type" { - try testCanonical( - \\pub fn toSlice(self: Buffer) [:0]u8 { - \\ return self.list.toSlice()[0..self.len()]; - \\} - \\ - ); -} - -test "zig fmt: anon literal in array" { - try testCanonical( - \\var arr: [2]Foo = .{ - \\ .{ .a = 2 }, - \\ .{ .b = 3 }, - \\}; - \\ - ); -} - -test "zig fmt: alignment in anonymous literal" { - try testTransform( - \\const a = .{ - \\ "U", "L", "F", - \\ "U'", - \\ "L'", - \\ "F'", - \\}; - \\ - , - \\const a = .{ - \\ "U", "L", "F", - \\ "U'", "L'", "F'", - \\}; - \\ - ); -} - -test "zig fmt: anon struct literal syntax" { - try testCanonical( - \\const x = .{ - \\ .a = b, - \\ .c = d, - \\}; - \\ - ); -} - -test "zig fmt: anon list literal syntax" { - try testCanonical( - \\const x = .{ a, b, c }; - \\ - ); -} - -test "zig fmt: async function" { - try testCanonical( - \\pub const Server = struct { - \\ handleRequestFn: fn (*Server, *const std.net.Address, File) callconv(.Async) void, - \\}; - \\test "hi" { - \\ var ptr = @ptrCast(fn (i32) callconv(.Async) void, other); - \\} - \\ - ); -} - -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 "" { - \\ const hi = x; - \\} - \\// zig fmt: off - \\test ""{ - \\ const a = b;} - \\ - ); -} - -test "zig fmt: while else err prong with no block" { - try testCanonical( - \\test "" { - \\ const result = while (returnError()) |value| { - \\ break value; - \\ } else |err| @as(i32, 2); - \\ expect(result == 2); - \\} - \\ - ); -} - -test "zig fmt: tagged union with enum values" { - try testCanonical( - \\const MultipleChoice2 = union(enum(u32)) { - \\ Unspecified1: i32, - \\ A: f32 = 20, - \\ Unspecified2: void, - \\ B: bool = 40, - \\ Unspecified3: i32, - \\ C: i8 = 60, - \\ Unspecified4: void, - \\ D: void = 1000, - \\ Unspecified5: i32, - \\}; - \\ - ); -} - -test "zig fmt: allowzero pointer" { - try testCanonical( - \\const T = [*]allowzero const u8; - \\ - ); -} - -test "zig fmt: enum literal" { - try testCanonical( - \\const x = .hi; - \\ - ); -} - -test "zig fmt: enum literal inside array literal" { - try testCanonical( - \\test "enums in arrays" { - \\ var colors = []Color{.Green}; - \\ colors = []Colors{ .Green, .Cyan }; - \\ colors = []Colors{ - \\ .Grey, - \\ .Green, - \\ .Cyan, - \\ }; - \\} - \\ - ); -} - -test "zig fmt: character literal larger than u8" { - try testCanonical( - \\const x = '\u{01f4a9}'; - \\ - ); -} - -test "zig fmt: infix operator and then multiline string literal" { - try testCanonical( - \\const x = "" ++ - \\ \\ hi - \\; - \\ - ); -} - -test "zig fmt: infix operator and then multiline string literal" { - try testCanonical( - \\const x = "" ++ - \\ \\ hi0 - \\ \\ hi1 - \\ \\ hi2 - \\; - \\ - ); -} - -test "zig fmt: C pointers" { - try testCanonical( - \\const Ptr = [*c]i32; - \\ - ); -} - -test "zig fmt: threadlocal" { - try testCanonical( - \\threadlocal var x: i32 = 1234; - \\ - ); -} - -test "zig fmt: linksection" { - try testCanonical( - \\export var aoeu: u64 linksection(".text.derp") = 1234; - \\export fn _start() linksection(".text.boot") callconv(.Naked) noreturn {} - \\ - ); -} - -test "zig fmt: correctly move doc comments on struct fields" { - try testTransform( - \\pub const section_64 = extern struct { - \\ sectname: [16]u8, /// name of this section - \\ segname: [16]u8, /// segment this section goes in - \\}; - , - \\pub const section_64 = extern struct { - \\ /// name of this section - \\ sectname: [16]u8, - \\ /// segment this section goes in - \\ segname: [16]u8, - \\}; - \\ - ); -} - -test "zig fmt: correctly space struct fields with doc comments" { - try testTransform( - \\pub const S = struct { - \\ /// A - \\ a: u8, - \\ /// B - \\ /// B (cont) - \\ b: u8, - \\ - \\ - \\ /// C - \\ c: u8, - \\}; - \\ - , - \\pub const S = struct { - \\ /// A - \\ a: u8, - \\ /// B - \\ /// B (cont) - \\ b: u8, - \\ - \\ /// C - \\ c: u8, - \\}; - \\ - ); -} - -test "zig fmt: doc comments on param decl" { - try testCanonical( - \\pub const Allocator = struct { - \\ shrinkFn: fn ( - \\ self: *Allocator, - \\ /// Guaranteed to be the same as what was returned from most recent call to - \\ /// `allocFn`, `reallocFn`, or `shrinkFn`. - \\ old_mem: []u8, - \\ /// Guaranteed to be the same as what was returned from most recent call to - \\ /// `allocFn`, `reallocFn`, or `shrinkFn`. - \\ old_alignment: u29, - \\ /// Guaranteed to be less than or equal to `old_mem.len`. - \\ new_byte_count: usize, - \\ /// Guaranteed to be less than or equal to `old_alignment`. - \\ new_alignment: u29, - \\ ) []u8, - \\}; - \\ - ); -} - -test "zig fmt: aligned struct field" { - try testCanonical( - \\pub const S = struct { - \\ f: i32 align(32), - \\}; - \\ - ); - try testCanonical( - \\pub const S = struct { - \\ f: i32 align(32) = 1, - \\}; - \\ - ); -} - -test "zig fmt: comment to disable/enable zig fmt first" { - try testCanonical( - \\// Test trailing comma syntax - \\// zig fmt: off - \\ - \\const struct_trailing_comma = struct { x: i32, y: i32, }; - ); -} - -test "zig fmt: comment to disable/enable zig fmt" { - try testTransform( - \\const a = b; - \\// zig fmt: off - \\const c = d; - \\// zig fmt: on - \\const e = f; - , - \\const a = b; - \\// zig fmt: off - \\const c = d; - \\// zig fmt: on - \\const e = f; - \\ - ); -} - -test "zig fmt: line comment following 'zig fmt: off'" { - try testCanonical( - \\// zig fmt: off - \\// Test - \\const e = f; - ); -} - -test "zig fmt: doc comment following 'zig fmt: off'" { - try testCanonical( - \\// zig fmt: off - \\/// test - \\const e = f; - ); -} - -test "zig fmt: line and doc comment following 'zig fmt: off'" { - try testCanonical( - \\// zig fmt: off - \\// test 1 - \\/// test 2 - \\const e = f; - ); -} - -test "zig fmt: doc and line comment following 'zig fmt: off'" { - try testCanonical( - \\// zig fmt: off - \\/// test 1 - \\// test 2 - \\const e = f; - ); -} - -test "zig fmt: alternating 'zig fmt: off' and 'zig fmt: on'" { - try testCanonical( - \\// zig fmt: off - \\// zig fmt: on - \\// zig fmt: off - \\const e = f; - \\// zig fmt: off - \\// zig fmt: on - \\// zig fmt: off - \\const a = b; - \\// zig fmt: on - \\const c = d; - \\// zig fmt: on - \\ - ); -} - -test "zig fmt: line comment following 'zig fmt: on'" { - try testCanonical( - \\// zig fmt: off - \\const e = f; - \\// zig fmt: on - \\// test - \\const e = f; - \\ - ); -} - -test "zig fmt: doc comment following 'zig fmt: on'" { - try testCanonical( - \\// zig fmt: off - \\const e = f; - \\// zig fmt: on - \\/// test - \\const e = f; - \\ - ); -} - -test "zig fmt: line and doc comment following 'zig fmt: on'" { - try testCanonical( - \\// zig fmt: off - \\const e = f; - \\// zig fmt: on - \\// test1 - \\/// test2 - \\const e = f; - \\ - ); -} - -test "zig fmt: doc and line comment following 'zig fmt: on'" { - try testCanonical( - \\// zig fmt: off - \\const e = f; - \\// zig fmt: on - \\/// test1 - \\// test2 - \\const e = f; - \\ - ); -} - -test "zig fmt: pointer of unknown length" { - try testCanonical( - \\fn foo(ptr: [*]u8) void {} - \\ - ); -} - -test "zig fmt: spaces around slice operator" { - try testCanonical( - \\var a = b[c..d]; - \\var a = b[c..d :0]; - \\var a = b[c + 1 .. d]; - \\var a = b[c + 1 ..]; - \\var a = b[c .. d + 1]; - \\var a = b[c .. d + 1 :0]; - \\var a = b[c.a..d.e]; - \\var a = b[c.a..d.e :0]; - \\ - ); -} - -test "zig fmt: async call in if condition" { - try testCanonical( - \\comptime { - \\ if (async b()) { - \\ a(); - \\ } - \\} - \\ - ); -} - -test "zig fmt: 2nd arg multiline string" { - try testCanonical( - \\comptime { - \\ cases.addAsm("hello world linux x86_64", - \\ \\.text - \\ , "Hello, world!\n"); - \\} - \\ - ); -} - -test "zig fmt: 2nd arg multiline string many args" { - try testCanonical( - \\comptime { - \\ cases.addAsm("hello world linux x86_64", - \\ \\.text - \\ , "Hello, world!\n", "Hello, world!\n"); - \\} - \\ - ); -} - -test "zig fmt: final arg multiline string" { - try testCanonical( - \\comptime { - \\ cases.addAsm("hello world linux x86_64", "Hello, world!\n", - \\ \\.text - \\ ); - \\} - \\ - ); -} - -test "zig fmt: if condition wraps" { - try testTransform( - \\comptime { - \\ if (cond and - \\ cond) { - \\ return x; - \\ } - \\ while (cond and - \\ cond) { - \\ return x; - \\ } - \\ if (a == b and - \\ c) { - \\ a = b; - \\ } - \\ while (a == b and - \\ c) { - \\ a = b; - \\ } - \\ if ((cond and - \\ cond)) { - \\ return x; - \\ } - \\ while ((cond and - \\ cond)) { - \\ return x; - \\ } - \\ var a = if (a) |*f| x: { - \\ break :x &a.b; - \\ } else |err| err; - \\ var a = if (cond and - \\ cond) |*f| - \\ x: { - \\ break :x &a.b; - \\ } else |err| err; - \\} - , - \\comptime { - \\ if (cond and - \\ cond) - \\ { - \\ return x; - \\ } - \\ while (cond and - \\ cond) - \\ { - \\ return x; - \\ } - \\ if (a == b and - \\ c) - \\ { - \\ a = b; - \\ } - \\ while (a == b and - \\ c) - \\ { - \\ a = b; - \\ } - \\ if ((cond and - \\ cond)) - \\ { - \\ return x; - \\ } - \\ while ((cond and - \\ cond)) - \\ { - \\ return x; - \\ } - \\ var a = if (a) |*f| x: { - \\ break :x &a.b; - \\ } else |err| err; - \\ var a = if (cond and - \\ cond) |*f| - \\ x: { - \\ break :x &a.b; - \\ } else |err| err; - \\} - \\ - ); -} - -test "zig fmt: if condition has line break but must not wrap" { - try testCanonical( - \\comptime { - \\ if (self.user_input_options.put( - \\ name, - \\ UserInputOption{ - \\ .name = name, - \\ .used = false, - \\ }, - \\ ) catch unreachable) |*prev_value| { - \\ foo(); - \\ bar(); - \\ } - \\ if (put( - \\ a, - \\ b, - \\ )) { - \\ foo(); - \\ } - \\} - \\ - ); -} - -test "zig fmt: if condition has line break but must not wrap" { - try testCanonical( - \\comptime { - \\ if (self.user_input_options.put(name, UserInputOption{ - \\ .name = name, - \\ .used = false, - \\ }) catch unreachable) |*prev_value| { - \\ foo(); - \\ bar(); - \\ } - \\ if (put( - \\ a, - \\ b, - \\ )) { - \\ foo(); - \\ } - \\} - \\ - ); -} - -test "zig fmt: function call with multiline argument" { - try testCanonical( - \\comptime { - \\ self.user_input_options.put(name, UserInputOption{ - \\ .name = name, - \\ .used = false, - \\ }); - \\} - \\ - ); -} - -test "zig fmt: same-line doc comment on variable declaration" { - try testTransform( - \\pub const MAP_ANONYMOUS = 0x1000; /// allocated from memory, swap space - \\pub const MAP_FILE = 0x0000; /// map from file (default) - \\ - \\pub const EMEDIUMTYPE = 124; /// Wrong medium type - \\ - \\// nameserver query return codes - \\pub const ENSROK = 0; /// DNS server returned answer with no data - , - \\/// allocated from memory, swap space - \\pub const MAP_ANONYMOUS = 0x1000; - \\/// map from file (default) - \\pub const MAP_FILE = 0x0000; - \\ - \\/// Wrong medium type - \\pub const EMEDIUMTYPE = 124; - \\ - \\// nameserver query return codes - \\/// DNS server returned answer with no data - \\pub const ENSROK = 0; - \\ - ); -} - -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).new(y - y, y - y); - \\ } // cexp(-inf +- i inf|nan) = 0 + i0 - \\ else if (hx & 0x80000000 != 0) { - \\ return Complex(f32).new(0, 0); - \\ } // cexp(+inf +- i inf|nan) = inf + i nan - \\ else { - \\ return Complex(f32).new(x, y - y); - \\ } - \\} - \\ - ); -} - -test "zig fmt: if nested" { - try testCanonical( - \\pub fn foo() void { - \\ return if ((aInt & bInt) >= 0) - \\ if (aInt < bInt) - \\ GE_LESS - \\ else if (aInt == bInt) - \\ GE_EQUAL - \\ else - \\ GE_GREATER - \\ else if (aInt > bInt) - \\ GE_LESS - \\ else if (aInt == bInt) - \\ GE_EQUAL - \\ else - \\ GE_GREATER; - \\} - \\ - ); -} - -test "zig fmt: respect line breaks in if-else" { - try testCanonical( - \\comptime { - \\ return if (cond) a else b; - \\ return if (cond) - \\ a - \\ else - \\ b; - \\ return if (cond) - \\ a - \\ else if (cond) - \\ b - \\ else - \\ c; - \\} - \\ - ); -} - -test "zig fmt: respect line breaks after infix operators" { - try testCanonical( - \\comptime { - \\ self.crc = - \\ lookup_tables[0][p[7]] ^ - \\ lookup_tables[1][p[6]] ^ - \\ lookup_tables[2][p[5]] ^ - \\ lookup_tables[3][p[4]] ^ - \\ lookup_tables[4][@truncate(u8, self.crc >> 24)] ^ - \\ lookup_tables[5][@truncate(u8, self.crc >> 16)] ^ - \\ lookup_tables[6][@truncate(u8, self.crc >> 8)] ^ - \\ lookup_tables[7][@truncate(u8, self.crc >> 0)]; - \\} - \\ - ); -} - -test "zig fmt: fn decl with trailing comma" { - try testTransform( - \\fn foo(a: i32, b: i32,) void {} - , - \\fn foo( - \\ a: i32, - \\ b: i32, - \\) void {} - \\ - ); -} - -test "zig fmt: enum decl with no trailing comma" { - try testTransform( - \\const StrLitKind = enum {Normal, C}; - , - \\const StrLitKind = enum { Normal, C }; - \\ - ); -} - -test "zig fmt: switch comment before prong" { - try testCanonical( - \\comptime { - \\ switch (a) { - \\ // hi - \\ 0 => {}, - \\ } - \\} - \\ - ); -} - -test "zig fmt: struct literal no trailing comma" { - try testTransform( - \\const a = foo{ .x = 1, .y = 2 }; - \\const a = foo{ .x = 1, - \\ .y = 2 }; - , - \\const a = foo{ .x = 1, .y = 2 }; - \\const a = foo{ - \\ .x = 1, - \\ .y = 2, - \\}; - \\ - ); -} - -test "zig fmt: struct literal containing a multiline expression" { - try testTransform( - \\const a = A{ .x = if (f1()) 10 else 20 }; - \\const a = A{ .x = if (f1()) 10 else 20, }; - \\const a = A{ .x = if (f1()) - \\ 10 else 20 }; - \\const a = A{ .x = if (f1()) 10 else 20, .y = f2() + 100 }; - \\const a = A{ .x = if (f1()) 10 else 20, .y = f2() + 100, }; - \\const a = A{ .x = if (f1()) - \\ 10 else 20}; - \\const a = A{ .x = switch(g) {0 => "ok", else => "no"} }; - \\ - , - \\const a = A{ .x = if (f1()) 10 else 20 }; - \\const a = A{ - \\ .x = if (f1()) 10 else 20, - \\}; - \\const a = A{ - \\ .x = if (f1()) - \\ 10 - \\ else - \\ 20, - \\}; - \\const a = A{ .x = if (f1()) 10 else 20, .y = f2() + 100 }; - \\const a = A{ - \\ .x = if (f1()) 10 else 20, - \\ .y = f2() + 100, - \\}; - \\const a = A{ - \\ .x = if (f1()) - \\ 10 - \\ else - \\ 20, - \\}; - \\const a = A{ - \\ .x = switch (g) { - \\ 0 => "ok", - \\ else => "no", - \\ }, - \\}; - \\ - ); -} - -test "zig fmt: array literal with hint" { - try testTransform( - \\const a = []u8{ - \\ 1, 2, // - \\ 3, - \\ 4, - \\ 5, - \\ 6, - \\ 7 }; - \\const a = []u8{ - \\ 1, 2, // - \\ 3, - \\ 4, - \\ 5, - \\ 6, - \\ 7, 8 }; - \\const a = []u8{ - \\ 1, 2, // - \\ 3, - \\ 4, - \\ 5, - \\ 6, // blah - \\ 7, 8 }; - \\const a = []u8{ - \\ 1, 2, // - \\ 3, // - \\ 4, - \\ 5, - \\ 6, - \\ 7 }; - \\const a = []u8{ - \\ 1, - \\ 2, - \\ 3, 4, // - \\ 5, 6, // - \\ 7, 8, // - \\}; - , - \\const a = []u8{ - \\ 1, 2, - \\ 3, 4, - \\ 5, 6, - \\ 7, - \\}; - \\const a = []u8{ - \\ 1, 2, - \\ 3, 4, - \\ 5, 6, - \\ 7, 8, - \\}; - \\const a = []u8{ - \\ 1, 2, - \\ 3, 4, - \\ 5, - \\ 6, // blah - \\ 7, - \\ 8, - \\}; - \\const a = []u8{ - \\ 1, 2, - \\ 3, // - \\ 4, - \\ 5, 6, - \\ 7, - \\}; - \\const a = []u8{ - \\ 1, - \\ 2, - \\ 3, - \\ 4, - \\ 5, - \\ 6, - \\ 7, - \\ 8, - \\}; - \\ - ); -} - -test "zig fmt: array literal veritical column alignment" { - try testTransform( - \\const a = []u8{ - \\ 1000, 200, - \\ 30, 4, - \\ 50000, 60 - \\}; - \\const a = []u8{0, 1, 2, 3, 40, - \\ 4,5,600,7, - \\ 80, - \\ 9, 10, 11, 0, 13, 14, 15}; - \\ - , - \\const a = []u8{ - \\ 1000, 200, - \\ 30, 4, - \\ 50000, 60, - \\}; - \\const a = []u8{ - \\ 0, 1, 2, 3, 40, - \\ 4, 5, 600, 7, 80, - \\ 9, 10, 11, 0, 13, - \\ 14, 15, - \\}; - \\ - ); -} - -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 {} - \\ \\ZIG_C_HEADER_FILES {} - \\ \\ZIG_DIA_GUIDS_LIB {} - \\ \\ - \\ , - \\ std.cstr.toSliceConst(c.ZIG_CMAKE_BINARY_DIR), - \\ std.cstr.toSliceConst(c.ZIG_CXX_COMPILER), - \\ std.cstr.toSliceConst(c.ZIG_DIA_GUIDS_LIB), - \\ ); - \\} - \\ - ); -} - -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: no trailing comma on struct decl" { - try testCanonical( - \\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: simple asm" { - try testTransform( - \\comptime { - \\ asm volatile ( - \\ \\.globl aoeu; - \\ \\.type aoeu, @function; - \\ \\.set aoeu, derp; - \\ ); - \\ - \\ asm ("not real assembly" - \\ :[a] "x" (x),); - \\ asm ("not real assembly" - \\ :[a] "x" (->i32),:[a] "x" (1),); - \\ asm ("still not real assembly" - \\ :::"a","b",); - \\} - , - \\comptime { - \\ asm volatile ( - \\ \\.globl aoeu; - \\ \\.type aoeu, @function; - \\ \\.set aoeu, derp; - \\ ); - \\ - \\ asm ("not real assembly" - \\ : [a] "x" (x) - \\ ); - \\ asm ("not real assembly" - \\ : [a] "x" (-> i32) - \\ : [a] "x" (1) - \\ ); - \\ asm ("still not real assembly" - \\ : - \\ : - \\ : "a", "b" - \\ ); - \\} - \\ - ); -} - -test "zig fmt: nested struct literal with one item" { - try testCanonical( - \\const a = foo{ - \\ .item = bar{ .a = b }, - \\}; - \\ - ); -} - -test "zig fmt: switch cases trailing comma" { - try testTransform( - \\fn switch_cases(x: i32) void { - \\ switch (x) { - \\ 1,2,3 => {}, - \\ 4,5, => {}, - \\ 6... 8, => {}, - \\ else => {}, - \\ } - \\} - , - \\fn switch_cases(x: i32) void { - \\ switch (x) { - \\ 1, 2, 3 => {}, - \\ 4, - \\ 5, - \\ => {}, - \\ 6...8 => {}, - \\ else => {}, - \\ } - \\} - \\ - ); -} - -test "zig fmt: slice align" { - try testCanonical( - \\const A = struct { - \\ items: []align(A) T, - \\}; - \\ - ); -} - -test "zig fmt: add trailing comma to array literal" { - try testTransform( - \\comptime { - \\ return []u16{'m', 's', 'y', 's', '-' // hi - \\ }; - \\ return []u16{'m', 's', 'y', 's', - \\ '-'}; - \\ return []u16{'m', 's', 'y', 's', '-'}; - \\} - , - \\comptime { - \\ return []u16{ - \\ 'm', 's', 'y', 's', '-', // hi - \\ }; - \\ return []u16{ - \\ 'm', 's', 'y', 's', - \\ '-', - \\ }; - \\ return []u16{ 'm', 's', 'y', 's', '-' }; - \\} - \\ - ); -} - -test "zig fmt: first thing in file is line comment" { - try testCanonical( - \\// Introspection and determination of system libraries needed by zig. - \\ - \\// Introspection and determination of system libraries needed by zig. - \\ - \\const std = @import("std"); - \\ - ); -} - -test "zig fmt: line comment after doc comment" { - try testCanonical( - \\/// doc comment - \\// line comment - \\fn foo() void {} - \\ - ); -} - -test "zig fmt: float literal with exponent" { - try testCanonical( - \\test "bit field alignment" { - \\ assert(@TypeOf(&blah.b) == *align(1:3:6) const u3); - \\} - \\ - ); -} - -test "zig fmt: float literal with exponent" { - try testCanonical( - \\test "aoeu" { - \\ switch (state) { - \\ TermState.Start => switch (c) { - \\ '\x1b' => state = TermState.Escape, - \\ else => try out.writeByte(c), - \\ }, - \\ } - \\} - \\ - ); -} -test "zig fmt: float literal with exponent" { - try testCanonical( - \\pub const f64_true_min = 4.94065645841246544177e-324; - \\const threshold = 0x1.a827999fcef32p+1022; - \\ - ); -} - -test "zig fmt: if-else end of comptime" { - try testCanonical( - \\comptime { - \\ if (a) { - \\ b(); - \\ } else { - \\ b(); - \\ } - \\} - \\ - ); -} - -test "zig fmt: nested blocks" { - try testCanonical( - \\comptime { - \\ { - \\ { - \\ { - \\ a(); - \\ } - \\ } - \\ } - \\} - \\ - ); -} - -test "zig fmt: block with same line comment after end brace" { - try testCanonical( - \\comptime { - \\ { - \\ b(); - \\ } // comment - \\} - \\ - ); -} - -test "zig fmt: statements with comment between" { - try testCanonical( - \\comptime { - \\ a = b; - \\ // comment - \\ a = b; - \\} - \\ - ); -} - -test "zig fmt: statements with empty line between" { - try testCanonical( - \\comptime { - \\ a = b; - \\ - \\ a = b; - \\} - \\ - ); -} - -test "zig fmt: ptr deref operator and unwrap optional operator" { - try testCanonical( - \\const a = b.*; - \\const a = b.?; - \\ - ); -} - -test "zig fmt: comment after if before another if" { - try testCanonical( - \\test "aoeu" { - \\ // comment - \\ if (x) { - \\ bar(); - \\ } - \\} - \\ - \\test "aoeu" { - \\ if (x) { - \\ foo(); - \\ } - \\ // comment - \\ if (x) { - \\ bar(); - \\ } - \\} - \\ - ); -} - -test "zig fmt: line comment between if block and else keyword" { - try testCanonical( - \\test "aoeu" { - \\ // cexp(finite|nan +- i inf|nan) = nan + i nan - \\ if ((hx & 0x7fffffff) != 0x7f800000) { - \\ return Complex(f32).new(y - y, y - y); - \\ } - \\ // cexp(-inf +- i inf|nan) = 0 + i0 - \\ else if (hx & 0x80000000 != 0) { - \\ return Complex(f32).new(0, 0); - \\ } - \\ // cexp(+inf +- i inf|nan) = inf + i nan - \\ // another comment - \\ else { - \\ return Complex(f32).new(x, y - y); - \\ } - \\} - \\ - ); -} - -test "zig fmt: same line comments in expression" { - try testCanonical( - \\test "aoeu" { - \\ const x = ( // a - \\ 0 // b - \\ ); // c - \\} - \\ - ); -} - -test "zig fmt: add comma on last switch prong" { - try testTransform( - \\test "aoeu" { - \\switch (self.init_arg_expr) { - \\ InitArg.Type => |t| { }, - \\ InitArg.None, - \\ InitArg.Enum => { } - \\} - \\ switch (self.init_arg_expr) { - \\ InitArg.Type => |t| { }, - \\ InitArg.None, - \\ InitArg.Enum => { }//line comment - \\ } - \\} - , - \\test "aoeu" { - \\ switch (self.init_arg_expr) { - \\ InitArg.Type => |t| {}, - \\ InitArg.None, InitArg.Enum => {}, - \\ } - \\ switch (self.init_arg_expr) { - \\ InitArg.Type => |t| {}, - \\ InitArg.None, InitArg.Enum => {}, //line comment - \\ } - \\} - \\ - ); -} - -test "zig fmt: same-line comment after a statement" { - try testCanonical( - \\test "" { - \\ a = b; - \\ debug.assert(H.digest_size <= H.block_size); // HMAC makes this assumption - \\ a = b; - \\} - \\ - ); -} - -test "zig fmt: same-line comment after var decl in struct" { - try testCanonical( - \\pub const vfs_cap_data = extern struct { - \\ const Data = struct {}; // when on disk. - \\}; - \\ - ); -} - -test "zig fmt: same-line comment after field decl" { - try testCanonical( - \\pub const dirent = extern struct { - \\ d_name: u8, - \\ d_name: u8, // comment 1 - \\ d_name: u8, - \\ d_name: u8, // comment 2 - \\ d_name: u8, - \\}; - \\ - ); -} - -test "zig fmt: same-line comment after switch prong" { - try testCanonical( - \\test "" { - \\ switch (err) { - \\ error.PathAlreadyExists => {}, // comment 2 - \\ else => return err, // comment 1 - \\ } - \\} - \\ - ); -} - -test "zig fmt: same-line comment after non-block if expression" { - try testCanonical( - \\comptime { - \\ if (sr > n_uword_bits - 1) // d > r - \\ return 0; - \\} - \\ - ); -} - -test "zig fmt: same-line comment on comptime expression" { - try testCanonical( - \\test "" { - \\ comptime assert(@typeInfo(T) == .Int); // must pass an integer to absInt - \\} - \\ - ); -} - -test "zig fmt: switch with empty body" { - try testCanonical( - \\test "" { - \\ foo() catch |err| switch (err) {}; - \\} - \\ - ); -} - -test "zig fmt: line comments in struct initializer" { - try testCanonical( - \\fn foo() void { - \\ return Self{ - \\ .a = b, - \\ - \\ // Initialize these two fields to buffer_size so that - \\ // in `readFn` we treat the state as being able to read - \\ .start_index = buffer_size, - \\ .end_index = buffer_size, - \\ - \\ // middle - \\ - \\ .a = b, - \\ - \\ // end - \\ }; - \\} - \\ - ); -} - -test "zig fmt: first line comment in struct initializer" { - try testCanonical( - \\pub fn acquire(self: *Self) HeldLock { - \\ return HeldLock{ - \\ // guaranteed allocation elision - \\ .held = self.lock.acquire(), - \\ .value = &self.private_data, - \\ }; - \\} - \\ - ); -} - -test "zig fmt: doc comments before struct field" { - try testCanonical( - \\pub const Allocator = struct { - \\ /// Allocate byte_count bytes and return them in a slice, with the - \\ /// slice's pointer aligned at least to alignment bytes. - \\ allocFn: fn () void, - \\}; - \\ - ); -} - -test "zig fmt: error set declaration" { - try testCanonical( - \\const E = error{ - \\ A, - \\ B, - \\ - \\ C, - \\}; - \\ - \\const Error = error{ - \\ /// no more memory - \\ OutOfMemory, - \\}; - \\ - \\const Error = error{ - \\ /// no more memory - \\ OutOfMemory, - \\ - \\ /// another - \\ Another, - \\ - \\ // end - \\}; - \\ - \\const Error = error{OutOfMemory}; - \\const Error = error{}; - \\ - \\const Error = error{ OutOfMemory, OutOfTime }; - \\ - ); -} - -test "zig fmt: union(enum(u32)) with assigned enum values" { - try testCanonical( - \\const MultipleChoice = union(enum(u32)) { - \\ A = 20, - \\ B = 40, - \\ C = 60, - \\ D = 1000, - \\}; - \\ - ); -} - -test "zig fmt: resume from suspend block" { - try testCanonical( - \\fn foo() void { - \\ suspend { - \\ resume @frame(); - \\ } - \\} - \\ - ); -} - -test "zig fmt: comments before error set decl" { - try testCanonical( - \\const UnexpectedError = error{ - \\ /// The Operating System returned an undocumented error code. - \\ Unexpected, - \\ // another - \\ Another, - \\ - \\ // in between - \\ - \\ // at end - \\}; - \\ - ); -} - -test "zig fmt: comments before switch prong" { - try testCanonical( - \\test "" { - \\ switch (err) { - \\ error.PathAlreadyExists => continue, - \\ - \\ // comment 1 - \\ - \\ // comment 2 - \\ else => return err, - \\ // at end - \\ } - \\} - \\ - ); -} - -test "zig fmt: comments before var decl in struct" { - try testCanonical( - \\pub const vfs_cap_data = extern struct { - \\ // All of these are mandated as little endian - \\ // when on disk. - \\ const Data = struct { - \\ permitted: u32, - \\ inheritable: u32, - \\ }; - \\ - \\ // in between - \\ - \\ /// All of these are mandated as little endian - \\ /// when on disk. - \\ const Data = struct { - \\ permitted: u32, - \\ inheritable: u32, - \\ }; - \\ - \\ // at end - \\}; - \\ - ); -} - -test "zig fmt: array literal with 1 item on 1 line" { - try testCanonical( - \\var s = []const u64{0} ** 25; - \\ - ); -} - -test "zig fmt: comments before global variables" { - try testCanonical( - \\/// Foo copies keys and values before they go into the map, and - \\/// frees them when they get removed. - \\pub const Foo = struct {}; - \\ - ); -} - -test "zig fmt: comments in statements" { - try testCanonical( - \\test "std" { - \\ // statement comment - \\ _ = @import("foo/bar.zig"); - \\ - \\ // middle - \\ // middle2 - \\ - \\ // end - \\} - \\ - ); -} - -test "zig fmt: comments before test decl" { - try testCanonical( - \\/// top level doc comment - \\test "hi" {} - \\ - \\// top level normal comment - \\test "hi" {} - \\ - \\// middle - \\ - \\// end - \\ - ); -} - -test "zig fmt: preserve spacing" { - try testCanonical( - \\const std = @import("std"); - \\ - \\pub fn main() !void { - \\ var stdout_file = std.io.getStdOut; - \\ var stdout_file = std.io.getStdOut; - \\ - \\ var stdout_file = std.io.getStdOut; - \\ var stdout_file = std.io.getStdOut; - \\} - \\ - ); -} - -test "zig fmt: return types" { - try testCanonical( - \\pub fn main() !void {} - \\pub fn main() anytype {} - \\pub fn main() i32 {} - \\ - ); -} - -test "zig fmt: imports" { - try testCanonical( - \\const std = @import("std"); - \\const std = @import(); - \\ - ); -} - -test "zig fmt: global declarations" { - try testCanonical( - \\const a = b; - \\pub const a = b; - \\var a = b; - \\pub var a = b; - \\const a: i32 = b; - \\pub const a: i32 = b; - \\var a: i32 = b; - \\pub var a: i32 = b; - \\extern const a: i32 = b; - \\pub extern const a: i32 = b; - \\extern var a: i32 = b; - \\pub extern var a: i32 = b; - \\extern "a" const a: i32 = b; - \\pub extern "a" const a: i32 = b; - \\extern "a" var a: i32 = b; - \\pub extern "a" var a: i32 = b; - \\ - ); -} - -test "zig fmt: extern declaration" { - try testCanonical( - \\extern var foo: c_int; - \\ - ); -} - -test "zig fmt: alignment" { - try testCanonical( - \\var foo: c_int align(1); - \\ - ); -} - -test "zig fmt: C main" { - try testCanonical( - \\fn main(argc: c_int, argv: **u8) c_int { - \\ const a = b; - \\} - \\ - ); -} - -test "zig fmt: return" { - try testCanonical( - \\fn foo(argc: c_int, argv: **u8) c_int { - \\ return 0; - \\} - \\ - \\fn bar() void { - \\ return; - \\} - \\ - ); -} - -test "zig fmt: pointer attributes" { - try testCanonical( - \\extern fn f1(s: *align(*u8) u8) c_int; - \\extern fn f2(s: **align(1) *const *volatile u8) c_int; - \\extern fn f3(s: *align(1) const *align(1) volatile *const volatile u8) c_int; - \\extern fn f4(s: *align(1) const volatile u8) c_int; - \\extern fn f5(s: [*:0]align(1) const volatile u8) c_int; - \\ - ); -} - -test "zig fmt: slice attributes" { - try testCanonical( - \\extern fn f1(s: *align(*u8) u8) c_int; - \\extern fn f2(s: **align(1) *const *volatile u8) c_int; - \\extern fn f3(s: *align(1) const *align(1) volatile *const volatile u8) c_int; - \\extern fn f4(s: *align(1) const volatile u8) c_int; - \\extern fn f5(s: [*:0]align(1) const volatile u8) c_int; - \\ - ); -} - -test "zig fmt: test declaration" { - try testCanonical( - \\test "test name" { - \\ const a = 1; - \\ var b = 1; - \\} - \\ - ); -} - -test "zig fmt: infix operators" { - try testCanonical( - \\test "infix operators" { - \\ var i = undefined; - \\ i = 2; - \\ i *= 2; - \\ i |= 2; - \\ i ^= 2; - \\ i <<= 2; - \\ i >>= 2; - \\ i &= 2; - \\ i *= 2; - \\ i *%= 2; - \\ i -= 2; - \\ i -%= 2; - \\ i += 2; - \\ i +%= 2; - \\ i /= 2; - \\ i %= 2; - \\ _ = i == i; - \\ _ = i != i; - \\ _ = i != i; - \\ _ = i.i; - \\ _ = i || i; - \\ _ = 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" { - \\ a!b(); - \\ (a!b)(); - \\ !a!b; - \\ !(a!b); - \\ !a{}; - \\ !(a{}); - \\ a + b{}; - \\ (a + b){}; - \\ a << b + c; - \\ (a << b) + c; - \\ a & b << c; - \\ (a & b) << c; - \\ a ^ b & c; - \\ (a ^ b) & c; - \\ a | b ^ c; - \\ (a | b) ^ c; - \\ a == b | c; - \\ (a == b) | c; - \\ a and b == c; - \\ (a and b) == c; - \\ a or b and c; - \\ (a or b) and c; - \\ (a or b) and c; - \\} - \\ - ); -} - -test "zig fmt: prefix operators" { - try testCanonical( - \\test "prefix operators" { - \\ try return --%~!&0; - \\} - \\ - ); -} - -test "zig fmt: call expression" { - try testCanonical( - \\test "test calls" { - \\ a(); - \\ a(1); - \\ a(1, 2); - \\ a(1, 2) + a(1, 2); - \\} - \\ - ); -} - -test "zig fmt: anytype type" { - try testCanonical( - \\fn print(args: anytype) anytype {} - \\ - ); -} - -test "zig fmt: functions" { - try testCanonical( - \\extern fn puts(s: *const u8) c_int; - \\extern "c" fn puts(s: *const u8) c_int; - \\export fn puts(s: *const u8) c_int; - \\inline fn puts(s: *const u8) c_int; - \\noinline fn puts(s: *const u8) c_int; - \\pub extern fn puts(s: *const u8) c_int; - \\pub extern "c" fn puts(s: *const u8) c_int; - \\pub export fn puts(s: *const u8) c_int; - \\pub inline fn puts(s: *const u8) c_int; - \\pub noinline fn puts(s: *const u8) c_int; - \\pub extern fn puts(s: *const u8) align(2 + 2) c_int; - \\pub extern "c" fn puts(s: *const u8) align(2 + 2) c_int; - \\pub export fn puts(s: *const u8) align(2 + 2) c_int; - \\pub inline fn puts(s: *const u8) align(2 + 2) c_int; - \\pub noinline fn puts(s: *const u8) align(2 + 2) c_int; - \\ - ); -} - -test "zig fmt: multiline string" { - try testCanonical( - \\test "" { - \\ const s1 = - \\ \\one - \\ \\two) - \\ \\three - \\ ; - \\ const s3 = // hi - \\ \\one - \\ \\two) - \\ \\three - \\ ; - \\} - \\ - ); -} - -test "zig fmt: values" { - try testCanonical( - \\test "values" { - \\ 1; - \\ 1.0; - \\ "string"; - \\ 'c'; - \\ true; - \\ false; - \\ null; - \\ undefined; - \\ anyerror; - \\ this; - \\ unreachable; - \\} - \\ - ); -} - -test "zig fmt: indexing" { - try testCanonical( - \\test "test index" { - \\ a[0]; - \\ a[0 + 5]; - \\ a[0..]; - \\ a[0..5]; - \\ a[a[0]]; - \\ a[a[0..]]; - \\ a[a[0..5]]; - \\ a[a[0]..]; - \\ a[a[0..5]..]; - \\ a[a[0]..a[0]]; - \\ a[a[0..5]..a[0]]; - \\ a[a[0..5]..a[0..5]]; - \\} - \\ - ); -} - -test "zig fmt: struct declaration" { - try testCanonical( - \\const S = struct { - \\ const Self = @This(); - \\ f1: u8, - \\ f3: u8, - \\ - \\ f2: u8, - \\ - \\ fn method(self: *Self) Self { - \\ return self.*; - \\ } - \\}; - \\ - \\const Ps = packed struct { - \\ a: u8, - \\ b: u8, - \\ - \\ c: u8, - \\}; - \\ - \\const Es = extern struct { - \\ a: u8, - \\ b: u8, - \\ - \\ c: u8, - \\}; - \\ - ); -} - -test "zig fmt: enum declaration" { - try testCanonical( - \\const E = enum { - \\ Ok, - \\ SomethingElse = 0, - \\}; - \\ - \\const E2 = enum(u8) { - \\ Ok, - \\ SomethingElse = 255, - \\ SomethingThird, - \\}; - \\ - \\const Ee = extern enum { - \\ Ok, - \\ SomethingElse, - \\ SomethingThird, - \\}; - \\ - \\const Ep = packed enum { - \\ Ok, - \\ SomethingElse, - \\ SomethingThird, - \\}; - \\ - ); -} - -test "zig fmt: union declaration" { - try testCanonical( - \\const U = union { - \\ Int: u8, - \\ Float: f32, - \\ None, - \\ Bool: bool, - \\}; - \\ - \\const Ue = union(enum) { - \\ Int: u8, - \\ Float: f32, - \\ None, - \\ Bool: bool, - \\}; - \\ - \\const E = enum { - \\ Int, - \\ Float, - \\ None, - \\ Bool, - \\}; - \\ - \\const Ue2 = union(E) { - \\ Int: u8, - \\ Float: f32, - \\ None, - \\ Bool: bool, - \\}; - \\ - \\const Eu = extern union { - \\ Int: u8, - \\ Float: f32, - \\ None, - \\ Bool: bool, - \\}; - \\ - ); -} - -test "zig fmt: arrays" { - try testCanonical( - \\test "test array" { - \\ const a: [2]u8 = [2]u8{ - \\ 1, - \\ 2, - \\ }; - \\ const a: [2]u8 = []u8{ - \\ 1, - \\ 2, - \\ }; - \\ const a: [0]u8 = []u8{}; - \\ const x: [4:0]u8 = undefined; - \\} - \\ - ); -} - -test "zig fmt: container initializers" { - try testCanonical( - \\const a0 = []u8{}; - \\const a1 = []u8{1}; - \\const a2 = []u8{ - \\ 1, - \\ 2, - \\ 3, - \\ 4, - \\}; - \\const s0 = S{}; - \\const s1 = S{ .a = 1 }; - \\const s2 = S{ - \\ .a = 1, - \\ .b = 2, - \\}; - \\ - ); -} - -test "zig fmt: catch" { - try testCanonical( - \\test "catch" { - \\ const a: anyerror!u8 = 0; - \\ _ = a catch return; - \\ _ = a catch |err| return; - \\} - \\ - ); -} - -test "zig fmt: blocks" { - try testCanonical( - \\test "blocks" { - \\ { - \\ const a = 0; - \\ const b = 0; - \\ } - \\ - \\ blk: { - \\ const a = 0; - \\ const b = 0; - \\ } - \\ - \\ const r = blk: { - \\ const a = 0; - \\ const b = 0; - \\ }; - \\} - \\ - ); -} - -test "zig fmt: switch" { - try testCanonical( - \\test "switch" { - \\ switch (0) { - \\ 0 => {}, - \\ 1 => unreachable, - \\ 2, 3 => {}, - \\ 4...7 => {}, - \\ 1 + 4 * 3 + 22 => {}, - \\ else => { - \\ const a = 1; - \\ const b = a; - \\ }, - \\ } - \\ - \\ const res = switch (0) { - \\ 0 => 0, - \\ 1 => 2, - \\ 1 => a = 4, - \\ else => 4, - \\ }; - \\ - \\ const Union = union(enum) { - \\ Int: i64, - \\ Float: f64, - \\ }; - \\ - \\ switch (u) { - \\ Union.Int => |int| {}, - \\ Union.Float => |*float| unreachable, - \\ } - \\} - \\ - ); -} - -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; - \\ } - \\ - \\ var a: ?u8 = 2; - \\ while (a) |v| : (a = null) { - \\ 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) |v, i| { - \\ continue; - \\ } - \\ - \\ for (a) |v, i| - \\ continue; - \\ - \\ for (a) |b| switch (b) { - \\ c => {}, - \\ d => {}, - \\ }; - \\ - \\ for (a) |b| - \\ switch (b) { - \\ c => {}, - \\ d => {}, - \\ }; - \\ - \\ const res = for (a) |v, i| { - \\ break v; - \\ } else { - \\ unreachable; - \\ }; - \\ - \\ var num: usize = 0; - \\ inline for (a) |v, i| { - \\ num += v; - \\ num += i; - \\ } - \\} - \\ - ); - - try testTransform( - \\test "fix for" { - \\ for (a) |x| - \\ f(x) else continue; - \\} - \\ - , - \\test "fix for" { - \\ for (a) |x| - \\ f(x) - \\ else continue; - \\} - \\ - ); -} - -test "zig fmt: if" { - try testCanonical( - \\test "if" { - \\ if (10 < 0) { - \\ unreachable; - \\ } - \\ - \\ if (10 < 0) unreachable; - \\ - \\ if (10 < 0) { - \\ unreachable; - \\ } else { - \\ const a = 20; - \\ } - \\ - \\ if (10 < 0) { - \\ unreachable; - \\ } else if (5 < 0) { - \\ unreachable; - \\ } else { - \\ const a = 20; - \\ } - \\ - \\ const is_world_broken = if (10 < 0) true else false; - \\ const some_number = 1 + if (10 < 0) 2 else 3; - \\ - \\ const a: ?u8 = 10; - \\ const b: ?u8 = null; - \\ if (a) |v| { - \\ const some = v; - \\ } else if (b) |*v| { - \\ unreachable; - \\ } else { - \\ const some = 10; - \\ } - \\ - \\ const non_null_a = if (a) |v| v else 0; - \\ - \\ const a_err: anyerror!u8 = 0; - \\ if (a_err) |v| { - \\ const p = v; - \\ } else |err| { - \\ unreachable; - \\ } - \\} - \\ - ); -} - -test "zig fmt: defer" { - try testCanonical( - \\test "defer" { - \\ var i: usize = 0; - \\ defer i = 1; - \\ defer { - \\ i += 2; - \\ i *= i; - \\ } - \\ - \\ errdefer i += 3; - \\ errdefer { - \\ i += 2; - \\ i /= i; - \\ } - \\} - \\ - ); -} - -test "zig fmt: comptime" { - try testCanonical( - \\fn a() u8 { - \\ return 5; - \\} - \\ - \\fn b(comptime i: u8) u8 { - \\ return i; - \\} - \\ - \\const av = comptime a(); - \\const av2 = comptime blk: { - \\ var res = a(); - \\ res *= b(2); - \\ break :blk res; - \\}; - \\ - \\comptime { - \\ _ = a(); - \\} - \\ - \\test "comptime" { - \\ const av3 = comptime a(); - \\ const av4 = comptime blk: { - \\ var res = a(); - \\ res *= a(); - \\ break :blk res; - \\ }; - \\ - \\ comptime var i = 0; - \\ comptime { - \\ i = a(); - \\ i += b(i); - \\ } - \\} - \\ - ); -} - -test "zig fmt: fn type" { - try testCanonical( - \\fn a(i: u8) u8 { - \\ return i + 1; - \\} - \\ - \\const a: fn (u8) u8 = undefined; - \\const b: fn (u8) callconv(.Naked) u8 = undefined; - \\const ap: fn (u8) u8 = a; - \\ - ); -} - -test "zig fmt: inline asm" { - try testCanonical( - \\pub fn syscall1(number: usize, arg1: usize) usize { - \\ return asm volatile ("syscall" - \\ : [ret] "={rax}" (-> usize) - \\ : [number] "{rax}" (number), - \\ [arg1] "{rdi}" (arg1) - \\ : "rcx", "r11" - \\ ); - \\} - \\ - ); -} - -test "zig fmt: async functions" { - try testCanonical( - \\fn simpleAsyncFn() void { - \\ const a = async a.b(); - \\ x += 1; - \\ suspend; - \\ x += 1; - \\ suspend; - \\ const p: anyframe->void = async simpleAsyncFn() catch unreachable; - \\ await p; - \\} - \\ - \\test "suspend, resume, await" { - \\ const p: anyframe = async testAsyncSeq(); - \\ resume p; - \\ await p; - \\} - \\ - ); -} - -test "zig fmt: nosuspend" { - try testCanonical( - \\const a = nosuspend foo(); - \\ - ); -} - -test "zig fmt: Block after if" { - try testCanonical( - \\test "Block after if" { - \\ if (true) { - \\ const a = 0; - \\ } - \\ - \\ { - \\ const a = 0; - \\ } - \\} - \\ - ); -} - -test "zig fmt: use" { - try testCanonical( - \\usingnamespace @import("std"); - \\pub usingnamespace @import("std"); - \\ - ); -} - -test "zig fmt: string identifier" { - try testCanonical( - \\const @"a b" = @"c d".@"e f"; - \\fn @"g h"() void {} - \\ - ); -} - -test "zig fmt: error return" { - try testCanonical( - \\fn err() anyerror { - \\ call(); - \\ return error.InvalidArgs; - \\} - \\ - ); -} - -test "zig fmt: comptime block in container" { - try testCanonical( - \\pub fn container() type { - \\ return struct { - \\ comptime { - \\ if (false) { - \\ unreachable; - \\ } - \\ } - \\ }; - \\} - \\ - ); -} - -test "zig fmt: inline asm parameter alignment" { - try testCanonical( - \\pub fn main() void { - \\ asm volatile ( - \\ \\ foo - \\ \\ bar - \\ ); - \\ asm volatile ( - \\ \\ foo - \\ \\ bar - \\ : [_] "" (-> usize), - \\ [_] "" (-> usize) - \\ ); - \\ asm volatile ( - \\ \\ foo - \\ \\ bar - \\ : - \\ : [_] "" (0), - \\ [_] "" (0) - \\ ); - \\ asm volatile ( - \\ \\ foo - \\ \\ bar - \\ : - \\ : - \\ : "", "" - \\ ); - \\ asm volatile ( - \\ \\ foo - \\ \\ bar - \\ : [_] "" (-> usize), - \\ [_] "" (-> usize) - \\ : [_] "" (0), - \\ [_] "" (0) - \\ : "", "" - \\ ); - \\} - \\ - ); -} - -test "zig fmt: multiline string in array" { - try testCanonical( - \\const Foo = [][]const u8{ - \\ \\aaa - \\ , - \\ \\bbb - \\}; - \\ - \\fn bar() void { - \\ const Foo = [][]const u8{ - \\ \\aaa - \\ , - \\ \\bbb - \\ }; - \\ const Bar = [][]const u8{ // comment here - \\ \\aaa - \\ \\ - \\ , // and another comment can go here - \\ \\bbb - \\ }; - \\} - \\ - ); -} - -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 - \\ - ); -} - -test "zig fmt: comment after empty comment" { - try testTransform( - \\const x = true; // - \\// - \\// - \\//a - \\ - , - \\const x = true; - \\//a - \\ - ); -} - -test "zig fmt: line comment in array" { - try testTransform( - \\test "a" { - \\ var arr = [_]u32{ - \\ 0 - \\ // 1, - \\ // 2, - \\ }; - \\} - \\ - , - \\test "a" { - \\ var arr = [_]u32{ - \\ 0, // 1, - \\ // 2, - \\ }; - \\} - \\ - ); - try testCanonical( - \\test "a" { - \\ var arr = [_]u32{ - \\ 0, - \\ // 1, - \\ // 2, - \\ }; - \\} - \\ - ); -} - -test "zig fmt: comment after params" { - try testTransform( - \\fn a( - \\ b: u32 - \\ // c: u32, - \\ // d: u32, - \\) void {} - \\ - , - \\fn a( - \\ b: u32, // c: u32, - \\ // d: u32, - \\) void {} - \\ - ); - try testCanonical( - \\fn a( - \\ b: u32, - \\ // c: u32, - \\ // d: u32, - \\) void {} - \\ - ); -} - -test "zig fmt: comment in array initializer/access" { - try testCanonical( - \\test "a" { - \\ var a = x{ //aa - \\ //bb - \\ }; - \\ var a = []x{ //aa - \\ //bb - \\ }; - \\ var b = [ //aa - \\ _ - \\ ]x{ //aa - \\ //bb - \\ 9, - \\ }; - \\ var c = b[ //aa - \\ 0 - \\ ]; - \\ var d = [_ - \\ //aa - \\ ]x{ //aa - \\ //bb - \\ 9, - \\ }; - \\ var e = d[0 - \\ //aa - \\ ]; - \\} - \\ - ); -} - -test "zig fmt: comments at several places in struct init" { - try testTransform( - \\var bar = Bar{ - \\ .x = 10, // test - \\ .y = "test" - \\ // test - \\}; - \\ - , - \\var bar = Bar{ - \\ .x = 10, // test - \\ .y = "test", // test - \\}; - \\ - ); - - try testCanonical( - \\var bar = Bar{ // test - \\ .x = 10, // test - \\ .y = "test", - \\ // test - \\}; - \\ - ); -} - -test "zig fmt: top level doc comments" { - try testCanonical( - \\//! tld 1 - \\//! tld 2 - \\//! tld 3 - \\ - \\// comment - \\ - \\/// A doc - \\const A = struct { - \\ //! A tld 1 - \\ //! A tld 2 - \\ //! A tld 3 - \\}; - \\ - \\/// B doc - \\const B = struct { - \\ //! B tld 1 - \\ //! B tld 2 - \\ //! B tld 3 - \\ - \\ /// b doc - \\ b: u32, - \\}; - \\ - \\/// C doc - \\const C = struct { - \\ //! C tld 1 - \\ //! C tld 2 - \\ //! C tld 3 - \\ - \\ /// c1 doc - \\ c1: u32, - \\ - \\ //! C tld 4 - \\ //! C tld 5 - \\ //! C tld 6 - \\ - \\ /// c2 doc - \\ c2: u32, - \\}; - \\ - ); - try testCanonical( - \\//! Top-level documentation. - \\ - \\/// This is A - \\pub const A = usize; - \\ - ); - try testCanonical( - \\//! Nothing here - \\ - ); -} - -test "zig fmt: extern without container keyword returns error" { - try testError( - \\const container = extern {}; - \\ - , &[_]Error{ - .ExpectedExpr, - .ExpectedVarDeclOrFn, - }); -} - -test "zig fmt: integer literals with underscore separators" { - try testTransform( - \\const - \\ x = - \\ 1_234_567 - \\ +(0b0_1-0o7_0+0xff_FF ) + 0_0; - , - \\const x = - \\ 1_234_567 + (0b0_1 - 0o7_0 + 0xff_FF) + 0_0; - \\ - ); -} - -test "zig fmt: hex literals with underscore separators" { - try testTransform( - \\pub fn orMask(a: [ 1_000 ]u64, b: [ 1_000] u64) [1_000]u64 { - \\ var c: [1_000]u64 = [1]u64{ 0xFFFF_FFFF_FFFF_FFFF}**1_000; - \\ for (c [ 0_0 .. ]) |_, i| { - \\ c[i] = (a[i] | b[i]) & 0xCCAA_CCAA_CCAA_CCAA; - \\ } - \\ return c; - \\} - \\ - \\ - , - \\pub fn orMask(a: [1_000]u64, b: [1_000]u64) [1_000]u64 { - \\ var c: [1_000]u64 = [1]u64{0xFFFF_FFFF_FFFF_FFFF} ** 1_000; - \\ for (c[0_0..]) |_, i| { - \\ c[i] = (a[i] | b[i]) & 0xCCAA_CCAA_CCAA_CCAA; - \\ } - \\ return c; - \\} - \\ - ); -} - -test "zig fmt: decimal float literals with underscore separators" { - try testTransform( - \\pub fn main() void { - \\ const a:f64=(10.0e-0+(10.e+0))+10_00.00_00e-2+00_00.00_10e+4; - \\ const b:f64=010.0--0_10.+0_1_0.0_0+1e2; - \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b }); - \\} - , - \\pub fn main() void { - \\ const a: f64 = (10.0e-0 + (10.e+0)) + 10_00.00_00e-2 + 00_00.00_10e+4; - \\ const b: f64 = 010.0 - -0_10. + 0_1_0.0_0 + 1e2; - \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b }); - \\} - \\ - ); -} - -test "zig fmt: hexadeciaml float literals with underscore separators" { - try testTransform( - \\pub fn main() void { - \\ const a: f64 = (0x10.0p-0+(0x10.p+0))+0x10_00.00_00p-8+0x00_00.00_10p+16; - \\ const b: f64 = 0x0010.0--0x00_10.+0x10.00+0x1p4; - \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b }); - \\} - , - \\pub fn main() void { - \\ const a: f64 = (0x10.0p-0 + (0x10.p+0)) + 0x10_00.00_00p-8 + 0x00_00.00_10p+16; - \\ const b: f64 = 0x0010.0 - -0x00_10. + 0x10.00 + 0x1p4; - \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b }); - \\} - \\ - ); -} - -test "zig fmt: convert async fn into callconv(.Async)" { - try testTransform( - \\async fn foo() void {} - , - \\fn foo() callconv(.Async) void {} - \\ - ); -} - -test "zig fmt: convert extern fn proto into callconv(.C)" { - try testTransform( - \\extern fn foo0() void {} - \\const foo1 = extern fn () void; - , - \\extern fn foo0() void {} - \\const foo1 = fn () callconv(.C) void; - \\ - ); -} - -test "zig fmt: C var args" { - try testCanonical( - \\pub extern "c" fn printf(format: [*:0]const u8, ...) c_int; - \\ - ); -} - -test "zig fmt: Only indent multiline string literals in function calls" { - try testCanonical( - \\test "zig fmt:" { - \\ try testTransform( - \\ \\const X = struct { - \\ \\ foo: i32, bar: i8 }; - \\ , - \\ \\const X = struct { - \\ \\ foo: i32, bar: i8 - \\ \\}; - \\ \\ - \\ ); - \\} - \\ - ); -} - -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 { - \\ if (cwd().symLink(existing_path, new_path, .{})) { - \\ return; - \\ } - \\} - \\ - ); -} - -test "zig fmt: comments in ternary ifs" { - try testCanonical( - \\const x = if (true) { - \\ 1; - \\} else if (false) - \\ // Comment - \\ 0; - \\const y = if (true) - \\ // Comment - \\ 1 - \\else - \\ 0; - \\ - \\pub extern "c" fn printf(format: [*:0]const u8, ...) c_int; - \\ - ); -} - -test "zig fmt: test comments in field access chain" { - try testCanonical( - \\pub const str = struct { - \\ pub const Thing = more.more // - \\ .more() // - \\ .more().more() // - \\ .more() // - \\ // .more() // - \\ .more() // - \\ .more(); - \\ data: Data, - \\}; - \\ - \\pub const str = struct { - \\ pub const Thing = more.more // - \\ .more() // - \\ // .more() // - \\ // .more() // - \\ // .more() // - \\ .more() // - \\ .more(); - \\ data: Data, - \\}; - \\ - \\pub const str = struct { - \\ pub const Thing = more // - \\ .more // - \\ .more() // - \\ .more(); - \\ data: Data, - \\}; - \\ - ); -} - -test "zig fmt: Indent comma correctly after multiline string literals in arg list (trailing comma)" { - try testCanonical( - \\fn foo() void { - \\ z.display_message_dialog( - \\ *const [323:0]u8, - \\ \\Message Text - \\ \\------------ - \\ \\xxxxxxxxxxxx - \\ \\xxxxxxxxxxxx - \\ , - \\ g.GtkMessageType.GTK_MESSAGE_WARNING, - \\ null, - \\ ); - \\ - \\ z.display_message_dialog(*const [323:0]u8, - \\ \\Message Text - \\ \\------------ - \\ \\xxxxxxxxxxxx - \\ \\xxxxxxxxxxxx - \\ , g.GtkMessageType.GTK_MESSAGE_WARNING, null); - \\} - \\ - ); -} - -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: " { - try testCanonical( - \\pub fn sendViewTags(self: Self) void { - \\ var it = ViewStack(View).iterator(self.output.views.first, std.math.maxInt(u32)); - \\ while (it.next()) |node| - \\ view_tags.append(node.view.current_tags) catch { - \\ c.wl_resource_post_no_memory(self.wl_resource); - \\ log.crit(.river_status, "out of memory", .{}); - \\ return; - \\ }; - \\} - \\ - ); -} - -test "zig fmt: allow trailing line comments to do manual array formatting" { - try testCanonical( - \\fn foo() void { - \\ self.code.appendSliceAssumeCapacity(&[_]u8{ - \\ 0x55, // push rbp - \\ 0x48, 0x89, 0xe5, // mov rbp, rsp - \\ 0x48, 0x81, 0xec, // sub rsp, imm32 (with reloc) - \\ }); - \\ - \\ di_buf.appendAssumeCapacity(&[_]u8{ - \\ 1, DW.TAG_compile_unit, DW.CHILDREN_no, // header - \\ DW.AT_stmt_list, DW_FORM_data4, // form value pairs - \\ DW.AT_low_pc, DW_FORM_addr, - \\ DW.AT_high_pc, DW_FORM_addr, - \\ DW.AT_name, DW_FORM_strp, - \\ DW.AT_comp_dir, DW_FORM_strp, - \\ DW.AT_producer, DW_FORM_strp, - \\ DW.AT_language, DW_FORM_data2, - \\ 0, 0, // sentinel - \\ }); - \\ - \\ self.code.appendSliceAssumeCapacity(&[_]u8{ - \\ 0x55, // push rbp - \\ 0x48, 0x89, 0xe5, // mov rbp, rsp - \\ // How do we handle this? - \\ //0x48, 0x81, 0xec, // sub rsp, imm32 (with reloc) - \\ // Here's a blank line, should that be allowed? - \\ - \\ 0x48, 0x89, 0xe5, - \\ 0x33, 0x45, - \\ // Now the comment breaks a single line -- how do we handle this? - \\ 0x88, - \\ }); - \\} - \\ - ); -} - -test "zig fmt: multiline string literals should play nice with array initializers" { - try testCanonical( - \\fn main() void { - \\ var a = .{.{.{.{.{.{.{.{ - \\ 0, - \\ }}}}}}}}; - \\ myFunc(.{ - \\ "aaaaaaa", "bbbbbb", "ccccc", - \\ "dddd", ("eee"), ("fff"), - \\ ("gggg"), - \\ // Line comment - \\ \\Multiline String Literals can be quite long - \\ , - \\ \\Multiline String Literals can be quite long - \\ \\Multiline String Literals can be quite long - \\ , - \\ \\Multiline String Literals can be quite long - \\ \\Multiline String Literals can be quite long - \\ \\Multiline String Literals can be quite long - \\ \\Multiline String Literals can be quite long - \\ , - \\ ( - \\ \\Multiline String Literals can be quite long - \\ ), - \\ .{ - \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - \\ }, - \\ .{( - \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - \\ )}, - \\ .{ - \\ "xxxxxxx", "xxx", - \\ ( - \\ \\ xxx - \\ ), - \\ "xxx", "xxx", - \\ }, - \\ .{ "xxxxxxx", "xxx", "xxx", "xxx" }, .{ "xxxxxxx", "xxx", "xxx", "xxx" }, - \\ "aaaaaaa", "bbbbbb", "ccccc", // - - \\ "dddd", ("eee"), ("fff"), - \\ .{ - \\ "xxx", "xxx", - \\ ( - \\ \\ xxx - \\ ), - \\ "xxxxxxxxxxxxxx", "xxx", - \\ }, - \\ .{ - \\ ( - \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - \\ ), - \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - \\ }, - \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - \\ }); - \\} - \\ - ); -} - -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 { - \\ cases.add( // fixed bug #2032 - \\ "compile diagnostic string for top level decl type", - \\ \\export fn entry() void { - \\ \\ var foo: u32 = @This(){}; - \\ \\} - \\ , &[_][]const u8{ - \\ "tmp.zig:2:27: error: type 'u32' does not support array initialization", - \\ }); - \\ @compileError( - \\ \\ unknown-length pointers and C pointers cannot be hashed deeply. - \\ \\ Consider providing your own hash function. - \\ \\ unknown-length pointers and C pointers cannot be hashed deeply. - \\ \\ Consider providing your own hash function. - \\ ); - \\ return @intCast(i1, doMemCheckClientRequestExpr(0, // default return - \\ .MakeMemUndefined, @ptrToInt(qzz.ptr), qzz.len, 0, 0, 0)); - \\} - \\ - \\// This looks like garbage don't do this - \\const rparen = tree.prevToken( - \\// the first token for the annotation expressions is the left - \\// parenthesis, hence the need for two prevToken - \\ if (fn_proto.getAlignExpr()) |align_expr| - \\ tree.prevToken(tree.prevToken(align_expr.firstToken())) - \\else if (fn_proto.getSectionExpr()) |section_expr| - \\ tree.prevToken(tree.prevToken(section_expr.firstToken())) - \\else if (fn_proto.getCallconvExpr()) |callconv_expr| - \\ tree.prevToken(tree.prevToken(callconv_expr.firstToken())) - \\else switch (fn_proto.return_type) { - \\ .Explicit => |node| node.firstToken(), - \\ .InferErrorSet => |node| tree.prevToken(node.firstToken()), - \\ .Invalid => unreachable, - \\}); - \\ - ); -} - -test "zig fmt: single argument trailing commas in @builtins()" { - try testCanonical( - \\pub fn foo(qzz: []u8) i1 { - \\ @panic( - \\ foo, - \\ ); - \\ panic( - \\ foo, - \\ ); - \\ @panic( - \\ foo, - \\ bar, - \\ ); - \\} - \\ - ); -} - -test "zig fmt: trailing comma should force multiline 1 column" { - try testTransform( - \\pub const UUID_NULL: uuid_t = [16]u8{0,0,0,0,}; - \\ - , - \\pub const UUID_NULL: uuid_t = [16]u8{ - \\ 0, - \\ 0, - \\ 0, - \\ 0, - \\}; - \\ - ); -} - -test "zig fmt: function params should align nicely" { - try testCanonical( - \\pub fn foo() void { - \\ cases.addRuntimeSafety("slicing operator with sentinel", - \\ \\const std = @import("std"); - \\ ++ check_panic_msg ++ - \\ \\pub fn main() void { - \\ \\ var buf = [4]u8{'a','b','c',0}; - \\ \\ const slice = buf[0..:0]; - \\ \\} - \\ ); - \\} - \\ - ); -} +test "zig fmt: simple top level comptime block" { + try testCanonical( + \\comptime {} + \\ + ); +} + +//test "recovery: top level" { +// try testError( +// \\test "" {inline} +// \\test "" {inline} +// , &[_]Error{ +// .ExpectedInlinable, +// .ExpectedInlinable, +// }); +//} +// +//test "recovery: block statements" { +// try testError( +// \\test "" { +// \\ foo + +; +// \\ inline; +// \\} +// , &[_]Error{ +// .InvalidToken, +// .ExpectedInlinable, +// }); +//} +// +//test "recovery: missing comma" { +// try testError( +// \\test "" { +// \\ switch (foo) { +// \\ 2 => {} +// \\ 3 => {} +// \\ else => { +// \\ foo && bar +; +// \\ } +// \\ } +// \\} +// , &[_]Error{ +// .ExpectedToken, +// .ExpectedToken, +// .InvalidAnd, +// .InvalidToken, +// }); +//} +// +//test "recovery: extra qualifier" { +// try testError( +// \\const a: *const const u8; +// \\test "" +// , &[_]Error{ +// .ExtraConstQualifier, +// .ExpectedLBrace, +// }); +//} +// +//test "recovery: missing return type" { +// try testError( +// \\fn foo() { +// \\ a && b; +// \\} +// \\test "" +// , &[_]Error{ +// .ExpectedReturnType, +// .InvalidAnd, +// .ExpectedLBrace, +// }); +//} +// +//test "recovery: continue after invalid decl" { +// try testError( +// \\fn foo { +// \\ inline; +// \\} +// \\pub test "" { +// \\ async a && b; +// \\} +// , &[_]Error{ +// .ExpectedToken, +// .ExpectedPubItem, +// .ExpectedParamList, +// .InvalidAnd, +// }); +// try testError( +// \\threadlocal test "" { +// \\ @a && b; +// \\} +// , &[_]Error{ +// .ExpectedVarDecl, +// .ExpectedParamList, +// .InvalidAnd, +// }); +//} +// +//test "recovery: invalid extern/inline" { +// try testError( +// \\inline test "" { a && b; } +// , &[_]Error{ +// .ExpectedFn, +// .InvalidAnd, +// }); +// try testError( +// \\extern "" test "" { a && b; } +// , &[_]Error{ +// .ExpectedVarDeclOrFn, +// .InvalidAnd, +// }); +//} +// +//test "recovery: missing semicolon" { +// try testError( +// \\test "" { +// \\ comptime a && b +// \\ c && d +// \\ @foo +// \\} +// , &[_]Error{ +// .InvalidAnd, +// .ExpectedToken, +// .InvalidAnd, +// .ExpectedToken, +// .ExpectedParamList, +// .ExpectedToken, +// }); +//} +// +//test "recovery: invalid container members" { +// try testError( +// \\usingnamespace; +// \\foo+ +// \\bar@, +// \\while (a == 2) { test "" {}} +// \\test "" { +// \\ a && b +// \\} +// , &[_]Error{ +// .ExpectedExpr, +// .ExpectedToken, +// .ExpectedToken, +// .ExpectedContainerMembers, +// .InvalidAnd, +// .ExpectedToken, +// }); +//} +// +//test "recovery: invalid parameter" { +// try testError( +// \\fn main() void { +// \\ a(comptime T: type) +// \\} +// , &[_]Error{ +// .ExpectedToken, +// }); +//} +// +//test "recovery: extra '}' at top level" { +// try testError( +// \\}}} +// \\test "" { +// \\ a && b; +// \\} +// , &[_]Error{ +// .ExpectedContainerMembers, +// .ExpectedContainerMembers, +// .ExpectedContainerMembers, +// .InvalidAnd, +// }); +//} +// +//test "recovery: mismatched bracket at top level" { +// try testError( +// \\const S = struct { +// \\ arr: 128]?G +// \\}; +// , &[_]Error{ +// .ExpectedToken, +// }); +//} +// +//test "recovery: invalid global error set access" { +// try testError( +// \\test "" { +// \\ error && foo; +// \\} +// , &[_]Error{ +// .ExpectedToken, +// .ExpectedIdentifier, +// .InvalidAnd, +// }); +//} +// +//test "recovery: invalid asterisk after pointer dereference" { +// try testError( +// \\test "" { +// \\ var sequence = "repeat".*** 10; +// \\} +// , &[_]Error{ +// .AsteriskAfterPointerDereference, +// }); +// try testError( +// \\test "" { +// \\ var sequence = "repeat".** 10&&a; +// \\} +// , &[_]Error{ +// .AsteriskAfterPointerDereference, +// .InvalidAnd, +// }); +//} +// +//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{ +// .ExpectedSemiOrElse, +// .ExpectedSemiOrElse, +// .ExpectedSemiOrElse, +// .InvalidAnd, +// }); +//} +// +//test "recovery: invalid comptime" { +// try testError( +// \\comptime +// , &[_]Error{ +// .ExpectedBlockOrField, +// }); +//} +// +//test "recovery: missing block after for/while loops" { +// try testError( +// \\test "" { while (foo) } +// , &[_]Error{ +// .ExpectedBlockOrAssignment, +// }); +// try testError( +// \\test "" { for (foo) |bar| } +// , &[_]Error{ +// .ExpectedBlockOrAssignment, +// }); +//} +// +//test "zig fmt: respect line breaks after var declarations" { +// try testCanonical( +// \\const crc = +// \\ lookup_tables[0][p[7]] ^ +// \\ lookup_tables[1][p[6]] ^ +// \\ lookup_tables[2][p[5]] ^ +// \\ lookup_tables[3][p[4]] ^ +// \\ lookup_tables[4][@truncate(u8, self.crc >> 24)] ^ +// \\ lookup_tables[5][@truncate(u8, self.crc >> 16)] ^ +// \\ lookup_tables[6][@truncate(u8, self.crc >> 8)] ^ +// \\ lookup_tables[7][@truncate(u8, self.crc >> 0)]; +// \\ +// ); +//} +// +//test "zig fmt: multiline string mixed with comments" { +// try testCanonical( +// \\const s1 = +// \\ //\\one +// \\ \\two) +// \\ \\three +// \\; +// \\const s2 = +// \\ \\one +// \\ \\two) +// \\ //\\three +// \\; +// \\const s3 = +// \\ \\one +// \\ //\\two) +// \\ \\three +// \\; +// \\const s4 = +// \\ \\one +// \\ //\\two +// \\ \\three +// \\ //\\four +// \\ \\five +// \\; +// \\const a = +// \\ 1; +// \\ +// ); +//} +// +//test "zig fmt: empty file" { +// try testCanonical( +// \\ +// ); +//} +// +//test "zig fmt: if statment" { +// try testCanonical( +// \\test "" { +// \\ if (optional()) |some| +// \\ bar = some.foo(); +// \\} +// \\ +// ); +//} +// +//test "zig fmt: top-level fields" { +// try testCanonical( +// \\a: did_you_know, +// \\b: all_files_are, +// \\structs: ?x, +// \\ +// ); +//} +// +//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{ +// .DeclBetweenFields, +// }); +//} +// +//test "zig fmt: eof after missing comma" { +// try testError( +// \\foo() +// , &[_]Error{ +// .ExpectedToken, +// }); +//} +// +//test "zig fmt: errdefer with payload" { +// try testCanonical( +// \\pub fn main() anyerror!void { +// \\ errdefer |a| x += 1; +// \\ errdefer |a| {} +// \\ errdefer |a| { +// \\ x += 1; +// \\ } +// \\} +// \\ +// ); +//} +// +//test "zig fmt: nosuspend block" { +// try testCanonical( +// \\pub fn main() anyerror!void { +// \\ nosuspend { +// \\ var foo: Foo = .{ .bar = 42 }; +// \\ } +// \\} +// \\ +// ); +//} +// +//test "zig fmt: nosuspend await" { +// try testCanonical( +// \\fn foo() void { +// \\ x = nosuspend await y; +// \\} +// \\ +// ); +//} +// +//test "zig fmt: trailing comma in container declaration" { +// try testCanonical( +// \\const X = struct { foo: i32 }; +// \\const X = struct { foo: i32, bar: i32 }; +// \\const X = struct { foo: i32 = 1, bar: i32 = 2 }; +// \\const X = struct { foo: i32 align(4), bar: i32 align(4) }; +// \\const X = struct { foo: i32 align(4) = 1, bar: i32 align(4) = 2 }; +// \\ +// ); +// try testCanonical( +// \\test "" { +// \\ comptime { +// \\ const X = struct { +// \\ x: i32 +// \\ }; +// \\ } +// \\} +// \\ +// ); +// try testTransform( +// \\const X = struct { +// \\ foo: i32, bar: i8 }; +// , +// \\const X = struct { +// \\ foo: i32, bar: i8 +// \\}; +// \\ +// ); +//} +// +//test "zig fmt: trailing comma in fn parameter list" { +// try testCanonical( +// \\pub fn f( +// \\ a: i32, +// \\ b: i32, +// \\) i32 {} +// \\pub fn f( +// \\ a: i32, +// \\ b: i32, +// \\) align(8) i32 {} +// \\pub fn f( +// \\ a: i32, +// \\ b: i32, +// \\) linksection(".text") i32 {} +// \\pub fn f( +// \\ a: i32, +// \\ b: i32, +// \\) callconv(.C) i32 {} +// \\pub fn f( +// \\ a: i32, +// \\ b: i32, +// \\) align(8) linksection(".text") i32 {} +// \\pub fn f( +// \\ a: i32, +// \\ b: i32, +// \\) align(8) callconv(.C) i32 {} +// \\pub fn f( +// \\ a: i32, +// \\ b: i32, +// \\) align(8) linksection(".text") callconv(.C) i32 {} +// \\pub fn f( +// \\ a: i32, +// \\ b: i32, +// \\) linksection(".text") callconv(.C) i32 {} +// \\ +// ); +//} +// +//test "zig fmt: comptime struct field" { +// try testCanonical( +// \\const Foo = struct { +// \\ a: i32, +// \\ comptime b: i32 = 1234, +// \\}; +// \\ +// ); +//} +// +//test "zig fmt: c pointer type" { +// try testCanonical( +// \\pub extern fn repro() [*c]const u8; +// \\ +// ); +//} +// +//test "zig fmt: builtin call with trailing comma" { +// try testCanonical( +// \\pub fn main() void { +// \\ @breakpoint(); +// \\ _ = @boolToInt(a); +// \\ _ = @call( +// \\ a, +// \\ b, +// \\ c, +// \\ ); +// \\} +// \\ +// ); +//} +// +//test "zig fmt: asm expression with comptime content" { +// try testCanonical( +// \\comptime { +// \\ asm ("foo" ++ "bar"); +// \\} +// \\pub fn main() void { +// \\ asm volatile ("foo" ++ "bar"); +// \\ asm volatile ("foo" ++ "bar" +// \\ : [_] "" (x) +// \\ ); +// \\ asm volatile ("foo" ++ "bar" +// \\ : [_] "" (x) +// \\ : [_] "" (y) +// \\ ); +// \\ asm volatile ("foo" ++ "bar" +// \\ : [_] "" (x) +// \\ : [_] "" (y) +// \\ : "h", "e", "l", "l", "o" +// \\ ); +// \\} +// \\ +// ); +//} +// +//test "zig fmt: anytype struct field" { +// try testCanonical( +// \\pub const Pointer = struct { +// \\ sentinel: anytype, +// \\}; +// \\ +// ); +//} +// +//test "zig fmt: sentinel-terminated array type" { +// try testCanonical( +// \\pub fn cStrToPrefixedFileW(s: [*:0]const u8) ![PATH_MAX_WIDE:0]u16 { +// \\ return sliceToPrefixedFileW(mem.toSliceConst(u8, s)); +// \\} +// \\ +// ); +//} +// +//test "zig fmt: sentinel-terminated slice type" { +// try testCanonical( +// \\pub fn toSlice(self: Buffer) [:0]u8 { +// \\ return self.list.toSlice()[0..self.len()]; +// \\} +// \\ +// ); +//} +// +//test "zig fmt: anon literal in array" { +// try testCanonical( +// \\var arr: [2]Foo = .{ +// \\ .{ .a = 2 }, +// \\ .{ .b = 3 }, +// \\}; +// \\ +// ); +//} +// +//test "zig fmt: alignment in anonymous literal" { +// try testTransform( +// \\const a = .{ +// \\ "U", "L", "F", +// \\ "U'", +// \\ "L'", +// \\ "F'", +// \\}; +// \\ +// , +// \\const a = .{ +// \\ "U", "L", "F", +// \\ "U'", "L'", "F'", +// \\}; +// \\ +// ); +//} +// +//test "zig fmt: anon struct literal syntax" { +// try testCanonical( +// \\const x = .{ +// \\ .a = b, +// \\ .c = d, +// \\}; +// \\ +// ); +//} +// +//test "zig fmt: anon list literal syntax" { +// try testCanonical( +// \\const x = .{ a, b, c }; +// \\ +// ); +//} +// +//test "zig fmt: async function" { +// try testCanonical( +// \\pub const Server = struct { +// \\ handleRequestFn: fn (*Server, *const std.net.Address, File) callconv(.Async) void, +// \\}; +// \\test "hi" { +// \\ var ptr = @ptrCast(fn (i32) callconv(.Async) void, other); +// \\} +// \\ +// ); +//} +// +//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 "" { +// \\ const hi = x; +// \\} +// \\// zig fmt: off +// \\test ""{ +// \\ const a = b;} +// \\ +// ); +//} +// +//test "zig fmt: while else err prong with no block" { +// try testCanonical( +// \\test "" { +// \\ const result = while (returnError()) |value| { +// \\ break value; +// \\ } else |err| @as(i32, 2); +// \\ expect(result == 2); +// \\} +// \\ +// ); +//} +// +//test "zig fmt: tagged union with enum values" { +// try testCanonical( +// \\const MultipleChoice2 = union(enum(u32)) { +// \\ Unspecified1: i32, +// \\ A: f32 = 20, +// \\ Unspecified2: void, +// \\ B: bool = 40, +// \\ Unspecified3: i32, +// \\ C: i8 = 60, +// \\ Unspecified4: void, +// \\ D: void = 1000, +// \\ Unspecified5: i32, +// \\}; +// \\ +// ); +//} +// +//test "zig fmt: allowzero pointer" { +// try testCanonical( +// \\const T = [*]allowzero const u8; +// \\ +// ); +//} +// +//test "zig fmt: enum literal" { +// try testCanonical( +// \\const x = .hi; +// \\ +// ); +//} +// +//test "zig fmt: enum literal inside array literal" { +// try testCanonical( +// \\test "enums in arrays" { +// \\ var colors = []Color{.Green}; +// \\ colors = []Colors{ .Green, .Cyan }; +// \\ colors = []Colors{ +// \\ .Grey, +// \\ .Green, +// \\ .Cyan, +// \\ }; +// \\} +// \\ +// ); +//} +// +//test "zig fmt: character literal larger than u8" { +// try testCanonical( +// \\const x = '\u{01f4a9}'; +// \\ +// ); +//} +// +//test "zig fmt: infix operator and then multiline string literal" { +// try testCanonical( +// \\const x = "" ++ +// \\ \\ hi +// \\; +// \\ +// ); +//} +// +//test "zig fmt: infix operator and then multiline string literal" { +// try testCanonical( +// \\const x = "" ++ +// \\ \\ hi0 +// \\ \\ hi1 +// \\ \\ hi2 +// \\; +// \\ +// ); +//} +// +//test "zig fmt: C pointers" { +// try testCanonical( +// \\const Ptr = [*c]i32; +// \\ +// ); +//} +// +//test "zig fmt: threadlocal" { +// try testCanonical( +// \\threadlocal var x: i32 = 1234; +// \\ +// ); +//} +// +//test "zig fmt: linksection" { +// try testCanonical( +// \\export var aoeu: u64 linksection(".text.derp") = 1234; +// \\export fn _start() linksection(".text.boot") callconv(.Naked) noreturn {} +// \\ +// ); +//} +// +//test "zig fmt: correctly move doc comments on struct fields" { +// try testTransform( +// \\pub const section_64 = extern struct { +// \\ sectname: [16]u8, /// name of this section +// \\ segname: [16]u8, /// segment this section goes in +// \\}; +// , +// \\pub const section_64 = extern struct { +// \\ /// name of this section +// \\ sectname: [16]u8, +// \\ /// segment this section goes in +// \\ segname: [16]u8, +// \\}; +// \\ +// ); +//} +// +//test "zig fmt: correctly space struct fields with doc comments" { +// try testTransform( +// \\pub const S = struct { +// \\ /// A +// \\ a: u8, +// \\ /// B +// \\ /// B (cont) +// \\ b: u8, +// \\ +// \\ +// \\ /// C +// \\ c: u8, +// \\}; +// \\ +// , +// \\pub const S = struct { +// \\ /// A +// \\ a: u8, +// \\ /// B +// \\ /// B (cont) +// \\ b: u8, +// \\ +// \\ /// C +// \\ c: u8, +// \\}; +// \\ +// ); +//} +// +//test "zig fmt: doc comments on param decl" { +// try testCanonical( +// \\pub const Allocator = struct { +// \\ shrinkFn: fn ( +// \\ self: *Allocator, +// \\ /// Guaranteed to be the same as what was returned from most recent call to +// \\ /// `allocFn`, `reallocFn`, or `shrinkFn`. +// \\ old_mem: []u8, +// \\ /// Guaranteed to be the same as what was returned from most recent call to +// \\ /// `allocFn`, `reallocFn`, or `shrinkFn`. +// \\ old_alignment: u29, +// \\ /// Guaranteed to be less than or equal to `old_mem.len`. +// \\ new_byte_count: usize, +// \\ /// Guaranteed to be less than or equal to `old_alignment`. +// \\ new_alignment: u29, +// \\ ) []u8, +// \\}; +// \\ +// ); +//} +// +//test "zig fmt: aligned struct field" { +// try testCanonical( +// \\pub const S = struct { +// \\ f: i32 align(32), +// \\}; +// \\ +// ); +// try testCanonical( +// \\pub const S = struct { +// \\ f: i32 align(32) = 1, +// \\}; +// \\ +// ); +//} +// +//test "zig fmt: comment to disable/enable zig fmt first" { +// try testCanonical( +// \\// Test trailing comma syntax +// \\// zig fmt: off +// \\ +// \\const struct_trailing_comma = struct { x: i32, y: i32, }; +// ); +//} +// +//test "zig fmt: comment to disable/enable zig fmt" { +// try testTransform( +// \\const a = b; +// \\// zig fmt: off +// \\const c = d; +// \\// zig fmt: on +// \\const e = f; +// , +// \\const a = b; +// \\// zig fmt: off +// \\const c = d; +// \\// zig fmt: on +// \\const e = f; +// \\ +// ); +//} +// +//test "zig fmt: line comment following 'zig fmt: off'" { +// try testCanonical( +// \\// zig fmt: off +// \\// Test +// \\const e = f; +// ); +//} +// +//test "zig fmt: doc comment following 'zig fmt: off'" { +// try testCanonical( +// \\// zig fmt: off +// \\/// test +// \\const e = f; +// ); +//} +// +//test "zig fmt: line and doc comment following 'zig fmt: off'" { +// try testCanonical( +// \\// zig fmt: off +// \\// test 1 +// \\/// test 2 +// \\const e = f; +// ); +//} +// +//test "zig fmt: doc and line comment following 'zig fmt: off'" { +// try testCanonical( +// \\// zig fmt: off +// \\/// test 1 +// \\// test 2 +// \\const e = f; +// ); +//} +// +//test "zig fmt: alternating 'zig fmt: off' and 'zig fmt: on'" { +// try testCanonical( +// \\// zig fmt: off +// \\// zig fmt: on +// \\// zig fmt: off +// \\const e = f; +// \\// zig fmt: off +// \\// zig fmt: on +// \\// zig fmt: off +// \\const a = b; +// \\// zig fmt: on +// \\const c = d; +// \\// zig fmt: on +// \\ +// ); +//} +// +//test "zig fmt: line comment following 'zig fmt: on'" { +// try testCanonical( +// \\// zig fmt: off +// \\const e = f; +// \\// zig fmt: on +// \\// test +// \\const e = f; +// \\ +// ); +//} +// +//test "zig fmt: doc comment following 'zig fmt: on'" { +// try testCanonical( +// \\// zig fmt: off +// \\const e = f; +// \\// zig fmt: on +// \\/// test +// \\const e = f; +// \\ +// ); +//} +// +//test "zig fmt: line and doc comment following 'zig fmt: on'" { +// try testCanonical( +// \\// zig fmt: off +// \\const e = f; +// \\// zig fmt: on +// \\// test1 +// \\/// test2 +// \\const e = f; +// \\ +// ); +//} +// +//test "zig fmt: doc and line comment following 'zig fmt: on'" { +// try testCanonical( +// \\// zig fmt: off +// \\const e = f; +// \\// zig fmt: on +// \\/// test1 +// \\// test2 +// \\const e = f; +// \\ +// ); +//} +// +//test "zig fmt: pointer of unknown length" { +// try testCanonical( +// \\fn foo(ptr: [*]u8) void {} +// \\ +// ); +//} +// +//test "zig fmt: spaces around slice operator" { +// try testCanonical( +// \\var a = b[c..d]; +// \\var a = b[c..d :0]; +// \\var a = b[c + 1 .. d]; +// \\var a = b[c + 1 ..]; +// \\var a = b[c .. d + 1]; +// \\var a = b[c .. d + 1 :0]; +// \\var a = b[c.a..d.e]; +// \\var a = b[c.a..d.e :0]; +// \\ +// ); +//} +// +//test "zig fmt: async call in if condition" { +// try testCanonical( +// \\comptime { +// \\ if (async b()) { +// \\ a(); +// \\ } +// \\} +// \\ +// ); +//} +// +//test "zig fmt: 2nd arg multiline string" { +// try testCanonical( +// \\comptime { +// \\ cases.addAsm("hello world linux x86_64", +// \\ \\.text +// \\ , "Hello, world!\n"); +// \\} +// \\ +// ); +//} +// +//test "zig fmt: 2nd arg multiline string many args" { +// try testCanonical( +// \\comptime { +// \\ cases.addAsm("hello world linux x86_64", +// \\ \\.text +// \\ , "Hello, world!\n", "Hello, world!\n"); +// \\} +// \\ +// ); +//} +// +//test "zig fmt: final arg multiline string" { +// try testCanonical( +// \\comptime { +// \\ cases.addAsm("hello world linux x86_64", "Hello, world!\n", +// \\ \\.text +// \\ ); +// \\} +// \\ +// ); +//} +// +//test "zig fmt: if condition wraps" { +// try testTransform( +// \\comptime { +// \\ if (cond and +// \\ cond) { +// \\ return x; +// \\ } +// \\ while (cond and +// \\ cond) { +// \\ return x; +// \\ } +// \\ if (a == b and +// \\ c) { +// \\ a = b; +// \\ } +// \\ while (a == b and +// \\ c) { +// \\ a = b; +// \\ } +// \\ if ((cond and +// \\ cond)) { +// \\ return x; +// \\ } +// \\ while ((cond and +// \\ cond)) { +// \\ return x; +// \\ } +// \\ var a = if (a) |*f| x: { +// \\ break :x &a.b; +// \\ } else |err| err; +// \\ var a = if (cond and +// \\ cond) |*f| +// \\ x: { +// \\ break :x &a.b; +// \\ } else |err| err; +// \\} +// , +// \\comptime { +// \\ if (cond and +// \\ cond) +// \\ { +// \\ return x; +// \\ } +// \\ while (cond and +// \\ cond) +// \\ { +// \\ return x; +// \\ } +// \\ if (a == b and +// \\ c) +// \\ { +// \\ a = b; +// \\ } +// \\ while (a == b and +// \\ c) +// \\ { +// \\ a = b; +// \\ } +// \\ if ((cond and +// \\ cond)) +// \\ { +// \\ return x; +// \\ } +// \\ while ((cond and +// \\ cond)) +// \\ { +// \\ return x; +// \\ } +// \\ var a = if (a) |*f| x: { +// \\ break :x &a.b; +// \\ } else |err| err; +// \\ var a = if (cond and +// \\ cond) |*f| +// \\ x: { +// \\ break :x &a.b; +// \\ } else |err| err; +// \\} +// \\ +// ); +//} +// +//test "zig fmt: if condition has line break but must not wrap" { +// try testCanonical( +// \\comptime { +// \\ if (self.user_input_options.put( +// \\ name, +// \\ UserInputOption{ +// \\ .name = name, +// \\ .used = false, +// \\ }, +// \\ ) catch unreachable) |*prev_value| { +// \\ foo(); +// \\ bar(); +// \\ } +// \\ if (put( +// \\ a, +// \\ b, +// \\ )) { +// \\ foo(); +// \\ } +// \\} +// \\ +// ); +//} +// +//test "zig fmt: if condition has line break but must not wrap" { +// try testCanonical( +// \\comptime { +// \\ if (self.user_input_options.put(name, UserInputOption{ +// \\ .name = name, +// \\ .used = false, +// \\ }) catch unreachable) |*prev_value| { +// \\ foo(); +// \\ bar(); +// \\ } +// \\ if (put( +// \\ a, +// \\ b, +// \\ )) { +// \\ foo(); +// \\ } +// \\} +// \\ +// ); +//} +// +//test "zig fmt: function call with multiline argument" { +// try testCanonical( +// \\comptime { +// \\ self.user_input_options.put(name, UserInputOption{ +// \\ .name = name, +// \\ .used = false, +// \\ }); +// \\} +// \\ +// ); +//} +// +//test "zig fmt: same-line doc comment on variable declaration" { +// try testTransform( +// \\pub const MAP_ANONYMOUS = 0x1000; /// allocated from memory, swap space +// \\pub const MAP_FILE = 0x0000; /// map from file (default) +// \\ +// \\pub const EMEDIUMTYPE = 124; /// Wrong medium type +// \\ +// \\// nameserver query return codes +// \\pub const ENSROK = 0; /// DNS server returned answer with no data +// , +// \\/// allocated from memory, swap space +// \\pub const MAP_ANONYMOUS = 0x1000; +// \\/// map from file (default) +// \\pub const MAP_FILE = 0x0000; +// \\ +// \\/// Wrong medium type +// \\pub const EMEDIUMTYPE = 124; +// \\ +// \\// nameserver query return codes +// \\/// DNS server returned answer with no data +// \\pub const ENSROK = 0; +// \\ +// ); +//} +// +//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).new(y - y, y - y); +// \\ } // cexp(-inf +- i inf|nan) = 0 + i0 +// \\ else if (hx & 0x80000000 != 0) { +// \\ return Complex(f32).new(0, 0); +// \\ } // cexp(+inf +- i inf|nan) = inf + i nan +// \\ else { +// \\ return Complex(f32).new(x, y - y); +// \\ } +// \\} +// \\ +// ); +//} +// +//test "zig fmt: if nested" { +// try testCanonical( +// \\pub fn foo() void { +// \\ return if ((aInt & bInt) >= 0) +// \\ if (aInt < bInt) +// \\ GE_LESS +// \\ else if (aInt == bInt) +// \\ GE_EQUAL +// \\ else +// \\ GE_GREATER +// \\ else if (aInt > bInt) +// \\ GE_LESS +// \\ else if (aInt == bInt) +// \\ GE_EQUAL +// \\ else +// \\ GE_GREATER; +// \\} +// \\ +// ); +//} +// +//test "zig fmt: respect line breaks in if-else" { +// try testCanonical( +// \\comptime { +// \\ return if (cond) a else b; +// \\ return if (cond) +// \\ a +// \\ else +// \\ b; +// \\ return if (cond) +// \\ a +// \\ else if (cond) +// \\ b +// \\ else +// \\ c; +// \\} +// \\ +// ); +//} +// +//test "zig fmt: respect line breaks after infix operators" { +// try testCanonical( +// \\comptime { +// \\ self.crc = +// \\ lookup_tables[0][p[7]] ^ +// \\ lookup_tables[1][p[6]] ^ +// \\ lookup_tables[2][p[5]] ^ +// \\ lookup_tables[3][p[4]] ^ +// \\ lookup_tables[4][@truncate(u8, self.crc >> 24)] ^ +// \\ lookup_tables[5][@truncate(u8, self.crc >> 16)] ^ +// \\ lookup_tables[6][@truncate(u8, self.crc >> 8)] ^ +// \\ lookup_tables[7][@truncate(u8, self.crc >> 0)]; +// \\} +// \\ +// ); +//} +// +//test "zig fmt: fn decl with trailing comma" { +// try testTransform( +// \\fn foo(a: i32, b: i32,) void {} +// , +// \\fn foo( +// \\ a: i32, +// \\ b: i32, +// \\) void {} +// \\ +// ); +//} +// +//test "zig fmt: enum decl with no trailing comma" { +// try testTransform( +// \\const StrLitKind = enum {Normal, C}; +// , +// \\const StrLitKind = enum { Normal, C }; +// \\ +// ); +//} +// +//test "zig fmt: switch comment before prong" { +// try testCanonical( +// \\comptime { +// \\ switch (a) { +// \\ // hi +// \\ 0 => {}, +// \\ } +// \\} +// \\ +// ); +//} +// +//test "zig fmt: struct literal no trailing comma" { +// try testTransform( +// \\const a = foo{ .x = 1, .y = 2 }; +// \\const a = foo{ .x = 1, +// \\ .y = 2 }; +// , +// \\const a = foo{ .x = 1, .y = 2 }; +// \\const a = foo{ +// \\ .x = 1, +// \\ .y = 2, +// \\}; +// \\ +// ); +//} +// +//test "zig fmt: struct literal containing a multiline expression" { +// try testTransform( +// \\const a = A{ .x = if (f1()) 10 else 20 }; +// \\const a = A{ .x = if (f1()) 10 else 20, }; +// \\const a = A{ .x = if (f1()) +// \\ 10 else 20 }; +// \\const a = A{ .x = if (f1()) 10 else 20, .y = f2() + 100 }; +// \\const a = A{ .x = if (f1()) 10 else 20, .y = f2() + 100, }; +// \\const a = A{ .x = if (f1()) +// \\ 10 else 20}; +// \\const a = A{ .x = switch(g) {0 => "ok", else => "no"} }; +// \\ +// , +// \\const a = A{ .x = if (f1()) 10 else 20 }; +// \\const a = A{ +// \\ .x = if (f1()) 10 else 20, +// \\}; +// \\const a = A{ +// \\ .x = if (f1()) +// \\ 10 +// \\ else +// \\ 20, +// \\}; +// \\const a = A{ .x = if (f1()) 10 else 20, .y = f2() + 100 }; +// \\const a = A{ +// \\ .x = if (f1()) 10 else 20, +// \\ .y = f2() + 100, +// \\}; +// \\const a = A{ +// \\ .x = if (f1()) +// \\ 10 +// \\ else +// \\ 20, +// \\}; +// \\const a = A{ +// \\ .x = switch (g) { +// \\ 0 => "ok", +// \\ else => "no", +// \\ }, +// \\}; +// \\ +// ); +//} +// +//test "zig fmt: array literal with hint" { +// try testTransform( +// \\const a = []u8{ +// \\ 1, 2, // +// \\ 3, +// \\ 4, +// \\ 5, +// \\ 6, +// \\ 7 }; +// \\const a = []u8{ +// \\ 1, 2, // +// \\ 3, +// \\ 4, +// \\ 5, +// \\ 6, +// \\ 7, 8 }; +// \\const a = []u8{ +// \\ 1, 2, // +// \\ 3, +// \\ 4, +// \\ 5, +// \\ 6, // blah +// \\ 7, 8 }; +// \\const a = []u8{ +// \\ 1, 2, // +// \\ 3, // +// \\ 4, +// \\ 5, +// \\ 6, +// \\ 7 }; +// \\const a = []u8{ +// \\ 1, +// \\ 2, +// \\ 3, 4, // +// \\ 5, 6, // +// \\ 7, 8, // +// \\}; +// , +// \\const a = []u8{ +// \\ 1, 2, +// \\ 3, 4, +// \\ 5, 6, +// \\ 7, +// \\}; +// \\const a = []u8{ +// \\ 1, 2, +// \\ 3, 4, +// \\ 5, 6, +// \\ 7, 8, +// \\}; +// \\const a = []u8{ +// \\ 1, 2, +// \\ 3, 4, +// \\ 5, +// \\ 6, // blah +// \\ 7, +// \\ 8, +// \\}; +// \\const a = []u8{ +// \\ 1, 2, +// \\ 3, // +// \\ 4, +// \\ 5, 6, +// \\ 7, +// \\}; +// \\const a = []u8{ +// \\ 1, +// \\ 2, +// \\ 3, +// \\ 4, +// \\ 5, +// \\ 6, +// \\ 7, +// \\ 8, +// \\}; +// \\ +// ); +//} +// +//test "zig fmt: array literal veritical column alignment" { +// try testTransform( +// \\const a = []u8{ +// \\ 1000, 200, +// \\ 30, 4, +// \\ 50000, 60 +// \\}; +// \\const a = []u8{0, 1, 2, 3, 40, +// \\ 4,5,600,7, +// \\ 80, +// \\ 9, 10, 11, 0, 13, 14, 15}; +// \\ +// , +// \\const a = []u8{ +// \\ 1000, 200, +// \\ 30, 4, +// \\ 50000, 60, +// \\}; +// \\const a = []u8{ +// \\ 0, 1, 2, 3, 40, +// \\ 4, 5, 600, 7, 80, +// \\ 9, 10, 11, 0, 13, +// \\ 14, 15, +// \\}; +// \\ +// ); +//} +// +//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 {} +// \\ \\ZIG_C_HEADER_FILES {} +// \\ \\ZIG_DIA_GUIDS_LIB {} +// \\ \\ +// \\ , +// \\ std.cstr.toSliceConst(c.ZIG_CMAKE_BINARY_DIR), +// \\ std.cstr.toSliceConst(c.ZIG_CXX_COMPILER), +// \\ std.cstr.toSliceConst(c.ZIG_DIA_GUIDS_LIB), +// \\ ); +// \\} +// \\ +// ); +//} +// +//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: no trailing comma on struct decl" { +// try testCanonical( +// \\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: simple asm" { +// try testTransform( +// \\comptime { +// \\ asm volatile ( +// \\ \\.globl aoeu; +// \\ \\.type aoeu, @function; +// \\ \\.set aoeu, derp; +// \\ ); +// \\ +// \\ asm ("not real assembly" +// \\ :[a] "x" (x),); +// \\ asm ("not real assembly" +// \\ :[a] "x" (->i32),:[a] "x" (1),); +// \\ asm ("still not real assembly" +// \\ :::"a","b",); +// \\} +// , +// \\comptime { +// \\ asm volatile ( +// \\ \\.globl aoeu; +// \\ \\.type aoeu, @function; +// \\ \\.set aoeu, derp; +// \\ ); +// \\ +// \\ asm ("not real assembly" +// \\ : [a] "x" (x) +// \\ ); +// \\ asm ("not real assembly" +// \\ : [a] "x" (-> i32) +// \\ : [a] "x" (1) +// \\ ); +// \\ asm ("still not real assembly" +// \\ : +// \\ : +// \\ : "a", "b" +// \\ ); +// \\} +// \\ +// ); +//} +// +//test "zig fmt: nested struct literal with one item" { +// try testCanonical( +// \\const a = foo{ +// \\ .item = bar{ .a = b }, +// \\}; +// \\ +// ); +//} +// +//test "zig fmt: switch cases trailing comma" { +// try testTransform( +// \\fn switch_cases(x: i32) void { +// \\ switch (x) { +// \\ 1,2,3 => {}, +// \\ 4,5, => {}, +// \\ 6... 8, => {}, +// \\ else => {}, +// \\ } +// \\} +// , +// \\fn switch_cases(x: i32) void { +// \\ switch (x) { +// \\ 1, 2, 3 => {}, +// \\ 4, +// \\ 5, +// \\ => {}, +// \\ 6...8 => {}, +// \\ else => {}, +// \\ } +// \\} +// \\ +// ); +//} +// +//test "zig fmt: slice align" { +// try testCanonical( +// \\const A = struct { +// \\ items: []align(A) T, +// \\}; +// \\ +// ); +//} +// +//test "zig fmt: add trailing comma to array literal" { +// try testTransform( +// \\comptime { +// \\ return []u16{'m', 's', 'y', 's', '-' // hi +// \\ }; +// \\ return []u16{'m', 's', 'y', 's', +// \\ '-'}; +// \\ return []u16{'m', 's', 'y', 's', '-'}; +// \\} +// , +// \\comptime { +// \\ return []u16{ +// \\ 'm', 's', 'y', 's', '-', // hi +// \\ }; +// \\ return []u16{ +// \\ 'm', 's', 'y', 's', +// \\ '-', +// \\ }; +// \\ return []u16{ 'm', 's', 'y', 's', '-' }; +// \\} +// \\ +// ); +//} +// +//test "zig fmt: first thing in file is line comment" { +// try testCanonical( +// \\// Introspection and determination of system libraries needed by zig. +// \\ +// \\// Introspection and determination of system libraries needed by zig. +// \\ +// \\const std = @import("std"); +// \\ +// ); +//} +// +//test "zig fmt: line comment after doc comment" { +// try testCanonical( +// \\/// doc comment +// \\// line comment +// \\fn foo() void {} +// \\ +// ); +//} +// +//test "zig fmt: float literal with exponent" { +// try testCanonical( +// \\test "bit field alignment" { +// \\ assert(@TypeOf(&blah.b) == *align(1:3:6) const u3); +// \\} +// \\ +// ); +//} +// +//test "zig fmt: float literal with exponent" { +// try testCanonical( +// \\test "aoeu" { +// \\ switch (state) { +// \\ TermState.Start => switch (c) { +// \\ '\x1b' => state = TermState.Escape, +// \\ else => try out.writeByte(c), +// \\ }, +// \\ } +// \\} +// \\ +// ); +//} +//test "zig fmt: float literal with exponent" { +// try testCanonical( +// \\pub const f64_true_min = 4.94065645841246544177e-324; +// \\const threshold = 0x1.a827999fcef32p+1022; +// \\ +// ); +//} +// +//test "zig fmt: if-else end of comptime" { +// try testCanonical( +// \\comptime { +// \\ if (a) { +// \\ b(); +// \\ } else { +// \\ b(); +// \\ } +// \\} +// \\ +// ); +//} +// +//test "zig fmt: nested blocks" { +// try testCanonical( +// \\comptime { +// \\ { +// \\ { +// \\ { +// \\ a(); +// \\ } +// \\ } +// \\ } +// \\} +// \\ +// ); +//} +// +//test "zig fmt: block with same line comment after end brace" { +// try testCanonical( +// \\comptime { +// \\ { +// \\ b(); +// \\ } // comment +// \\} +// \\ +// ); +//} +// +//test "zig fmt: statements with comment between" { +// try testCanonical( +// \\comptime { +// \\ a = b; +// \\ // comment +// \\ a = b; +// \\} +// \\ +// ); +//} +// +//test "zig fmt: statements with empty line between" { +// try testCanonical( +// \\comptime { +// \\ a = b; +// \\ +// \\ a = b; +// \\} +// \\ +// ); +//} +// +//test "zig fmt: ptr deref operator and unwrap optional operator" { +// try testCanonical( +// \\const a = b.*; +// \\const a = b.?; +// \\ +// ); +//} +// +//test "zig fmt: comment after if before another if" { +// try testCanonical( +// \\test "aoeu" { +// \\ // comment +// \\ if (x) { +// \\ bar(); +// \\ } +// \\} +// \\ +// \\test "aoeu" { +// \\ if (x) { +// \\ foo(); +// \\ } +// \\ // comment +// \\ if (x) { +// \\ bar(); +// \\ } +// \\} +// \\ +// ); +//} +// +//test "zig fmt: line comment between if block and else keyword" { +// try testCanonical( +// \\test "aoeu" { +// \\ // cexp(finite|nan +- i inf|nan) = nan + i nan +// \\ if ((hx & 0x7fffffff) != 0x7f800000) { +// \\ return Complex(f32).new(y - y, y - y); +// \\ } +// \\ // cexp(-inf +- i inf|nan) = 0 + i0 +// \\ else if (hx & 0x80000000 != 0) { +// \\ return Complex(f32).new(0, 0); +// \\ } +// \\ // cexp(+inf +- i inf|nan) = inf + i nan +// \\ // another comment +// \\ else { +// \\ return Complex(f32).new(x, y - y); +// \\ } +// \\} +// \\ +// ); +//} +// +//test "zig fmt: same line comments in expression" { +// try testCanonical( +// \\test "aoeu" { +// \\ const x = ( // a +// \\ 0 // b +// \\ ); // c +// \\} +// \\ +// ); +//} +// +//test "zig fmt: add comma on last switch prong" { +// try testTransform( +// \\test "aoeu" { +// \\switch (self.init_arg_expr) { +// \\ InitArg.Type => |t| { }, +// \\ InitArg.None, +// \\ InitArg.Enum => { } +// \\} +// \\ switch (self.init_arg_expr) { +// \\ InitArg.Type => |t| { }, +// \\ InitArg.None, +// \\ InitArg.Enum => { }//line comment +// \\ } +// \\} +// , +// \\test "aoeu" { +// \\ switch (self.init_arg_expr) { +// \\ InitArg.Type => |t| {}, +// \\ InitArg.None, InitArg.Enum => {}, +// \\ } +// \\ switch (self.init_arg_expr) { +// \\ InitArg.Type => |t| {}, +// \\ InitArg.None, InitArg.Enum => {}, //line comment +// \\ } +// \\} +// \\ +// ); +//} +// +//test "zig fmt: same-line comment after a statement" { +// try testCanonical( +// \\test "" { +// \\ a = b; +// \\ debug.assert(H.digest_size <= H.block_size); // HMAC makes this assumption +// \\ a = b; +// \\} +// \\ +// ); +//} +// +//test "zig fmt: same-line comment after var decl in struct" { +// try testCanonical( +// \\pub const vfs_cap_data = extern struct { +// \\ const Data = struct {}; // when on disk. +// \\}; +// \\ +// ); +//} +// +//test "zig fmt: same-line comment after field decl" { +// try testCanonical( +// \\pub const dirent = extern struct { +// \\ d_name: u8, +// \\ d_name: u8, // comment 1 +// \\ d_name: u8, +// \\ d_name: u8, // comment 2 +// \\ d_name: u8, +// \\}; +// \\ +// ); +//} +// +//test "zig fmt: same-line comment after switch prong" { +// try testCanonical( +// \\test "" { +// \\ switch (err) { +// \\ error.PathAlreadyExists => {}, // comment 2 +// \\ else => return err, // comment 1 +// \\ } +// \\} +// \\ +// ); +//} +// +//test "zig fmt: same-line comment after non-block if expression" { +// try testCanonical( +// \\comptime { +// \\ if (sr > n_uword_bits - 1) // d > r +// \\ return 0; +// \\} +// \\ +// ); +//} +// +//test "zig fmt: same-line comment on comptime expression" { +// try testCanonical( +// \\test "" { +// \\ comptime assert(@typeInfo(T) == .Int); // must pass an integer to absInt +// \\} +// \\ +// ); +//} +// +//test "zig fmt: switch with empty body" { +// try testCanonical( +// \\test "" { +// \\ foo() catch |err| switch (err) {}; +// \\} +// \\ +// ); +//} +// +//test "zig fmt: line comments in struct initializer" { +// try testCanonical( +// \\fn foo() void { +// \\ return Self{ +// \\ .a = b, +// \\ +// \\ // Initialize these two fields to buffer_size so that +// \\ // in `readFn` we treat the state as being able to read +// \\ .start_index = buffer_size, +// \\ .end_index = buffer_size, +// \\ +// \\ // middle +// \\ +// \\ .a = b, +// \\ +// \\ // end +// \\ }; +// \\} +// \\ +// ); +//} +// +//test "zig fmt: first line comment in struct initializer" { +// try testCanonical( +// \\pub fn acquire(self: *Self) HeldLock { +// \\ return HeldLock{ +// \\ // guaranteed allocation elision +// \\ .held = self.lock.acquire(), +// \\ .value = &self.private_data, +// \\ }; +// \\} +// \\ +// ); +//} +// +//test "zig fmt: doc comments before struct field" { +// try testCanonical( +// \\pub const Allocator = struct { +// \\ /// Allocate byte_count bytes and return them in a slice, with the +// \\ /// slice's pointer aligned at least to alignment bytes. +// \\ allocFn: fn () void, +// \\}; +// \\ +// ); +//} +// +//test "zig fmt: error set declaration" { +// try testCanonical( +// \\const E = error{ +// \\ A, +// \\ B, +// \\ +// \\ C, +// \\}; +// \\ +// \\const Error = error{ +// \\ /// no more memory +// \\ OutOfMemory, +// \\}; +// \\ +// \\const Error = error{ +// \\ /// no more memory +// \\ OutOfMemory, +// \\ +// \\ /// another +// \\ Another, +// \\ +// \\ // end +// \\}; +// \\ +// \\const Error = error{OutOfMemory}; +// \\const Error = error{}; +// \\ +// \\const Error = error{ OutOfMemory, OutOfTime }; +// \\ +// ); +//} +// +//test "zig fmt: union(enum(u32)) with assigned enum values" { +// try testCanonical( +// \\const MultipleChoice = union(enum(u32)) { +// \\ A = 20, +// \\ B = 40, +// \\ C = 60, +// \\ D = 1000, +// \\}; +// \\ +// ); +//} +// +//test "zig fmt: resume from suspend block" { +// try testCanonical( +// \\fn foo() void { +// \\ suspend { +// \\ resume @frame(); +// \\ } +// \\} +// \\ +// ); +//} +// +//test "zig fmt: comments before error set decl" { +// try testCanonical( +// \\const UnexpectedError = error{ +// \\ /// The Operating System returned an undocumented error code. +// \\ Unexpected, +// \\ // another +// \\ Another, +// \\ +// \\ // in between +// \\ +// \\ // at end +// \\}; +// \\ +// ); +//} +// +//test "zig fmt: comments before switch prong" { +// try testCanonical( +// \\test "" { +// \\ switch (err) { +// \\ error.PathAlreadyExists => continue, +// \\ +// \\ // comment 1 +// \\ +// \\ // comment 2 +// \\ else => return err, +// \\ // at end +// \\ } +// \\} +// \\ +// ); +//} +// +//test "zig fmt: comments before var decl in struct" { +// try testCanonical( +// \\pub const vfs_cap_data = extern struct { +// \\ // All of these are mandated as little endian +// \\ // when on disk. +// \\ const Data = struct { +// \\ permitted: u32, +// \\ inheritable: u32, +// \\ }; +// \\ +// \\ // in between +// \\ +// \\ /// All of these are mandated as little endian +// \\ /// when on disk. +// \\ const Data = struct { +// \\ permitted: u32, +// \\ inheritable: u32, +// \\ }; +// \\ +// \\ // at end +// \\}; +// \\ +// ); +//} +// +//test "zig fmt: array literal with 1 item on 1 line" { +// try testCanonical( +// \\var s = []const u64{0} ** 25; +// \\ +// ); +//} +// +//test "zig fmt: comments before global variables" { +// try testCanonical( +// \\/// Foo copies keys and values before they go into the map, and +// \\/// frees them when they get removed. +// \\pub const Foo = struct {}; +// \\ +// ); +//} +// +//test "zig fmt: comments in statements" { +// try testCanonical( +// \\test "std" { +// \\ // statement comment +// \\ _ = @import("foo/bar.zig"); +// \\ +// \\ // middle +// \\ // middle2 +// \\ +// \\ // end +// \\} +// \\ +// ); +//} +// +//test "zig fmt: comments before test decl" { +// try testCanonical( +// \\/// top level doc comment +// \\test "hi" {} +// \\ +// \\// top level normal comment +// \\test "hi" {} +// \\ +// \\// middle +// \\ +// \\// end +// \\ +// ); +//} +// +//test "zig fmt: preserve spacing" { +// try testCanonical( +// \\const std = @import("std"); +// \\ +// \\pub fn main() !void { +// \\ var stdout_file = std.io.getStdOut; +// \\ var stdout_file = std.io.getStdOut; +// \\ +// \\ var stdout_file = std.io.getStdOut; +// \\ var stdout_file = std.io.getStdOut; +// \\} +// \\ +// ); +//} +// +//test "zig fmt: return types" { +// try testCanonical( +// \\pub fn main() !void {} +// \\pub fn main() anytype {} +// \\pub fn main() i32 {} +// \\ +// ); +//} +// +//test "zig fmt: imports" { +// try testCanonical( +// \\const std = @import("std"); +// \\const std = @import(); +// \\ +// ); +//} +// +//test "zig fmt: global declarations" { +// try testCanonical( +// \\const a = b; +// \\pub const a = b; +// \\var a = b; +// \\pub var a = b; +// \\const a: i32 = b; +// \\pub const a: i32 = b; +// \\var a: i32 = b; +// \\pub var a: i32 = b; +// \\extern const a: i32 = b; +// \\pub extern const a: i32 = b; +// \\extern var a: i32 = b; +// \\pub extern var a: i32 = b; +// \\extern "a" const a: i32 = b; +// \\pub extern "a" const a: i32 = b; +// \\extern "a" var a: i32 = b; +// \\pub extern "a" var a: i32 = b; +// \\ +// ); +//} +// +//test "zig fmt: extern declaration" { +// try testCanonical( +// \\extern var foo: c_int; +// \\ +// ); +//} +// +//test "zig fmt: alignment" { +// try testCanonical( +// \\var foo: c_int align(1); +// \\ +// ); +//} +// +//test "zig fmt: C main" { +// try testCanonical( +// \\fn main(argc: c_int, argv: **u8) c_int { +// \\ const a = b; +// \\} +// \\ +// ); +//} +// +//test "zig fmt: return" { +// try testCanonical( +// \\fn foo(argc: c_int, argv: **u8) c_int { +// \\ return 0; +// \\} +// \\ +// \\fn bar() void { +// \\ return; +// \\} +// \\ +// ); +//} +// +//test "zig fmt: pointer attributes" { +// try testCanonical( +// \\extern fn f1(s: *align(*u8) u8) c_int; +// \\extern fn f2(s: **align(1) *const *volatile u8) c_int; +// \\extern fn f3(s: *align(1) const *align(1) volatile *const volatile u8) c_int; +// \\extern fn f4(s: *align(1) const volatile u8) c_int; +// \\extern fn f5(s: [*:0]align(1) const volatile u8) c_int; +// \\ +// ); +//} +// +//test "zig fmt: slice attributes" { +// try testCanonical( +// \\extern fn f1(s: *align(*u8) u8) c_int; +// \\extern fn f2(s: **align(1) *const *volatile u8) c_int; +// \\extern fn f3(s: *align(1) const *align(1) volatile *const volatile u8) c_int; +// \\extern fn f4(s: *align(1) const volatile u8) c_int; +// \\extern fn f5(s: [*:0]align(1) const volatile u8) c_int; +// \\ +// ); +//} +// +//test "zig fmt: test declaration" { +// try testCanonical( +// \\test "test name" { +// \\ const a = 1; +// \\ var b = 1; +// \\} +// \\ +// ); +//} +// +//test "zig fmt: infix operators" { +// try testCanonical( +// \\test "infix operators" { +// \\ var i = undefined; +// \\ i = 2; +// \\ i *= 2; +// \\ i |= 2; +// \\ i ^= 2; +// \\ i <<= 2; +// \\ i >>= 2; +// \\ i &= 2; +// \\ i *= 2; +// \\ i *%= 2; +// \\ i -= 2; +// \\ i -%= 2; +// \\ i += 2; +// \\ i +%= 2; +// \\ i /= 2; +// \\ i %= 2; +// \\ _ = i == i; +// \\ _ = i != i; +// \\ _ = i != i; +// \\ _ = i.i; +// \\ _ = i || i; +// \\ _ = 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" { +// \\ a!b(); +// \\ (a!b)(); +// \\ !a!b; +// \\ !(a!b); +// \\ !a{}; +// \\ !(a{}); +// \\ a + b{}; +// \\ (a + b){}; +// \\ a << b + c; +// \\ (a << b) + c; +// \\ a & b << c; +// \\ (a & b) << c; +// \\ a ^ b & c; +// \\ (a ^ b) & c; +// \\ a | b ^ c; +// \\ (a | b) ^ c; +// \\ a == b | c; +// \\ (a == b) | c; +// \\ a and b == c; +// \\ (a and b) == c; +// \\ a or b and c; +// \\ (a or b) and c; +// \\ (a or b) and c; +// \\} +// \\ +// ); +//} +// +//test "zig fmt: prefix operators" { +// try testCanonical( +// \\test "prefix operators" { +// \\ try return --%~!&0; +// \\} +// \\ +// ); +//} +// +//test "zig fmt: call expression" { +// try testCanonical( +// \\test "test calls" { +// \\ a(); +// \\ a(1); +// \\ a(1, 2); +// \\ a(1, 2) + a(1, 2); +// \\} +// \\ +// ); +//} +// +//test "zig fmt: anytype type" { +// try testCanonical( +// \\fn print(args: anytype) anytype {} +// \\ +// ); +//} +// +//test "zig fmt: functions" { +// try testCanonical( +// \\extern fn puts(s: *const u8) c_int; +// \\extern "c" fn puts(s: *const u8) c_int; +// \\export fn puts(s: *const u8) c_int; +// \\inline fn puts(s: *const u8) c_int; +// \\noinline fn puts(s: *const u8) c_int; +// \\pub extern fn puts(s: *const u8) c_int; +// \\pub extern "c" fn puts(s: *const u8) c_int; +// \\pub export fn puts(s: *const u8) c_int; +// \\pub inline fn puts(s: *const u8) c_int; +// \\pub noinline fn puts(s: *const u8) c_int; +// \\pub extern fn puts(s: *const u8) align(2 + 2) c_int; +// \\pub extern "c" fn puts(s: *const u8) align(2 + 2) c_int; +// \\pub export fn puts(s: *const u8) align(2 + 2) c_int; +// \\pub inline fn puts(s: *const u8) align(2 + 2) c_int; +// \\pub noinline fn puts(s: *const u8) align(2 + 2) c_int; +// \\ +// ); +//} +// +//test "zig fmt: multiline string" { +// try testCanonical( +// \\test "" { +// \\ const s1 = +// \\ \\one +// \\ \\two) +// \\ \\three +// \\ ; +// \\ const s3 = // hi +// \\ \\one +// \\ \\two) +// \\ \\three +// \\ ; +// \\} +// \\ +// ); +//} +// +//test "zig fmt: values" { +// try testCanonical( +// \\test "values" { +// \\ 1; +// \\ 1.0; +// \\ "string"; +// \\ 'c'; +// \\ true; +// \\ false; +// \\ null; +// \\ undefined; +// \\ anyerror; +// \\ this; +// \\ unreachable; +// \\} +// \\ +// ); +//} +// +//test "zig fmt: indexing" { +// try testCanonical( +// \\test "test index" { +// \\ a[0]; +// \\ a[0 + 5]; +// \\ a[0..]; +// \\ a[0..5]; +// \\ a[a[0]]; +// \\ a[a[0..]]; +// \\ a[a[0..5]]; +// \\ a[a[0]..]; +// \\ a[a[0..5]..]; +// \\ a[a[0]..a[0]]; +// \\ a[a[0..5]..a[0]]; +// \\ a[a[0..5]..a[0..5]]; +// \\} +// \\ +// ); +//} +// +//test "zig fmt: struct declaration" { +// try testCanonical( +// \\const S = struct { +// \\ const Self = @This(); +// \\ f1: u8, +// \\ f3: u8, +// \\ +// \\ f2: u8, +// \\ +// \\ fn method(self: *Self) Self { +// \\ return self.*; +// \\ } +// \\}; +// \\ +// \\const Ps = packed struct { +// \\ a: u8, +// \\ b: u8, +// \\ +// \\ c: u8, +// \\}; +// \\ +// \\const Es = extern struct { +// \\ a: u8, +// \\ b: u8, +// \\ +// \\ c: u8, +// \\}; +// \\ +// ); +//} +// +//test "zig fmt: enum declaration" { +// try testCanonical( +// \\const E = enum { +// \\ Ok, +// \\ SomethingElse = 0, +// \\}; +// \\ +// \\const E2 = enum(u8) { +// \\ Ok, +// \\ SomethingElse = 255, +// \\ SomethingThird, +// \\}; +// \\ +// \\const Ee = extern enum { +// \\ Ok, +// \\ SomethingElse, +// \\ SomethingThird, +// \\}; +// \\ +// \\const Ep = packed enum { +// \\ Ok, +// \\ SomethingElse, +// \\ SomethingThird, +// \\}; +// \\ +// ); +//} +// +//test "zig fmt: union declaration" { +// try testCanonical( +// \\const U = union { +// \\ Int: u8, +// \\ Float: f32, +// \\ None, +// \\ Bool: bool, +// \\}; +// \\ +// \\const Ue = union(enum) { +// \\ Int: u8, +// \\ Float: f32, +// \\ None, +// \\ Bool: bool, +// \\}; +// \\ +// \\const E = enum { +// \\ Int, +// \\ Float, +// \\ None, +// \\ Bool, +// \\}; +// \\ +// \\const Ue2 = union(E) { +// \\ Int: u8, +// \\ Float: f32, +// \\ None, +// \\ Bool: bool, +// \\}; +// \\ +// \\const Eu = extern union { +// \\ Int: u8, +// \\ Float: f32, +// \\ None, +// \\ Bool: bool, +// \\}; +// \\ +// ); +//} +// +//test "zig fmt: arrays" { +// try testCanonical( +// \\test "test array" { +// \\ const a: [2]u8 = [2]u8{ +// \\ 1, +// \\ 2, +// \\ }; +// \\ const a: [2]u8 = []u8{ +// \\ 1, +// \\ 2, +// \\ }; +// \\ const a: [0]u8 = []u8{}; +// \\ const x: [4:0]u8 = undefined; +// \\} +// \\ +// ); +//} +// +//test "zig fmt: container initializers" { +// try testCanonical( +// \\const a0 = []u8{}; +// \\const a1 = []u8{1}; +// \\const a2 = []u8{ +// \\ 1, +// \\ 2, +// \\ 3, +// \\ 4, +// \\}; +// \\const s0 = S{}; +// \\const s1 = S{ .a = 1 }; +// \\const s2 = S{ +// \\ .a = 1, +// \\ .b = 2, +// \\}; +// \\ +// ); +//} +// +//test "zig fmt: catch" { +// try testCanonical( +// \\test "catch" { +// \\ const a: anyerror!u8 = 0; +// \\ _ = a catch return; +// \\ _ = a catch |err| return; +// \\} +// \\ +// ); +//} +// +//test "zig fmt: blocks" { +// try testCanonical( +// \\test "blocks" { +// \\ { +// \\ const a = 0; +// \\ const b = 0; +// \\ } +// \\ +// \\ blk: { +// \\ const a = 0; +// \\ const b = 0; +// \\ } +// \\ +// \\ const r = blk: { +// \\ const a = 0; +// \\ const b = 0; +// \\ }; +// \\} +// \\ +// ); +//} +// +//test "zig fmt: switch" { +// try testCanonical( +// \\test "switch" { +// \\ switch (0) { +// \\ 0 => {}, +// \\ 1 => unreachable, +// \\ 2, 3 => {}, +// \\ 4...7 => {}, +// \\ 1 + 4 * 3 + 22 => {}, +// \\ else => { +// \\ const a = 1; +// \\ const b = a; +// \\ }, +// \\ } +// \\ +// \\ const res = switch (0) { +// \\ 0 => 0, +// \\ 1 => 2, +// \\ 1 => a = 4, +// \\ else => 4, +// \\ }; +// \\ +// \\ const Union = union(enum) { +// \\ Int: i64, +// \\ Float: f64, +// \\ }; +// \\ +// \\ switch (u) { +// \\ Union.Int => |int| {}, +// \\ Union.Float => |*float| unreachable, +// \\ } +// \\} +// \\ +// ); +//} +// +//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; +// \\ } +// \\ +// \\ var a: ?u8 = 2; +// \\ while (a) |v| : (a = null) { +// \\ 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) |v, i| { +// \\ continue; +// \\ } +// \\ +// \\ for (a) |v, i| +// \\ continue; +// \\ +// \\ for (a) |b| switch (b) { +// \\ c => {}, +// \\ d => {}, +// \\ }; +// \\ +// \\ for (a) |b| +// \\ switch (b) { +// \\ c => {}, +// \\ d => {}, +// \\ }; +// \\ +// \\ const res = for (a) |v, i| { +// \\ break v; +// \\ } else { +// \\ unreachable; +// \\ }; +// \\ +// \\ var num: usize = 0; +// \\ inline for (a) |v, i| { +// \\ num += v; +// \\ num += i; +// \\ } +// \\} +// \\ +// ); +// +// try testTransform( +// \\test "fix for" { +// \\ for (a) |x| +// \\ f(x) else continue; +// \\} +// \\ +// , +// \\test "fix for" { +// \\ for (a) |x| +// \\ f(x) +// \\ else continue; +// \\} +// \\ +// ); +//} +// +//test "zig fmt: if" { +// try testCanonical( +// \\test "if" { +// \\ if (10 < 0) { +// \\ unreachable; +// \\ } +// \\ +// \\ if (10 < 0) unreachable; +// \\ +// \\ if (10 < 0) { +// \\ unreachable; +// \\ } else { +// \\ const a = 20; +// \\ } +// \\ +// \\ if (10 < 0) { +// \\ unreachable; +// \\ } else if (5 < 0) { +// \\ unreachable; +// \\ } else { +// \\ const a = 20; +// \\ } +// \\ +// \\ const is_world_broken = if (10 < 0) true else false; +// \\ const some_number = 1 + if (10 < 0) 2 else 3; +// \\ +// \\ const a: ?u8 = 10; +// \\ const b: ?u8 = null; +// \\ if (a) |v| { +// \\ const some = v; +// \\ } else if (b) |*v| { +// \\ unreachable; +// \\ } else { +// \\ const some = 10; +// \\ } +// \\ +// \\ const non_null_a = if (a) |v| v else 0; +// \\ +// \\ const a_err: anyerror!u8 = 0; +// \\ if (a_err) |v| { +// \\ const p = v; +// \\ } else |err| { +// \\ unreachable; +// \\ } +// \\} +// \\ +// ); +//} +// +//test "zig fmt: defer" { +// try testCanonical( +// \\test "defer" { +// \\ var i: usize = 0; +// \\ defer i = 1; +// \\ defer { +// \\ i += 2; +// \\ i *= i; +// \\ } +// \\ +// \\ errdefer i += 3; +// \\ errdefer { +// \\ i += 2; +// \\ i /= i; +// \\ } +// \\} +// \\ +// ); +//} +// +//test "zig fmt: comptime" { +// try testCanonical( +// \\fn a() u8 { +// \\ return 5; +// \\} +// \\ +// \\fn b(comptime i: u8) u8 { +// \\ return i; +// \\} +// \\ +// \\const av = comptime a(); +// \\const av2 = comptime blk: { +// \\ var res = a(); +// \\ res *= b(2); +// \\ break :blk res; +// \\}; +// \\ +// \\comptime { +// \\ _ = a(); +// \\} +// \\ +// \\test "comptime" { +// \\ const av3 = comptime a(); +// \\ const av4 = comptime blk: { +// \\ var res = a(); +// \\ res *= a(); +// \\ break :blk res; +// \\ }; +// \\ +// \\ comptime var i = 0; +// \\ comptime { +// \\ i = a(); +// \\ i += b(i); +// \\ } +// \\} +// \\ +// ); +//} +// +//test "zig fmt: fn type" { +// try testCanonical( +// \\fn a(i: u8) u8 { +// \\ return i + 1; +// \\} +// \\ +// \\const a: fn (u8) u8 = undefined; +// \\const b: fn (u8) callconv(.Naked) u8 = undefined; +// \\const ap: fn (u8) u8 = a; +// \\ +// ); +//} +// +//test "zig fmt: inline asm" { +// try testCanonical( +// \\pub fn syscall1(number: usize, arg1: usize) usize { +// \\ return asm volatile ("syscall" +// \\ : [ret] "={rax}" (-> usize) +// \\ : [number] "{rax}" (number), +// \\ [arg1] "{rdi}" (arg1) +// \\ : "rcx", "r11" +// \\ ); +// \\} +// \\ +// ); +//} +// +//test "zig fmt: async functions" { +// try testCanonical( +// \\fn simpleAsyncFn() void { +// \\ const a = async a.b(); +// \\ x += 1; +// \\ suspend; +// \\ x += 1; +// \\ suspend; +// \\ const p: anyframe->void = async simpleAsyncFn() catch unreachable; +// \\ await p; +// \\} +// \\ +// \\test "suspend, resume, await" { +// \\ const p: anyframe = async testAsyncSeq(); +// \\ resume p; +// \\ await p; +// \\} +// \\ +// ); +//} +// +//test "zig fmt: nosuspend" { +// try testCanonical( +// \\const a = nosuspend foo(); +// \\ +// ); +//} +// +//test "zig fmt: Block after if" { +// try testCanonical( +// \\test "Block after if" { +// \\ if (true) { +// \\ const a = 0; +// \\ } +// \\ +// \\ { +// \\ const a = 0; +// \\ } +// \\} +// \\ +// ); +//} +// +//test "zig fmt: use" { +// try testCanonical( +// \\usingnamespace @import("std"); +// \\pub usingnamespace @import("std"); +// \\ +// ); +//} +// +//test "zig fmt: string identifier" { +// try testCanonical( +// \\const @"a b" = @"c d".@"e f"; +// \\fn @"g h"() void {} +// \\ +// ); +//} +// +//test "zig fmt: error return" { +// try testCanonical( +// \\fn err() anyerror { +// \\ call(); +// \\ return error.InvalidArgs; +// \\} +// \\ +// ); +//} +// +//test "zig fmt: comptime block in container" { +// try testCanonical( +// \\pub fn container() type { +// \\ return struct { +// \\ comptime { +// \\ if (false) { +// \\ unreachable; +// \\ } +// \\ } +// \\ }; +// \\} +// \\ +// ); +//} +// +//test "zig fmt: inline asm parameter alignment" { +// try testCanonical( +// \\pub fn main() void { +// \\ asm volatile ( +// \\ \\ foo +// \\ \\ bar +// \\ ); +// \\ asm volatile ( +// \\ \\ foo +// \\ \\ bar +// \\ : [_] "" (-> usize), +// \\ [_] "" (-> usize) +// \\ ); +// \\ asm volatile ( +// \\ \\ foo +// \\ \\ bar +// \\ : +// \\ : [_] "" (0), +// \\ [_] "" (0) +// \\ ); +// \\ asm volatile ( +// \\ \\ foo +// \\ \\ bar +// \\ : +// \\ : +// \\ : "", "" +// \\ ); +// \\ asm volatile ( +// \\ \\ foo +// \\ \\ bar +// \\ : [_] "" (-> usize), +// \\ [_] "" (-> usize) +// \\ : [_] "" (0), +// \\ [_] "" (0) +// \\ : "", "" +// \\ ); +// \\} +// \\ +// ); +//} +// +//test "zig fmt: multiline string in array" { +// try testCanonical( +// \\const Foo = [][]const u8{ +// \\ \\aaa +// \\ , +// \\ \\bbb +// \\}; +// \\ +// \\fn bar() void { +// \\ const Foo = [][]const u8{ +// \\ \\aaa +// \\ , +// \\ \\bbb +// \\ }; +// \\ const Bar = [][]const u8{ // comment here +// \\ \\aaa +// \\ \\ +// \\ , // and another comment can go here +// \\ \\bbb +// \\ }; +// \\} +// \\ +// ); +//} +// +//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 +// \\ +// ); +//} +// +//test "zig fmt: comment after empty comment" { +// try testTransform( +// \\const x = true; // +// \\// +// \\// +// \\//a +// \\ +// , +// \\const x = true; +// \\//a +// \\ +// ); +//} +// +//test "zig fmt: line comment in array" { +// try testTransform( +// \\test "a" { +// \\ var arr = [_]u32{ +// \\ 0 +// \\ // 1, +// \\ // 2, +// \\ }; +// \\} +// \\ +// , +// \\test "a" { +// \\ var arr = [_]u32{ +// \\ 0, // 1, +// \\ // 2, +// \\ }; +// \\} +// \\ +// ); +// try testCanonical( +// \\test "a" { +// \\ var arr = [_]u32{ +// \\ 0, +// \\ // 1, +// \\ // 2, +// \\ }; +// \\} +// \\ +// ); +//} +// +//test "zig fmt: comment after params" { +// try testTransform( +// \\fn a( +// \\ b: u32 +// \\ // c: u32, +// \\ // d: u32, +// \\) void {} +// \\ +// , +// \\fn a( +// \\ b: u32, // c: u32, +// \\ // d: u32, +// \\) void {} +// \\ +// ); +// try testCanonical( +// \\fn a( +// \\ b: u32, +// \\ // c: u32, +// \\ // d: u32, +// \\) void {} +// \\ +// ); +//} +// +//test "zig fmt: comment in array initializer/access" { +// try testCanonical( +// \\test "a" { +// \\ var a = x{ //aa +// \\ //bb +// \\ }; +// \\ var a = []x{ //aa +// \\ //bb +// \\ }; +// \\ var b = [ //aa +// \\ _ +// \\ ]x{ //aa +// \\ //bb +// \\ 9, +// \\ }; +// \\ var c = b[ //aa +// \\ 0 +// \\ ]; +// \\ var d = [_ +// \\ //aa +// \\ ]x{ //aa +// \\ //bb +// \\ 9, +// \\ }; +// \\ var e = d[0 +// \\ //aa +// \\ ]; +// \\} +// \\ +// ); +//} +// +//test "zig fmt: comments at several places in struct init" { +// try testTransform( +// \\var bar = Bar{ +// \\ .x = 10, // test +// \\ .y = "test" +// \\ // test +// \\}; +// \\ +// , +// \\var bar = Bar{ +// \\ .x = 10, // test +// \\ .y = "test", // test +// \\}; +// \\ +// ); +// +// try testCanonical( +// \\var bar = Bar{ // test +// \\ .x = 10, // test +// \\ .y = "test", +// \\ // test +// \\}; +// \\ +// ); +//} +// +//test "zig fmt: top level doc comments" { +// try testCanonical( +// \\//! tld 1 +// \\//! tld 2 +// \\//! tld 3 +// \\ +// \\// comment +// \\ +// \\/// A doc +// \\const A = struct { +// \\ //! A tld 1 +// \\ //! A tld 2 +// \\ //! A tld 3 +// \\}; +// \\ +// \\/// B doc +// \\const B = struct { +// \\ //! B tld 1 +// \\ //! B tld 2 +// \\ //! B tld 3 +// \\ +// \\ /// b doc +// \\ b: u32, +// \\}; +// \\ +// \\/// C doc +// \\const C = struct { +// \\ //! C tld 1 +// \\ //! C tld 2 +// \\ //! C tld 3 +// \\ +// \\ /// c1 doc +// \\ c1: u32, +// \\ +// \\ //! C tld 4 +// \\ //! C tld 5 +// \\ //! C tld 6 +// \\ +// \\ /// c2 doc +// \\ c2: u32, +// \\}; +// \\ +// ); +// try testCanonical( +// \\//! Top-level documentation. +// \\ +// \\/// This is A +// \\pub const A = usize; +// \\ +// ); +// try testCanonical( +// \\//! Nothing here +// \\ +// ); +//} +// +//test "zig fmt: extern without container keyword returns error" { +// try testError( +// \\const container = extern {}; +// \\ +// , &[_]Error{ +// .ExpectedExpr, +// .ExpectedVarDeclOrFn, +// }); +//} +// +//test "zig fmt: integer literals with underscore separators" { +// try testTransform( +// \\const +// \\ x = +// \\ 1_234_567 +// \\ +(0b0_1-0o7_0+0xff_FF ) + 0_0; +// , +// \\const x = +// \\ 1_234_567 + (0b0_1 - 0o7_0 + 0xff_FF) + 0_0; +// \\ +// ); +//} +// +//test "zig fmt: hex literals with underscore separators" { +// try testTransform( +// \\pub fn orMask(a: [ 1_000 ]u64, b: [ 1_000] u64) [1_000]u64 { +// \\ var c: [1_000]u64 = [1]u64{ 0xFFFF_FFFF_FFFF_FFFF}**1_000; +// \\ for (c [ 0_0 .. ]) |_, i| { +// \\ c[i] = (a[i] | b[i]) & 0xCCAA_CCAA_CCAA_CCAA; +// \\ } +// \\ return c; +// \\} +// \\ +// \\ +// , +// \\pub fn orMask(a: [1_000]u64, b: [1_000]u64) [1_000]u64 { +// \\ var c: [1_000]u64 = [1]u64{0xFFFF_FFFF_FFFF_FFFF} ** 1_000; +// \\ for (c[0_0..]) |_, i| { +// \\ c[i] = (a[i] | b[i]) & 0xCCAA_CCAA_CCAA_CCAA; +// \\ } +// \\ return c; +// \\} +// \\ +// ); +//} +// +//test "zig fmt: decimal float literals with underscore separators" { +// try testTransform( +// \\pub fn main() void { +// \\ const a:f64=(10.0e-0+(10.e+0))+10_00.00_00e-2+00_00.00_10e+4; +// \\ const b:f64=010.0--0_10.+0_1_0.0_0+1e2; +// \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b }); +// \\} +// , +// \\pub fn main() void { +// \\ const a: f64 = (10.0e-0 + (10.e+0)) + 10_00.00_00e-2 + 00_00.00_10e+4; +// \\ const b: f64 = 010.0 - -0_10. + 0_1_0.0_0 + 1e2; +// \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b }); +// \\} +// \\ +// ); +//} +// +//test "zig fmt: hexadeciaml float literals with underscore separators" { +// try testTransform( +// \\pub fn main() void { +// \\ const a: f64 = (0x10.0p-0+(0x10.p+0))+0x10_00.00_00p-8+0x00_00.00_10p+16; +// \\ const b: f64 = 0x0010.0--0x00_10.+0x10.00+0x1p4; +// \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b }); +// \\} +// , +// \\pub fn main() void { +// \\ const a: f64 = (0x10.0p-0 + (0x10.p+0)) + 0x10_00.00_00p-8 + 0x00_00.00_10p+16; +// \\ const b: f64 = 0x0010.0 - -0x00_10. + 0x10.00 + 0x1p4; +// \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b }); +// \\} +// \\ +// ); +//} +// +//test "zig fmt: convert async fn into callconv(.Async)" { +// try testTransform( +// \\async fn foo() void {} +// , +// \\fn foo() callconv(.Async) void {} +// \\ +// ); +//} +// +//test "zig fmt: convert extern fn proto into callconv(.C)" { +// try testTransform( +// \\extern fn foo0() void {} +// \\const foo1 = extern fn () void; +// , +// \\extern fn foo0() void {} +// \\const foo1 = fn () callconv(.C) void; +// \\ +// ); +//} +// +//test "zig fmt: C var args" { +// try testCanonical( +// \\pub extern "c" fn printf(format: [*:0]const u8, ...) c_int; +// \\ +// ); +//} +// +//test "zig fmt: Only indent multiline string literals in function calls" { +// try testCanonical( +// \\test "zig fmt:" { +// \\ try testTransform( +// \\ \\const X = struct { +// \\ \\ foo: i32, bar: i8 }; +// \\ , +// \\ \\const X = struct { +// \\ \\ foo: i32, bar: i8 +// \\ \\}; +// \\ \\ +// \\ ); +// \\} +// \\ +// ); +//} +// +//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 { +// \\ if (cwd().symLink(existing_path, new_path, .{})) { +// \\ return; +// \\ } +// \\} +// \\ +// ); +//} +// +//test "zig fmt: comments in ternary ifs" { +// try testCanonical( +// \\const x = if (true) { +// \\ 1; +// \\} else if (false) +// \\ // Comment +// \\ 0; +// \\const y = if (true) +// \\ // Comment +// \\ 1 +// \\else +// \\ 0; +// \\ +// \\pub extern "c" fn printf(format: [*:0]const u8, ...) c_int; +// \\ +// ); +//} +// +//test "zig fmt: test comments in field access chain" { +// try testCanonical( +// \\pub const str = struct { +// \\ pub const Thing = more.more // +// \\ .more() // +// \\ .more().more() // +// \\ .more() // +// \\ // .more() // +// \\ .more() // +// \\ .more(); +// \\ data: Data, +// \\}; +// \\ +// \\pub const str = struct { +// \\ pub const Thing = more.more // +// \\ .more() // +// \\ // .more() // +// \\ // .more() // +// \\ // .more() // +// \\ .more() // +// \\ .more(); +// \\ data: Data, +// \\}; +// \\ +// \\pub const str = struct { +// \\ pub const Thing = more // +// \\ .more // +// \\ .more() // +// \\ .more(); +// \\ data: Data, +// \\}; +// \\ +// ); +//} +// +//test "zig fmt: Indent comma correctly after multiline string literals in arg list (trailing comma)" { +// try testCanonical( +// \\fn foo() void { +// \\ z.display_message_dialog( +// \\ *const [323:0]u8, +// \\ \\Message Text +// \\ \\------------ +// \\ \\xxxxxxxxxxxx +// \\ \\xxxxxxxxxxxx +// \\ , +// \\ g.GtkMessageType.GTK_MESSAGE_WARNING, +// \\ null, +// \\ ); +// \\ +// \\ z.display_message_dialog(*const [323:0]u8, +// \\ \\Message Text +// \\ \\------------ +// \\ \\xxxxxxxxxxxx +// \\ \\xxxxxxxxxxxx +// \\ , g.GtkMessageType.GTK_MESSAGE_WARNING, null); +// \\} +// \\ +// ); +//} +// +//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: " { +// try testCanonical( +// \\pub fn sendViewTags(self: Self) void { +// \\ var it = ViewStack(View).iterator(self.output.views.first, std.math.maxInt(u32)); +// \\ while (it.next()) |node| +// \\ view_tags.append(node.view.current_tags) catch { +// \\ c.wl_resource_post_no_memory(self.wl_resource); +// \\ log.crit(.river_status, "out of memory", .{}); +// \\ return; +// \\ }; +// \\} +// \\ +// ); +//} +// +//test "zig fmt: allow trailing line comments to do manual array formatting" { +// try testCanonical( +// \\fn foo() void { +// \\ self.code.appendSliceAssumeCapacity(&[_]u8{ +// \\ 0x55, // push rbp +// \\ 0x48, 0x89, 0xe5, // mov rbp, rsp +// \\ 0x48, 0x81, 0xec, // sub rsp, imm32 (with reloc) +// \\ }); +// \\ +// \\ di_buf.appendAssumeCapacity(&[_]u8{ +// \\ 1, DW.TAG_compile_unit, DW.CHILDREN_no, // header +// \\ DW.AT_stmt_list, DW_FORM_data4, // form value pairs +// \\ DW.AT_low_pc, DW_FORM_addr, +// \\ DW.AT_high_pc, DW_FORM_addr, +// \\ DW.AT_name, DW_FORM_strp, +// \\ DW.AT_comp_dir, DW_FORM_strp, +// \\ DW.AT_producer, DW_FORM_strp, +// \\ DW.AT_language, DW_FORM_data2, +// \\ 0, 0, // sentinel +// \\ }); +// \\ +// \\ self.code.appendSliceAssumeCapacity(&[_]u8{ +// \\ 0x55, // push rbp +// \\ 0x48, 0x89, 0xe5, // mov rbp, rsp +// \\ // How do we handle this? +// \\ //0x48, 0x81, 0xec, // sub rsp, imm32 (with reloc) +// \\ // Here's a blank line, should that be allowed? +// \\ +// \\ 0x48, 0x89, 0xe5, +// \\ 0x33, 0x45, +// \\ // Now the comment breaks a single line -- how do we handle this? +// \\ 0x88, +// \\ }); +// \\} +// \\ +// ); +//} +// +//test "zig fmt: multiline string literals should play nice with array initializers" { +// try testCanonical( +// \\fn main() void { +// \\ var a = .{.{.{.{.{.{.{.{ +// \\ 0, +// \\ }}}}}}}}; +// \\ myFunc(.{ +// \\ "aaaaaaa", "bbbbbb", "ccccc", +// \\ "dddd", ("eee"), ("fff"), +// \\ ("gggg"), +// \\ // Line comment +// \\ \\Multiline String Literals can be quite long +// \\ , +// \\ \\Multiline String Literals can be quite long +// \\ \\Multiline String Literals can be quite long +// \\ , +// \\ \\Multiline String Literals can be quite long +// \\ \\Multiline String Literals can be quite long +// \\ \\Multiline String Literals can be quite long +// \\ \\Multiline String Literals can be quite long +// \\ , +// \\ ( +// \\ \\Multiline String Literals can be quite long +// \\ ), +// \\ .{ +// \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +// \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +// \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +// \\ }, +// \\ .{( +// \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +// \\ )}, +// \\ .{ +// \\ "xxxxxxx", "xxx", +// \\ ( +// \\ \\ xxx +// \\ ), +// \\ "xxx", "xxx", +// \\ }, +// \\ .{ "xxxxxxx", "xxx", "xxx", "xxx" }, .{ "xxxxxxx", "xxx", "xxx", "xxx" }, +// \\ "aaaaaaa", "bbbbbb", "ccccc", // - +// \\ "dddd", ("eee"), ("fff"), +// \\ .{ +// \\ "xxx", "xxx", +// \\ ( +// \\ \\ xxx +// \\ ), +// \\ "xxxxxxxxxxxxxx", "xxx", +// \\ }, +// \\ .{ +// \\ ( +// \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +// \\ ), +// \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +// \\ }, +// \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +// \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +// \\ }); +// \\} +// \\ +// ); +//} +// +//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 { +// \\ cases.add( // fixed bug #2032 +// \\ "compile diagnostic string for top level decl type", +// \\ \\export fn entry() void { +// \\ \\ var foo: u32 = @This(){}; +// \\ \\} +// \\ , &[_][]const u8{ +// \\ "tmp.zig:2:27: error: type 'u32' does not support array initialization", +// \\ }); +// \\ @compileError( +// \\ \\ unknown-length pointers and C pointers cannot be hashed deeply. +// \\ \\ Consider providing your own hash function. +// \\ \\ unknown-length pointers and C pointers cannot be hashed deeply. +// \\ \\ Consider providing your own hash function. +// \\ ); +// \\ return @intCast(i1, doMemCheckClientRequestExpr(0, // default return +// \\ .MakeMemUndefined, @ptrToInt(qzz.ptr), qzz.len, 0, 0, 0)); +// \\} +// \\ +// \\// This looks like garbage don't do this +// \\const rparen = tree.prevToken( +// \\// the first token for the annotation expressions is the left +// \\// parenthesis, hence the need for two prevToken +// \\ if (fn_proto.getAlignExpr()) |align_expr| +// \\ tree.prevToken(tree.prevToken(align_expr.firstToken())) +// \\else if (fn_proto.getSectionExpr()) |section_expr| +// \\ tree.prevToken(tree.prevToken(section_expr.firstToken())) +// \\else if (fn_proto.getCallconvExpr()) |callconv_expr| +// \\ tree.prevToken(tree.prevToken(callconv_expr.firstToken())) +// \\else switch (fn_proto.return_type) { +// \\ .Explicit => |node| node.firstToken(), +// \\ .InferErrorSet => |node| tree.prevToken(node.firstToken()), +// \\ .Invalid => unreachable, +// \\}); +// \\ +// ); +//} +// +//test "zig fmt: single argument trailing commas in @builtins()" { +// try testCanonical( +// \\pub fn foo(qzz: []u8) i1 { +// \\ @panic( +// \\ foo, +// \\ ); +// \\ panic( +// \\ foo, +// \\ ); +// \\ @panic( +// \\ foo, +// \\ bar, +// \\ ); +// \\} +// \\ +// ); +//} +// +//test "zig fmt: trailing comma should force multiline 1 column" { +// try testTransform( +// \\pub const UUID_NULL: uuid_t = [16]u8{0,0,0,0,}; +// \\ +// , +// \\pub const UUID_NULL: uuid_t = [16]u8{ +// \\ 0, +// \\ 0, +// \\ 0, +// \\ 0, +// \\}; +// \\ +// ); +//} +// +//test "zig fmt: function params should align nicely" { +// try testCanonical( +// \\pub fn foo() void { +// \\ cases.addRuntimeSafety("slicing operator with sentinel", +// \\ \\const std = @import("std"); +// \\ ++ check_panic_msg ++ +// \\ \\pub fn main() void { +// \\ \\ var buf = [4]u8{'a','b','c',0}; +// \\ \\ const slice = buf[0..:0]; +// \\ \\} +// \\ ); +// \\} +// \\ +// ); +//} const std = @import("std"); const mem = std.mem; @@ -3763,8 +3740,10 @@ fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *b errdefer buffer.deinit(); const writer = buffer.writer(); - anything_changed.* = try std.zig.render(allocator, writer, tree); - return buffer.toOwnedSlice(); + try std.zig.render(allocator, writer, tree); + const result = buffer.toOwnedSlice(); + anything_changed.* = !mem.eql(u8, result, source); + return result; } fn testTransform(source: []const u8, expected_source: []const u8) !void { const needed_alloc_count = x: { diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index c8568301ea..17c59776b5 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -14,2167 +14,2072 @@ const indent_delta = 4; const asm_indent_delta = 2; pub const Error = error{ - /// Ran out of memory allocating call stack frames to complete rendering. + /// Ran out of memory allocating call stack frames to complete rendering, or + /// ran out of memory allocating space in the output buffer. OutOfMemory, }; -/// Returns whether anything changed -pub fn render(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tree) (@TypeOf(stream).Error || Error)!bool { - // cannot render an invalid tree - std.debug.assert(tree.errors.len == 0); +const Writer = std.ArrayList(u8).Writer; +const Ais = std.io.AutoIndentingStream(Writer); - var change_detection_stream = std.io.changeDetectionStream(tree.source, stream); - var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, change_detection_stream.writer()); - - try renderRoot(allocator, &auto_indenting_stream, tree); - - return change_detection_stream.changeDetected(); +/// Returns whether anything changed. +/// `gpa` is used for allocating extra stack memory if needed, because +/// this function utilizes recursion. +pub fn render(gpa: *mem.Allocator, writer: Writer, tree: ast.Tree) Error!void { + assert(tree.errors.len == 0); // cannot render an invalid tree + var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, writer); + try renderRoot(&auto_indenting_stream, tree); } -fn renderRoot( - allocator: *mem.Allocator, - ais: anytype, - tree: *ast.Tree, -) (@TypeOf(ais.*).Error || Error)!void { - - // render all the line comments at the beginning of the file - for (tree.token_ids) |token_id, i| { - if (token_id != .LineComment) break; - const token_loc = tree.token_locs[i]; - try ais.writer().print("{s}\n", .{mem.trimRight(u8, tree.tokenSliceLoc(token_loc), " ")}); - const next_token = tree.token_locs[i + 1]; - const loc = tree.tokenLocationLoc(token_loc.end, next_token); - if (loc.line >= 2) { - try ais.insertNewline(); - } - } - - var decl_i: ast.NodeIndex = 0; - const root_decls = tree.root_node.decls(); - - if (root_decls.len == 0) return; +/// Assumes there are no tokens in between start and end. +fn renderComments(ais: *Ais, tree: ast.Tree, start: usize, end: usize, prefix: []const u8) Error!usize { + var index: usize = start; + var count: usize = 0; while (true) { - var decl = root_decls[decl_i]; - - // This loop does the following: - // - // - Iterates through line/doc comment tokens that precedes the current - // decl. - // - Figures out the first token index (`copy_start_token_index`) which - // hasn't been copied to the output stream yet. - // - Detects `zig fmt: (off|on)` in the line comment tokens, and - // determines whether the current decl should be reformatted or not. - // - var token_index = decl.firstToken(); - var fmt_active = true; - var found_fmt_directive = false; - - var copy_start_token_index = token_index; - - while (token_index != 0) { - token_index -= 1; - const token_id = tree.token_ids[token_index]; - switch (token_id) { - .LineComment => {}, - .DocComment => { - copy_start_token_index = token_index; - continue; - }, - else => break, - } - - const token_loc = tree.token_locs[token_index]; - if (mem.eql(u8, mem.trim(u8, tree.tokenSliceLoc(token_loc)[2..], " "), "zig fmt: off")) { - if (!found_fmt_directive) { - fmt_active = false; - found_fmt_directive = true; - } - } else if (mem.eql(u8, mem.trim(u8, tree.tokenSliceLoc(token_loc)[2..], " "), "zig fmt: on")) { - if (!found_fmt_directive) { - fmt_active = true; - found_fmt_directive = true; - } + // Scan forward to the next line comment, counting newlines. + const comment_start = mem.indexOf(u8, tree.source[index..end], "//") orelse return count; + const newline = mem.indexOfScalar(u8, tree.source[comment_start..end], '\n').?; + const untrimmed_comment = tree.source[comment_start..][0..newline]; + const trimmed_comment = mem.trimRight(u8, untrimmed_comment, " \r\t"); + if (count == 0) { + count += 1; + try ais.writer().writeAll(prefix); + } else { + // If another newline occurs between prev comment and this one + // we honor it, but not any additional ones. + if (mem.indexOfScalar(u8, tree.source[index..comment_start], '\n') != null) { + try ais.insertNewline(); } } + try ais.writer().print("{s}\n", .{trimmed_comment}); + index += comment_start + newline; + } +} - if (!fmt_active) { - // Reformatting is disabled for the current decl and possibly some - // more decls that follow. - // Find the next `decl` for which reformatting is re-enabled. - token_index = decl.firstToken(); - - while (!fmt_active) { - decl_i += 1; - if (decl_i >= root_decls.len) { - // If there's no next reformatted `decl`, just copy the - // remaining input tokens and bail out. - const start = tree.token_locs[copy_start_token_index].start; - try copyFixingWhitespace(ais, tree.source[start..]); - return; - } - decl = root_decls[decl_i]; - var decl_first_token_index = decl.firstToken(); - - while (token_index < decl_first_token_index) : (token_index += 1) { - const token_id = tree.token_ids[token_index]; - switch (token_id) { - .LineComment => {}, - .Eof => unreachable, - else => continue, - } - const token_loc = tree.token_locs[token_index]; - if (mem.eql(u8, mem.trim(u8, tree.tokenSliceLoc(token_loc)[2..], " "), "zig fmt: on")) { - fmt_active = true; - } else if (mem.eql(u8, mem.trim(u8, tree.tokenSliceLoc(token_loc)[2..], " "), "zig fmt: off")) { - fmt_active = false; - } - } - } - - // Found the next `decl` for which reformatting is enabled. Copy - // the input tokens before the `decl` that haven't been copied yet. - var copy_end_token_index = decl.firstToken(); - token_index = copy_end_token_index; - while (token_index != 0) { - token_index -= 1; - const token_id = tree.token_ids[token_index]; - switch (token_id) { - .LineComment => {}, - .DocComment => { - copy_end_token_index = token_index; - continue; - }, - else => break, - } - } +fn renderRoot(ais: *Ais, tree: ast.Tree) Error!void { + // Render all the line comments at the beginning of the file. + const src_start: usize = if (mem.startsWith(u8, tree.source, "\xEF\xBB\xBF")) 3 else 0; + const comment_end_loc: usize = tree.tokens.items(.start)[0]; + _ = try renderComments(ais, tree, src_start, comment_end_loc, ""); - const start = tree.token_locs[copy_start_token_index].start; - const end = tree.token_locs[copy_end_token_index].start; - try copyFixingWhitespace(ais, tree.source[start..end]); - } + // Root is always index 0. + const nodes_data = tree.nodes.items(.data); + const root_decls = tree.extra_data[nodes_data[0].lhs..nodes_data[0].rhs]; + if (root_decls.len == 0) return; - try renderTopLevelDecl(allocator, ais, tree, decl); - decl_i += 1; - if (decl_i >= root_decls.len) return; - try renderExtraNewline(tree, ais, root_decls[decl_i]); + for (root_decls) |decl| { + try renderTopLevelDecl(ais, tree, decl); } } -fn renderExtraNewline(tree: *ast.Tree, ais: anytype, node: *ast.Node) @TypeOf(ais.*).Error!void { - return renderExtraNewlineToken(tree, ais, node.firstToken()); +fn renderExtraNewline(tree: ast.Tree, ais: *Ais, node: ast.Node.Index) Error!void { + return renderExtraNewlineToken(tree, ais, tree.firstToken(node)); } -fn renderExtraNewlineToken( - tree: *ast.Tree, - ais: anytype, - first_token: ast.TokenIndex, -) @TypeOf(ais.*).Error!void { - var prev_token = first_token; - if (prev_token == 0) return; - var newline_threshold: usize = 2; - while (tree.token_ids[prev_token - 1] == .DocComment) { - if (tree.tokenLocation(tree.token_locs[prev_token - 1].end, prev_token).line == 1) { - newline_threshold += 1; - } - prev_token -= 1; - } - const prev_token_end = tree.token_locs[prev_token - 1].end; - const loc = tree.tokenLocation(prev_token_end, first_token); - if (loc.line >= newline_threshold) { - try ais.insertNewline(); - } +fn renderExtraNewlineToken(tree: ast.Tree, ais: *Ais, first_token: ast.TokenIndex) Error!void { + @panic("TODO implement renderExtraNewlineToken"); + //var prev_token = first_token; + //if (prev_token == 0) return; + //const token_tags = tree.tokens.items(.tag); + //var newline_threshold: usize = 2; + //while (token_tags[prev_token - 1] == .DocComment) { + // if (tree.tokenLocation(tree.token_locs[prev_token - 1].end, prev_token).line == 1) { + // newline_threshold += 1; + // } + // prev_token -= 1; + //} + //const prev_token_end = tree.token_locs[prev_token - 1].end; + //const loc = tree.tokenLocation(prev_token_end, first_token); + //if (loc.line >= newline_threshold) { + // try ais.insertNewline(); + //} } -fn renderTopLevelDecl(allocator: *mem.Allocator, ais: anytype, tree: *ast.Tree, decl: *ast.Node) (@TypeOf(ais.*).Error || Error)!void { - try renderContainerDecl(allocator, ais, tree, decl, .Newline); +fn renderTopLevelDecl(ais: *Ais, tree: ast.Tree, decl: ast.Node.Index) Error!void { + return renderContainerDecl(ais, tree, decl, .Newline); } -fn renderContainerDecl(allocator: *mem.Allocator, ais: anytype, tree: *ast.Tree, decl: *ast.Node, space: Space) (@TypeOf(ais.*).Error || Error)!void { - switch (decl.tag) { - .FnProto => { - const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl); - - try renderDocComments(tree, ais, fn_proto, fn_proto.getDocComments()); - - if (fn_proto.getBodyNode()) |body_node| { - try renderExpression(allocator, ais, tree, decl, .Space); - try renderExpression(allocator, ais, tree, body_node, space); - } else { - try renderExpression(allocator, ais, tree, decl, .None); - try renderToken(tree, ais, tree.nextToken(decl.lastToken()), space); - } - }, - - .Use => { - const use_decl = @fieldParentPtr(ast.Node.Use, "base", decl); - - if (use_decl.visib_token) |visib_token| { - try renderToken(tree, ais, visib_token, .Space); // pub - } - try renderToken(tree, ais, use_decl.use_token, .Space); // usingnamespace - try renderExpression(allocator, ais, tree, use_decl.expr, .None); - try renderToken(tree, ais, use_decl.semicolon_token, space); // ; - }, - - .VarDecl => { - const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", decl); - - try renderDocComments(tree, ais, var_decl, var_decl.getDocComments()); - try renderVarDecl(allocator, ais, tree, var_decl); - }, - - .TestDecl => { - const test_decl = @fieldParentPtr(ast.Node.TestDecl, "base", decl); - - try renderDocComments(tree, ais, test_decl, test_decl.doc_comments); - try renderToken(tree, ais, test_decl.test_token, .Space); - if (test_decl.name) |name| - try renderExpression(allocator, ais, tree, name, .Space); - try renderExpression(allocator, ais, tree, test_decl.body_node, space); - }, - - .ContainerField => { - const field = @fieldParentPtr(ast.Node.ContainerField, "base", decl); - - try renderDocComments(tree, ais, field, field.doc_comments); - if (field.comptime_token) |t| { - try renderToken(tree, ais, t, .Space); // comptime - } - - const src_has_trailing_comma = blk: { - const maybe_comma = tree.nextToken(field.lastToken()); - break :blk tree.token_ids[maybe_comma] == .Comma; - }; - - // The trailing comma is emitted at the end, but if it's not present - // we still have to respect the specified `space` parameter - const last_token_space: Space = if (src_has_trailing_comma) .None else space; - - if (field.type_expr == null and field.value_expr == null) { - try renderToken(tree, ais, field.name_token, last_token_space); // name - } else if (field.type_expr != null and field.value_expr == null) { - try renderToken(tree, ais, field.name_token, .None); // name - try renderToken(tree, ais, tree.nextToken(field.name_token), .Space); // : - - if (field.align_expr) |align_value_expr| { - try renderExpression(allocator, ais, tree, field.type_expr.?, .Space); // type - const lparen_token = tree.prevToken(align_value_expr.firstToken()); - const align_kw = tree.prevToken(lparen_token); - const rparen_token = tree.nextToken(align_value_expr.lastToken()); - try renderToken(tree, ais, align_kw, .None); // align - try renderToken(tree, ais, lparen_token, .None); // ( - try renderExpression(allocator, ais, tree, align_value_expr, .None); // alignment - try renderToken(tree, ais, rparen_token, last_token_space); // ) - } else { - try renderExpression(allocator, ais, tree, field.type_expr.?, last_token_space); // type - } - } else if (field.type_expr == null and field.value_expr != null) { - try renderToken(tree, ais, field.name_token, .Space); // name - try renderToken(tree, ais, tree.nextToken(field.name_token), .Space); // = - try renderExpression(allocator, ais, tree, field.value_expr.?, last_token_space); // value - } else { - try renderToken(tree, ais, field.name_token, .None); // name - try renderToken(tree, ais, tree.nextToken(field.name_token), .Space); // : - - if (field.align_expr) |align_value_expr| { - try renderExpression(allocator, ais, tree, field.type_expr.?, .Space); // type - const lparen_token = tree.prevToken(align_value_expr.firstToken()); - const align_kw = tree.prevToken(lparen_token); - const rparen_token = tree.nextToken(align_value_expr.lastToken()); - try renderToken(tree, ais, align_kw, .None); // align - try renderToken(tree, ais, lparen_token, .None); // ( - try renderExpression(allocator, ais, tree, align_value_expr, .None); // alignment - try renderToken(tree, ais, rparen_token, .Space); // ) - } else { - try renderExpression(allocator, ais, tree, field.type_expr.?, .Space); // type - } - try renderToken(tree, ais, tree.prevToken(field.value_expr.?.firstToken()), .Space); // = - try renderExpression(allocator, ais, tree, field.value_expr.?, last_token_space); // value - } - - if (src_has_trailing_comma) { - const comma = tree.nextToken(field.lastToken()); - try renderToken(tree, ais, comma, space); - } - }, +fn renderContainerDecl(ais: *Ais, tree: ast.Tree, decl: ast.Node.Index, space: Space) Error!void { + switch (tree.nodes.items(.tag)[decl]) { + .UsingNamespace, + .FnProtoSimple, + .FnProtoSimpleMulti, + .FnProtoOne, + .FnProto, + .FnDecl, + .GlobalVarDecl, + .LocalVarDecl, + .SimpleVarDecl, + .AlignedVarDecl, + .TestDecl, + .ContainerFieldInit, + .ContainerFieldAlign, + .ContainerField, + => @panic("TODO implement renderContainerDecl"), - .Comptime => { - assert(!decl.requireSemiColon()); - try renderExpression(allocator, ais, tree, decl, space); - }, + .Comptime => return renderExpression(ais, tree, decl, space), - .DocComment => { - const comment = @fieldParentPtr(ast.Node.DocComment, "base", decl); - const kind = tree.token_ids[comment.first_line]; - try renderToken(tree, ais, comment.first_line, .Newline); - var tok_i = comment.first_line + 1; - while (true) : (tok_i += 1) { - const tok_id = tree.token_ids[tok_i]; - if (tok_id == kind) { - try renderToken(tree, ais, tok_i, .Newline); - } else if (tok_id == .LineComment) { - continue; - } else { - break; - } - } - }, else => unreachable, } + //switch (tag) { + // .FnProto => { + // const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl); + + // try renderDocComments(tree, ais, fn_proto, fn_proto.getDocComments()); + + // if (fn_proto.getBodyNode()) |body_node| { + // try renderExpression(allocator, ais, tree, decl, .Space); + // try renderExpression(allocator, ais, tree, body_node, space); + // } else { + // try renderExpression(allocator, ais, tree, decl, .None); + // try renderToken(ais, tree, tree.nextToken(decl.lastToken()), space); + // } + // }, + + // .Use => { + // const use_decl = @fieldParentPtr(ast.Node.Use, "base", decl); + + // if (use_decl.visib_token) |visib_token| { + // try renderToken(ais, tree, visib_token, .Space); // pub + // } + // try renderToken(ais, tree, use_decl.use_token, .Space); // usingnamespace + // try renderExpression(allocator, ais, tree, use_decl.expr, .None); + // try renderToken(ais, tree, use_decl.semicolon_token, space); // ; + // }, + + // .VarDecl => { + // const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", decl); + + // try renderDocComments(tree, ais, var_decl, var_decl.getDocComments()); + // try renderVarDecl(allocator, ais, tree, var_decl); + // }, + + // .TestDecl => { + // const test_decl = @fieldParentPtr(ast.Node.TestDecl, "base", decl); + + // try renderDocComments(tree, ais, test_decl, test_decl.doc_comments); + // try renderToken(ais, tree, test_decl.test_token, .Space); + // if (test_decl.name) |name| + // try renderExpression(allocator, ais, tree, name, .Space); + // try renderExpression(allocator, ais, tree, test_decl.body_node, space); + // }, + + // .ContainerField => { + // const field = @fieldParentPtr(ast.Node.ContainerField, "base", decl); + + // try renderDocComments(tree, ais, field, field.doc_comments); + // if (field.comptime_token) |t| { + // try renderToken(ais, tree, t, .Space); // comptime + // } + + // const src_has_trailing_comma = blk: { + // const maybe_comma = tree.nextToken(field.lastToken()); + // break :blk tree.token_tags[maybe_comma] == .Comma; + // }; + + // // The trailing comma is emitted at the end, but if it's not present + // // we still have to respect the specified `space` parameter + // const last_token_space: Space = if (src_has_trailing_comma) .None else space; + + // if (field.type_expr == null and field.value_expr == null) { + // try renderToken(ais, tree, field.name_token, last_token_space); // name + // } else if (field.type_expr != null and field.value_expr == null) { + // try renderToken(ais, tree, field.name_token, .None); // name + // try renderToken(ais, tree, tree.nextToken(field.name_token), .Space); // : + + // if (field.align_expr) |align_value_expr| { + // try renderExpression(allocator, ais, tree, field.type_expr.?, .Space); // type + // const lparen_token = tree.prevToken(align_value_expr.firstToken()); + // const align_kw = tree.prevToken(lparen_token); + // const rparen_token = tree.nextToken(align_value_expr.lastToken()); + // try renderToken(ais, tree, align_kw, .None); // align + // try renderToken(ais, tree, lparen_token, .None); // ( + // try renderExpression(allocator, ais, tree, align_value_expr, .None); // alignment + // try renderToken(ais, tree, rparen_token, last_token_space); // ) + // } else { + // try renderExpression(allocator, ais, tree, field.type_expr.?, last_token_space); // type + // } + // } else if (field.type_expr == null and field.value_expr != null) { + // try renderToken(ais, tree, field.name_token, .Space); // name + // try renderToken(ais, tree, tree.nextToken(field.name_token), .Space); // = + // try renderExpression(allocator, ais, tree, field.value_expr.?, last_token_space); // value + // } else { + // try renderToken(ais, tree, field.name_token, .None); // name + // try renderToken(ais, tree, tree.nextToken(field.name_token), .Space); // : + + // if (field.align_expr) |align_value_expr| { + // try renderExpression(allocator, ais, tree, field.type_expr.?, .Space); // type + // const lparen_token = tree.prevToken(align_value_expr.firstToken()); + // const align_kw = tree.prevToken(lparen_token); + // const rparen_token = tree.nextToken(align_value_expr.lastToken()); + // try renderToken(ais, tree, align_kw, .None); // align + // try renderToken(ais, tree, lparen_token, .None); // ( + // try renderExpression(allocator, ais, tree, align_value_expr, .None); // alignment + // try renderToken(ais, tree, rparen_token, .Space); // ) + // } else { + // try renderExpression(allocator, ais, tree, field.type_expr.?, .Space); // type + // } + // try renderToken(ais, tree, tree.prevToken(field.value_expr.?.firstToken()), .Space); // = + // try renderExpression(allocator, ais, tree, field.value_expr.?, last_token_space); // value + // } + + // if (src_has_trailing_comma) { + // const comma = tree.nextToken(field.lastToken()); + // try renderToken(ais, tree, comma, space); + // } + // }, + + // .DocComment => { + // const comment = @fieldParentPtr(ast.Node.DocComment, "base", decl); + // const kind = tree.token_tags[comment.first_line]; + // try renderToken(ais, tree, comment.first_line, .Newline); + // var tok_i = comment.first_line + 1; + // while (true) : (tok_i += 1) { + // const tok_id = tree.token_tags[tok_i]; + // if (tok_id == kind) { + // try renderToken(ais, tree, tok_i, .Newline); + // } else if (tok_id == .LineComment) { + // continue; + // } else { + // break; + // } + // } + // }, + // else => unreachable, + //} } -fn renderExpression( - allocator: *mem.Allocator, - ais: anytype, - tree: *ast.Tree, - base: *ast.Node, - space: Space, -) (@TypeOf(ais.*).Error || Error)!void { - switch (base.tag) { - .Identifier, - .IntegerLiteral, - .FloatLiteral, - .StringLiteral, - .CharLiteral, - .BoolLiteral, - .NullLiteral, - .Unreachable, - .ErrorType, - .UndefinedLiteral, - => { - const casted_node = base.cast(ast.Node.OneToken).?; - return renderToken(tree, ais, casted_node.token, space); - }, - - .AnyType => { - const any_type = base.castTag(.AnyType).?; - if (mem.eql(u8, tree.tokenSlice(any_type.token), "var")) { - // TODO remove in next release cycle - try ais.writer().writeAll("anytype"); - if (space == .Comma) try ais.writer().writeAll(",\n"); - return; - } - return renderToken(tree, ais, any_type.token, space); - }, - - .Block, .LabeledBlock => { - const block: struct { - label: ?ast.TokenIndex, - statements: []*ast.Node, - lbrace: ast.TokenIndex, - rbrace: ast.TokenIndex, - } = b: { - if (base.castTag(.Block)) |block| { - break :b .{ - .label = null, - .statements = block.statements(), - .lbrace = block.lbrace, - .rbrace = block.rbrace, - }; - } else if (base.castTag(.LabeledBlock)) |block| { - break :b .{ - .label = block.label, - .statements = block.statements(), - .lbrace = block.lbrace, - .rbrace = block.rbrace, - }; - } else { - unreachable; - } - }; - - if (block.label) |label| { - try renderToken(tree, ais, label, Space.None); - try renderToken(tree, ais, tree.nextToken(label), Space.Space); - } - - if (block.statements.len == 0) { - ais.pushIndentNextLine(); - defer ais.popIndent(); - try renderToken(tree, ais, block.lbrace, Space.None); - } else { - ais.pushIndentNextLine(); - defer ais.popIndent(); - - try renderToken(tree, ais, block.lbrace, Space.Newline); - - for (block.statements) |statement, i| { - try renderStatement(allocator, ais, tree, statement); - - if (i + 1 < block.statements.len) { - try renderExtraNewline(tree, ais, block.statements[i + 1]); - } - } - } - return renderToken(tree, ais, block.rbrace, space); - }, - - .Defer => { - const defer_node = @fieldParentPtr(ast.Node.Defer, "base", base); - - try renderToken(tree, ais, defer_node.defer_token, Space.Space); - if (defer_node.payload) |payload| { - try renderExpression(allocator, ais, tree, payload, Space.Space); - } - return renderExpression(allocator, ais, tree, defer_node.expr, space); - }, - .Comptime => { - const comptime_node = @fieldParentPtr(ast.Node.Comptime, "base", base); - - try renderToken(tree, ais, comptime_node.comptime_token, Space.Space); - return renderExpression(allocator, ais, tree, comptime_node.expr, space); - }, - .Nosuspend => { - const nosuspend_node = @fieldParentPtr(ast.Node.Nosuspend, "base", base); - if (mem.eql(u8, tree.tokenSlice(nosuspend_node.nosuspend_token), "noasync")) { - // TODO: remove this - try ais.writer().writeAll("nosuspend "); - } else { - try renderToken(tree, ais, nosuspend_node.nosuspend_token, Space.Space); - } - return renderExpression(allocator, ais, tree, nosuspend_node.expr, space); - }, - - .Suspend => { - const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base); - - if (suspend_node.body) |body| { - try renderToken(tree, ais, suspend_node.suspend_token, Space.Space); - return renderExpression(allocator, ais, tree, body, space); - } else { - return renderToken(tree, ais, suspend_node.suspend_token, space); - } - }, - - .Catch => { - const infix_op_node = @fieldParentPtr(ast.Node.Catch, "base", base); - - const op_space = Space.Space; - try renderExpression(allocator, ais, tree, infix_op_node.lhs, op_space); - - const after_op_space = blk: { - const same_line = tree.tokensOnSameLine(infix_op_node.op_token, tree.nextToken(infix_op_node.op_token)); - break :blk if (same_line) op_space else Space.Newline; - }; - - try renderToken(tree, ais, infix_op_node.op_token, after_op_space); - - if (infix_op_node.payload) |payload| { - try renderExpression(allocator, ais, tree, payload, Space.Space); - } - - ais.pushIndentOneShot(); - return renderExpression(allocator, ais, tree, infix_op_node.rhs, space); - }, - - .Add, - .AddWrap, - .ArrayCat, - .ArrayMult, - .Assign, - .AssignBitAnd, - .AssignBitOr, - .AssignBitShiftLeft, - .AssignBitShiftRight, - .AssignBitXor, - .AssignDiv, - .AssignSub, - .AssignSubWrap, - .AssignMod, - .AssignAdd, - .AssignAddWrap, - .AssignMul, - .AssignMulWrap, - .BangEqual, - .BitAnd, - .BitOr, - .BitShiftLeft, - .BitShiftRight, - .BitXor, - .BoolAnd, - .BoolOr, - .Div, - .EqualEqual, - .ErrorUnion, - .GreaterOrEqual, - .GreaterThan, - .LessOrEqual, - .LessThan, - .MergeErrorSets, - .Mod, - .Mul, - .MulWrap, - .Period, - .Range, - .Sub, - .SubWrap, - .OrElse, - => { - const infix_op_node = @fieldParentPtr(ast.Node.SimpleInfixOp, "base", base); - - const op_space = switch (base.tag) { - .Period, .ErrorUnion, .Range => Space.None, - else => Space.Space, - }; - try renderExpression(allocator, ais, tree, infix_op_node.lhs, op_space); - - const after_op_space = blk: { - const loc = tree.tokenLocation(tree.token_locs[infix_op_node.op_token].end, tree.nextToken(infix_op_node.op_token)); - break :blk if (loc.line == 0) op_space else Space.Newline; - }; - - { - ais.pushIndent(); - defer ais.popIndent(); - try renderToken(tree, ais, infix_op_node.op_token, after_op_space); - } - ais.pushIndentOneShot(); - return renderExpression(allocator, ais, tree, infix_op_node.rhs, space); - }, - - .BitNot, - .BoolNot, - .Negation, - .NegationWrap, - .OptionalType, - .AddressOf, - => { - const casted_node = @fieldParentPtr(ast.Node.SimplePrefixOp, "base", base); - try renderToken(tree, ais, casted_node.op_token, Space.None); - return renderExpression(allocator, ais, tree, casted_node.rhs, space); - }, - - .Try, - .Resume, - .Await, - => { - const casted_node = @fieldParentPtr(ast.Node.SimplePrefixOp, "base", base); - try renderToken(tree, ais, casted_node.op_token, Space.Space); - return renderExpression(allocator, ais, tree, casted_node.rhs, space); - }, - - .ArrayType => { - const array_type = @fieldParentPtr(ast.Node.ArrayType, "base", base); - return renderArrayType( - allocator, - ais, - tree, - array_type.op_token, - array_type.rhs, - array_type.len_expr, - null, - space, - ); - }, - .ArrayTypeSentinel => { - const array_type = @fieldParentPtr(ast.Node.ArrayTypeSentinel, "base", base); - return renderArrayType( - allocator, - ais, - tree, - array_type.op_token, - array_type.rhs, - array_type.len_expr, - array_type.sentinel, - space, - ); - }, - - .PtrType => { - const ptr_type = @fieldParentPtr(ast.Node.PtrType, "base", base); - const op_tok_id = tree.token_ids[ptr_type.op_token]; - switch (op_tok_id) { - .Asterisk, .AsteriskAsterisk => try ais.writer().writeByte('*'), - .LBracket => if (tree.token_ids[ptr_type.op_token + 2] == .Identifier) - try ais.writer().writeAll("[*c") - else - try ais.writer().writeAll("[*"), - else => unreachable, - } - if (ptr_type.ptr_info.sentinel) |sentinel| { - const colon_token = tree.prevToken(sentinel.firstToken()); - try renderToken(tree, ais, colon_token, Space.None); // : - const sentinel_space = switch (op_tok_id) { - .LBracket => Space.None, - else => Space.Space, - }; - try renderExpression(allocator, ais, tree, sentinel, sentinel_space); - } - switch (op_tok_id) { - .Asterisk, .AsteriskAsterisk => {}, - .LBracket => try ais.writer().writeByte(']'), - else => unreachable, - } - if (ptr_type.ptr_info.allowzero_token) |allowzero_token| { - try renderToken(tree, ais, allowzero_token, Space.Space); // allowzero - } - if (ptr_type.ptr_info.align_info) |align_info| { - const lparen_token = tree.prevToken(align_info.node.firstToken()); - const align_token = tree.prevToken(lparen_token); - - try renderToken(tree, ais, align_token, Space.None); // align - try renderToken(tree, ais, lparen_token, Space.None); // ( - - try renderExpression(allocator, ais, tree, align_info.node, Space.None); - - if (align_info.bit_range) |bit_range| { - const colon1 = tree.prevToken(bit_range.start.firstToken()); - const colon2 = tree.prevToken(bit_range.end.firstToken()); - - try renderToken(tree, ais, colon1, Space.None); // : - try renderExpression(allocator, ais, tree, bit_range.start, Space.None); - try renderToken(tree, ais, colon2, Space.None); // : - try renderExpression(allocator, ais, tree, bit_range.end, Space.None); - - const rparen_token = tree.nextToken(bit_range.end.lastToken()); - try renderToken(tree, ais, rparen_token, Space.Space); // ) - } else { - const rparen_token = tree.nextToken(align_info.node.lastToken()); - try renderToken(tree, ais, rparen_token, Space.Space); // ) - } - } - if (ptr_type.ptr_info.const_token) |const_token| { - try renderToken(tree, ais, const_token, Space.Space); // const - } - if (ptr_type.ptr_info.volatile_token) |volatile_token| { - try renderToken(tree, ais, volatile_token, Space.Space); // volatile - } - return renderExpression(allocator, ais, tree, ptr_type.rhs, space); - }, - - .SliceType => { - const slice_type = @fieldParentPtr(ast.Node.SliceType, "base", base); - try renderToken(tree, ais, slice_type.op_token, Space.None); // [ - if (slice_type.ptr_info.sentinel) |sentinel| { - const colon_token = tree.prevToken(sentinel.firstToken()); - try renderToken(tree, ais, colon_token, Space.None); // : - try renderExpression(allocator, ais, tree, sentinel, Space.None); - try renderToken(tree, ais, tree.nextToken(sentinel.lastToken()), Space.None); // ] - } else { - try renderToken(tree, ais, tree.nextToken(slice_type.op_token), Space.None); // ] - } - - if (slice_type.ptr_info.allowzero_token) |allowzero_token| { - try renderToken(tree, ais, allowzero_token, Space.Space); // allowzero - } - if (slice_type.ptr_info.align_info) |align_info| { - const lparen_token = tree.prevToken(align_info.node.firstToken()); - const align_token = tree.prevToken(lparen_token); - - try renderToken(tree, ais, align_token, Space.None); // align - try renderToken(tree, ais, lparen_token, Space.None); // ( - - try renderExpression(allocator, ais, tree, align_info.node, Space.None); - - if (align_info.bit_range) |bit_range| { - const colon1 = tree.prevToken(bit_range.start.firstToken()); - const colon2 = tree.prevToken(bit_range.end.firstToken()); - - try renderToken(tree, ais, colon1, Space.None); // : - try renderExpression(allocator, ais, tree, bit_range.start, Space.None); - try renderToken(tree, ais, colon2, Space.None); // : - try renderExpression(allocator, ais, tree, bit_range.end, Space.None); - - const rparen_token = tree.nextToken(bit_range.end.lastToken()); - try renderToken(tree, ais, rparen_token, Space.Space); // ) - } else { - const rparen_token = tree.nextToken(align_info.node.lastToken()); - try renderToken(tree, ais, rparen_token, Space.Space); // ) - } - } - if (slice_type.ptr_info.const_token) |const_token| { - try renderToken(tree, ais, const_token, Space.Space); - } - if (slice_type.ptr_info.volatile_token) |volatile_token| { - try renderToken(tree, ais, volatile_token, Space.Space); - } - return renderExpression(allocator, ais, tree, slice_type.rhs, space); - }, - - .ArrayInitializer, .ArrayInitializerDot => { - var rtoken: ast.TokenIndex = undefined; - var exprs: []*ast.Node = undefined; - const lhs: union(enum) { dot: ast.TokenIndex, node: *ast.Node } = switch (base.tag) { - .ArrayInitializerDot => blk: { - const casted = @fieldParentPtr(ast.Node.ArrayInitializerDot, "base", base); - rtoken = casted.rtoken; - exprs = casted.list(); - break :blk .{ .dot = casted.dot }; - }, - .ArrayInitializer => blk: { - const casted = @fieldParentPtr(ast.Node.ArrayInitializer, "base", base); - rtoken = casted.rtoken; - exprs = casted.list(); - break :blk .{ .node = casted.lhs }; - }, - else => unreachable, - }; - - const lbrace = switch (lhs) { - .dot => |dot| tree.nextToken(dot), - .node => |node| tree.nextToken(node.lastToken()), - }; - - switch (lhs) { - .dot => |dot| try renderToken(tree, ais, dot, Space.None), - .node => |node| try renderExpression(allocator, ais, tree, node, Space.None), - } - - if (exprs.len == 0) { - try renderToken(tree, ais, lbrace, Space.None); - return renderToken(tree, ais, rtoken, space); - } - - if (exprs.len == 1 and exprs[0].tag != .MultilineStringLiteral and tree.token_ids[exprs[0].*.lastToken() + 1] == .RBrace) { - const expr = exprs[0]; - - try renderToken(tree, ais, lbrace, Space.None); - try renderExpression(allocator, ais, tree, expr, Space.None); - return renderToken(tree, ais, rtoken, space); - } - - // scan to find row size - if (rowSize(tree, exprs, rtoken) != null) { - { - ais.pushIndentNextLine(); - defer ais.popIndent(); - try renderToken(tree, ais, lbrace, Space.Newline); - - var expr_index: usize = 0; - while (rowSize(tree, exprs[expr_index..], rtoken)) |row_size| { - const row_exprs = exprs[expr_index..]; - // A place to store the width of each expression and its column's maximum - var widths = try allocator.alloc(usize, row_exprs.len + row_size); - defer allocator.free(widths); - mem.set(usize, widths, 0); - - var expr_newlines = try allocator.alloc(bool, row_exprs.len); - defer allocator.free(expr_newlines); - mem.set(bool, expr_newlines, false); - - var expr_widths = widths[0 .. widths.len - row_size]; - var column_widths = widths[widths.len - row_size ..]; - - // Find next row with trailing comment (if any) to end the current section - var section_end = sec_end: { - var this_line_first_expr: usize = 0; - var this_line_size = rowSize(tree, row_exprs, rtoken); - for (row_exprs) |expr, i| { - // Ignore comment on first line of this section - if (i == 0 or tree.tokensOnSameLine(row_exprs[0].firstToken(), expr.lastToken())) continue; - // Track start of line containing comment - if (!tree.tokensOnSameLine(row_exprs[this_line_first_expr].firstToken(), expr.lastToken())) { - this_line_first_expr = i; - this_line_size = rowSize(tree, row_exprs[this_line_first_expr..], rtoken); - } - - const maybe_comma = expr.lastToken() + 1; - const maybe_comment = expr.lastToken() + 2; - if (maybe_comment < tree.token_ids.len) { - if (tree.token_ids[maybe_comma] == .Comma and - tree.token_ids[maybe_comment] == .LineComment and - tree.tokensOnSameLine(expr.lastToken(), maybe_comment)) - { - var comment_token_loc = tree.token_locs[maybe_comment]; - const comment_is_empty = mem.trimRight(u8, tree.tokenSliceLoc(comment_token_loc), " ").len == 2; - if (!comment_is_empty) { - // Found row ending in comment - break :sec_end i - this_line_size.? + 1; - } - } - } - } - break :sec_end row_exprs.len; - }; - expr_index += section_end; - - const section_exprs = row_exprs[0..section_end]; - - // Null stream for counting the printed length of each expression - var line_find_stream = std.io.findByteWriter('\n', std.io.null_writer); - var counting_stream = std.io.countingWriter(line_find_stream.writer()); - var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, counting_stream.writer()); - - // Calculate size of columns in current section - var column_counter: usize = 0; - var single_line = true; - for (section_exprs) |expr, i| { - if (i + 1 < section_exprs.len) { - counting_stream.bytes_written = 0; - line_find_stream.byte_found = false; - try renderExpression(allocator, &auto_indenting_stream, tree, expr, Space.None); - const width = @intCast(usize, counting_stream.bytes_written); - expr_widths[i] = width; - expr_newlines[i] = line_find_stream.byte_found; - - if (!line_find_stream.byte_found) { - const column = column_counter % row_size; - column_widths[column] = std.math.max(column_widths[column], width); - - const expr_last_token = expr.*.lastToken() + 1; - const next_expr = section_exprs[i + 1]; - const loc = tree.tokenLocation(tree.token_locs[expr_last_token].start, next_expr.*.firstToken()); - - column_counter += 1; - - if (loc.line != 0) single_line = false; - } else { - single_line = false; - column_counter = 0; - } - } else { - counting_stream.bytes_written = 0; - try renderExpression(allocator, &auto_indenting_stream, tree, expr, Space.None); - const width = @intCast(usize, counting_stream.bytes_written); - expr_widths[i] = width; - expr_newlines[i] = line_find_stream.byte_found; - - if (!line_find_stream.byte_found) { - const column = column_counter % row_size; - column_widths[column] = std.math.max(column_widths[column], width); - } - break; - } - } - - // Render exprs in current section - column_counter = 0; - var last_col_index: usize = row_size - 1; - for (section_exprs) |expr, i| { - if (i + 1 < section_exprs.len) { - const next_expr = section_exprs[i + 1]; - try renderExpression(allocator, ais, tree, expr, Space.None); - - const comma = tree.nextToken(expr.*.lastToken()); - - if (column_counter != last_col_index) { - if (!expr_newlines[i] and !expr_newlines[i + 1]) { - // Neither the current or next expression is multiline - try renderToken(tree, ais, comma, Space.Space); // , - assert(column_widths[column_counter % row_size] >= expr_widths[i]); - const padding = column_widths[column_counter % row_size] - expr_widths[i]; - try ais.writer().writeByteNTimes(' ', padding); - - column_counter += 1; - continue; - } - } - if (single_line and row_size != 1) { - try renderToken(tree, ais, comma, Space.Space); // , - continue; - } - - column_counter = 0; - try renderToken(tree, ais, comma, Space.Newline); // , - try renderExtraNewline(tree, ais, next_expr); - } else { - const maybe_comma = tree.nextToken(expr.*.lastToken()); - if (tree.token_ids[maybe_comma] == .Comma) { - try renderExpression(allocator, ais, tree, expr, Space.None); // , - try renderToken(tree, ais, maybe_comma, Space.Newline); // , - } else { - try renderExpression(allocator, ais, tree, expr, Space.Comma); // , - } - } - } - - if (expr_index == exprs.len) { - break; - } - } - } - - return renderToken(tree, ais, rtoken, space); - } - - // Single line - try renderToken(tree, ais, lbrace, Space.Space); - for (exprs) |expr, i| { - if (i + 1 < exprs.len) { - const next_expr = exprs[i + 1]; - try renderExpression(allocator, ais, tree, expr, Space.None); - const comma = tree.nextToken(expr.*.lastToken()); - try renderToken(tree, ais, comma, Space.Space); // , - } else { - try renderExpression(allocator, ais, tree, expr, Space.Space); - } - } - - return renderToken(tree, ais, rtoken, space); - }, - - .StructInitializer, .StructInitializerDot => { - var rtoken: ast.TokenIndex = undefined; - var field_inits: []*ast.Node = undefined; - const lhs: union(enum) { dot: ast.TokenIndex, node: *ast.Node } = switch (base.tag) { - .StructInitializerDot => blk: { - const casted = @fieldParentPtr(ast.Node.StructInitializerDot, "base", base); - rtoken = casted.rtoken; - field_inits = casted.list(); - break :blk .{ .dot = casted.dot }; - }, - .StructInitializer => blk: { - const casted = @fieldParentPtr(ast.Node.StructInitializer, "base", base); - rtoken = casted.rtoken; - field_inits = casted.list(); - break :blk .{ .node = casted.lhs }; - }, - else => unreachable, - }; - - const lbrace = switch (lhs) { - .dot => |dot| tree.nextToken(dot), - .node => |node| tree.nextToken(node.lastToken()), - }; - - if (field_inits.len == 0) { - switch (lhs) { - .dot => |dot| try renderToken(tree, ais, dot, Space.None), - .node => |node| try renderExpression(allocator, ais, tree, node, Space.None), - } - - { - ais.pushIndentNextLine(); - defer ais.popIndent(); - try renderToken(tree, ais, lbrace, Space.None); - } - - return renderToken(tree, ais, rtoken, space); - } - - const src_has_trailing_comma = blk: { - const maybe_comma = tree.prevToken(rtoken); - break :blk tree.token_ids[maybe_comma] == .Comma; - }; - - const src_same_line = blk: { - const loc = tree.tokenLocation(tree.token_locs[lbrace].end, rtoken); - break :blk loc.line == 0; - }; - - const expr_outputs_one_line = blk: { - // render field expressions until a LF is found - for (field_inits) |field_init| { - var find_stream = std.io.findByteWriter('\n', std.io.null_writer); - var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, find_stream.writer()); - - try renderExpression(allocator, &auto_indenting_stream, tree, field_init, Space.None); - if (find_stream.byte_found) break :blk false; - } - break :blk true; - }; - - if (field_inits.len == 1) blk: { - if (field_inits[0].cast(ast.Node.FieldInitializer)) |field_init| { - switch (field_init.expr.tag) { - .StructInitializer, - .StructInitializerDot, - => break :blk, - else => {}, - } - } - - // if the expression outputs to multiline, make this struct multiline - if (!expr_outputs_one_line or src_has_trailing_comma) { - break :blk; - } - - switch (lhs) { - .dot => |dot| try renderToken(tree, ais, dot, Space.None), - .node => |node| try renderExpression(allocator, ais, tree, node, Space.None), - } - try renderToken(tree, ais, lbrace, Space.Space); - try renderExpression(allocator, ais, tree, field_inits[0], Space.Space); - return renderToken(tree, ais, rtoken, space); - } - - if (!src_has_trailing_comma and src_same_line and expr_outputs_one_line) { - // render all on one line, no trailing comma - switch (lhs) { - .dot => |dot| try renderToken(tree, ais, dot, Space.None), - .node => |node| try renderExpression(allocator, ais, tree, node, Space.None), - } - try renderToken(tree, ais, lbrace, Space.Space); - - for (field_inits) |field_init, i| { - if (i + 1 < field_inits.len) { - try renderExpression(allocator, ais, tree, field_init, Space.None); - - const comma = tree.nextToken(field_init.lastToken()); - try renderToken(tree, ais, comma, Space.Space); - } else { - try renderExpression(allocator, ais, tree, field_init, Space.Space); - } - } - - return renderToken(tree, ais, rtoken, space); - } - - { - switch (lhs) { - .dot => |dot| try renderToken(tree, ais, dot, Space.None), - .node => |node| try renderExpression(allocator, ais, tree, node, Space.None), - } - - ais.pushIndentNextLine(); - defer ais.popIndent(); - - try renderToken(tree, ais, lbrace, Space.Newline); - - for (field_inits) |field_init, i| { - if (i + 1 < field_inits.len) { - const next_field_init = field_inits[i + 1]; - try renderExpression(allocator, ais, tree, field_init, Space.None); - - const comma = tree.nextToken(field_init.lastToken()); - try renderToken(tree, ais, comma, Space.Newline); - - try renderExtraNewline(tree, ais, next_field_init); - } else { - try renderExpression(allocator, ais, tree, field_init, Space.Comma); - } - } - } - - return renderToken(tree, ais, rtoken, space); - }, - - .Call => { - const call = @fieldParentPtr(ast.Node.Call, "base", base); - if (call.async_token) |async_token| { - try renderToken(tree, ais, async_token, Space.Space); - } - - try renderExpression(allocator, ais, tree, call.lhs, Space.None); - - const lparen = tree.nextToken(call.lhs.lastToken()); - - if (call.params_len == 0) { - try renderToken(tree, ais, lparen, Space.None); - return renderToken(tree, ais, call.rtoken, space); - } - - const src_has_trailing_comma = blk: { - const maybe_comma = tree.prevToken(call.rtoken); - break :blk tree.token_ids[maybe_comma] == .Comma; - }; - - if (src_has_trailing_comma) { - { - ais.pushIndent(); - defer ais.popIndent(); - - try renderToken(tree, ais, lparen, Space.Newline); // ( - const params = call.params(); - for (params) |param_node, i| { - if (i + 1 < params.len) { - const next_node = params[i + 1]; - try renderExpression(allocator, ais, tree, param_node, Space.None); - - // Unindent the comma for multiline string literals - const maybe_multiline_string = param_node.firstToken(); - const is_multiline_string = tree.token_ids[maybe_multiline_string] == .MultilineStringLiteralLine; - if (is_multiline_string) ais.popIndent(); - defer if (is_multiline_string) ais.pushIndent(); - - const comma = tree.nextToken(param_node.lastToken()); - try renderToken(tree, ais, comma, Space.Newline); // , - try renderExtraNewline(tree, ais, next_node); - } else { - try renderExpression(allocator, ais, tree, param_node, Space.Comma); - } - } - } - return renderToken(tree, ais, call.rtoken, space); - } - - try renderToken(tree, ais, lparen, Space.None); // ( - - const params = call.params(); - for (params) |param_node, i| { - const maybe_comment = param_node.firstToken() - 1; - const maybe_multiline_string = param_node.firstToken(); - if (tree.token_ids[maybe_multiline_string] == .MultilineStringLiteralLine or tree.token_ids[maybe_comment] == .LineComment) { - ais.pushIndentOneShot(); - } - - try renderExpression(allocator, ais, tree, param_node, Space.None); - - if (i + 1 < params.len) { - const comma = tree.nextToken(param_node.lastToken()); - try renderToken(tree, ais, comma, Space.Space); - } - } - return renderToken(tree, ais, call.rtoken, space); // ) - }, - - .ArrayAccess => { - const suffix_op = base.castTag(.ArrayAccess).?; - - const lbracket = tree.nextToken(suffix_op.lhs.lastToken()); - const rbracket = tree.nextToken(suffix_op.index_expr.lastToken()); - - try renderExpression(allocator, ais, tree, suffix_op.lhs, Space.None); - try renderToken(tree, ais, lbracket, Space.None); // [ - - const starts_with_comment = tree.token_ids[lbracket + 1] == .LineComment; - const ends_with_comment = tree.token_ids[rbracket - 1] == .LineComment; - { - const new_space = if (ends_with_comment) Space.Newline else Space.None; - - ais.pushIndent(); - defer ais.popIndent(); - try renderExpression(allocator, ais, tree, suffix_op.index_expr, new_space); - } - if (starts_with_comment) try ais.maybeInsertNewline(); - return renderToken(tree, ais, rbracket, space); // ] - }, - - .Slice => { - const suffix_op = base.castTag(.Slice).?; - try renderExpression(allocator, ais, tree, suffix_op.lhs, Space.None); - - const lbracket = tree.prevToken(suffix_op.start.firstToken()); - const dotdot = tree.nextToken(suffix_op.start.lastToken()); - - const after_start_space_bool = nodeCausesSliceOpSpace(suffix_op.start) or - (if (suffix_op.end) |end| nodeCausesSliceOpSpace(end) else false); - const after_start_space = if (after_start_space_bool) Space.Space else Space.None; - const after_op_space = if (suffix_op.end != null) after_start_space else Space.None; - - try renderToken(tree, ais, lbracket, Space.None); // [ - try renderExpression(allocator, ais, tree, suffix_op.start, after_start_space); - try renderToken(tree, ais, dotdot, after_op_space); // .. - if (suffix_op.end) |end| { - const after_end_space = if (suffix_op.sentinel != null) Space.Space else Space.None; - try renderExpression(allocator, ais, tree, end, after_end_space); - } - if (suffix_op.sentinel) |sentinel| { - const colon = tree.prevToken(sentinel.firstToken()); - try renderToken(tree, ais, colon, Space.None); // : - try renderExpression(allocator, ais, tree, sentinel, Space.None); - } - return renderToken(tree, ais, suffix_op.rtoken, space); // ] - }, - - .Deref => { - const suffix_op = base.castTag(.Deref).?; - - try renderExpression(allocator, ais, tree, suffix_op.lhs, Space.None); - return renderToken(tree, ais, suffix_op.rtoken, space); // .* - }, - .UnwrapOptional => { - const suffix_op = base.castTag(.UnwrapOptional).?; - - try renderExpression(allocator, ais, tree, suffix_op.lhs, Space.None); - try renderToken(tree, ais, tree.prevToken(suffix_op.rtoken), Space.None); // . - return renderToken(tree, ais, suffix_op.rtoken, space); // ? - }, - - .Break => { - const flow_expr = base.castTag(.Break).?; - const maybe_rhs = flow_expr.getRHS(); - const maybe_label = flow_expr.getLabel(); - - if (maybe_label == null and maybe_rhs == null) { - return renderToken(tree, ais, flow_expr.ltoken, space); // break - } - - try renderToken(tree, ais, flow_expr.ltoken, Space.Space); // break - if (maybe_label) |label| { - const colon = tree.nextToken(flow_expr.ltoken); - try renderToken(tree, ais, colon, Space.None); // : - - if (maybe_rhs == null) { - return renderToken(tree, ais, label, space); // label - } - try renderToken(tree, ais, label, Space.Space); // label - } - return renderExpression(allocator, ais, tree, maybe_rhs.?, space); - }, - - .Continue => { - const flow_expr = base.castTag(.Continue).?; - if (flow_expr.getLabel()) |label| { - try renderToken(tree, ais, flow_expr.ltoken, Space.Space); // continue - const colon = tree.nextToken(flow_expr.ltoken); - try renderToken(tree, ais, colon, Space.None); // : - return renderToken(tree, ais, label, space); // label - } else { - return renderToken(tree, ais, flow_expr.ltoken, space); // continue - } - }, - - .Return => { - const flow_expr = base.castTag(.Return).?; - if (flow_expr.getRHS()) |rhs| { - try renderToken(tree, ais, flow_expr.ltoken, Space.Space); - return renderExpression(allocator, ais, tree, rhs, space); - } else { - return renderToken(tree, ais, flow_expr.ltoken, space); - } - }, - - .Payload => { - const payload = @fieldParentPtr(ast.Node.Payload, "base", base); - - try renderToken(tree, ais, payload.lpipe, Space.None); - try renderExpression(allocator, ais, tree, payload.error_symbol, Space.None); - return renderToken(tree, ais, payload.rpipe, space); - }, - - .PointerPayload => { - const payload = @fieldParentPtr(ast.Node.PointerPayload, "base", base); - - try renderToken(tree, ais, payload.lpipe, Space.None); - if (payload.ptr_token) |ptr_token| { - try renderToken(tree, ais, ptr_token, Space.None); - } - try renderExpression(allocator, ais, tree, payload.value_symbol, Space.None); - return renderToken(tree, ais, payload.rpipe, space); - }, - - .PointerIndexPayload => { - const payload = @fieldParentPtr(ast.Node.PointerIndexPayload, "base", base); - - try renderToken(tree, ais, payload.lpipe, Space.None); - if (payload.ptr_token) |ptr_token| { - try renderToken(tree, ais, ptr_token, Space.None); - } - try renderExpression(allocator, ais, tree, payload.value_symbol, Space.None); - - if (payload.index_symbol) |index_symbol| { - const comma = tree.nextToken(payload.value_symbol.lastToken()); - - try renderToken(tree, ais, comma, Space.Space); - try renderExpression(allocator, ais, tree, index_symbol, Space.None); - } - - return renderToken(tree, ais, payload.rpipe, space); - }, - - .GroupedExpression => { - const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", base); - - try renderToken(tree, ais, grouped_expr.lparen, Space.None); +fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Space) Error!void { + const token_tags = tree.tokens.items(.tag); + const main_tokens = tree.nodes.items(.main_token); + switch (tree.nodes.items(.tag)[node]) { + //.Identifier, + //.IntegerLiteral, + //.FloatLiteral, + //.StringLiteral, + //.CharLiteral, + //.BoolLiteral, + //.NullLiteral, + //.Unreachable, + //.ErrorType, + //.UndefinedLiteral, + //=> { + // const casted_node = base.cast(ast.Node.OneToken).?; + // return renderToken(ais, tree, casted_node.token, space); + //}, + + //.AnyType => { + // const any_type = base.castTag(.AnyType).?; + // if (mem.eql(u8, tree.tokenSlice(any_type.token), "var")) { + // // TODO remove in next release cycle + // try ais.writer().writeAll("anytype"); + // if (space == .Comma) try ais.writer().writeAll(",\n"); + // return; + // } + // return renderToken(ais, tree, any_type.token, space); + //}, + .Block => { + const lbrace = main_tokens[node]; + if (token_tags[lbrace - 1] == .Colon and + token_tags[lbrace - 2] == .Identifier) { - ais.pushIndentOneShot(); - try renderExpression(allocator, ais, tree, grouped_expr.expr, Space.None); - } - return renderToken(tree, ais, grouped_expr.rparen, space); - }, - - .FieldInitializer => { - const field_init = @fieldParentPtr(ast.Node.FieldInitializer, "base", base); - - try renderToken(tree, ais, field_init.period_token, Space.None); // . - try renderToken(tree, ais, field_init.name_token, Space.Space); // name - try renderToken(tree, ais, tree.nextToken(field_init.name_token), Space.Space); // = - return renderExpression(allocator, ais, tree, field_init.expr, space); - }, - - .ContainerDecl => { - const container_decl = @fieldParentPtr(ast.Node.ContainerDecl, "base", base); - - if (container_decl.layout_token) |layout_token| { - try renderToken(tree, ais, layout_token, Space.Space); - } - - switch (container_decl.init_arg_expr) { - .None => { - try renderToken(tree, ais, container_decl.kind_token, Space.Space); // union - }, - .Enum => |enum_tag_type| { - try renderToken(tree, ais, container_decl.kind_token, Space.None); // union - - const lparen = tree.nextToken(container_decl.kind_token); - const enum_token = tree.nextToken(lparen); - - try renderToken(tree, ais, lparen, Space.None); // ( - try renderToken(tree, ais, enum_token, Space.None); // enum - - if (enum_tag_type) |expr| { - try renderToken(tree, ais, tree.nextToken(enum_token), Space.None); // ( - try renderExpression(allocator, ais, tree, expr, Space.None); - - const rparen = tree.nextToken(expr.lastToken()); - try renderToken(tree, ais, rparen, Space.None); // ) - try renderToken(tree, ais, tree.nextToken(rparen), Space.Space); // ) - } else { - try renderToken(tree, ais, tree.nextToken(enum_token), Space.Space); // ) - } - }, - .Type => |type_expr| { - try renderToken(tree, ais, container_decl.kind_token, Space.None); // union - - const lparen = tree.nextToken(container_decl.kind_token); - const rparen = tree.nextToken(type_expr.lastToken()); - - try renderToken(tree, ais, lparen, Space.None); // ( - try renderExpression(allocator, ais, tree, type_expr, Space.None); - try renderToken(tree, ais, rparen, Space.Space); // ) - }, + try renderToken(ais, tree, lbrace - 2, .None); + try renderToken(ais, tree, lbrace - 1, .Space); } + const nodes_data = tree.nodes.items(.data); + const statements = tree.extra_data[nodes_data[node].lhs..nodes_data[node].rhs]; - if (container_decl.fields_and_decls_len == 0) { - { - ais.pushIndentNextLine(); - defer ais.popIndent(); - try renderToken(tree, ais, container_decl.lbrace_token, Space.None); // { - } - return renderToken(tree, ais, container_decl.rbrace_token, space); // } - } - - const src_has_trailing_comma = blk: { - var maybe_comma = tree.prevToken(container_decl.lastToken()); - // Doc comments for a field may also appear after the comma, eg. - // field_name: T, // comment attached to field_name - if (tree.token_ids[maybe_comma] == .DocComment) - maybe_comma = tree.prevToken(maybe_comma); - break :blk tree.token_ids[maybe_comma] == .Comma; - }; - - const fields_and_decls = container_decl.fieldsAndDecls(); - - // Check if the first declaration and the { are on the same line - const src_has_newline = !tree.tokensOnSameLine( - container_decl.lbrace_token, - fields_and_decls[0].firstToken(), - ); - - // We can only print all the elements in-line if all the - // declarations inside are fields - const src_has_only_fields = blk: { - for (fields_and_decls) |decl| { - if (decl.tag != .ContainerField) break :blk false; - } - break :blk true; - }; - - if (src_has_trailing_comma or !src_has_only_fields) { - // One declaration per line + if (statements.len == 0) { ais.pushIndentNextLine(); - defer ais.popIndent(); - try renderToken(tree, ais, container_decl.lbrace_token, .Newline); // { - - for (fields_and_decls) |decl, i| { - try renderContainerDecl(allocator, ais, tree, decl, .Newline); - - if (i + 1 < fields_and_decls.len) { - try renderExtraNewline(tree, ais, fields_and_decls[i + 1]); - } - } - } else if (src_has_newline) { - // All the declarations on the same line, but place the items on - // their own line - try renderToken(tree, ais, container_decl.lbrace_token, .Newline); // { - - ais.pushIndent(); - defer ais.popIndent(); - - for (fields_and_decls) |decl, i| { - const space_after_decl: Space = if (i + 1 >= fields_and_decls.len) .Newline else .Space; - try renderContainerDecl(allocator, ais, tree, decl, space_after_decl); - } - } else { - // All the declarations on the same line - try renderToken(tree, ais, container_decl.lbrace_token, .Space); // { - - for (fields_and_decls) |decl| { - try renderContainerDecl(allocator, ais, tree, decl, .Space); - } - } - - return renderToken(tree, ais, container_decl.rbrace_token, space); // } - }, - - .ErrorSetDecl => { - const err_set_decl = @fieldParentPtr(ast.Node.ErrorSetDecl, "base", base); - - const lbrace = tree.nextToken(err_set_decl.error_token); - - if (err_set_decl.decls_len == 0) { - try renderToken(tree, ais, err_set_decl.error_token, Space.None); - try renderToken(tree, ais, lbrace, Space.None); - return renderToken(tree, ais, err_set_decl.rbrace_token, space); - } - - if (err_set_decl.decls_len == 1) blk: { - const node = err_set_decl.decls()[0]; - - // if there are any doc comments or same line comments - // don't try to put it all on one line - if (node.cast(ast.Node.ErrorTag)) |tag| { - if (tag.doc_comments != null) break :blk; - } else { - break :blk; - } - - try renderToken(tree, ais, err_set_decl.error_token, Space.None); // error - try renderToken(tree, ais, lbrace, Space.None); // { - try renderExpression(allocator, ais, tree, node, Space.None); - return renderToken(tree, ais, err_set_decl.rbrace_token, space); // } - } - - try renderToken(tree, ais, err_set_decl.error_token, Space.None); // error - - const src_has_trailing_comma = blk: { - const maybe_comma = tree.prevToken(err_set_decl.rbrace_token); - break :blk tree.token_ids[maybe_comma] == .Comma; - }; - - if (src_has_trailing_comma) { - { - ais.pushIndent(); - defer ais.popIndent(); - - try renderToken(tree, ais, lbrace, Space.Newline); // { - const decls = err_set_decl.decls(); - for (decls) |node, i| { - if (i + 1 < decls.len) { - try renderExpression(allocator, ais, tree, node, Space.None); - try renderToken(tree, ais, tree.nextToken(node.lastToken()), Space.Newline); // , - - try renderExtraNewline(tree, ais, decls[i + 1]); - } else { - try renderExpression(allocator, ais, tree, node, Space.Comma); - } - } - } - - return renderToken(tree, ais, err_set_decl.rbrace_token, space); // } + try renderToken(ais, tree, lbrace, .None); + ais.popIndent(); + const rbrace = lbrace + 1; + return renderToken(ais, tree, rbrace, space); } else { - try renderToken(tree, ais, lbrace, Space.Space); // { - - const decls = err_set_decl.decls(); - for (decls) |node, i| { - if (i + 1 < decls.len) { - try renderExpression(allocator, ais, tree, node, Space.None); - - const comma_token = tree.nextToken(node.lastToken()); - assert(tree.token_ids[comma_token] == .Comma); - try renderToken(tree, ais, comma_token, Space.Space); // , - try renderExtraNewline(tree, ais, decls[i + 1]); - } else { - try renderExpression(allocator, ais, tree, node, Space.Space); - } - } - - return renderToken(tree, ais, err_set_decl.rbrace_token, space); // } - } - }, - - .ErrorTag => { - const tag = @fieldParentPtr(ast.Node.ErrorTag, "base", base); - - try renderDocComments(tree, ais, tag, tag.doc_comments); - return renderToken(tree, ais, tag.name_token, space); // name - }, - - .MultilineStringLiteral => { - const multiline_str_literal = @fieldParentPtr(ast.Node.MultilineStringLiteral, "base", base); - - { - const locked_indents = ais.lockOneShotIndent(); - defer { - var i: u8 = 0; - while (i < locked_indents) : (i += 1) ais.popIndent(); - } - try ais.maybeInsertNewline(); - - for (multiline_str_literal.lines()) |t| try renderToken(tree, ais, t, Space.None); - } - }, - - .BuiltinCall => { - const builtin_call = @fieldParentPtr(ast.Node.BuiltinCall, "base", base); - - // TODO remove after 0.7.0 release - if (mem.eql(u8, tree.tokenSlice(builtin_call.builtin_token), "@OpaqueType")) - return ais.writer().writeAll("opaque {}"); - - // TODO remove after 0.7.0 release - { - const params = builtin_call.paramsConst(); - if (mem.eql(u8, tree.tokenSlice(builtin_call.builtin_token), "@Type") and - params.len == 1) - { - if (params[0].castTag(.EnumLiteral)) |enum_literal| - if (mem.eql(u8, tree.tokenSlice(enum_literal.name), "Opaque")) - return ais.writer().writeAll("opaque {}"); - } - } - - try renderToken(tree, ais, builtin_call.builtin_token, Space.None); // @name - - const src_params_trailing_comma = blk: { - if (builtin_call.params_len == 0) break :blk false; - const last_node = builtin_call.params()[builtin_call.params_len - 1]; - const maybe_comma = tree.nextToken(last_node.lastToken()); - break :blk tree.token_ids[maybe_comma] == .Comma; - }; - - const lparen = tree.nextToken(builtin_call.builtin_token); - - if (!src_params_trailing_comma) { - try renderToken(tree, ais, lparen, Space.None); // ( - - // render all on one line, no trailing comma - const params = builtin_call.params(); - for (params) |param_node, i| { - const maybe_comment = param_node.firstToken() - 1; - if (param_node.*.tag == .MultilineStringLiteral or tree.token_ids[maybe_comment] == .LineComment) { - ais.pushIndentOneShot(); - } - try renderExpression(allocator, ais, tree, param_node, Space.None); - - if (i + 1 < params.len) { - const comma_token = tree.nextToken(param_node.lastToken()); - try renderToken(tree, ais, comma_token, Space.Space); // , - } - } - } else { - // one param per line - ais.pushIndent(); - defer ais.popIndent(); - try renderToken(tree, ais, lparen, Space.Newline); // ( - - for (builtin_call.params()) |param_node| { - try renderExpression(allocator, ais, tree, param_node, Space.Comma); - } - } - - return renderToken(tree, ais, builtin_call.rparen_token, space); // ) - }, - - .FnProto => { - const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", base); - - if (fn_proto.getVisibToken()) |visib_token_index| { - const visib_token = tree.token_ids[visib_token_index]; - assert(visib_token == .Keyword_pub or visib_token == .Keyword_export); - - try renderToken(tree, ais, visib_token_index, Space.Space); // pub - } - - if (fn_proto.getExternExportInlineToken()) |extern_export_inline_token| { - if (fn_proto.getIsExternPrototype() == null) - try renderToken(tree, ais, extern_export_inline_token, Space.Space); // extern/export/inline - } - - if (fn_proto.getLibName()) |lib_name| { - try renderExpression(allocator, ais, tree, lib_name, Space.Space); - } - - const lparen = if (fn_proto.getNameToken()) |name_token| blk: { - try renderToken(tree, ais, fn_proto.fn_token, Space.Space); // fn - try renderToken(tree, ais, name_token, Space.None); // name - break :blk tree.nextToken(name_token); - } else blk: { - try renderToken(tree, ais, fn_proto.fn_token, Space.Space); // fn - break :blk tree.nextToken(fn_proto.fn_token); - }; - assert(tree.token_ids[lparen] == .LParen); - - const rparen = tree.prevToken( - // the first token for the annotation expressions is the left - // parenthesis, hence the need for two prevToken - if (fn_proto.getAlignExpr()) |align_expr| - tree.prevToken(tree.prevToken(align_expr.firstToken())) - else if (fn_proto.getSectionExpr()) |section_expr| - tree.prevToken(tree.prevToken(section_expr.firstToken())) - else if (fn_proto.getCallconvExpr()) |callconv_expr| - tree.prevToken(tree.prevToken(callconv_expr.firstToken())) - else switch (fn_proto.return_type) { - .Explicit => |node| node.firstToken(), - .InferErrorSet => |node| tree.prevToken(node.firstToken()), - .Invalid => unreachable, - }, - ); - assert(tree.token_ids[rparen] == .RParen); - - const src_params_trailing_comma = blk: { - const maybe_comma = tree.token_ids[rparen - 1]; - break :blk maybe_comma == .Comma or maybe_comma == .LineComment; - }; - - if (!src_params_trailing_comma) { - try renderToken(tree, ais, lparen, Space.None); // ( - - // render all on one line, no trailing comma - for (fn_proto.params()) |param_decl, i| { - try renderParamDecl(allocator, ais, tree, param_decl, Space.None); - - if (i + 1 < fn_proto.params_len or fn_proto.getVarArgsToken() != null) { - const comma = tree.nextToken(param_decl.lastToken()); - try renderToken(tree, ais, comma, Space.Space); // , - } - } - if (fn_proto.getVarArgsToken()) |var_args_token| { - try renderToken(tree, ais, var_args_token, Space.None); - } - } else { - // one param per line - ais.pushIndent(); - defer ais.popIndent(); - try renderToken(tree, ais, lparen, Space.Newline); // ( - - for (fn_proto.params()) |param_decl| { - try renderParamDecl(allocator, ais, tree, param_decl, Space.Comma); - } - if (fn_proto.getVarArgsToken()) |var_args_token| { - try renderToken(tree, ais, var_args_token, Space.Comma); - } - } - - try renderToken(tree, ais, rparen, Space.Space); // ) - - if (fn_proto.getAlignExpr()) |align_expr| { - const align_rparen = tree.nextToken(align_expr.lastToken()); - const align_lparen = tree.prevToken(align_expr.firstToken()); - const align_kw = tree.prevToken(align_lparen); - - try renderToken(tree, ais, align_kw, Space.None); // align - try renderToken(tree, ais, align_lparen, Space.None); // ( - try renderExpression(allocator, ais, tree, align_expr, Space.None); - try renderToken(tree, ais, align_rparen, Space.Space); // ) - } - - if (fn_proto.getSectionExpr()) |section_expr| { - const section_rparen = tree.nextToken(section_expr.lastToken()); - const section_lparen = tree.prevToken(section_expr.firstToken()); - const section_kw = tree.prevToken(section_lparen); - - try renderToken(tree, ais, section_kw, Space.None); // section - try renderToken(tree, ais, section_lparen, Space.None); // ( - try renderExpression(allocator, ais, tree, section_expr, Space.None); - try renderToken(tree, ais, section_rparen, Space.Space); // ) - } - - if (fn_proto.getCallconvExpr()) |callconv_expr| { - const callconv_rparen = tree.nextToken(callconv_expr.lastToken()); - const callconv_lparen = tree.prevToken(callconv_expr.firstToken()); - const callconv_kw = tree.prevToken(callconv_lparen); - - try renderToken(tree, ais, callconv_kw, Space.None); // callconv - try renderToken(tree, ais, callconv_lparen, Space.None); // ( - try renderExpression(allocator, ais, tree, callconv_expr, Space.None); - try renderToken(tree, ais, callconv_rparen, Space.Space); // ) - } else if (fn_proto.getIsExternPrototype() != null) { - try ais.writer().writeAll("callconv(.C) "); - } else if (fn_proto.getIsAsync() != null) { - try ais.writer().writeAll("callconv(.Async) "); - } - - switch (fn_proto.return_type) { - .Explicit => |node| { - return renderExpression(allocator, ais, tree, node, space); - }, - .InferErrorSet => |node| { - try renderToken(tree, ais, tree.prevToken(node.firstToken()), Space.None); // ! - return renderExpression(allocator, ais, tree, node, space); - }, - .Invalid => unreachable, - } - }, - - .AnyFrameType => { - const anyframe_type = @fieldParentPtr(ast.Node.AnyFrameType, "base", base); - - if (anyframe_type.result) |result| { - try renderToken(tree, ais, anyframe_type.anyframe_token, Space.None); // anyframe - try renderToken(tree, ais, result.arrow_token, Space.None); // -> - return renderExpression(allocator, ais, tree, result.return_type, space); - } else { - return renderToken(tree, ais, anyframe_type.anyframe_token, space); // anyframe - } - }, - - .DocComment => unreachable, // doc comments are attached to nodes - - .Switch => { - const switch_node = @fieldParentPtr(ast.Node.Switch, "base", base); - - try renderToken(tree, ais, switch_node.switch_token, Space.Space); // switch - try renderToken(tree, ais, tree.nextToken(switch_node.switch_token), Space.None); // ( - - const rparen = tree.nextToken(switch_node.expr.lastToken()); - const lbrace = tree.nextToken(rparen); - - if (switch_node.cases_len == 0) { - try renderExpression(allocator, ais, tree, switch_node.expr, Space.None); - try renderToken(tree, ais, rparen, Space.Space); // ) - try renderToken(tree, ais, lbrace, Space.None); // { - return renderToken(tree, ais, switch_node.rbrace, space); // } - } - - try renderExpression(allocator, ais, tree, switch_node.expr, Space.None); - try renderToken(tree, ais, rparen, Space.Space); // ) - - { ais.pushIndentNextLine(); - defer ais.popIndent(); - try renderToken(tree, ais, lbrace, Space.Newline); // { - - const cases = switch_node.cases(); - for (cases) |node, i| { - try renderExpression(allocator, ais, tree, node, Space.Comma); - - if (i + 1 < cases.len) { - try renderExtraNewline(tree, ais, cases[i + 1]); - } - } - } - - return renderToken(tree, ais, switch_node.rbrace, space); // } - }, - - .SwitchCase => { - const switch_case = @fieldParentPtr(ast.Node.SwitchCase, "base", base); - - assert(switch_case.items_len != 0); - const src_has_trailing_comma = blk: { - const last_node = switch_case.items()[switch_case.items_len - 1]; - const maybe_comma = tree.nextToken(last_node.lastToken()); - break :blk tree.token_ids[maybe_comma] == .Comma; - }; - - if (switch_case.items_len == 1 or !src_has_trailing_comma) { - const items = switch_case.items(); - for (items) |node, i| { - if (i + 1 < items.len) { - try renderExpression(allocator, ais, tree, node, Space.None); - - const comma_token = tree.nextToken(node.lastToken()); - try renderToken(tree, ais, comma_token, Space.Space); // , - try renderExtraNewline(tree, ais, items[i + 1]); - } else { - try renderExpression(allocator, ais, tree, node, Space.Space); - } - } - } else { - const items = switch_case.items(); - for (items) |node, i| { - if (i + 1 < items.len) { - try renderExpression(allocator, ais, tree, node, Space.None); - - const comma_token = tree.nextToken(node.lastToken()); - try renderToken(tree, ais, comma_token, Space.Newline); // , - try renderExtraNewline(tree, ais, items[i + 1]); - } else { - try renderExpression(allocator, ais, tree, node, Space.Comma); - } - } - } - - try renderToken(tree, ais, switch_case.arrow_token, Space.Space); // => - - if (switch_case.payload) |payload| { - try renderExpression(allocator, ais, tree, payload, Space.Space); - } - - return renderExpression(allocator, ais, tree, switch_case.expr, space); - }, - .SwitchElse => { - const switch_else = @fieldParentPtr(ast.Node.SwitchElse, "base", base); - return renderToken(tree, ais, switch_else.token, space); - }, - .Else => { - const else_node = @fieldParentPtr(ast.Node.Else, "base", base); - - const body_is_block = nodeIsBlock(else_node.body); - const same_line = body_is_block or tree.tokensOnSameLine(else_node.else_token, else_node.body.lastToken()); - - const after_else_space = if (same_line or else_node.payload != null) Space.Space else Space.Newline; - try renderToken(tree, ais, else_node.else_token, after_else_space); - if (else_node.payload) |payload| { - const payload_space = if (same_line) Space.Space else Space.Newline; - try renderExpression(allocator, ais, tree, payload, payload_space); - } - - if (same_line) { - return renderExpression(allocator, ais, tree, else_node.body, space); - } else { - ais.pushIndent(); - defer ais.popIndent(); - return renderExpression(allocator, ais, tree, else_node.body, space); - } - }, - - .While => { - const while_node = @fieldParentPtr(ast.Node.While, "base", base); - - if (while_node.label) |label| { - try renderToken(tree, ais, label, Space.None); // label - try renderToken(tree, ais, tree.nextToken(label), Space.Space); // : - } - - if (while_node.inline_token) |inline_token| { - try renderToken(tree, ais, inline_token, Space.Space); // inline - } - - try renderToken(tree, ais, while_node.while_token, Space.Space); // while - try renderToken(tree, ais, tree.nextToken(while_node.while_token), Space.None); // ( - try renderExpression(allocator, ais, tree, while_node.condition, Space.None); - - const cond_rparen = tree.nextToken(while_node.condition.lastToken()); - - const body_is_block = nodeIsBlock(while_node.body); - - var block_start_space: Space = undefined; - var after_body_space: Space = undefined; - - if (body_is_block) { - block_start_space = Space.BlockStart; - after_body_space = if (while_node.@"else" == null) space else Space.SpaceOrOutdent; - } else if (tree.tokensOnSameLine(cond_rparen, while_node.body.lastToken())) { - block_start_space = Space.Space; - after_body_space = if (while_node.@"else" == null) space else Space.Space; - } else { - block_start_space = Space.Newline; - after_body_space = if (while_node.@"else" == null) space else Space.Newline; - } - - { - const rparen_space = if (while_node.payload != null or while_node.continue_expr != null) Space.Space else block_start_space; - try renderToken(tree, ais, cond_rparen, rparen_space); // ) - } - - if (while_node.payload) |payload| { - const payload_space = if (while_node.continue_expr != null) Space.Space else block_start_space; - try renderExpression(allocator, ais, tree, payload, payload_space); - } - - if (while_node.continue_expr) |continue_expr| { - const rparen = tree.nextToken(continue_expr.lastToken()); - const lparen = tree.prevToken(continue_expr.firstToken()); - const colon = tree.prevToken(lparen); - - try renderToken(tree, ais, colon, Space.Space); // : - try renderToken(tree, ais, lparen, Space.None); // ( - - try renderExpression(allocator, ais, tree, continue_expr, Space.None); - - try renderToken(tree, ais, rparen, block_start_space); // ) - } - - { - if (!body_is_block) ais.pushIndent(); - defer if (!body_is_block) ais.popIndent(); - try renderExpression(allocator, ais, tree, while_node.body, after_body_space); - } - - if (while_node.@"else") |@"else"| { - return renderExpression(allocator, ais, tree, &@"else".base, space); - } - }, - - .For => { - const for_node = @fieldParentPtr(ast.Node.For, "base", base); - - if (for_node.label) |label| { - try renderToken(tree, ais, label, Space.None); // label - try renderToken(tree, ais, tree.nextToken(label), Space.Space); // : - } - - if (for_node.inline_token) |inline_token| { - try renderToken(tree, ais, inline_token, Space.Space); // inline - } - - try renderToken(tree, ais, for_node.for_token, Space.Space); // for - try renderToken(tree, ais, tree.nextToken(for_node.for_token), Space.None); // ( - try renderExpression(allocator, ais, tree, for_node.array_expr, Space.None); - - const rparen = tree.nextToken(for_node.array_expr.lastToken()); + try renderToken(ais, tree, lbrace, .Newline); - const body_is_block = for_node.body.tag.isBlock(); - const src_one_line_to_body = !body_is_block and tree.tokensOnSameLine(rparen, for_node.body.firstToken()); - const body_on_same_line = body_is_block or src_one_line_to_body; + for (statements) |statement, i| { + try renderStatement(ais, tree, statement); - try renderToken(tree, ais, rparen, Space.Space); // ) - - const space_after_payload = if (body_on_same_line) Space.Space else Space.Newline; - try renderExpression(allocator, ais, tree, for_node.payload, space_after_payload); // |x| - - const space_after_body = blk: { - if (for_node.@"else") |@"else"| { - const src_one_line_to_else = tree.tokensOnSameLine(rparen, @"else".firstToken()); - if (body_is_block or src_one_line_to_else) { - break :blk Space.Space; - } else { - break :blk Space.Newline; + if (i + 1 < statements.len) { + try renderExtraNewline(tree, ais, statements[i + 1]); } - } else { - break :blk space; } - }; - - { - if (!body_on_same_line) ais.pushIndent(); - defer if (!body_on_same_line) ais.popIndent(); - try renderExpression(allocator, ais, tree, for_node.body, space_after_body); // { body } - } - - if (for_node.@"else") |@"else"| { - return renderExpression(allocator, ais, tree, &@"else".base, space); // else + ais.popIndent(); + const rbrace = tree.lastToken(statements[statements.len - 1]) + 1; + return renderToken(ais, tree, rbrace, space); } }, - .If => { - const if_node = @fieldParentPtr(ast.Node.If, "base", base); - - const lparen = tree.nextToken(if_node.if_token); - const rparen = tree.nextToken(if_node.condition.lastToken()); - - try renderToken(tree, ais, if_node.if_token, Space.Space); // if - try renderToken(tree, ais, lparen, Space.None); // ( - - try renderExpression(allocator, ais, tree, if_node.condition, Space.None); // condition - - const body_is_if_block = if_node.body.tag == .If; - const body_is_block = nodeIsBlock(if_node.body); - - if (body_is_if_block) { - try renderExtraNewline(tree, ais, if_node.body); - } else if (body_is_block) { - const after_rparen_space = if (if_node.payload == null) Space.BlockStart else Space.Space; - try renderToken(tree, ais, rparen, after_rparen_space); // ) - - if (if_node.payload) |payload| { - try renderExpression(allocator, ais, tree, payload, Space.BlockStart); // |x| - } - - if (if_node.@"else") |@"else"| { - try renderExpression(allocator, ais, tree, if_node.body, Space.SpaceOrOutdent); - return renderExpression(allocator, ais, tree, &@"else".base, space); - } else { - return renderExpression(allocator, ais, tree, if_node.body, space); - } - } - - const src_has_newline = !tree.tokensOnSameLine(rparen, if_node.body.lastToken()); - - if (src_has_newline) { - const after_rparen_space = if (if_node.payload == null) Space.Newline else Space.Space; - - { - ais.pushIndent(); - defer ais.popIndent(); - try renderToken(tree, ais, rparen, after_rparen_space); // ) - } - - if (if_node.payload) |payload| { - try renderExpression(allocator, ais, tree, payload, Space.Newline); - } - - if (if_node.@"else") |@"else"| { - const else_is_block = nodeIsBlock(@"else".body); - - { - ais.pushIndent(); - defer ais.popIndent(); - try renderExpression(allocator, ais, tree, if_node.body, Space.Newline); - } - - if (else_is_block) { - try renderToken(tree, ais, @"else".else_token, Space.Space); // else - - if (@"else".payload) |payload| { - try renderExpression(allocator, ais, tree, payload, Space.Space); - } - - return renderExpression(allocator, ais, tree, @"else".body, space); - } else { - const after_else_space = if (@"else".payload == null) Space.Newline else Space.Space; - try renderToken(tree, ais, @"else".else_token, after_else_space); // else - - if (@"else".payload) |payload| { - try renderExpression(allocator, ais, tree, payload, Space.Newline); - } - - ais.pushIndent(); - defer ais.popIndent(); - return renderExpression(allocator, ais, tree, @"else".body, space); - } - } else { - ais.pushIndent(); - defer ais.popIndent(); - return renderExpression(allocator, ais, tree, if_node.body, space); - } - } - - // Single line if statement - - try renderToken(tree, ais, rparen, Space.Space); // ) - - if (if_node.payload) |payload| { - try renderExpression(allocator, ais, tree, payload, Space.Space); - } + //.Defer => { + // const defer_node = @fieldParentPtr(ast.Node.Defer, "base", base); - if (if_node.@"else") |@"else"| { - try renderExpression(allocator, ais, tree, if_node.body, Space.Space); - try renderToken(tree, ais, @"else".else_token, Space.Space); - - if (@"else".payload) |payload| { - try renderExpression(allocator, ais, tree, payload, Space.Space); - } - - return renderExpression(allocator, ais, tree, @"else".body, space); - } else { - return renderExpression(allocator, ais, tree, if_node.body, space); - } - }, - - .Asm => { - const asm_node = @fieldParentPtr(ast.Node.Asm, "base", base); - - try renderToken(tree, ais, asm_node.asm_token, Space.Space); // asm - - if (asm_node.volatile_token) |volatile_token| { - try renderToken(tree, ais, volatile_token, Space.Space); // volatile - try renderToken(tree, ais, tree.nextToken(volatile_token), Space.None); // ( - } else { - try renderToken(tree, ais, tree.nextToken(asm_node.asm_token), Space.None); // ( - } - - asmblk: { - ais.pushIndent(); - defer ais.popIndent(); - - if (asm_node.outputs.len == 0 and asm_node.inputs.len == 0 and asm_node.clobbers.len == 0) { - try renderExpression(allocator, ais, tree, asm_node.template, Space.None); - break :asmblk; - } - - try renderExpression(allocator, ais, tree, asm_node.template, Space.Newline); - - ais.setIndentDelta(asm_indent_delta); - defer ais.setIndentDelta(indent_delta); - - const colon1 = tree.nextToken(asm_node.template.lastToken()); - - const colon2 = if (asm_node.outputs.len == 0) blk: { - try renderToken(tree, ais, colon1, Space.Newline); // : - - break :blk tree.nextToken(colon1); - } else blk: { - try renderToken(tree, ais, colon1, Space.Space); // : - - ais.pushIndent(); - defer ais.popIndent(); - - for (asm_node.outputs) |*asm_output, i| { - if (i + 1 < asm_node.outputs.len) { - const next_asm_output = asm_node.outputs[i + 1]; - try renderAsmOutput(allocator, ais, tree, asm_output, Space.None); - - const comma = tree.prevToken(next_asm_output.firstToken()); - try renderToken(tree, ais, comma, Space.Newline); // , - try renderExtraNewlineToken(tree, ais, next_asm_output.firstToken()); - } else if (asm_node.inputs.len == 0 and asm_node.clobbers.len == 0) { - try renderAsmOutput(allocator, ais, tree, asm_output, Space.Newline); - break :asmblk; - } else { - try renderAsmOutput(allocator, ais, tree, asm_output, Space.Newline); - const comma_or_colon = tree.nextToken(asm_output.lastToken()); - break :blk switch (tree.token_ids[comma_or_colon]) { - .Comma => tree.nextToken(comma_or_colon), - else => comma_or_colon, - }; - } - } - unreachable; - }; - - const colon3 = if (asm_node.inputs.len == 0) blk: { - try renderToken(tree, ais, colon2, Space.Newline); // : - break :blk tree.nextToken(colon2); - } else blk: { - try renderToken(tree, ais, colon2, Space.Space); // : - ais.pushIndent(); - defer ais.popIndent(); - for (asm_node.inputs) |*asm_input, i| { - if (i + 1 < asm_node.inputs.len) { - const next_asm_input = &asm_node.inputs[i + 1]; - try renderAsmInput(allocator, ais, tree, asm_input, Space.None); - - const comma = tree.prevToken(next_asm_input.firstToken()); - try renderToken(tree, ais, comma, Space.Newline); // , - try renderExtraNewlineToken(tree, ais, next_asm_input.firstToken()); - } else if (asm_node.clobbers.len == 0) { - try renderAsmInput(allocator, ais, tree, asm_input, Space.Newline); - break :asmblk; - } else { - try renderAsmInput(allocator, ais, tree, asm_input, Space.Newline); - const comma_or_colon = tree.nextToken(asm_input.lastToken()); - break :blk switch (tree.token_ids[comma_or_colon]) { - .Comma => tree.nextToken(comma_or_colon), - else => comma_or_colon, - }; - } - } - unreachable; - }; - - try renderToken(tree, ais, colon3, Space.Space); // : - ais.pushIndent(); - defer ais.popIndent(); - for (asm_node.clobbers) |clobber_node, i| { - if (i + 1 >= asm_node.clobbers.len) { - try renderExpression(allocator, ais, tree, clobber_node, Space.Newline); - break :asmblk; - } else { - try renderExpression(allocator, ais, tree, clobber_node, Space.None); - const comma = tree.nextToken(clobber_node.lastToken()); - try renderToken(tree, ais, comma, Space.Space); // , - } - } - } - - return renderToken(tree, ais, asm_node.rparen, space); - }, - - .EnumLiteral => { - const enum_literal = @fieldParentPtr(ast.Node.EnumLiteral, "base", base); - - try renderToken(tree, ais, enum_literal.dot, Space.None); // . - return renderToken(tree, ais, enum_literal.name, space); // name + // try renderToken(ais, tree, defer_node.defer_token, Space.Space); + // if (defer_node.payload) |payload| { + // try renderExpression(allocator, ais, tree, payload, Space.Space); + // } + // return renderExpression(allocator, ais, tree, defer_node.expr, space); + //}, + .Comptime => { + const comptime_token = tree.nodes.items(.main_token)[node]; + const block = tree.nodes.items(.data)[node].lhs; + try renderToken(ais, tree, comptime_token, .Space); + return renderExpression(ais, tree, block, space); }, - - .ContainerField, - .Root, - .VarDecl, - .Use, - .TestDecl, - => unreachable, + //.Nosuspend => { + // const nosuspend_node = @fieldParentPtr(ast.Node.Nosuspend, "base", base); + // if (mem.eql(u8, tree.tokenSlice(nosuspend_node.nosuspend_token), "noasync")) { + // // TODO: remove this + // try ais.writer().writeAll("nosuspend "); + // } else { + // try renderToken(ais, tree, nosuspend_node.nosuspend_token, Space.Space); + // } + // return renderExpression(allocator, ais, tree, nosuspend_node.expr, space); + //}, + + //.Suspend => { + // const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base); + + // if (suspend_node.body) |body| { + // try renderToken(ais, tree, suspend_node.suspend_token, Space.Space); + // return renderExpression(allocator, ais, tree, body, space); + // } else { + // return renderToken(ais, tree, suspend_node.suspend_token, space); + // } + //}, + + //.Catch => { + // const infix_op_node = @fieldParentPtr(ast.Node.Catch, "base", base); + + // const op_space = Space.Space; + // try renderExpression(allocator, ais, tree, infix_op_node.lhs, op_space); + + // const after_op_space = blk: { + // const same_line = tree.tokensOnSameLine(infix_op_node.op_token, tree.nextToken(infix_op_node.op_token)); + // break :blk if (same_line) op_space else Space.Newline; + // }; + + // try renderToken(ais, tree, infix_op_node.op_token, after_op_space); + + // if (infix_op_node.payload) |payload| { + // try renderExpression(allocator, ais, tree, payload, Space.Space); + // } + + // ais.pushIndentOneShot(); + // return renderExpression(allocator, ais, tree, infix_op_node.rhs, space); + //}, + + //.Add, + //.AddWrap, + //.ArrayCat, + //.ArrayMult, + //.Assign, + //.AssignBitAnd, + //.AssignBitOr, + //.AssignBitShiftLeft, + //.AssignBitShiftRight, + //.AssignBitXor, + //.AssignDiv, + //.AssignSub, + //.AssignSubWrap, + //.AssignMod, + //.AssignAdd, + //.AssignAddWrap, + //.AssignMul, + //.AssignMulWrap, + //.BangEqual, + //.BitAnd, + //.BitOr, + //.BitShiftLeft, + //.BitShiftRight, + //.BitXor, + //.BoolAnd, + //.BoolOr, + //.Div, + //.EqualEqual, + //.ErrorUnion, + //.GreaterOrEqual, + //.GreaterThan, + //.LessOrEqual, + //.LessThan, + //.MergeErrorSets, + //.Mod, + //.Mul, + //.MulWrap, + //.Period, + //.Range, + //.Sub, + //.SubWrap, + //.OrElse, + //=> { + // const infix_op_node = @fieldParentPtr(ast.Node.SimpleInfixOp, "base", base); + + // const op_space = switch (base.tag) { + // .Period, .ErrorUnion, .Range => Space.None, + // else => Space.Space, + // }; + // try renderExpression(allocator, ais, tree, infix_op_node.lhs, op_space); + + // const after_op_space = blk: { + // const loc = tree.tokenLocation(tree.token_locs[infix_op_node.op_token].end, tree.nextToken(infix_op_node.op_token)); + // break :blk if (loc.line == 0) op_space else Space.Newline; + // }; + + // { + // ais.pushIndent(); + // defer ais.popIndent(); + // try renderToken(ais, tree, infix_op_node.op_token, after_op_space); + // } + // ais.pushIndentOneShot(); + // return renderExpression(allocator, ais, tree, infix_op_node.rhs, space); + //}, + + //.BitNot, + //.BoolNot, + //.Negation, + //.NegationWrap, + //.OptionalType, + //.AddressOf, + //=> { + // const casted_node = @fieldParentPtr(ast.Node.SimplePrefixOp, "base", base); + // try renderToken(ais, tree, casted_node.op_token, Space.None); + // return renderExpression(allocator, ais, tree, casted_node.rhs, space); + //}, + + //.Try, + //.Resume, + //.Await, + //=> { + // const casted_node = @fieldParentPtr(ast.Node.SimplePrefixOp, "base", base); + // try renderToken(ais, tree, casted_node.op_token, Space.Space); + // return renderExpression(allocator, ais, tree, casted_node.rhs, space); + //}, + + //.ArrayType => { + // const array_type = @fieldParentPtr(ast.Node.ArrayType, "base", base); + // return renderArrayType( + // allocator, + // ais, + // tree, + // array_type.op_token, + // array_type.rhs, + // array_type.len_expr, + // null, + // space, + // ); + //}, + //.ArrayTypeSentinel => { + // const array_type = @fieldParentPtr(ast.Node.ArrayTypeSentinel, "base", base); + // return renderArrayType( + // allocator, + // ais, + // tree, + // array_type.op_token, + // array_type.rhs, + // array_type.len_expr, + // array_type.sentinel, + // space, + // ); + //}, + + //.PtrType => { + // const ptr_type = @fieldParentPtr(ast.Node.PtrType, "base", base); + // const op_tok_id = tree.token_tags[ptr_type.op_token]; + // switch (op_tok_id) { + // .Asterisk, .AsteriskAsterisk => try ais.writer().writeByte('*'), + // .LBracket => if (tree.token_tags[ptr_type.op_token + 2] == .Identifier) + // try ais.writer().writeAll("[*c") + // else + // try ais.writer().writeAll("[*"), + // else => unreachable, + // } + // if (ptr_type.ptr_info.sentinel) |sentinel| { + // const colon_token = tree.prevToken(sentinel.firstToken()); + // try renderToken(ais, tree, colon_token, Space.None); // : + // const sentinel_space = switch (op_tok_id) { + // .LBracket => Space.None, + // else => Space.Space, + // }; + // try renderExpression(allocator, ais, tree, sentinel, sentinel_space); + // } + // switch (op_tok_id) { + // .Asterisk, .AsteriskAsterisk => {}, + // .LBracket => try ais.writer().writeByte(']'), + // else => unreachable, + // } + // if (ptr_type.ptr_info.allowzero_token) |allowzero_token| { + // try renderToken(ais, tree, allowzero_token, Space.Space); // allowzero + // } + // if (ptr_type.ptr_info.align_info) |align_info| { + // const lparen_token = tree.prevToken(align_info.node.firstToken()); + // const align_token = tree.prevToken(lparen_token); + + // try renderToken(ais, tree, align_token, Space.None); // align + // try renderToken(ais, tree, lparen_token, Space.None); // ( + + // try renderExpression(allocator, ais, tree, align_info.node, Space.None); + + // if (align_info.bit_range) |bit_range| { + // const colon1 = tree.prevToken(bit_range.start.firstToken()); + // const colon2 = tree.prevToken(bit_range.end.firstToken()); + + // try renderToken(ais, tree, colon1, Space.None); // : + // try renderExpression(allocator, ais, tree, bit_range.start, Space.None); + // try renderToken(ais, tree, colon2, Space.None); // : + // try renderExpression(allocator, ais, tree, bit_range.end, Space.None); + + // const rparen_token = tree.nextToken(bit_range.end.lastToken()); + // try renderToken(ais, tree, rparen_token, Space.Space); // ) + // } else { + // const rparen_token = tree.nextToken(align_info.node.lastToken()); + // try renderToken(ais, tree, rparen_token, Space.Space); // ) + // } + // } + // if (ptr_type.ptr_info.const_token) |const_token| { + // try renderToken(ais, tree, const_token, Space.Space); // const + // } + // if (ptr_type.ptr_info.volatile_token) |volatile_token| { + // try renderToken(ais, tree, volatile_token, Space.Space); // volatile + // } + // return renderExpression(allocator, ais, tree, ptr_type.rhs, space); + //}, + + //.SliceType => { + // const slice_type = @fieldParentPtr(ast.Node.SliceType, "base", base); + // try renderToken(ais, tree, slice_type.op_token, Space.None); // [ + // if (slice_type.ptr_info.sentinel) |sentinel| { + // const colon_token = tree.prevToken(sentinel.firstToken()); + // try renderToken(ais, tree, colon_token, Space.None); // : + // try renderExpression(allocator, ais, tree, sentinel, Space.None); + // try renderToken(ais, tree, tree.nextToken(sentinel.lastToken()), Space.None); // ] + // } else { + // try renderToken(ais, tree, tree.nextToken(slice_type.op_token), Space.None); // ] + // } + + // if (slice_type.ptr_info.allowzero_token) |allowzero_token| { + // try renderToken(ais, tree, allowzero_token, Space.Space); // allowzero + // } + // if (slice_type.ptr_info.align_info) |align_info| { + // const lparen_token = tree.prevToken(align_info.node.firstToken()); + // const align_token = tree.prevToken(lparen_token); + + // try renderToken(ais, tree, align_token, Space.None); // align + // try renderToken(ais, tree, lparen_token, Space.None); // ( + + // try renderExpression(allocator, ais, tree, align_info.node, Space.None); + + // if (align_info.bit_range) |bit_range| { + // const colon1 = tree.prevToken(bit_range.start.firstToken()); + // const colon2 = tree.prevToken(bit_range.end.firstToken()); + + // try renderToken(ais, tree, colon1, Space.None); // : + // try renderExpression(allocator, ais, tree, bit_range.start, Space.None); + // try renderToken(ais, tree, colon2, Space.None); // : + // try renderExpression(allocator, ais, tree, bit_range.end, Space.None); + + // const rparen_token = tree.nextToken(bit_range.end.lastToken()); + // try renderToken(ais, tree, rparen_token, Space.Space); // ) + // } else { + // const rparen_token = tree.nextToken(align_info.node.lastToken()); + // try renderToken(ais, tree, rparen_token, Space.Space); // ) + // } + // } + // if (slice_type.ptr_info.const_token) |const_token| { + // try renderToken(ais, tree, const_token, Space.Space); + // } + // if (slice_type.ptr_info.volatile_token) |volatile_token| { + // try renderToken(ais, tree, volatile_token, Space.Space); + // } + // return renderExpression(allocator, ais, tree, slice_type.rhs, space); + //}, + + //.ArrayInitializer, .ArrayInitializerDot => { + // var rtoken: ast.TokenIndex = undefined; + // var exprs: []ast.Node.Index = undefined; + // const lhs: union(enum) { dot: ast.TokenIndex, node: ast.Node.Index } = switch (base.tag) { + // .ArrayInitializerDot => blk: { + // const casted = @fieldParentPtr(ast.Node.ArrayInitializerDot, "base", base); + // rtoken = casted.rtoken; + // exprs = casted.list(); + // break :blk .{ .dot = casted.dot }; + // }, + // .ArrayInitializer => blk: { + // const casted = @fieldParentPtr(ast.Node.ArrayInitializer, "base", base); + // rtoken = casted.rtoken; + // exprs = casted.list(); + // break :blk .{ .node = casted.lhs }; + // }, + // else => unreachable, + // }; + + // const lbrace = switch (lhs) { + // .dot => |dot| tree.nextToken(dot), + // .node => |node| tree.nextToken(node.lastToken()), + // }; + + // switch (lhs) { + // .dot => |dot| try renderToken(ais, tree, dot, Space.None), + // .node => |node| try renderExpression(allocator, ais, tree, node, Space.None), + // } + + // if (exprs.len == 0) { + // try renderToken(ais, tree, lbrace, Space.None); + // return renderToken(ais, tree, rtoken, space); + // } + + // if (exprs.len == 1 and exprs[0].tag != .MultilineStringLiteral and tree.token_tags[exprs[0].*.lastToken() + 1] == .RBrace) { + // const expr = exprs[0]; + + // try renderToken(ais, tree, lbrace, Space.None); + // try renderExpression(allocator, ais, tree, expr, Space.None); + // return renderToken(ais, tree, rtoken, space); + // } + + // // scan to find row size + // if (rowSize(tree, exprs, rtoken) != null) { + // { + // ais.pushIndentNextLine(); + // defer ais.popIndent(); + // try renderToken(ais, tree, lbrace, Space.Newline); + + // var expr_index: usize = 0; + // while (rowSize(tree, exprs[expr_index..], rtoken)) |row_size| { + // const row_exprs = exprs[expr_index..]; + // // A place to store the width of each expression and its column's maximum + // var widths = try allocator.alloc(usize, row_exprs.len + row_size); + // defer allocator.free(widths); + // mem.set(usize, widths, 0); + + // var expr_newlines = try allocator.alloc(bool, row_exprs.len); + // defer allocator.free(expr_newlines); + // mem.set(bool, expr_newlines, false); + + // var expr_widths = widths[0 .. widths.len - row_size]; + // var column_widths = widths[widths.len - row_size ..]; + + // // Find next row with trailing comment (if any) to end the current section + // var section_end = sec_end: { + // var this_line_first_expr: usize = 0; + // var this_line_size = rowSize(tree, row_exprs, rtoken); + // for (row_exprs) |expr, i| { + // // Ignore comment on first line of this section + // if (i == 0 or tree.tokensOnSameLine(row_exprs[0].firstToken(), expr.lastToken())) continue; + // // Track start of line containing comment + // if (!tree.tokensOnSameLine(row_exprs[this_line_first_expr].firstToken(), expr.lastToken())) { + // this_line_first_expr = i; + // this_line_size = rowSize(tree, row_exprs[this_line_first_expr..], rtoken); + // } + + // const maybe_comma = expr.lastToken() + 1; + // const maybe_comment = expr.lastToken() + 2; + // if (maybe_comment < tree.token_tags.len) { + // if (tree.token_tags[maybe_comma] == .Comma and + // tree.token_tags[maybe_comment] == .LineComment and + // tree.tokensOnSameLine(expr.lastToken(), maybe_comment)) + // { + // var comment_token_loc = tree.token_locs[maybe_comment]; + // const comment_is_empty = mem.trimRight(u8, tree.tokenSliceLoc(comment_token_loc), " ").len == 2; + // if (!comment_is_empty) { + // // Found row ending in comment + // break :sec_end i - this_line_size.? + 1; + // } + // } + // } + // } + // break :sec_end row_exprs.len; + // }; + // expr_index += section_end; + + // const section_exprs = row_exprs[0..section_end]; + + // // Null stream for counting the printed length of each expression + // var line_find_stream = std.io.findByteWriter('\n', std.io.null_writer); + // var counting_stream = std.io.countingWriter(line_find_stream.writer()); + // var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, counting_stream.writer()); + + // // Calculate size of columns in current section + // var column_counter: usize = 0; + // var single_line = true; + // for (section_exprs) |expr, i| { + // if (i + 1 < section_exprs.len) { + // counting_stream.bytes_written = 0; + // line_find_stream.byte_found = false; + // try renderExpression(allocator, &auto_indenting_stream, tree, expr, Space.None); + // const width = @intCast(usize, counting_stream.bytes_written); + // expr_widths[i] = width; + // expr_newlines[i] = line_find_stream.byte_found; + + // if (!line_find_stream.byte_found) { + // const column = column_counter % row_size; + // column_widths[column] = std.math.max(column_widths[column], width); + + // const expr_last_token = expr.*.lastToken() + 1; + // const next_expr = section_exprs[i + 1]; + // const loc = tree.tokenLocation(tree.token_locs[expr_last_token].start, next_expr.*.firstToken()); + + // column_counter += 1; + + // if (loc.line != 0) single_line = false; + // } else { + // single_line = false; + // column_counter = 0; + // } + // } else { + // counting_stream.bytes_written = 0; + // try renderExpression(allocator, &auto_indenting_stream, tree, expr, Space.None); + // const width = @intCast(usize, counting_stream.bytes_written); + // expr_widths[i] = width; + // expr_newlines[i] = line_find_stream.byte_found; + + // if (!line_find_stream.byte_found) { + // const column = column_counter % row_size; + // column_widths[column] = std.math.max(column_widths[column], width); + // } + // break; + // } + // } + + // // Render exprs in current section + // column_counter = 0; + // var last_col_index: usize = row_size - 1; + // for (section_exprs) |expr, i| { + // if (i + 1 < section_exprs.len) { + // const next_expr = section_exprs[i + 1]; + // try renderExpression(allocator, ais, tree, expr, Space.None); + + // const comma = tree.nextToken(expr.*.lastToken()); + + // if (column_counter != last_col_index) { + // if (!expr_newlines[i] and !expr_newlines[i + 1]) { + // // Neither the current or next expression is multiline + // try renderToken(ais, tree, comma, Space.Space); // , + // assert(column_widths[column_counter % row_size] >= expr_widths[i]); + // const padding = column_widths[column_counter % row_size] - expr_widths[i]; + // try ais.writer().writeByteNTimes(' ', padding); + + // column_counter += 1; + // continue; + // } + // } + // if (single_line and row_size != 1) { + // try renderToken(ais, tree, comma, Space.Space); // , + // continue; + // } + + // column_counter = 0; + // try renderToken(ais, tree, comma, Space.Newline); // , + // try renderExtraNewline(tree, ais, next_expr); + // } else { + // const maybe_comma = tree.nextToken(expr.*.lastToken()); + // if (tree.token_tags[maybe_comma] == .Comma) { + // try renderExpression(allocator, ais, tree, expr, Space.None); // , + // try renderToken(ais, tree, maybe_comma, Space.Newline); // , + // } else { + // try renderExpression(allocator, ais, tree, expr, Space.Comma); // , + // } + // } + // } + + // if (expr_index == exprs.len) { + // break; + // } + // } + // } + + // return renderToken(ais, tree, rtoken, space); + // } + + // // Single line + // try renderToken(ais, tree, lbrace, Space.Space); + // for (exprs) |expr, i| { + // if (i + 1 < exprs.len) { + // const next_expr = exprs[i + 1]; + // try renderExpression(allocator, ais, tree, expr, Space.None); + // const comma = tree.nextToken(expr.*.lastToken()); + // try renderToken(ais, tree, comma, Space.Space); // , + // } else { + // try renderExpression(allocator, ais, tree, expr, Space.Space); + // } + // } + + // return renderToken(ais, tree, rtoken, space); + //}, + + //.StructInitializer, .StructInitializerDot => { + // var rtoken: ast.TokenIndex = undefined; + // var field_inits: []ast.Node.Index = undefined; + // const lhs: union(enum) { dot: ast.TokenIndex, node: ast.Node.Index } = switch (base.tag) { + // .StructInitializerDot => blk: { + // const casted = @fieldParentPtr(ast.Node.StructInitializerDot, "base", base); + // rtoken = casted.rtoken; + // field_inits = casted.list(); + // break :blk .{ .dot = casted.dot }; + // }, + // .StructInitializer => blk: { + // const casted = @fieldParentPtr(ast.Node.StructInitializer, "base", base); + // rtoken = casted.rtoken; + // field_inits = casted.list(); + // break :blk .{ .node = casted.lhs }; + // }, + // else => unreachable, + // }; + + // const lbrace = switch (lhs) { + // .dot => |dot| tree.nextToken(dot), + // .node => |node| tree.nextToken(node.lastToken()), + // }; + + // if (field_inits.len == 0) { + // switch (lhs) { + // .dot => |dot| try renderToken(ais, tree, dot, Space.None), + // .node => |node| try renderExpression(allocator, ais, tree, node, Space.None), + // } + + // { + // ais.pushIndentNextLine(); + // defer ais.popIndent(); + // try renderToken(ais, tree, lbrace, Space.None); + // } + + // return renderToken(ais, tree, rtoken, space); + // } + + // const src_has_trailing_comma = blk: { + // const maybe_comma = tree.prevToken(rtoken); + // break :blk tree.token_tags[maybe_comma] == .Comma; + // }; + + // const src_same_line = blk: { + // const loc = tree.tokenLocation(tree.token_locs[lbrace].end, rtoken); + // break :blk loc.line == 0; + // }; + + // const expr_outputs_one_line = blk: { + // // render field expressions until a LF is found + // for (field_inits) |field_init| { + // var find_stream = std.io.findByteWriter('\n', std.io.null_writer); + // var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, find_stream.writer()); + + // try renderExpression(allocator, &auto_indenting_stream, tree, field_init, Space.None); + // if (find_stream.byte_found) break :blk false; + // } + // break :blk true; + // }; + + // if (field_inits.len == 1) blk: { + // if (field_inits[0].cast(ast.Node.FieldInitializer)) |field_init| { + // switch (field_init.expr.tag) { + // .StructInitializer, + // .StructInitializerDot, + // => break :blk, + // else => {}, + // } + // } + + // // if the expression outputs to multiline, make this struct multiline + // if (!expr_outputs_one_line or src_has_trailing_comma) { + // break :blk; + // } + + // switch (lhs) { + // .dot => |dot| try renderToken(ais, tree, dot, Space.None), + // .node => |node| try renderExpression(allocator, ais, tree, node, Space.None), + // } + // try renderToken(ais, tree, lbrace, Space.Space); + // try renderExpression(allocator, ais, tree, field_inits[0], Space.Space); + // return renderToken(ais, tree, rtoken, space); + // } + + // if (!src_has_trailing_comma and src_same_line and expr_outputs_one_line) { + // // render all on one line, no trailing comma + // switch (lhs) { + // .dot => |dot| try renderToken(ais, tree, dot, Space.None), + // .node => |node| try renderExpression(allocator, ais, tree, node, Space.None), + // } + // try renderToken(ais, tree, lbrace, Space.Space); + + // for (field_inits) |field_init, i| { + // if (i + 1 < field_inits.len) { + // try renderExpression(allocator, ais, tree, field_init, Space.None); + + // const comma = tree.nextToken(field_init.lastToken()); + // try renderToken(ais, tree, comma, Space.Space); + // } else { + // try renderExpression(allocator, ais, tree, field_init, Space.Space); + // } + // } + + // return renderToken(ais, tree, rtoken, space); + // } + + // { + // switch (lhs) { + // .dot => |dot| try renderToken(ais, tree, dot, Space.None), + // .node => |node| try renderExpression(allocator, ais, tree, node, Space.None), + // } + + // ais.pushIndentNextLine(); + // defer ais.popIndent(); + + // try renderToken(ais, tree, lbrace, Space.Newline); + + // for (field_inits) |field_init, i| { + // if (i + 1 < field_inits.len) { + // const next_field_init = field_inits[i + 1]; + // try renderExpression(allocator, ais, tree, field_init, Space.None); + + // const comma = tree.nextToken(field_init.lastToken()); + // try renderToken(ais, tree, comma, Space.Newline); + + // try renderExtraNewline(tree, ais, next_field_init); + // } else { + // try renderExpression(allocator, ais, tree, field_init, Space.Comma); + // } + // } + // } + + // return renderToken(ais, tree, rtoken, space); + //}, + + //.Call => { + // const call = @fieldParentPtr(ast.Node.Call, "base", base); + // if (call.async_token) |async_token| { + // try renderToken(ais, tree, async_token, Space.Space); + // } + + // try renderExpression(allocator, ais, tree, call.lhs, Space.None); + + // const lparen = tree.nextToken(call.lhs.lastToken()); + + // if (call.params_len == 0) { + // try renderToken(ais, tree, lparen, Space.None); + // return renderToken(ais, tree, call.rtoken, space); + // } + + // const src_has_trailing_comma = blk: { + // const maybe_comma = tree.prevToken(call.rtoken); + // break :blk tree.token_tags[maybe_comma] == .Comma; + // }; + + // if (src_has_trailing_comma) { + // { + // ais.pushIndent(); + // defer ais.popIndent(); + + // try renderToken(ais, tree, lparen, Space.Newline); // ( + // const params = call.params(); + // for (params) |param_node, i| { + // if (i + 1 < params.len) { + // const next_node = params[i + 1]; + // try renderExpression(allocator, ais, tree, param_node, Space.None); + + // // Unindent the comma for multiline string literals + // const maybe_multiline_string = param_node.firstToken(); + // const is_multiline_string = tree.token_tags[maybe_multiline_string] == .MultilineStringLiteralLine; + // if (is_multiline_string) ais.popIndent(); + // defer if (is_multiline_string) ais.pushIndent(); + + // const comma = tree.nextToken(param_node.lastToken()); + // try renderToken(ais, tree, comma, Space.Newline); // , + // try renderExtraNewline(tree, ais, next_node); + // } else { + // try renderExpression(allocator, ais, tree, param_node, Space.Comma); + // } + // } + // } + // return renderToken(ais, tree, call.rtoken, space); + // } + + // try renderToken(ais, tree, lparen, Space.None); // ( + + // const params = call.params(); + // for (params) |param_node, i| { + // const maybe_comment = param_node.firstToken() - 1; + // const maybe_multiline_string = param_node.firstToken(); + // if (tree.token_tags[maybe_multiline_string] == .MultilineStringLiteralLine or tree.token_tags[maybe_comment] == .LineComment) { + // ais.pushIndentOneShot(); + // } + + // try renderExpression(allocator, ais, tree, param_node, Space.None); + + // if (i + 1 < params.len) { + // const comma = tree.nextToken(param_node.lastToken()); + // try renderToken(ais, tree, comma, Space.Space); + // } + // } + // return renderToken(ais, tree, call.rtoken, space); // ) + //}, + + //.ArrayAccess => { + // const suffix_op = base.castTag(.ArrayAccess).?; + + // const lbracket = tree.nextToken(suffix_op.lhs.lastToken()); + // const rbracket = tree.nextToken(suffix_op.index_expr.lastToken()); + + // try renderExpression(allocator, ais, tree, suffix_op.lhs, Space.None); + // try renderToken(ais, tree, lbracket, Space.None); // [ + + // const starts_with_comment = tree.token_tags[lbracket + 1] == .LineComment; + // const ends_with_comment = tree.token_tags[rbracket - 1] == .LineComment; + // { + // const new_space = if (ends_with_comment) Space.Newline else Space.None; + + // ais.pushIndent(); + // defer ais.popIndent(); + // try renderExpression(allocator, ais, tree, suffix_op.index_expr, new_space); + // } + // if (starts_with_comment) try ais.maybeInsertNewline(); + // return renderToken(ais, tree, rbracket, space); // ] + //}, + + //.Slice => { + // const suffix_op = base.castTag(.Slice).?; + // try renderExpression(allocator, ais, tree, suffix_op.lhs, Space.None); + + // const lbracket = tree.prevToken(suffix_op.start.firstToken()); + // const dotdot = tree.nextToken(suffix_op.start.lastToken()); + + // const after_start_space_bool = nodeCausesSliceOpSpace(suffix_op.start) or + // (if (suffix_op.end) |end| nodeCausesSliceOpSpace(end) else false); + // const after_start_space = if (after_start_space_bool) Space.Space else Space.None; + // const after_op_space = if (suffix_op.end != null) after_start_space else Space.None; + + // try renderToken(ais, tree, lbracket, Space.None); // [ + // try renderExpression(allocator, ais, tree, suffix_op.start, after_start_space); + // try renderToken(ais, tree, dotdot, after_op_space); // .. + // if (suffix_op.end) |end| { + // const after_end_space = if (suffix_op.sentinel != null) Space.Space else Space.None; + // try renderExpression(allocator, ais, tree, end, after_end_space); + // } + // if (suffix_op.sentinel) |sentinel| { + // const colon = tree.prevToken(sentinel.firstToken()); + // try renderToken(ais, tree, colon, Space.None); // : + // try renderExpression(allocator, ais, tree, sentinel, Space.None); + // } + // return renderToken(ais, tree, suffix_op.rtoken, space); // ] + //}, + + //.Deref => { + // const suffix_op = base.castTag(.Deref).?; + + // try renderExpression(allocator, ais, tree, suffix_op.lhs, Space.None); + // return renderToken(ais, tree, suffix_op.rtoken, space); // .* + //}, + //.UnwrapOptional => { + // const suffix_op = base.castTag(.UnwrapOptional).?; + + // try renderExpression(allocator, ais, tree, suffix_op.lhs, Space.None); + // try renderToken(ais, tree, tree.prevToken(suffix_op.rtoken), Space.None); // . + // return renderToken(ais, tree, suffix_op.rtoken, space); // ? + //}, + + //.Break => { + // const flow_expr = base.castTag(.Break).?; + // const maybe_rhs = flow_expr.getRHS(); + // const maybe_label = flow_expr.getLabel(); + + // if (maybe_label == null and maybe_rhs == null) { + // return renderToken(ais, tree, flow_expr.ltoken, space); // break + // } + + // try renderToken(ais, tree, flow_expr.ltoken, Space.Space); // break + // if (maybe_label) |label| { + // const colon = tree.nextToken(flow_expr.ltoken); + // try renderToken(ais, tree, colon, Space.None); // : + + // if (maybe_rhs == null) { + // return renderToken(ais, tree, label, space); // label + // } + // try renderToken(ais, tree, label, Space.Space); // label + // } + // return renderExpression(allocator, ais, tree, maybe_rhs.?, space); + //}, + + //.Continue => { + // const flow_expr = base.castTag(.Continue).?; + // if (flow_expr.getLabel()) |label| { + // try renderToken(ais, tree, flow_expr.ltoken, Space.Space); // continue + // const colon = tree.nextToken(flow_expr.ltoken); + // try renderToken(ais, tree, colon, Space.None); // : + // return renderToken(ais, tree, label, space); // label + // } else { + // return renderToken(ais, tree, flow_expr.ltoken, space); // continue + // } + //}, + + //.Return => { + // const flow_expr = base.castTag(.Return).?; + // if (flow_expr.getRHS()) |rhs| { + // try renderToken(ais, tree, flow_expr.ltoken, Space.Space); + // return renderExpression(allocator, ais, tree, rhs, space); + // } else { + // return renderToken(ais, tree, flow_expr.ltoken, space); + // } + //}, + + //.Payload => { + // const payload = @fieldParentPtr(ast.Node.Payload, "base", base); + + // try renderToken(ais, tree, payload.lpipe, Space.None); + // try renderExpression(allocator, ais, tree, payload.error_symbol, Space.None); + // return renderToken(ais, tree, payload.rpipe, space); + //}, + + //.PointerPayload => { + // const payload = @fieldParentPtr(ast.Node.PointerPayload, "base", base); + + // try renderToken(ais, tree, payload.lpipe, Space.None); + // if (payload.ptr_token) |ptr_token| { + // try renderToken(ais, tree, ptr_token, Space.None); + // } + // try renderExpression(allocator, ais, tree, payload.value_symbol, Space.None); + // return renderToken(ais, tree, payload.rpipe, space); + //}, + + //.PointerIndexPayload => { + // const payload = @fieldParentPtr(ast.Node.PointerIndexPayload, "base", base); + + // try renderToken(ais, tree, payload.lpipe, Space.None); + // if (payload.ptr_token) |ptr_token| { + // try renderToken(ais, tree, ptr_token, Space.None); + // } + // try renderExpression(allocator, ais, tree, payload.value_symbol, Space.None); + + // if (payload.index_symbol) |index_symbol| { + // const comma = tree.nextToken(payload.value_symbol.lastToken()); + + // try renderToken(ais, tree, comma, Space.Space); + // try renderExpression(allocator, ais, tree, index_symbol, Space.None); + // } + + // return renderToken(ais, tree, payload.rpipe, space); + //}, + + //.GroupedExpression => { + // const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", base); + + // try renderToken(ais, tree, grouped_expr.lparen, Space.None); + // { + // ais.pushIndentOneShot(); + // try renderExpression(allocator, ais, tree, grouped_expr.expr, Space.None); + // } + // return renderToken(ais, tree, grouped_expr.rparen, space); + //}, + + //.FieldInitializer => { + // const field_init = @fieldParentPtr(ast.Node.FieldInitializer, "base", base); + + // try renderToken(ais, tree, field_init.period_token, Space.None); // . + // try renderToken(ais, tree, field_init.name_token, Space.Space); // name + // try renderToken(ais, tree, tree.nextToken(field_init.name_token), Space.Space); // = + // return renderExpression(allocator, ais, tree, field_init.expr, space); + //}, + + //.ContainerDecl => { + // const container_decl = @fieldParentPtr(ast.Node.ContainerDecl, "base", base); + + // if (container_decl.layout_token) |layout_token| { + // try renderToken(ais, tree, layout_token, Space.Space); + // } + + // switch (container_decl.init_arg_expr) { + // .None => { + // try renderToken(ais, tree, container_decl.kind_token, Space.Space); // union + // }, + // .Enum => |enum_tag_type| { + // try renderToken(ais, tree, container_decl.kind_token, Space.None); // union + + // const lparen = tree.nextToken(container_decl.kind_token); + // const enum_token = tree.nextToken(lparen); + + // try renderToken(ais, tree, lparen, Space.None); // ( + // try renderToken(ais, tree, enum_token, Space.None); // enum + + // if (enum_tag_type) |expr| { + // try renderToken(ais, tree, tree.nextToken(enum_token), Space.None); // ( + // try renderExpression(allocator, ais, tree, expr, Space.None); + + // const rparen = tree.nextToken(expr.lastToken()); + // try renderToken(ais, tree, rparen, Space.None); // ) + // try renderToken(ais, tree, tree.nextToken(rparen), Space.Space); // ) + // } else { + // try renderToken(ais, tree, tree.nextToken(enum_token), Space.Space); // ) + // } + // }, + // .Type => |type_expr| { + // try renderToken(ais, tree, container_decl.kind_token, Space.None); // union + + // const lparen = tree.nextToken(container_decl.kind_token); + // const rparen = tree.nextToken(type_expr.lastToken()); + + // try renderToken(ais, tree, lparen, Space.None); // ( + // try renderExpression(allocator, ais, tree, type_expr, Space.None); + // try renderToken(ais, tree, rparen, Space.Space); // ) + // }, + // } + + // if (container_decl.fields_and_decls_len == 0) { + // { + // ais.pushIndentNextLine(); + // defer ais.popIndent(); + // try renderToken(ais, tree, container_decl.lbrace_token, Space.None); // { + // } + // return renderToken(ais, tree, container_decl.rbrace_token, space); // } + // } + + // const src_has_trailing_comma = blk: { + // var maybe_comma = tree.prevToken(container_decl.lastToken()); + // // Doc comments for a field may also appear after the comma, eg. + // // field_name: T, // comment attached to field_name + // if (tree.token_tags[maybe_comma] == .DocComment) + // maybe_comma = tree.prevToken(maybe_comma); + // break :blk tree.token_tags[maybe_comma] == .Comma; + // }; + + // const fields_and_decls = container_decl.fieldsAndDecls(); + + // // Check if the first declaration and the { are on the same line + // const src_has_newline = !tree.tokensOnSameLine( + // container_decl.lbrace_token, + // fields_and_decls[0].firstToken(), + // ); + + // // We can only print all the elements in-line if all the + // // declarations inside are fields + // const src_has_only_fields = blk: { + // for (fields_and_decls) |decl| { + // if (decl.tag != .ContainerField) break :blk false; + // } + // break :blk true; + // }; + + // if (src_has_trailing_comma or !src_has_only_fields) { + // // One declaration per line + // ais.pushIndentNextLine(); + // defer ais.popIndent(); + // try renderToken(ais, tree, container_decl.lbrace_token, .Newline); // { + + // for (fields_and_decls) |decl, i| { + // try renderContainerDecl(allocator, ais, tree, decl, .Newline); + + // if (i + 1 < fields_and_decls.len) { + // try renderExtraNewline(tree, ais, fields_and_decls[i + 1]); + // } + // } + // } else if (src_has_newline) { + // // All the declarations on the same line, but place the items on + // // their own line + // try renderToken(ais, tree, container_decl.lbrace_token, .Newline); // { + + // ais.pushIndent(); + // defer ais.popIndent(); + + // for (fields_and_decls) |decl, i| { + // const space_after_decl: Space = if (i + 1 >= fields_and_decls.len) .Newline else .Space; + // try renderContainerDecl(allocator, ais, tree, decl, space_after_decl); + // } + // } else { + // // All the declarations on the same line + // try renderToken(ais, tree, container_decl.lbrace_token, .Space); // { + + // for (fields_and_decls) |decl| { + // try renderContainerDecl(allocator, ais, tree, decl, .Space); + // } + // } + + // return renderToken(ais, tree, container_decl.rbrace_token, space); // } + //}, + + //.ErrorSetDecl => { + // const err_set_decl = @fieldParentPtr(ast.Node.ErrorSetDecl, "base", base); + + // const lbrace = tree.nextToken(err_set_decl.error_token); + + // if (err_set_decl.decls_len == 0) { + // try renderToken(ais, tree, err_set_decl.error_token, Space.None); + // try renderToken(ais, tree, lbrace, Space.None); + // return renderToken(ais, tree, err_set_decl.rbrace_token, space); + // } + + // if (err_set_decl.decls_len == 1) blk: { + // const node = err_set_decl.decls()[0]; + + // // if there are any doc comments or same line comments + // // don't try to put it all on one line + // if (node.cast(ast.Node.ErrorTag)) |tag| { + // if (tag.doc_comments != null) break :blk; + // } else { + // break :blk; + // } + + // try renderToken(ais, tree, err_set_decl.error_token, Space.None); // error + // try renderToken(ais, tree, lbrace, Space.None); // { + // try renderExpression(allocator, ais, tree, node, Space.None); + // return renderToken(ais, tree, err_set_decl.rbrace_token, space); // } + // } + + // try renderToken(ais, tree, err_set_decl.error_token, Space.None); // error + + // const src_has_trailing_comma = blk: { + // const maybe_comma = tree.prevToken(err_set_decl.rbrace_token); + // break :blk tree.token_tags[maybe_comma] == .Comma; + // }; + + // if (src_has_trailing_comma) { + // { + // ais.pushIndent(); + // defer ais.popIndent(); + + // try renderToken(ais, tree, lbrace, Space.Newline); // { + // const decls = err_set_decl.decls(); + // for (decls) |node, i| { + // if (i + 1 < decls.len) { + // try renderExpression(allocator, ais, tree, node, Space.None); + // try renderToken(ais, tree, tree.nextToken(node.lastToken()), Space.Newline); // , + + // try renderExtraNewline(tree, ais, decls[i + 1]); + // } else { + // try renderExpression(allocator, ais, tree, node, Space.Comma); + // } + // } + // } + + // return renderToken(ais, tree, err_set_decl.rbrace_token, space); // } + // } else { + // try renderToken(ais, tree, lbrace, Space.Space); // { + + // const decls = err_set_decl.decls(); + // for (decls) |node, i| { + // if (i + 1 < decls.len) { + // try renderExpression(allocator, ais, tree, node, Space.None); + + // const comma_token = tree.nextToken(node.lastToken()); + // assert(tree.token_tags[comma_token] == .Comma); + // try renderToken(ais, tree, comma_token, Space.Space); // , + // try renderExtraNewline(tree, ais, decls[i + 1]); + // } else { + // try renderExpression(allocator, ais, tree, node, Space.Space); + // } + // } + + // return renderToken(ais, tree, err_set_decl.rbrace_token, space); // } + // } + //}, + + //.ErrorTag => { + // const tag = @fieldParentPtr(ast.Node.ErrorTag, "base", base); + + // try renderDocComments(tree, ais, tag, tag.doc_comments); + // return renderToken(ais, tree, tag.name_token, space); // name + //}, + + //.MultilineStringLiteral => { + // const multiline_str_literal = @fieldParentPtr(ast.Node.MultilineStringLiteral, "base", base); + + // { + // const locked_indents = ais.lockOneShotIndent(); + // defer { + // var i: u8 = 0; + // while (i < locked_indents) : (i += 1) ais.popIndent(); + // } + // try ais.maybeInsertNewline(); + + // for (multiline_str_literal.lines()) |t| try renderToken(ais, tree, t, Space.None); + // } + //}, + + //.BuiltinCall => { + // const builtin_call = @fieldParentPtr(ast.Node.BuiltinCall, "base", base); + + // // TODO remove after 0.7.0 release + // if (mem.eql(u8, tree.tokenSlice(builtin_call.builtin_token), "@OpaqueType")) + // return ais.writer().writeAll("opaque {}"); + + // // TODO remove after 0.7.0 release + // { + // const params = builtin_call.paramsConst(); + // if (mem.eql(u8, tree.tokenSlice(builtin_call.builtin_token), "@Type") and + // params.len == 1) + // { + // if (params[0].castTag(.EnumLiteral)) |enum_literal| + // if (mem.eql(u8, tree.tokenSlice(enum_literal.name), "Opaque")) + // return ais.writer().writeAll("opaque {}"); + // } + // } + + // try renderToken(ais, tree, builtin_call.builtin_token, Space.None); // @name + + // const src_params_trailing_comma = blk: { + // if (builtin_call.params_len == 0) break :blk false; + // const last_node = builtin_call.params()[builtin_call.params_len - 1]; + // const maybe_comma = tree.nextToken(last_node.lastToken()); + // break :blk tree.token_tags[maybe_comma] == .Comma; + // }; + + // const lparen = tree.nextToken(builtin_call.builtin_token); + + // if (!src_params_trailing_comma) { + // try renderToken(ais, tree, lparen, Space.None); // ( + + // // render all on one line, no trailing comma + // const params = builtin_call.params(); + // for (params) |param_node, i| { + // const maybe_comment = param_node.firstToken() - 1; + // if (param_node.*.tag == .MultilineStringLiteral or tree.token_tags[maybe_comment] == .LineComment) { + // ais.pushIndentOneShot(); + // } + // try renderExpression(allocator, ais, tree, param_node, Space.None); + + // if (i + 1 < params.len) { + // const comma_token = tree.nextToken(param_node.lastToken()); + // try renderToken(ais, tree, comma_token, Space.Space); // , + // } + // } + // } else { + // // one param per line + // ais.pushIndent(); + // defer ais.popIndent(); + // try renderToken(ais, tree, lparen, Space.Newline); // ( + + // for (builtin_call.params()) |param_node| { + // try renderExpression(allocator, ais, tree, param_node, Space.Comma); + // } + // } + + // return renderToken(ais, tree, builtin_call.rparen_token, space); // ) + //}, + + //.FnProto => { + // const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", base); + + // if (fn_proto.getVisibToken()) |visib_token_index| { + // const visib_token = tree.token_tags[visib_token_index]; + // assert(visib_token == .Keyword_pub or visib_token == .Keyword_export); + + // try renderToken(ais, tree, visib_token_index, Space.Space); // pub + // } + + // if (fn_proto.getExternExportInlineToken()) |extern_export_inline_token| { + // if (fn_proto.getIsExternPrototype() == null) + // try renderToken(ais, tree, extern_export_inline_token, Space.Space); // extern/export/inline + // } + + // if (fn_proto.getLibName()) |lib_name| { + // try renderExpression(allocator, ais, tree, lib_name, Space.Space); + // } + + // const lparen = if (fn_proto.getNameToken()) |name_token| blk: { + // try renderToken(ais, tree, fn_proto.fn_token, Space.Space); // fn + // try renderToken(ais, tree, name_token, Space.None); // name + // break :blk tree.nextToken(name_token); + // } else blk: { + // try renderToken(ais, tree, fn_proto.fn_token, Space.Space); // fn + // break :blk tree.nextToken(fn_proto.fn_token); + // }; + // assert(tree.token_tags[lparen] == .LParen); + + // const rparen = tree.prevToken( + // // the first token for the annotation expressions is the left + // // parenthesis, hence the need for two prevToken + // if (fn_proto.getAlignExpr()) |align_expr| + // tree.prevToken(tree.prevToken(align_expr.firstToken())) + // else if (fn_proto.getSectionExpr()) |section_expr| + // tree.prevToken(tree.prevToken(section_expr.firstToken())) + // else if (fn_proto.getCallconvExpr()) |callconv_expr| + // tree.prevToken(tree.prevToken(callconv_expr.firstToken())) + // else switch (fn_proto.return_type) { + // .Explicit => |node| node.firstToken(), + // .InferErrorSet => |node| tree.prevToken(node.firstToken()), + // .Invalid => unreachable, + // }, + // ); + // assert(tree.token_tags[rparen] == .RParen); + + // const src_params_trailing_comma = blk: { + // const maybe_comma = tree.token_tags[rparen - 1]; + // break :blk maybe_comma == .Comma or maybe_comma == .LineComment; + // }; + + // if (!src_params_trailing_comma) { + // try renderToken(ais, tree, lparen, Space.None); // ( + + // // render all on one line, no trailing comma + // for (fn_proto.params()) |param_decl, i| { + // try renderParamDecl(allocator, ais, tree, param_decl, Space.None); + + // if (i + 1 < fn_proto.params_len or fn_proto.getVarArgsToken() != null) { + // const comma = tree.nextToken(param_decl.lastToken()); + // try renderToken(ais, tree, comma, Space.Space); // , + // } + // } + // if (fn_proto.getVarArgsToken()) |var_args_token| { + // try renderToken(ais, tree, var_args_token, Space.None); + // } + // } else { + // // one param per line + // ais.pushIndent(); + // defer ais.popIndent(); + // try renderToken(ais, tree, lparen, Space.Newline); // ( + + // for (fn_proto.params()) |param_decl| { + // try renderParamDecl(allocator, ais, tree, param_decl, Space.Comma); + // } + // if (fn_proto.getVarArgsToken()) |var_args_token| { + // try renderToken(ais, tree, var_args_token, Space.Comma); + // } + // } + + // try renderToken(ais, tree, rparen, Space.Space); // ) + + // if (fn_proto.getAlignExpr()) |align_expr| { + // const align_rparen = tree.nextToken(align_expr.lastToken()); + // const align_lparen = tree.prevToken(align_expr.firstToken()); + // const align_kw = tree.prevToken(align_lparen); + + // try renderToken(ais, tree, align_kw, Space.None); // align + // try renderToken(ais, tree, align_lparen, Space.None); // ( + // try renderExpression(allocator, ais, tree, align_expr, Space.None); + // try renderToken(ais, tree, align_rparen, Space.Space); // ) + // } + + // if (fn_proto.getSectionExpr()) |section_expr| { + // const section_rparen = tree.nextToken(section_expr.lastToken()); + // const section_lparen = tree.prevToken(section_expr.firstToken()); + // const section_kw = tree.prevToken(section_lparen); + + // try renderToken(ais, tree, section_kw, Space.None); // section + // try renderToken(ais, tree, section_lparen, Space.None); // ( + // try renderExpression(allocator, ais, tree, section_expr, Space.None); + // try renderToken(ais, tree, section_rparen, Space.Space); // ) + // } + + // if (fn_proto.getCallconvExpr()) |callconv_expr| { + // const callconv_rparen = tree.nextToken(callconv_expr.lastToken()); + // const callconv_lparen = tree.prevToken(callconv_expr.firstToken()); + // const callconv_kw = tree.prevToken(callconv_lparen); + + // try renderToken(ais, tree, callconv_kw, Space.None); // callconv + // try renderToken(ais, tree, callconv_lparen, Space.None); // ( + // try renderExpression(allocator, ais, tree, callconv_expr, Space.None); + // try renderToken(ais, tree, callconv_rparen, Space.Space); // ) + // } else if (fn_proto.getIsExternPrototype() != null) { + // try ais.writer().writeAll("callconv(.C) "); + // } else if (fn_proto.getIsAsync() != null) { + // try ais.writer().writeAll("callconv(.Async) "); + // } + + // switch (fn_proto.return_type) { + // .Explicit => |node| { + // return renderExpression(allocator, ais, tree, node, space); + // }, + // .InferErrorSet => |node| { + // try renderToken(ais, tree, tree.prevToken(node.firstToken()), Space.None); // ! + // return renderExpression(allocator, ais, tree, node, space); + // }, + // .Invalid => unreachable, + // } + //}, + + //.AnyFrameType => { + // const anyframe_type = @fieldParentPtr(ast.Node.AnyFrameType, "base", base); + + // if (anyframe_type.result) |result| { + // try renderToken(ais, tree, anyframe_type.anyframe_token, Space.None); // anyframe + // try renderToken(ais, tree, result.arrow_token, Space.None); // -> + // return renderExpression(allocator, ais, tree, result.return_type, space); + // } else { + // return renderToken(ais, tree, anyframe_type.anyframe_token, space); // anyframe + // } + //}, + + //.DocComment => unreachable, // doc comments are attached to nodes + + //.Switch => { + // const switch_node = @fieldParentPtr(ast.Node.Switch, "base", base); + + // try renderToken(ais, tree, switch_node.switch_token, Space.Space); // switch + // try renderToken(ais, tree, tree.nextToken(switch_node.switch_token), Space.None); // ( + + // const rparen = tree.nextToken(switch_node.expr.lastToken()); + // const lbrace = tree.nextToken(rparen); + + // if (switch_node.cases_len == 0) { + // try renderExpression(allocator, ais, tree, switch_node.expr, Space.None); + // try renderToken(ais, tree, rparen, Space.Space); // ) + // try renderToken(ais, tree, lbrace, Space.None); // { + // return renderToken(ais, tree, switch_node.rbrace, space); // } + // } + + // try renderExpression(allocator, ais, tree, switch_node.expr, Space.None); + // try renderToken(ais, tree, rparen, Space.Space); // ) + + // { + // ais.pushIndentNextLine(); + // defer ais.popIndent(); + // try renderToken(ais, tree, lbrace, Space.Newline); // { + + // const cases = switch_node.cases(); + // for (cases) |node, i| { + // try renderExpression(allocator, ais, tree, node, Space.Comma); + + // if (i + 1 < cases.len) { + // try renderExtraNewline(tree, ais, cases[i + 1]); + // } + // } + // } + + // return renderToken(ais, tree, switch_node.rbrace, space); // } + //}, + + //.SwitchCase => { + // const switch_case = @fieldParentPtr(ast.Node.SwitchCase, "base", base); + + // assert(switch_case.items_len != 0); + // const src_has_trailing_comma = blk: { + // const last_node = switch_case.items()[switch_case.items_len - 1]; + // const maybe_comma = tree.nextToken(last_node.lastToken()); + // break :blk tree.token_tags[maybe_comma] == .Comma; + // }; + + // if (switch_case.items_len == 1 or !src_has_trailing_comma) { + // const items = switch_case.items(); + // for (items) |node, i| { + // if (i + 1 < items.len) { + // try renderExpression(allocator, ais, tree, node, Space.None); + + // const comma_token = tree.nextToken(node.lastToken()); + // try renderToken(ais, tree, comma_token, Space.Space); // , + // try renderExtraNewline(tree, ais, items[i + 1]); + // } else { + // try renderExpression(allocator, ais, tree, node, Space.Space); + // } + // } + // } else { + // const items = switch_case.items(); + // for (items) |node, i| { + // if (i + 1 < items.len) { + // try renderExpression(allocator, ais, tree, node, Space.None); + + // const comma_token = tree.nextToken(node.lastToken()); + // try renderToken(ais, tree, comma_token, Space.Newline); // , + // try renderExtraNewline(tree, ais, items[i + 1]); + // } else { + // try renderExpression(allocator, ais, tree, node, Space.Comma); + // } + // } + // } + + // try renderToken(ais, tree, switch_case.arrow_token, Space.Space); // => + + // if (switch_case.payload) |payload| { + // try renderExpression(allocator, ais, tree, payload, Space.Space); + // } + + // return renderExpression(allocator, ais, tree, switch_case.expr, space); + //}, + //.SwitchElse => { + // const switch_else = @fieldParentPtr(ast.Node.SwitchElse, "base", base); + // return renderToken(ais, tree, switch_else.token, space); + //}, + //.Else => { + // const else_node = @fieldParentPtr(ast.Node.Else, "base", base); + + // const body_is_block = nodeIsBlock(else_node.body); + // const same_line = body_is_block or tree.tokensOnSameLine(else_node.else_token, else_node.body.lastToken()); + + // const after_else_space = if (same_line or else_node.payload != null) Space.Space else Space.Newline; + // try renderToken(ais, tree, else_node.else_token, after_else_space); + + // if (else_node.payload) |payload| { + // const payload_space = if (same_line) Space.Space else Space.Newline; + // try renderExpression(allocator, ais, tree, payload, payload_space); + // } + + // if (same_line) { + // return renderExpression(allocator, ais, tree, else_node.body, space); + // } else { + // ais.pushIndent(); + // defer ais.popIndent(); + // return renderExpression(allocator, ais, tree, else_node.body, space); + // } + //}, + + //.While => { + // const while_node = @fieldParentPtr(ast.Node.While, "base", base); + + // if (while_node.label) |label| { + // try renderToken(ais, tree, label, Space.None); // label + // try renderToken(ais, tree, tree.nextToken(label), Space.Space); // : + // } + + // if (while_node.inline_token) |inline_token| { + // try renderToken(ais, tree, inline_token, Space.Space); // inline + // } + + // try renderToken(ais, tree, while_node.while_token, Space.Space); // while + // try renderToken(ais, tree, tree.nextToken(while_node.while_token), Space.None); // ( + // try renderExpression(allocator, ais, tree, while_node.condition, Space.None); + + // const cond_rparen = tree.nextToken(while_node.condition.lastToken()); + + // const body_is_block = nodeIsBlock(while_node.body); + + // var block_start_space: Space = undefined; + // var after_body_space: Space = undefined; + + // if (body_is_block) { + // block_start_space = Space.BlockStart; + // after_body_space = if (while_node.@"else" == null) space else Space.SpaceOrOutdent; + // } else if (tree.tokensOnSameLine(cond_rparen, while_node.body.lastToken())) { + // block_start_space = Space.Space; + // after_body_space = if (while_node.@"else" == null) space else Space.Space; + // } else { + // block_start_space = Space.Newline; + // after_body_space = if (while_node.@"else" == null) space else Space.Newline; + // } + + // { + // const rparen_space = if (while_node.payload != null or while_node.continue_expr != null) Space.Space else block_start_space; + // try renderToken(ais, tree, cond_rparen, rparen_space); // ) + // } + + // if (while_node.payload) |payload| { + // const payload_space = if (while_node.continue_expr != null) Space.Space else block_start_space; + // try renderExpression(allocator, ais, tree, payload, payload_space); + // } + + // if (while_node.continue_expr) |continue_expr| { + // const rparen = tree.nextToken(continue_expr.lastToken()); + // const lparen = tree.prevToken(continue_expr.firstToken()); + // const colon = tree.prevToken(lparen); + + // try renderToken(ais, tree, colon, Space.Space); // : + // try renderToken(ais, tree, lparen, Space.None); // ( + + // try renderExpression(allocator, ais, tree, continue_expr, Space.None); + + // try renderToken(ais, tree, rparen, block_start_space); // ) + // } + + // { + // if (!body_is_block) ais.pushIndent(); + // defer if (!body_is_block) ais.popIndent(); + // try renderExpression(allocator, ais, tree, while_node.body, after_body_space); + // } + + // if (while_node.@"else") |@"else"| { + // return renderExpression(allocator, ais, tree, &@"else".base, space); + // } + //}, + + //.For => { + // const for_node = @fieldParentPtr(ast.Node.For, "base", base); + + // if (for_node.label) |label| { + // try renderToken(ais, tree, label, Space.None); // label + // try renderToken(ais, tree, tree.nextToken(label), Space.Space); // : + // } + + // if (for_node.inline_token) |inline_token| { + // try renderToken(ais, tree, inline_token, Space.Space); // inline + // } + + // try renderToken(ais, tree, for_node.for_token, Space.Space); // for + // try renderToken(ais, tree, tree.nextToken(for_node.for_token), Space.None); // ( + // try renderExpression(allocator, ais, tree, for_node.array_expr, Space.None); + + // const rparen = tree.nextToken(for_node.array_expr.lastToken()); + + // const body_is_block = for_node.body.tag.isBlock(); + // const src_one_line_to_body = !body_is_block and tree.tokensOnSameLine(rparen, for_node.body.firstToken()); + // const body_on_same_line = body_is_block or src_one_line_to_body; + + // try renderToken(ais, tree, rparen, Space.Space); // ) + + // const space_after_payload = if (body_on_same_line) Space.Space else Space.Newline; + // try renderExpression(allocator, ais, tree, for_node.payload, space_after_payload); // |x| + + // const space_after_body = blk: { + // if (for_node.@"else") |@"else"| { + // const src_one_line_to_else = tree.tokensOnSameLine(rparen, @"else".firstToken()); + // if (body_is_block or src_one_line_to_else) { + // break :blk Space.Space; + // } else { + // break :blk Space.Newline; + // } + // } else { + // break :blk space; + // } + // }; + + // { + // if (!body_on_same_line) ais.pushIndent(); + // defer if (!body_on_same_line) ais.popIndent(); + // try renderExpression(allocator, ais, tree, for_node.body, space_after_body); // { body } + // } + + // if (for_node.@"else") |@"else"| { + // return renderExpression(allocator, ais, tree, &@"else".base, space); // else + // } + //}, + + //.If => { + // const if_node = @fieldParentPtr(ast.Node.If, "base", base); + + // const lparen = tree.nextToken(if_node.if_token); + // const rparen = tree.nextToken(if_node.condition.lastToken()); + + // try renderToken(ais, tree, if_node.if_token, Space.Space); // if + // try renderToken(ais, tree, lparen, Space.None); // ( + + // try renderExpression(allocator, ais, tree, if_node.condition, Space.None); // condition + + // const body_is_if_block = if_node.body.tag == .If; + // const body_is_block = nodeIsBlock(if_node.body); + + // if (body_is_if_block) { + // try renderExtraNewline(tree, ais, if_node.body); + // } else if (body_is_block) { + // const after_rparen_space = if (if_node.payload == null) Space.BlockStart else Space.Space; + // try renderToken(ais, tree, rparen, after_rparen_space); // ) + + // if (if_node.payload) |payload| { + // try renderExpression(allocator, ais, tree, payload, Space.BlockStart); // |x| + // } + + // if (if_node.@"else") |@"else"| { + // try renderExpression(allocator, ais, tree, if_node.body, Space.SpaceOrOutdent); + // return renderExpression(allocator, ais, tree, &@"else".base, space); + // } else { + // return renderExpression(allocator, ais, tree, if_node.body, space); + // } + // } + + // const src_has_newline = !tree.tokensOnSameLine(rparen, if_node.body.lastToken()); + + // if (src_has_newline) { + // const after_rparen_space = if (if_node.payload == null) Space.Newline else Space.Space; + + // { + // ais.pushIndent(); + // defer ais.popIndent(); + // try renderToken(ais, tree, rparen, after_rparen_space); // ) + // } + + // if (if_node.payload) |payload| { + // try renderExpression(allocator, ais, tree, payload, Space.Newline); + // } + + // if (if_node.@"else") |@"else"| { + // const else_is_block = nodeIsBlock(@"else".body); + + // { + // ais.pushIndent(); + // defer ais.popIndent(); + // try renderExpression(allocator, ais, tree, if_node.body, Space.Newline); + // } + + // if (else_is_block) { + // try renderToken(ais, tree, @"else".else_token, Space.Space); // else + + // if (@"else".payload) |payload| { + // try renderExpression(allocator, ais, tree, payload, Space.Space); + // } + + // return renderExpression(allocator, ais, tree, @"else".body, space); + // } else { + // const after_else_space = if (@"else".payload == null) Space.Newline else Space.Space; + // try renderToken(ais, tree, @"else".else_token, after_else_space); // else + + // if (@"else".payload) |payload| { + // try renderExpression(allocator, ais, tree, payload, Space.Newline); + // } + + // ais.pushIndent(); + // defer ais.popIndent(); + // return renderExpression(allocator, ais, tree, @"else".body, space); + // } + // } else { + // ais.pushIndent(); + // defer ais.popIndent(); + // return renderExpression(allocator, ais, tree, if_node.body, space); + // } + // } + + // // Single line if statement + + // try renderToken(ais, tree, rparen, Space.Space); // ) + + // if (if_node.payload) |payload| { + // try renderExpression(allocator, ais, tree, payload, Space.Space); + // } + + // if (if_node.@"else") |@"else"| { + // try renderExpression(allocator, ais, tree, if_node.body, Space.Space); + // try renderToken(ais, tree, @"else".else_token, Space.Space); + + // if (@"else".payload) |payload| { + // try renderExpression(allocator, ais, tree, payload, Space.Space); + // } + + // return renderExpression(allocator, ais, tree, @"else".body, space); + // } else { + // return renderExpression(allocator, ais, tree, if_node.body, space); + // } + //}, + + //.Asm => { + // const asm_node = @fieldParentPtr(ast.Node.Asm, "base", base); + + // try renderToken(ais, tree, asm_node.asm_token, Space.Space); // asm + + // if (asm_node.volatile_token) |volatile_token| { + // try renderToken(ais, tree, volatile_token, Space.Space); // volatile + // try renderToken(ais, tree, tree.nextToken(volatile_token), Space.None); // ( + // } else { + // try renderToken(ais, tree, tree.nextToken(asm_node.asm_token), Space.None); // ( + // } + + // asmblk: { + // ais.pushIndent(); + // defer ais.popIndent(); + + // if (asm_node.outputs.len == 0 and asm_node.inputs.len == 0 and asm_node.clobbers.len == 0) { + // try renderExpression(allocator, ais, tree, asm_node.template, Space.None); + // break :asmblk; + // } + + // try renderExpression(allocator, ais, tree, asm_node.template, Space.Newline); + + // ais.setIndentDelta(asm_indent_delta); + // defer ais.setIndentDelta(indent_delta); + + // const colon1 = tree.nextToken(asm_node.template.lastToken()); + + // const colon2 = if (asm_node.outputs.len == 0) blk: { + // try renderToken(ais, tree, colon1, Space.Newline); // : + + // break :blk tree.nextToken(colon1); + // } else blk: { + // try renderToken(ais, tree, colon1, Space.Space); // : + + // ais.pushIndent(); + // defer ais.popIndent(); + + // for (asm_node.outputs) |*asm_output, i| { + // if (i + 1 < asm_node.outputs.len) { + // const next_asm_output = asm_node.outputs[i + 1]; + // try renderAsmOutput(allocator, ais, tree, asm_output, Space.None); + + // const comma = tree.prevToken(next_asm_output.firstToken()); + // try renderToken(ais, tree, comma, Space.Newline); // , + // try renderExtraNewlineToken(tree, ais, next_asm_output.firstToken()); + // } else if (asm_node.inputs.len == 0 and asm_node.clobbers.len == 0) { + // try renderAsmOutput(allocator, ais, tree, asm_output, Space.Newline); + // break :asmblk; + // } else { + // try renderAsmOutput(allocator, ais, tree, asm_output, Space.Newline); + // const comma_or_colon = tree.nextToken(asm_output.lastToken()); + // break :blk switch (tree.token_tags[comma_or_colon]) { + // .Comma => tree.nextToken(comma_or_colon), + // else => comma_or_colon, + // }; + // } + // } + // unreachable; + // }; + + // const colon3 = if (asm_node.inputs.len == 0) blk: { + // try renderToken(ais, tree, colon2, Space.Newline); // : + // break :blk tree.nextToken(colon2); + // } else blk: { + // try renderToken(ais, tree, colon2, Space.Space); // : + // ais.pushIndent(); + // defer ais.popIndent(); + // for (asm_node.inputs) |*asm_input, i| { + // if (i + 1 < asm_node.inputs.len) { + // const next_asm_input = &asm_node.inputs[i + 1]; + // try renderAsmInput(allocator, ais, tree, asm_input, Space.None); + + // const comma = tree.prevToken(next_asm_input.firstToken()); + // try renderToken(ais, tree, comma, Space.Newline); // , + // try renderExtraNewlineToken(tree, ais, next_asm_input.firstToken()); + // } else if (asm_node.clobbers.len == 0) { + // try renderAsmInput(allocator, ais, tree, asm_input, Space.Newline); + // break :asmblk; + // } else { + // try renderAsmInput(allocator, ais, tree, asm_input, Space.Newline); + // const comma_or_colon = tree.nextToken(asm_input.lastToken()); + // break :blk switch (tree.token_tags[comma_or_colon]) { + // .Comma => tree.nextToken(comma_or_colon), + // else => comma_or_colon, + // }; + // } + // } + // unreachable; + // }; + + // try renderToken(ais, tree, colon3, Space.Space); // : + // ais.pushIndent(); + // defer ais.popIndent(); + // for (asm_node.clobbers) |clobber_node, i| { + // if (i + 1 >= asm_node.clobbers.len) { + // try renderExpression(allocator, ais, tree, clobber_node, Space.Newline); + // break :asmblk; + // } else { + // try renderExpression(allocator, ais, tree, clobber_node, Space.None); + // const comma = tree.nextToken(clobber_node.lastToken()); + // try renderToken(ais, tree, comma, Space.Space); // , + // } + // } + // } + + // return renderToken(ais, tree, asm_node.rparen, space); + //}, + + //.EnumLiteral => { + // const enum_literal = @fieldParentPtr(ast.Node.EnumLiteral, "base", base); + + // try renderToken(ais, tree, enum_literal.dot, Space.None); // . + // return renderToken(ais, tree, enum_literal.name, space); // name + //}, + + //.ContainerField, + //.Root, + //.VarDecl, + //.Use, + //.TestDecl, + //=> unreachable, + else => @panic("TODO implement more renderExpression"), } } fn renderArrayType( allocator: *mem.Allocator, - ais: anytype, - tree: *ast.Tree, + ais: *Ais, + tree: ast.Tree, lbracket: ast.TokenIndex, - rhs: *ast.Node, - len_expr: *ast.Node, - opt_sentinel: ?*ast.Node, + rhs: ast.Node.Index, + len_expr: ast.Node.Index, + opt_sentinel: ?ast.Node.Index, space: Space, -) (@TypeOf(ais.*).Error || Error)!void { +) Error!void { const rbracket = tree.nextToken(if (opt_sentinel) |sentinel| sentinel.lastToken() else len_expr.lastToken()); - const starts_with_comment = tree.token_ids[lbracket + 1] == .LineComment; - const ends_with_comment = tree.token_ids[rbracket - 1] == .LineComment; + const starts_with_comment = tree.token_tags[lbracket + 1] == .LineComment; + const ends_with_comment = tree.token_tags[rbracket - 1] == .LineComment; const new_space = if (ends_with_comment) Space.Newline else Space.None; { const do_indent = (starts_with_comment or ends_with_comment); if (do_indent) ais.pushIndent(); defer if (do_indent) ais.popIndent(); - try renderToken(tree, ais, lbracket, Space.None); // [ + try renderToken(ais, tree, lbracket, Space.None); // [ try renderExpression(allocator, ais, tree, len_expr, new_space); if (starts_with_comment) { @@ -2182,25 +2087,25 @@ fn renderArrayType( } if (opt_sentinel) |sentinel| { const colon_token = tree.prevToken(sentinel.firstToken()); - try renderToken(tree, ais, colon_token, Space.None); // : + try renderToken(ais, tree, colon_token, Space.None); // : try renderExpression(allocator, ais, tree, sentinel, Space.None); } if (starts_with_comment) { try ais.maybeInsertNewline(); } } - try renderToken(tree, ais, rbracket, Space.None); // ] + try renderToken(ais, tree, rbracket, Space.None); // ] return renderExpression(allocator, ais, tree, rhs, space); } fn renderAsmOutput( allocator: *mem.Allocator, - ais: anytype, - tree: *ast.Tree, + ais: *Ais, + tree: ast.Tree, asm_output: *const ast.Node.Asm.Output, space: Space, -) (@TypeOf(ais.*).Error || Error)!void { +) Error!void { try ais.writer().writeAll("["); try renderExpression(allocator, ais, tree, asm_output.symbolic_name, Space.None); try ais.writer().writeAll("] "); @@ -2217,37 +2122,37 @@ fn renderAsmOutput( }, } - return renderToken(tree, ais, asm_output.lastToken(), space); // ) + return renderToken(ais, tree, asm_output.lastToken(), space); // ) } fn renderAsmInput( allocator: *mem.Allocator, - ais: anytype, - tree: *ast.Tree, + ais: *Ais, + tree: ast.Tree, asm_input: *const ast.Node.Asm.Input, space: Space, -) (@TypeOf(ais.*).Error || Error)!void { +) Error!void { try ais.writer().writeAll("["); try renderExpression(allocator, ais, tree, asm_input.symbolic_name, Space.None); try ais.writer().writeAll("] "); try renderExpression(allocator, ais, tree, asm_input.constraint, Space.None); try ais.writer().writeAll(" ("); try renderExpression(allocator, ais, tree, asm_input.expr, Space.None); - return renderToken(tree, ais, asm_input.lastToken(), space); // ) + return renderToken(ais, tree, asm_input.lastToken(), space); // ) } fn renderVarDecl( allocator: *mem.Allocator, - ais: anytype, - tree: *ast.Tree, - var_decl: *ast.Node.VarDecl, -) (@TypeOf(ais.*).Error || Error)!void { + ais: *Ais, + tree: ast.Tree, + var_decl: ast.Node.Index.VarDecl, +) Error!void { if (var_decl.getVisibToken()) |visib_token| { - try renderToken(tree, ais, visib_token, Space.Space); // pub + try renderToken(ais, tree, visib_token, Space.Space); // pub } if (var_decl.getExternExportToken()) |extern_export_token| { - try renderToken(tree, ais, extern_export_token, Space.Space); // extern + try renderToken(ais, tree, extern_export_token, Space.Space); // extern if (var_decl.getLibName()) |lib_name| { try renderExpression(allocator, ais, tree, lib_name, Space.Space); // "lib" @@ -2255,13 +2160,13 @@ fn renderVarDecl( } if (var_decl.getComptimeToken()) |comptime_token| { - try renderToken(tree, ais, comptime_token, Space.Space); // comptime + try renderToken(ais, tree, comptime_token, Space.Space); // comptime } if (var_decl.getThreadLocalToken()) |thread_local_token| { - try renderToken(tree, ais, thread_local_token, Space.Space); // threadlocal + try renderToken(ais, tree, thread_local_token, Space.Space); // threadlocal } - try renderToken(tree, ais, var_decl.mut_token, Space.Space); // var + try renderToken(ais, tree, var_decl.mut_token, Space.Space); // var const name_space = if (var_decl.getTypeNode() == null and (var_decl.getAlignNode() != null or @@ -2270,10 +2175,10 @@ fn renderVarDecl( Space.Space else Space.None; - try renderToken(tree, ais, var_decl.name_token, name_space); + try renderToken(ais, tree, var_decl.name_token, name_space); if (var_decl.getTypeNode()) |type_node| { - try renderToken(tree, ais, tree.nextToken(var_decl.name_token), Space.Space); + try renderToken(ais, tree, tree.nextToken(var_decl.name_token), Space.Space); const s = if (var_decl.getAlignNode() != null or var_decl.getSectionNode() != null or var_decl.getInitNode() != null) Space.Space else Space.None; @@ -2284,22 +2189,22 @@ fn renderVarDecl( const lparen = tree.prevToken(align_node.firstToken()); const align_kw = tree.prevToken(lparen); const rparen = tree.nextToken(align_node.lastToken()); - try renderToken(tree, ais, align_kw, Space.None); // align - try renderToken(tree, ais, lparen, Space.None); // ( + try renderToken(ais, tree, align_kw, Space.None); // align + try renderToken(ais, tree, lparen, Space.None); // ( try renderExpression(allocator, ais, tree, align_node, Space.None); const s = if (var_decl.getSectionNode() != null or var_decl.getInitNode() != null) Space.Space else Space.None; - try renderToken(tree, ais, rparen, s); // ) + try renderToken(ais, tree, rparen, s); // ) } if (var_decl.getSectionNode()) |section_node| { const lparen = tree.prevToken(section_node.firstToken()); const section_kw = tree.prevToken(lparen); const rparen = tree.nextToken(section_node.lastToken()); - try renderToken(tree, ais, section_kw, Space.None); // linksection - try renderToken(tree, ais, lparen, Space.None); // ( + try renderToken(ais, tree, section_kw, Space.None); // linksection + try renderToken(ais, tree, lparen, Space.None); // ( try renderExpression(allocator, ais, tree, section_node, Space.None); const s = if (var_decl.getInitNode() != null) Space.Space else Space.None; - try renderToken(tree, ais, rparen, s); // ) + try renderToken(ais, tree, rparen, s); // ) } if (var_decl.getInitNode()) |init_node| { @@ -2312,268 +2217,150 @@ fn renderVarDecl( { ais.pushIndent(); defer ais.popIndent(); - try renderToken(tree, ais, eq_token, eq_space); // = + try renderToken(ais, tree, eq_token, eq_space); // = } ais.pushIndentOneShot(); try renderExpression(allocator, ais, tree, init_node, Space.None); } - try renderToken(tree, ais, var_decl.semicolon_token, Space.Newline); + try renderToken(ais, tree, var_decl.semicolon_token, Space.Newline); } fn renderParamDecl( allocator: *mem.Allocator, - ais: anytype, - tree: *ast.Tree, + ais: *Ais, + tree: ast.Tree, param_decl: ast.Node.FnProto.ParamDecl, space: Space, -) (@TypeOf(ais.*).Error || Error)!void { +) Error!void { try renderDocComments(tree, ais, param_decl, param_decl.doc_comments); if (param_decl.comptime_token) |comptime_token| { - try renderToken(tree, ais, comptime_token, Space.Space); + try renderToken(ais, tree, comptime_token, Space.Space); } if (param_decl.noalias_token) |noalias_token| { - try renderToken(tree, ais, noalias_token, Space.Space); + try renderToken(ais, tree, noalias_token, Space.Space); } if (param_decl.name_token) |name_token| { - try renderToken(tree, ais, name_token, Space.None); - try renderToken(tree, ais, tree.nextToken(name_token), Space.Space); // : + try renderToken(ais, tree, name_token, Space.None); + try renderToken(ais, tree, tree.nextToken(name_token), Space.Space); // : } switch (param_decl.param_type) { .any_type, .type_expr => |node| try renderExpression(allocator, ais, tree, node, space), } } -fn renderStatement( - allocator: *mem.Allocator, - ais: anytype, - tree: *ast.Tree, - base: *ast.Node, -) (@TypeOf(ais.*).Error || Error)!void { - switch (base.tag) { - .VarDecl => { - const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", base); - try renderVarDecl(allocator, ais, tree, var_decl); - }, - else => { - if (base.requireSemiColon()) { - try renderExpression(allocator, ais, tree, base, Space.None); - - const semicolon_index = tree.nextToken(base.lastToken()); - assert(tree.token_ids[semicolon_index] == .Semicolon); - try renderToken(tree, ais, semicolon_index, Space.Newline); - } else { - try renderExpression(allocator, ais, tree, base, Space.Newline); - } - }, - } +fn renderStatement(ais: *Ais, tree: ast.Tree, base: ast.Node.Index) Error!void { + @panic("TODO render statement"); + //switch (base.tag) { + // .VarDecl => { + // const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", base); + // try renderVarDecl(allocator, ais, tree, var_decl); + // }, + // else => { + // if (base.requireSemiColon()) { + // try renderExpression(allocator, ais, tree, base, Space.None); + + // const semicolon_index = tree.nextToken(base.lastToken()); + // assert(tree.token_tags[semicolon_index] == .Semicolon); + // try renderToken(ais, tree, semicolon_index, Space.Newline); + // } else { + // try renderExpression(allocator, ais, tree, base, Space.Newline); + // } + // }, + //} } const Space = enum { None, Newline, + /// `renderToken` will additionally consume the next token if it is a comma. Comma, Space, SpaceOrOutdent, NoNewline, + /// Skips writing the possible line comment after the token. NoComment, BlockStart, }; -fn renderTokenOffset( - tree: *ast.Tree, - ais: anytype, - token_index: ast.TokenIndex, - space: Space, - token_skip_bytes: usize, -) (@TypeOf(ais.*).Error || Error)!void { +fn renderToken(ais: *Ais, tree: ast.Tree, token_index: ast.TokenIndex, space: Space) Error!void { if (space == Space.BlockStart) { - // If placing the lbrace on the current line would cause an uggly gap then put the lbrace on the next line + // If placing the lbrace on the current line would cause an ugly gap then put the lbrace on the next line. const new_space = if (ais.isLineOverIndented()) Space.Newline else Space.Space; - return renderToken(tree, ais, token_index, new_space); + return renderToken(ais, tree, token_index, new_space); } - var token_loc = tree.token_locs[token_index]; - try ais.writer().writeAll(mem.trimRight(u8, tree.tokenSliceLoc(token_loc)[token_skip_bytes..], " ")); + const token_tags = tree.tokens.items(.tag); + const token_starts = tree.tokens.items(.start); - if (space == Space.NoComment) - return; + const token_start = token_starts[token_index]; + const token_tag = token_tags[token_index]; + const lexeme = token_tag.lexeme() orelse lexeme: { + var tokenizer: std.zig.Tokenizer = .{ + .buffer = tree.source, + .index = token_start, + .pending_invalid_token = null, + }; + const token = tokenizer.next(); + assert(token.tag == token_tag); + break :lexeme tree.source[token.loc.start..token.loc.end]; + }; + try ais.writer().writeAll(lexeme); - var next_token_id = tree.token_ids[token_index + 1]; - var next_token_loc = tree.token_locs[token_index + 1]; + switch (space) { + .NoComment => {}, + .NoNewline => {}, + .None => {}, + .Comma => { + const count = try renderComments(ais, tree, token_start + lexeme.len, token_starts[token_index + 1], ", "); + if (count == 0 and token_tags[token_index + 1] == .Comma) { + return renderToken(ais, tree, token_index + 1, Space.Newline); + } + try ais.writer().writeAll(","); - if (space == Space.Comma) switch (next_token_id) { - .Comma => return renderToken(tree, ais, token_index + 1, Space.Newline), - .LineComment => { - try ais.writer().writeAll(", "); - return renderToken(tree, ais, token_index + 1, Space.Newline); - }, - else => { - if (token_index + 2 < tree.token_ids.len and - tree.token_ids[token_index + 2] == .MultilineStringLiteralLine) - { - try ais.writer().writeAll(","); - return; - } else { - try ais.writer().writeAll(","); + if (token_tags[token_index + 2] != .MultilineStringLiteralLine) { try ais.insertNewline(); - return; } }, - }; - - // Skip over same line doc comments - var offset: usize = 1; - if (next_token_id == .DocComment) { - const loc = tree.tokenLocationLoc(token_loc.end, next_token_loc); - if (loc.line == 0) { - offset += 1; - next_token_id = tree.token_ids[token_index + offset]; - next_token_loc = tree.token_locs[token_index + offset]; - } - } - - if (next_token_id != .LineComment) { - switch (space) { - Space.None, Space.NoNewline => return, - Space.Newline => { - if (next_token_id == .MultilineStringLiteralLine) { - return; - } else { - try ais.insertNewline(); - return; - } - }, - Space.Space, Space.SpaceOrOutdent => { - if (next_token_id == .MultilineStringLiteralLine) - return; - try ais.writer().writeByte(' '); - return; - }, - Space.NoComment, Space.Comma, Space.BlockStart => unreachable, - } - } - - while (true) { - const comment_is_empty = mem.trimRight(u8, tree.tokenSliceLoc(next_token_loc), " ").len == 2; - if (comment_is_empty) { - switch (space) { - Space.Newline => { - offset += 1; - token_loc = next_token_loc; - next_token_id = tree.token_ids[token_index + offset]; - next_token_loc = tree.token_locs[token_index + offset]; - if (next_token_id != .LineComment) { - try ais.insertNewline(); - return; - } - }, - else => break, - } - } else { - break; - } - } - - var loc = tree.tokenLocationLoc(token_loc.end, next_token_loc); - if (loc.line == 0) { - if (tree.token_ids[token_index] != .MultilineStringLiteralLine) { + .SpaceOrOutdent => @panic("what does this even do"), + .Space => { + _ = try renderComments(ais, tree, token_start + lexeme.len, token_starts[token_index + 1], ""); try ais.writer().writeByte(' '); - } - try ais.writer().writeAll(mem.trimRight(u8, tree.tokenSliceLoc(next_token_loc), " ")); - offset = 2; - token_loc = next_token_loc; - next_token_loc = tree.token_locs[token_index + offset]; - next_token_id = tree.token_ids[token_index + offset]; - if (next_token_id != .LineComment) { - switch (space) { - .None, .Space, .SpaceOrOutdent => { - try ais.insertNewline(); - }, - .Newline => { - if (next_token_id == .MultilineStringLiteralLine) { - return; - } else { - try ais.insertNewline(); - return; - } - }, - .NoNewline => {}, - .NoComment, .Comma, .BlockStart => unreachable, - } - return; - } - loc = tree.tokenLocationLoc(token_loc.end, next_token_loc); - } - - while (true) { - // translate-c doesn't generate correct newlines - // in generated code (loc.line == 0) so treat that case - // as though there was meant to be a newline between the tokens - var newline_count = if (loc.line <= 1) @as(u8, 1) else @as(u8, 2); - while (newline_count > 0) : (newline_count -= 1) try ais.insertNewline(); - try ais.writer().writeAll(mem.trimRight(u8, tree.tokenSliceLoc(next_token_loc), " ")); - - offset += 1; - token_loc = next_token_loc; - next_token_loc = tree.token_locs[token_index + offset]; - next_token_id = tree.token_ids[token_index + offset]; - if (next_token_id != .LineComment) { - switch (space) { - .Newline => { - if (next_token_id == .MultilineStringLiteralLine) { - return; - } else { - try ais.insertNewline(); - return; - } - }, - .None, .Space, .SpaceOrOutdent => { - try ais.insertNewline(); - }, - .NoNewline => {}, - .NoComment, .Comma, .BlockStart => unreachable, + }, + .Newline => { + if (token_tags[token_index + 1] != .MultilineStringLiteralLine) { + try ais.insertNewline(); } - return; - } - loc = tree.tokenLocationLoc(token_loc.end, next_token_loc); + }, + .BlockStart => unreachable, } } -fn renderToken( - tree: *ast.Tree, - ais: anytype, - token_index: ast.TokenIndex, - space: Space, -) (@TypeOf(ais.*).Error || Error)!void { - return renderTokenOffset(tree, ais, token_index, space, 0); -} - fn renderDocComments( - tree: *ast.Tree, - ais: anytype, + tree: ast.Tree, + ais: *Ais, node: anytype, - doc_comments: ?*ast.Node.DocComment, -) (@TypeOf(ais.*).Error || Error)!void { + doc_comments: ?ast.Node.Index.DocComment, +) Error!void { const comment = doc_comments orelse return; return renderDocCommentsToken(tree, ais, comment, node.firstToken()); } fn renderDocCommentsToken( - tree: *ast.Tree, - ais: anytype, - comment: *ast.Node.DocComment, + tree: ast.Tree, + ais: *Ais, + comment: ast.Node.Index.DocComment, first_token: ast.TokenIndex, -) (@TypeOf(ais.*).Error || Error)!void { +) Error!void { var tok_i = comment.first_line; while (true) : (tok_i += 1) { - switch (tree.token_ids[tok_i]) { + switch (tree.token_tags[tok_i]) { .DocComment, .ContainerDocComment => { if (comment.first_line < first_token) { - try renderToken(tree, ais, tok_i, Space.Newline); + try renderToken(ais, tree, tok_i, Space.Newline); } else { - try renderToken(tree, ais, tok_i, Space.NoComment); + try renderToken(ais, tree, tok_i, Space.NoComment); try ais.insertNewline(); } }, @@ -2596,7 +2383,7 @@ fn nodeIsBlock(base: *const ast.Node) bool { }; } -fn nodeCausesSliceOpSpace(base: *ast.Node) bool { +fn nodeCausesSliceOpSpace(base: ast.Node.Index) bool { return switch (base.tag) { .Catch, .Add, @@ -2646,7 +2433,7 @@ fn nodeCausesSliceOpSpace(base: *ast.Node) bool { }; } -fn copyFixingWhitespace(ais: anytype, slice: []const u8) @TypeOf(ais.*).Error!void { +fn copyFixingWhitespace(ais: *Ais, slice: []const u8) @TypeOf(ais.*).Error!void { for (slice) |byte| switch (byte) { '\t' => try ais.writer().writeAll(" "), '\r' => {}, @@ -2656,12 +2443,12 @@ fn copyFixingWhitespace(ais: anytype, slice: []const u8) @TypeOf(ais.*).Error!vo // Returns the number of nodes in `expr` that are on the same line as `rtoken`, // or null if they all are on the same line. -fn rowSize(tree: *ast.Tree, exprs: []*ast.Node, rtoken: ast.TokenIndex) ?usize { +fn rowSize(tree: ast.Tree, exprs: []ast.Node.Index, rtoken: ast.TokenIndex) ?usize { const first_token = exprs[0].firstToken(); const first_loc = tree.tokenLocation(tree.token_locs[first_token].start, rtoken); if (first_loc.line == 0) { const maybe_comma = tree.prevToken(rtoken); - if (tree.token_ids[maybe_comma] == .Comma) + if (tree.token_tags[maybe_comma] == .Comma) return 1; return null; // no newlines } diff --git a/lib/std/zig/tokenizer.zig b/lib/std/zig/tokenizer.zig index 8692713eb3..642c09e477 100644 --- a/lib/std/zig/tokenizer.zig +++ b/lib/std/zig/tokenizer.zig @@ -195,22 +195,23 @@ pub const Token = struct { Keyword_volatile, Keyword_while, - pub fn symbol(tag: Tag) []const u8 { + pub fn lexeme(tag: Tag) ?[]const u8 { return switch (tag) { - .Invalid => "Invalid", + .Invalid, + .Identifier, + .StringLiteral, + .MultilineStringLiteralLine, + .CharLiteral, + .Eof, + .Builtin, + .IntegerLiteral, + .FloatLiteral, + .DocComment, + .ContainerDocComment, + => null, + .Invalid_ampersands => "&&", .Invalid_periodasterisks => ".**", - .Identifier => "Identifier", - .StringLiteral => "StringLiteral", - .MultilineStringLiteralLine => "MultilineStringLiteralLine", - .CharLiteral => "CharLiteral", - .Eof => "Eof", - .Builtin => "Builtin", - .IntegerLiteral => "IntegerLiteral", - .FloatLiteral => "FloatLiteral", - .DocComment => "DocComment", - .ContainerDocComment => "ContainerDocComment", - .Bang => "!", .Pipe => "|", .PipePipe => "||", @@ -319,6 +320,10 @@ pub const Token = struct { .Keyword_while => "while", }; } + + pub fn symbol(tag: Tag) []const u8 { + return tag.lexeme() orelse @tagName(tag); + } }; }; |
