Commit 20554d32c0

Andrew Kelley <andrew@ziglang.org>
2021-02-02 01:23:49
zig fmt: start reworking with new memory layout
* start implementation of ast.Tree.firstToken and lastToken * clarify some ast.Node doc comments * reimplement renderToken
1 parent bf8fafc
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,
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();
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: {
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();
-}
-
-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;
-    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;
-                }
-            }
-        }
-
-        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,
-                }
-            }
-
-            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]);
-        }
-
-        try renderTopLevelDecl(allocator, ais, tree, decl);
-        decl_i += 1;
-        if (decl_i >= root_decls.len) return;
-        try renderExtraNewline(tree, ais, root_decls[decl_i]);
-    }
-}
-
-fn renderExtraNewline(tree: *ast.Tree, ais: anytype, node: *ast.Node) @TypeOf(ais.*).Error!void {
-    return renderExtraNewlineToken(tree, ais, node.firstToken());
-}
-
-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 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 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);
-            }
-        },
-
-        .Comptime => {
-            assert(!decl.requireSemiColon());
-            try renderExpression(allocator, 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,
-    }
-}
-
-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);
-            {
-                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); // )
-                },
-            }
-
-            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
-                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); // }
-            } 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);
-            }
+/// 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);
+}
 
-            if (while_node.@"else") |@"else"| {
-                return renderExpression(allocator, ais, tree, &@"else".base, space);
+/// 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) {
+        // 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;
+    }
+}
 
-        .For => {
-            const for_node = @fieldParentPtr(ast.Node.For, "base", base);
+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, "");
 
-            if (for_node.label) |label| {
-                try renderToken(tree, ais, label, Space.None); // label
-                try renderToken(tree, ais, tree.nextToken(label), Space.Space); // :
-            }
+    // 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;
 
-            if (for_node.inline_token) |inline_token| {
-                try renderToken(tree, ais, inline_token, Space.Space); // inline
-            }
+    for (root_decls) |decl| {
+        try renderTopLevelDecl(ais, tree, decl);
+    }
+}
 
-            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);
+fn renderExtraNewline(tree: ast.Tree, ais: *Ais, node: ast.Node.Index) Error!void {
+    return renderExtraNewlineToken(tree, ais, tree.firstToken(node));
+}
 
-            const rparen = tree.nextToken(for_node.array_expr.lastToken());
+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();
+    //}
+}
 
-            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;
+fn renderTopLevelDecl(ais: *Ais, tree: ast.Tree, decl: ast.Node.Index) Error!void {
+    return renderContainerDecl(ais, tree, decl, .Newline);
+}
 
-            try renderToken(tree, ais, rparen, Space.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"),
 
-            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|
+        .Comptime => return renderExpression(ais, tree, decl, space),
 
-            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;
-                }
-            };
+        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(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)
             {
-                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(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);
-            }
-
-            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);
+                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];
 
-        .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); // (
+            if (statements.len == 0) {
+                ais.pushIndentNextLine();
+                try renderToken(ais, tree, lbrace, .None);
+                ais.popIndent();
+                const rbrace = lbrace + 1;
+                return renderToken(ais, tree, rbrace, space);
             } else {
-                try renderToken(tree, ais, tree.nextToken(asm_node.asm_token), Space.None); // (
-            }
+                ais.pushIndentNextLine();
 
-            asmblk: {
-                ais.pushIndent();
-                defer ais.popIndent();
+                try renderToken(ais, tree, lbrace, .Newline);
 
-                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;
-                }
+                for (statements) |statement, i| {
+                    try renderStatement(ais, tree, statement);
 
-                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); // ,
+                    if (i + 1 < statements.len) {
+                        try renderExtraNewline(tree, ais, statements[i + 1]);
                     }
                 }
+                ais.popIndent();
+                const rbrace = tree.lastToken(statements[statements.len - 1]) + 1;
+                return renderToken(ais, tree, rbrace, space);
             }
-
-            return renderToken(tree, ais, asm_node.rparen, space);
         },
 
-        .EnumLiteral => {
-            const enum_literal = @fieldParentPtr(ast.Node.EnumLiteral, "base", base);
+        //.Defer => {
+        //    const defer_node = @fieldParentPtr(ast.Node.Defer, "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
     }
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);
+        }
     };
 };