Commit 6e57243a79

Andrew Kelley <superjoe30@gmail.com>
2018-04-20 08:15:09
zig fmt: preserve comments in front of test blocks
* refactor std.zig.parser * fix compiler crashing for some compile errors * take advantage of @field in std.zig.ast * move ast.NodeFoo to ast.Node.Foo * comment preservation is more explicit See #911
1 parent cc35f08
Changed files (3)
src/ir.cpp
@@ -6523,6 +6523,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
         case NodeTypeFieldAccessExpr:
             {
                 IrInstruction *ptr_instruction = ir_gen_field_access(irb, scope, node);
+                if (ptr_instruction == irb->codegen->invalid_instruction)
+                    return ptr_instruction;
                 if (lval.is_ptr)
                     return ptr_instruction;
 
@@ -15556,6 +15558,8 @@ static TypeTableEntry *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira,
     }
 
     ensure_complete_type(ira->codegen, container_type);
+    if (type_is_invalid(container_type))
+        return ira->codegen->builtin_types.entry_invalid;
 
     TypeStructField *field = find_struct_type_field(container_type, field_name);
     if (field == nullptr) {
std/zig/ast.zig
@@ -6,7 +6,6 @@ const mem = std.mem;
 
 pub const Node = struct {
     id: Id,
-    comment: ?&NodeLineComment,
 
     pub const Id = enum {
         // Top level
@@ -74,1750 +73,1686 @@ pub const Node = struct {
         FieldInitializer,
     };
 
-    const IdTypePair = struct {
-        id: Id,
-        Type: type,
-    };
-
-    // TODO: When @field exists, we could generate this by iterating over all members of `Id`,
-    //       and making an array of `IdTypePair { .id = @field(Id, @memberName(Id, i)), .Type = @field(ast, "Node" ++ @memberName(Id, i)) }`
-    const idTypeTable = []IdTypePair {
-        IdTypePair { .id = Id.Root, .Type = NodeRoot },
-        IdTypePair { .id = Id.Use, .Type = NodeUse },
-        IdTypePair { .id = Id.TestDecl, .Type = NodeTestDecl },
-
-        IdTypePair { .id = Id.VarDecl, .Type = NodeVarDecl },
-        IdTypePair { .id = Id.Defer, .Type = NodeDefer },
-
-        IdTypePair { .id = Id.InfixOp, .Type = NodeInfixOp },
-        IdTypePair { .id = Id.PrefixOp, .Type = NodePrefixOp },
-        IdTypePair { .id = Id.SuffixOp, .Type = NodeSuffixOp },
-
-        IdTypePair { .id = Id.Switch, .Type = NodeSwitch },
-        IdTypePair { .id = Id.While, .Type = NodeWhile },
-        IdTypePair { .id = Id.For, .Type = NodeFor },
-        IdTypePair { .id = Id.If, .Type = NodeIf },
-        IdTypePair { .id = Id.ControlFlowExpression, .Type = NodeControlFlowExpression },
-        IdTypePair { .id = Id.Suspend, .Type = NodeSuspend },
-
-        IdTypePair { .id = Id.VarType, .Type = NodeVarType },
-        IdTypePair { .id = Id.ErrorType, .Type = NodeErrorType },
-        IdTypePair { .id = Id.FnProto, .Type = NodeFnProto },
-
-        IdTypePair { .id = Id.IntegerLiteral, .Type = NodeIntegerLiteral },
-        IdTypePair { .id = Id.FloatLiteral, .Type = NodeFloatLiteral },
-        IdTypePair { .id = Id.StringLiteral, .Type = NodeStringLiteral },
-        IdTypePair { .id = Id.MultilineStringLiteral, .Type = NodeMultilineStringLiteral },
-        IdTypePair { .id = Id.CharLiteral, .Type = NodeCharLiteral },
-        IdTypePair { .id = Id.BoolLiteral, .Type = NodeBoolLiteral },
-        IdTypePair { .id = Id.NullLiteral, .Type = NodeNullLiteral },
-        IdTypePair { .id = Id.UndefinedLiteral, .Type = NodeUndefinedLiteral },
-        IdTypePair { .id = Id.ThisLiteral, .Type = NodeThisLiteral },
-        IdTypePair { .id = Id.Unreachable, .Type = NodeUnreachable },
-        IdTypePair { .id = Id.Identifier, .Type = NodeIdentifier },
-        IdTypePair { .id = Id.GroupedExpression, .Type = NodeGroupedExpression },
-        IdTypePair { .id = Id.BuiltinCall, .Type = NodeBuiltinCall },
-        IdTypePair { .id = Id.ErrorSetDecl, .Type = NodeErrorSetDecl },
-        IdTypePair { .id = Id.ContainerDecl, .Type = NodeContainerDecl },
-        IdTypePair { .id = Id.Asm, .Type = NodeAsm },
-        IdTypePair { .id = Id.Comptime, .Type = NodeComptime },
-        IdTypePair { .id = Id.Block, .Type = NodeBlock },
-
-        IdTypePair { .id = Id.LineComment, .Type = NodeLineComment },
-        IdTypePair { .id = Id.SwitchCase, .Type = NodeSwitchCase },
-        IdTypePair { .id = Id.SwitchElse, .Type = NodeSwitchElse },
-        IdTypePair { .id = Id.Else, .Type = NodeElse },
-        IdTypePair { .id = Id.Payload, .Type = NodePayload },
-        IdTypePair { .id = Id.PointerPayload, .Type = NodePointerPayload },
-        IdTypePair { .id = Id.PointerIndexPayload, .Type = NodePointerIndexPayload },
-        IdTypePair { .id = Id.StructField, .Type = NodeStructField },
-        IdTypePair { .id = Id.UnionTag, .Type = NodeUnionTag },
-        IdTypePair { .id = Id.EnumTag, .Type = NodeEnumTag },
-        IdTypePair { .id = Id.AsmInput, .Type = NodeAsmInput },
-        IdTypePair { .id = Id.AsmOutput, .Type = NodeAsmOutput },
-        IdTypePair { .id = Id.AsyncAttribute, .Type = NodeAsyncAttribute },
-        IdTypePair { .id = Id.ParamDecl, .Type = NodeParamDecl },
-        IdTypePair { .id = Id.FieldInitializer, .Type = NodeFieldInitializer },
-    };
-
-    pub fn IdToType(comptime id: Id) type {
-        inline for (idTypeTable) |id_type_pair| {
-            if (id == id_type_pair.id)
-                return id_type_pair.Type;
-        }
-
-        unreachable;
-    }
-
-    pub fn typeToId(comptime T: type) Id {
-        inline for (idTypeTable) |id_type_pair| {
-            if (T == id_type_pair.Type)
-                return id_type_pair.id;
-        }
-
-        unreachable;
-    }
-
     pub fn iterate(base: &Node, index: usize) ?&Node {
-        inline for (idTypeTable) |id_type_pair| {
-            if (base.id == id_type_pair.id)
-                return @fieldParentPtr(id_type_pair.Type, "base", base).iterate(index);
+        comptime var i = 0;
+        inline while (i < @memberCount(Id)) : (i += 1) {
+            if (base.id == @field(Id, @memberName(Id, i))) {
+                const T = @field(Node, @memberName(Id, i));
+                return @fieldParentPtr(T, "base", base).iterate(index);
+            }
         }
-
         unreachable;
     }
 
     pub fn firstToken(base: &Node) Token {
-        inline for (idTypeTable) |id_type_pair| {
-            if (base.id == id_type_pair.id)
-                return @fieldParentPtr(id_type_pair.Type, "base", base).firstToken();
+        comptime var i = 0;
+        inline while (i < @memberCount(Id)) : (i += 1) {
+            if (base.id == @field(Id, @memberName(Id, i))) {
+                const T = @field(Node, @memberName(Id, i));
+                return @fieldParentPtr(T, "base", base).firstToken();
+            }
         }
-
         unreachable;
     }
 
     pub fn lastToken(base: &Node) Token {
-        inline for (idTypeTable) |id_type_pair| {
-            if (base.id == id_type_pair.id)
-                return @fieldParentPtr(id_type_pair.Type, "base", base).lastToken();
+        comptime var i = 0;
+        inline while (i < @memberCount(Id)) : (i += 1) {
+            if (base.id == @field(Id, @memberName(Id, i))) {
+                const T = @field(Node, @memberName(Id, i));
+                return @fieldParentPtr(T, "base", base).lastToken();
+            }
         }
-
         unreachable;
     }
-};
 
-pub const NodeRoot = struct {
-    base: Node,
-    decls: ArrayList(&Node),
-    eof_token: Token,
-
-    pub fn iterate(self: &NodeRoot, index: usize) ?&Node {
-        if (index < self.decls.len) {
-            return self.decls.items[self.decls.len - index - 1];
+    pub fn typeToId(comptime T: type) Id {
+        comptime var i = 0;
+        inline while (i < @memberCount(Id)) : (i += 1) {
+            if (T == @field(Node, @memberName(Id, i))) {
+                return @field(Id, @memberName(Id, i));
+            }
         }
-        return null;
-    }
-
-    pub fn firstToken(self: &NodeRoot) Token {
-        return if (self.decls.len == 0) self.eof_token else self.decls.at(0).firstToken();
+        unreachable;
     }
 
-    pub fn lastToken(self: &NodeRoot) Token {
-        return if (self.decls.len == 0) self.eof_token else self.decls.at(self.decls.len - 1).lastToken();
-    }
-};
+    pub const Root = struct {
+        base: Node,
+        decls: ArrayList(&Node),
+        eof_token: Token,
 
-pub const NodeVarDecl = struct {
-    base: Node,
-    visib_token: ?Token,
-    name_token: Token,
-    eq_token: Token,
-    mut_token: Token,
-    comptime_token: ?Token,
-    extern_export_token: ?Token,
-    lib_name: ?&Node,
-    type_node: ?&Node,
-    align_node: ?&Node,
-    init_node: ?&Node,
-    semicolon_token: Token,
-
-    pub fn iterate(self: &NodeVarDecl, index: usize) ?&Node {
-        var i = index;
-
-        if (self.type_node) |type_node| {
-            if (i < 1) return type_node;
-            i -= 1;
+        pub fn iterate(self: &Root, index: usize) ?&Node {
+            if (index < self.decls.len) {
+                return self.decls.items[self.decls.len - index - 1];
+            }
+            return null;
         }
 
-        if (self.align_node) |align_node| {
-            if (i < 1) return align_node;
-            i -= 1;
+        pub fn firstToken(self: &Root) Token {
+            return if (self.decls.len == 0) self.eof_token else self.decls.at(0).firstToken();
         }
 
-        if (self.init_node) |init_node| {
-            if (i < 1) return init_node;
-            i -= 1;
+        pub fn lastToken(self: &Root) Token {
+            return if (self.decls.len == 0) self.eof_token else self.decls.at(self.decls.len - 1).lastToken();
         }
+    };
 
-        return null;
-    }
-
-    pub fn firstToken(self: &NodeVarDecl) Token {
-        if (self.visib_token) |visib_token| return visib_token;
-        if (self.comptime_token) |comptime_token| return comptime_token;
-        if (self.extern_export_token) |extern_export_token| return extern_export_token;
-        assert(self.lib_name == null);
-        return self.mut_token;
-    }
-
-    pub fn lastToken(self: &NodeVarDecl) Token {
-        return self.semicolon_token;
-    }
-};
-
-pub const NodeUse = struct {
-    base: Node,
-    visib_token: ?Token,
-    expr: &Node,
-    semicolon_token: Token,
-
-    pub fn iterate(self: &NodeUse, index: usize) ?&Node {
-        var i = index;
+    pub const VarDecl = struct {
+        base: Node,
+        comments: ?&LineComment,
+        visib_token: ?Token,
+        name_token: Token,
+        eq_token: Token,
+        mut_token: Token,
+        comptime_token: ?Token,
+        extern_export_token: ?Token,
+        lib_name: ?&Node,
+        type_node: ?&Node,
+        align_node: ?&Node,
+        init_node: ?&Node,
+        semicolon_token: Token,
+
+        pub fn iterate(self: &VarDecl, index: usize) ?&Node {
+            var i = index;
+
+            if (self.type_node) |type_node| {
+                if (i < 1) return type_node;
+                i -= 1;
+            }
 
-        if (i < 1) return self.expr;
-        i -= 1;
+            if (self.align_node) |align_node| {
+                if (i < 1) return align_node;
+                i -= 1;
+            }
 
-        return null;
-    }
+            if (self.init_node) |init_node| {
+                if (i < 1) return init_node;
+                i -= 1;
+            }
 
-    pub fn firstToken(self: &NodeUse) Token {
-        if (self.visib_token) |visib_token| return visib_token;
-        return self.expr.firstToken();
-    }
+            return null;
+        }
 
-    pub fn lastToken(self: &NodeUse) Token {
-        return self.semicolon_token;
-    }
-};
+        pub fn firstToken(self: &VarDecl) Token {
+            if (self.visib_token) |visib_token| return visib_token;
+            if (self.comptime_token) |comptime_token| return comptime_token;
+            if (self.extern_export_token) |extern_export_token| return extern_export_token;
+            assert(self.lib_name == null);
+            return self.mut_token;
+        }
 
-pub const NodeErrorSetDecl = struct {
-    base: Node,
-    error_token: Token,
-    decls: ArrayList(&Node),
-    rbrace_token: Token,
+        pub fn lastToken(self: &VarDecl) Token {
+            return self.semicolon_token;
+        }
+    };
 
-    pub fn iterate(self: &NodeErrorSetDecl, index: usize) ?&Node {
-        var i = index;
+    pub const Use = struct {
+        base: Node,
+        visib_token: ?Token,
+        expr: &Node,
+        semicolon_token: Token,
 
-        if (i < self.decls.len) return self.decls.at(i);
-        i -= self.decls.len;
+        pub fn iterate(self: &Use, index: usize) ?&Node {
+            var i = index;
 
-        return null;
-    }
+            if (i < 1) return self.expr;
+            i -= 1;
 
-    pub fn firstToken(self: &NodeErrorSetDecl) Token {
-        return self.error_token;
-    }
+            return null;
+        }
 
-    pub fn lastToken(self: &NodeErrorSetDecl) Token {
-        return self.rbrace_token;
-    }
-};
+        pub fn firstToken(self: &Use) Token {
+            if (self.visib_token) |visib_token| return visib_token;
+            return self.expr.firstToken();
+        }
 
-pub const NodeContainerDecl = struct {
-    base: Node,
-    ltoken: Token,
-    layout: Layout,
-    kind: Kind,
-    init_arg_expr: InitArg,
-    fields_and_decls: ArrayList(&Node),
-    rbrace_token: Token,
-
-    const Layout = enum {
-        Auto,
-        Extern,
-        Packed,
+        pub fn lastToken(self: &Use) Token {
+            return self.semicolon_token;
+        }
     };
 
-    const Kind = enum {
-        Struct,
-        Enum,
-        Union,
-    };
+    pub const ErrorSetDecl = struct {
+        base: Node,
+        error_token: Token,
+        decls: ArrayList(&Node),
+        rbrace_token: Token,
 
-    const InitArg = union(enum) {
-        None,
-        Enum,
-        Type: &Node,
-    };
+        pub fn iterate(self: &ErrorSetDecl, index: usize) ?&Node {
+            var i = index;
 
-    pub fn iterate(self: &NodeContainerDecl, index: usize) ?&Node {
-        var i = index;
+            if (i < self.decls.len) return self.decls.at(i);
+            i -= self.decls.len;
 
-        switch (self.init_arg_expr) {
-            InitArg.Type => |t| {
-                if (i < 1) return t;
-                i -= 1;
-            },
-            InitArg.None,
-            InitArg.Enum => { }
+            return null;
         }
 
-        if (i < self.fields_and_decls.len) return self.fields_and_decls.at(i);
-        i -= self.fields_and_decls.len;
+        pub fn firstToken(self: &ErrorSetDecl) Token {
+            return self.error_token;
+        }
 
-        return null;
-    }
+        pub fn lastToken(self: &ErrorSetDecl) Token {
+            return self.rbrace_token;
+        }
+    };
 
-    pub fn firstToken(self: &NodeContainerDecl) Token {
-        return self.ltoken;
-    }
+    pub const ContainerDecl = struct {
+        base: Node,
+        ltoken: Token,
+        layout: Layout,
+        kind: Kind,
+        init_arg_expr: InitArg,
+        fields_and_decls: ArrayList(&Node),
+        rbrace_token: Token,
+
+        const Layout = enum {
+            Auto,
+            Extern,
+            Packed,
+        };
 
-    pub fn lastToken(self: &NodeContainerDecl) Token {
-        return self.rbrace_token;
-    }
-};
+        const Kind = enum {
+            Struct,
+            Enum,
+            Union,
+        };
+
+        const InitArg = union(enum) {
+            None,
+            Enum,
+            Type: &Node,
+        };
 
-pub const NodeStructField = struct {
-    base: Node,
-    visib_token: ?Token,
-    name_token: Token,
-    type_expr: &Node,
+        pub fn iterate(self: &ContainerDecl, index: usize) ?&Node {
+            var i = index;
 
-    pub fn iterate(self: &NodeStructField, index: usize) ?&Node {
-        var i = index;
+            switch (self.init_arg_expr) {
+                InitArg.Type => |t| {
+                    if (i < 1) return t;
+                    i -= 1;
+                },
+                InitArg.None,
+                InitArg.Enum => { }
+            }
 
-        if (i < 1) return self.type_expr;
-        i -= 1;
+            if (i < self.fields_and_decls.len) return self.fields_and_decls.at(i);
+            i -= self.fields_and_decls.len;
 
-        return null;
-    }
+            return null;
+        }
 
-    pub fn firstToken(self: &NodeStructField) Token {
-        if (self.visib_token) |visib_token| return visib_token;
-        return self.name_token;
-    }
+        pub fn firstToken(self: &ContainerDecl) Token {
+            return self.ltoken;
+        }
 
-    pub fn lastToken(self: &NodeStructField) Token {
-        return self.type_expr.lastToken();
-    }
-};
+        pub fn lastToken(self: &ContainerDecl) Token {
+            return self.rbrace_token;
+        }
+    };
 
-pub const NodeUnionTag = struct {
-    base: Node,
-    name_token: Token,
-    type_expr: ?&Node,
+    pub const StructField = struct {
+        base: Node,
+        visib_token: ?Token,
+        name_token: Token,
+        type_expr: &Node,
 
-    pub fn iterate(self: &NodeUnionTag, index: usize) ?&Node {
-        var i = index;
+        pub fn iterate(self: &StructField, index: usize) ?&Node {
+            var i = index;
 
-        if (self.type_expr) |type_expr| {
-            if (i < 1) return type_expr;
+            if (i < 1) return self.type_expr;
             i -= 1;
-        }
 
-        return null;
-    }
+            return null;
+        }
 
-    pub fn firstToken(self: &NodeUnionTag) Token {
-        return self.name_token;
-    }
+        pub fn firstToken(self: &StructField) Token {
+            if (self.visib_token) |visib_token| return visib_token;
+            return self.name_token;
+        }
 
-    pub fn lastToken(self: &NodeUnionTag) Token {
-        if (self.type_expr) |type_expr| {
-            return type_expr.lastToken();
+        pub fn lastToken(self: &StructField) Token {
+            return self.type_expr.lastToken();
         }
+    };
 
-        return self.name_token;
-    }
-};
+    pub const UnionTag = struct {
+        base: Node,
+        name_token: Token,
+        type_expr: ?&Node,
 
-pub const NodeEnumTag = struct {
-    base: Node,
-    name_token: Token,
-    value: ?&Node,
+        pub fn iterate(self: &UnionTag, index: usize) ?&Node {
+            var i = index;
 
-    pub fn iterate(self: &NodeEnumTag, index: usize) ?&Node {
-        var i = index;
+            if (self.type_expr) |type_expr| {
+                if (i < 1) return type_expr;
+                i -= 1;
+            }
 
-        if (self.value) |value| {
-            if (i < 1) return value;
-            i -= 1;
+            return null;
         }
 
-        return null;
-    }
+        pub fn firstToken(self: &UnionTag) Token {
+            return self.name_token;
+        }
 
-    pub fn firstToken(self: &NodeEnumTag) Token {
-        return self.name_token;
-    }
+        pub fn lastToken(self: &UnionTag) Token {
+            if (self.type_expr) |type_expr| {
+                return type_expr.lastToken();
+            }
 
-    pub fn lastToken(self: &NodeEnumTag) Token {
-        if (self.value) |value| {
-            return value.lastToken();
+            return self.name_token;
         }
+    };
 
-        return self.name_token;
-    }
-};
-
-pub const NodeIdentifier = struct {
-    base: Node,
-    token: Token,
+    pub const EnumTag = struct {
+        base: Node,
+        name_token: Token,
+        value: ?&Node,
 
-    pub fn iterate(self: &NodeIdentifier, index: usize) ?&Node {
-        return null;
-    }
+        pub fn iterate(self: &EnumTag, index: usize) ?&Node {
+            var i = index;
 
-    pub fn firstToken(self: &NodeIdentifier) Token {
-        return self.token;
-    }
+            if (self.value) |value| {
+                if (i < 1) return value;
+                i -= 1;
+            }
 
-    pub fn lastToken(self: &NodeIdentifier) Token {
-        return self.token;
-    }
-};
+            return null;
+        }
 
-pub const NodeAsyncAttribute = struct {
-    base: Node,
-    async_token: Token,
-    allocator_type: ?&Node,
-    rangle_bracket: ?Token,
+        pub fn firstToken(self: &EnumTag) Token {
+            return self.name_token;
+        }
 
-    pub fn iterate(self: &NodeAsyncAttribute, index: usize) ?&Node {
-        var i = index;
+        pub fn lastToken(self: &EnumTag) Token {
+            if (self.value) |value| {
+                return value.lastToken();
+            }
 
-        if (self.allocator_type) |allocator_type| {
-            if (i < 1) return allocator_type;
-            i -= 1;
+            return self.name_token;
         }
+    };
 
-        return null;
-    }
-
-    pub fn firstToken(self: &NodeAsyncAttribute) Token {
-        return self.async_token;
-    }
+    pub const Identifier = struct {
+        base: Node,
+        token: Token,
 
-    pub fn lastToken(self: &NodeAsyncAttribute) Token {
-        if (self.rangle_bracket) |rangle_bracket| {
-            return rangle_bracket;
+        pub fn iterate(self: &Identifier, index: usize) ?&Node {
+            return null;
         }
 
-        return self.async_token;
-    }
-};
+        pub fn firstToken(self: &Identifier) Token {
+            return self.token;
+        }
 
-pub const NodeFnProto = struct {
-    base: Node,
-    visib_token: ?Token,
-    fn_token: Token,
-    name_token: ?Token,
-    params: ArrayList(&Node),
-    return_type: ReturnType,
-    var_args_token: ?Token,
-    extern_export_inline_token: ?Token,
-    cc_token: ?Token,
-    async_attr: ?&NodeAsyncAttribute,
-    body_node: ?&Node,
-    lib_name: ?&Node, // populated if this is an extern declaration
-    align_expr: ?&Node, // populated if align(A) is present
-
-    pub const ReturnType = union(enum) {
-        Explicit: &Node,
-        InferErrorSet: &Node,
+        pub fn lastToken(self: &Identifier) Token {
+            return self.token;
+        }
     };
 
-    pub fn iterate(self: &NodeFnProto, index: usize) ?&Node {
-        var i = index;
+    pub const AsyncAttribute = struct {
+        base: Node,
+        async_token: Token,
+        allocator_type: ?&Node,
+        rangle_bracket: ?Token,
 
-        if (self.body_node) |body_node| {
-            if (i < 1) return body_node;
-            i -= 1;
-        }
+        pub fn iterate(self: &AsyncAttribute, index: usize) ?&Node {
+            var i = index;
 
-        switch (self.return_type) {
-            // TODO allow this and next prong to share bodies since the types are the same
-            ReturnType.Explicit => |node| {
-                if (i < 1) return node;
+            if (self.allocator_type) |allocator_type| {
+                if (i < 1) return allocator_type;
                 i -= 1;
-            },
-            ReturnType.InferErrorSet => |node| {
-                if (i < 1) return node;
-                i -= 1;
-            },
+            }
+
+            return null;
         }
 
-        if (self.align_expr) |align_expr| {
-            if (i < 1) return align_expr;
-            i -= 1;
+        pub fn firstToken(self: &AsyncAttribute) Token {
+            return self.async_token;
         }
 
-        if (i < self.params.len) return self.params.items[self.params.len - i - 1];
-        i -= self.params.len;
+        pub fn lastToken(self: &AsyncAttribute) Token {
+            if (self.rangle_bracket) |rangle_bracket| {
+                return rangle_bracket;
+            }
 
-        if (self.lib_name) |lib_name| {
-            if (i < 1) return lib_name;
-            i -= 1;
+            return self.async_token;
         }
+    };
 
-        return null;
-    }
+    pub const FnProto = struct {
+        base: Node,
+        comments: ?&LineComment,
+        visib_token: ?Token,
+        fn_token: Token,
+        name_token: ?Token,
+        params: ArrayList(&Node),
+        return_type: ReturnType,
+        var_args_token: ?Token,
+        extern_export_inline_token: ?Token,
+        cc_token: ?Token,
+        async_attr: ?&AsyncAttribute,
+        body_node: ?&Node,
+        lib_name: ?&Node, // populated if this is an extern declaration
+        align_expr: ?&Node, // populated if align(A) is present
+
+        pub const ReturnType = union(enum) {
+            Explicit: &Node,
+            InferErrorSet: &Node,
+        };
 
-    pub fn firstToken(self: &NodeFnProto) Token {
-        if (self.visib_token) |visib_token| return visib_token;
-        if (self.extern_export_inline_token) |extern_export_inline_token| return extern_export_inline_token;
-        assert(self.lib_name == null);
-        if (self.cc_token) |cc_token| return cc_token;
-        return self.fn_token;
-    }
+        pub fn iterate(self: &FnProto, index: usize) ?&Node {
+            var i = index;
 
-    pub fn lastToken(self: &NodeFnProto) Token {
-        if (self.body_node) |body_node| return body_node.lastToken();
-        switch (self.return_type) {
-            // TODO allow this and next prong to share bodies since the types are the same
-            ReturnType.Explicit => |node| return node.lastToken(),
-            ReturnType.InferErrorSet => |node| return node.lastToken(),
-        }
-    }
-};
+            if (self.body_node) |body_node| {
+                if (i < 1) return body_node;
+                i -= 1;
+            }
 
-pub const NodeParamDecl = struct {
-    base: Node,
-    comptime_token: ?Token,
-    noalias_token: ?Token,
-    name_token: ?Token,
-    type_node: &Node,
-    var_args_token: ?Token,
+            switch (self.return_type) {
+                // TODO allow this and next prong to share bodies since the types are the same
+                ReturnType.Explicit => |node| {
+                    if (i < 1) return node;
+                    i -= 1;
+                },
+                ReturnType.InferErrorSet => |node| {
+                    if (i < 1) return node;
+                    i -= 1;
+                },
+            }
 
-    pub fn iterate(self: &NodeParamDecl, index: usize) ?&Node {
-        var i = index;
+            if (self.align_expr) |align_expr| {
+                if (i < 1) return align_expr;
+                i -= 1;
+            }
 
-        if (i < 1) return self.type_node;
-        i -= 1;
+            if (i < self.params.len) return self.params.items[self.params.len - i - 1];
+            i -= self.params.len;
 
-        return null;
-    }
+            if (self.lib_name) |lib_name| {
+                if (i < 1) return lib_name;
+                i -= 1;
+            }
 
-    pub fn firstToken(self: &NodeParamDecl) Token {
-        if (self.comptime_token) |comptime_token| return comptime_token;
-        if (self.noalias_token) |noalias_token| return noalias_token;
-        if (self.name_token) |name_token| return name_token;
-        return self.type_node.firstToken();
-    }
+            return null;
+        }
 
-    pub fn lastToken(self: &NodeParamDecl) Token {
-        if (self.var_args_token) |var_args_token| return var_args_token;
-        return self.type_node.lastToken();
-    }
-};
+        pub fn firstToken(self: &FnProto) Token {
+            if (self.visib_token) |visib_token| return visib_token;
+            if (self.extern_export_inline_token) |extern_export_inline_token| return extern_export_inline_token;
+            assert(self.lib_name == null);
+            if (self.cc_token) |cc_token| return cc_token;
+            return self.fn_token;
+        }
 
-pub const NodeBlock = struct {
-    base: Node,
-    label: ?Token,
-    lbrace: Token,
-    statements: ArrayList(&Node),
-    rbrace: Token,
+        pub fn lastToken(self: &FnProto) Token {
+            if (self.body_node) |body_node| return body_node.lastToken();
+            switch (self.return_type) {
+                // TODO allow this and next prong to share bodies since the types are the same
+                ReturnType.Explicit => |node| return node.lastToken(),
+                ReturnType.InferErrorSet => |node| return node.lastToken(),
+            }
+        }
+    };
 
-    pub fn iterate(self: &NodeBlock, index: usize) ?&Node {
-        var i = index;
+    pub const ParamDecl = struct {
+        base: Node,
+        comptime_token: ?Token,
+        noalias_token: ?Token,
+        name_token: ?Token,
+        type_node: &Node,
+        var_args_token: ?Token,
 
-        if (i < self.statements.len) return self.statements.items[i];
-        i -= self.statements.len;
+        pub fn iterate(self: &ParamDecl, index: usize) ?&Node {
+            var i = index;
 
-        return null;
-    }
+            if (i < 1) return self.type_node;
+            i -= 1;
 
-    pub fn firstToken(self: &NodeBlock) Token {
-        if (self.label) |label| {
-            return label;
+            return null;
         }
 
-        return self.lbrace;
-    }
+        pub fn firstToken(self: &ParamDecl) Token {
+            if (self.comptime_token) |comptime_token| return comptime_token;
+            if (self.noalias_token) |noalias_token| return noalias_token;
+            if (self.name_token) |name_token| return name_token;
+            return self.type_node.firstToken();
+        }
 
-    pub fn lastToken(self: &NodeBlock) Token {
-        return self.rbrace;
-    }
-};
+        pub fn lastToken(self: &ParamDecl) Token {
+            if (self.var_args_token) |var_args_token| return var_args_token;
+            return self.type_node.lastToken();
+        }
+    };
 
-pub const NodeDefer = struct {
-    base: Node,
-    defer_token: Token,
-    kind: Kind,
-    expr: &Node,
+    pub const Block = struct {
+        base: Node,
+        label: ?Token,
+        lbrace: Token,
+        statements: ArrayList(&Node),
+        rbrace: Token,
 
-    const Kind = enum {
-        Error,
-        Unconditional,
-    };
+        pub fn iterate(self: &Block, index: usize) ?&Node {
+            var i = index;
 
-    pub fn iterate(self: &NodeDefer, index: usize) ?&Node {
-        var i = index;
+            if (i < self.statements.len) return self.statements.items[i];
+            i -= self.statements.len;
 
-        if (i < 1) return self.expr;
-        i -= 1;
+            return null;
+        }
 
-        return null;
-    }
+        pub fn firstToken(self: &Block) Token {
+            if (self.label) |label| {
+                return label;
+            }
 
-    pub fn firstToken(self: &NodeDefer) Token {
-        return self.defer_token;
-    }
+            return self.lbrace;
+        }
 
-    pub fn lastToken(self: &NodeDefer) Token {
-        return self.expr.lastToken();
-    }
-};
+        pub fn lastToken(self: &Block) Token {
+            return self.rbrace;
+        }
+    };
 
-pub const NodeComptime = struct {
-    base: Node,
-    comptime_token: Token,
-    expr: &Node,
+    pub const Defer = struct {
+        base: Node,
+        defer_token: Token,
+        kind: Kind,
+        expr: &Node,
 
-    pub fn iterate(self: &NodeComptime, index: usize) ?&Node {
-        var i = index;
+        const Kind = enum {
+            Error,
+            Unconditional,
+        };
 
-        if (i < 1) return self.expr;
-        i -= 1;
+        pub fn iterate(self: &Defer, index: usize) ?&Node {
+            var i = index;
 
-        return null;
-    }
+            if (i < 1) return self.expr;
+            i -= 1;
 
-    pub fn firstToken(self: &NodeComptime) Token {
-        return self.comptime_token;
-    }
+            return null;
+        }
 
-    pub fn lastToken(self: &NodeComptime) Token {
-        return self.expr.lastToken();
-    }
-};
+        pub fn firstToken(self: &Defer) Token {
+            return self.defer_token;
+        }
 
-pub const NodePayload = struct {
-    base: Node,
-    lpipe: Token,
-    error_symbol: &Node,
-    rpipe: Token,
+        pub fn lastToken(self: &Defer) Token {
+            return self.expr.lastToken();
+        }
+    };
 
-    pub fn iterate(self: &NodePayload, index: usize) ?&Node {
-        var i = index;
+    pub const Comptime = struct {
+        base: Node,
+        comptime_token: Token,
+        expr: &Node,
 
-        if (i < 1) return self.error_symbol;
-        i -= 1;
+        pub fn iterate(self: &Comptime, index: usize) ?&Node {
+            var i = index;
 
-        return null;
-    }
+            if (i < 1) return self.expr;
+            i -= 1;
 
-    pub fn firstToken(self: &NodePayload) Token {
-        return self.lpipe;
-    }
+            return null;
+        }
 
-    pub fn lastToken(self: &NodePayload) Token {
-        return self.rpipe;
-    }
-};
+        pub fn firstToken(self: &Comptime) Token {
+            return self.comptime_token;
+        }
 
-pub const NodePointerPayload = struct {
-    base: Node,
-    lpipe: Token,
-    ptr_token: ?Token,
-    value_symbol: &Node,
-    rpipe: Token,
+        pub fn lastToken(self: &Comptime) Token {
+            return self.expr.lastToken();
+        }
+    };
 
-    pub fn iterate(self: &NodePointerPayload, index: usize) ?&Node {
-        var i = index;
+    pub const Payload = struct {
+        base: Node,
+        lpipe: Token,
+        error_symbol: &Node,
+        rpipe: Token,
 
-        if (i < 1) return self.value_symbol;
-        i -= 1;
+        pub fn iterate(self: &Payload, index: usize) ?&Node {
+            var i = index;
 
-        return null;
-    }
+            if (i < 1) return self.error_symbol;
+            i -= 1;
 
-    pub fn firstToken(self: &NodePointerPayload) Token {
-        return self.lpipe;
-    }
+            return null;
+        }
 
-    pub fn lastToken(self: &NodePointerPayload) Token {
-        return self.rpipe;
-    }
-};
+        pub fn firstToken(self: &Payload) Token {
+            return self.lpipe;
+        }
 
-pub const NodePointerIndexPayload = struct {
-    base: Node,
-    lpipe: Token,
-    ptr_token: ?Token,
-    value_symbol: &Node,
-    index_symbol: ?&Node,
-    rpipe: Token,
+        pub fn lastToken(self: &Payload) Token {
+            return self.rpipe;
+        }
+    };
 
-    pub fn iterate(self: &NodePointerIndexPayload, index: usize) ?&Node {
-        var i = index;
+    pub const PointerPayload = struct {
+        base: Node,
+        lpipe: Token,
+        ptr_token: ?Token,
+        value_symbol: &Node,
+        rpipe: Token,
 
-        if (i < 1) return self.value_symbol;
-        i -= 1;
+        pub fn iterate(self: &PointerPayload, index: usize) ?&Node {
+            var i = index;
 
-        if (self.index_symbol) |index_symbol| {
-            if (i < 1) return index_symbol;
+            if (i < 1) return self.value_symbol;
             i -= 1;
-        }
 
-        return null;
-    }
+            return null;
+        }
 
-    pub fn firstToken(self: &NodePointerIndexPayload) Token {
-        return self.lpipe;
-    }
+        pub fn firstToken(self: &PointerPayload) Token {
+            return self.lpipe;
+        }
 
-    pub fn lastToken(self: &NodePointerIndexPayload) Token {
-        return self.rpipe;
-    }
-};
+        pub fn lastToken(self: &PointerPayload) Token {
+            return self.rpipe;
+        }
+    };
 
-pub const NodeElse = struct {
-    base: Node,
-    else_token: Token,
-    payload: ?&Node,
-    body: &Node,
+    pub const PointerIndexPayload = struct {
+        base: Node,
+        lpipe: Token,
+        ptr_token: ?Token,
+        value_symbol: &Node,
+        index_symbol: ?&Node,
+        rpipe: Token,
 
-    pub fn iterate(self: &NodeElse, index: usize) ?&Node {
-        var i = index;
+        pub fn iterate(self: &PointerIndexPayload, index: usize) ?&Node {
+            var i = index;
 
-        if (self.payload) |payload| {
-            if (i < 1) return payload;
+            if (i < 1) return self.value_symbol;
             i -= 1;
-        }
 
-        if (i < 1) return self.body;
-        i -= 1;
-
-        return null;
-    }
+            if (self.index_symbol) |index_symbol| {
+                if (i < 1) return index_symbol;
+                i -= 1;
+            }
 
-    pub fn firstToken(self: &NodeElse) Token {
-        return self.else_token;
-    }
+            return null;
+        }
 
-    pub fn lastToken(self: &NodeElse) Token {
-        return self.body.lastToken();
-    }
-};
+        pub fn firstToken(self: &PointerIndexPayload) Token {
+            return self.lpipe;
+        }
 
-pub const NodeSwitch = struct {
-    base: Node,
-    switch_token: Token,
-    expr: &Node,
-    cases: ArrayList(&NodeSwitchCase),
-    rbrace: Token,
+        pub fn lastToken(self: &PointerIndexPayload) Token {
+            return self.rpipe;
+        }
+    };
 
-    pub fn iterate(self: &NodeSwitch, index: usize) ?&Node {
-        var i = index;
+    pub const Else = struct {
+        base: Node,
+        else_token: Token,
+        payload: ?&Node,
+        body: &Node,
 
-        if (i < 1) return self.expr;
-        i -= 1;
+        pub fn iterate(self: &Else, index: usize) ?&Node {
+            var i = index;
 
-        if (i < self.cases.len) return &self.cases.at(i).base;
-        i -= self.cases.len;
+            if (self.payload) |payload| {
+                if (i < 1) return payload;
+                i -= 1;
+            }
 
-        return null;
-    }
+            if (i < 1) return self.body;
+            i -= 1;
 
-    pub fn firstToken(self: &NodeSwitch) Token {
-        return self.switch_token;
-    }
+            return null;
+        }
 
-    pub fn lastToken(self: &NodeSwitch) Token {
-        return self.rbrace;
-    }
-};
+        pub fn firstToken(self: &Else) Token {
+            return self.else_token;
+        }
 
-pub const NodeSwitchCase = struct {
-    base: Node,
-    items: ArrayList(&Node),
-    payload: ?&Node,
-    expr: &Node,
+        pub fn lastToken(self: &Else) Token {
+            return self.body.lastToken();
+        }
+    };
 
-    pub fn iterate(self: &NodeSwitchCase, index: usize) ?&Node {
-        var i = index;
+    pub const Switch = struct {
+        base: Node,
+        switch_token: Token,
+        expr: &Node,
+        cases: ArrayList(&SwitchCase),
+        rbrace: Token,
 
-        if (i < self.items.len) return self.items.at(i);
-        i -= self.items.len;
+        pub fn iterate(self: &Switch, index: usize) ?&Node {
+            var i = index;
 
-        if (self.payload) |payload| {
-            if (i < 1) return payload;
+            if (i < 1) return self.expr;
             i -= 1;
-        }
 
-        if (i < 1) return self.expr;
-        i -= 1;
+            if (i < self.cases.len) return &self.cases.at(i).base;
+            i -= self.cases.len;
 
-        return null;
-    }
+            return null;
+        }
 
-    pub fn firstToken(self: &NodeSwitchCase) Token {
-        return self.items.at(0).firstToken();
-    }
+        pub fn firstToken(self: &Switch) Token {
+            return self.switch_token;
+        }
 
-    pub fn lastToken(self: &NodeSwitchCase) Token {
-        return self.expr.lastToken();
-    }
-};
+        pub fn lastToken(self: &Switch) Token {
+            return self.rbrace;
+        }
+    };
 
-pub const NodeSwitchElse = struct {
-    base: Node,
-    token: Token,
+    pub const SwitchCase = struct {
+        base: Node,
+        items: ArrayList(&Node),
+        payload: ?&Node,
+        expr: &Node,
 
-    pub fn iterate(self: &NodeSwitchElse, index: usize) ?&Node {
-        return null;
-    }
+        pub fn iterate(self: &SwitchCase, index: usize) ?&Node {
+            var i = index;
 
-    pub fn firstToken(self: &NodeSwitchElse) Token {
-        return self.token;
-    }
+            if (i < self.items.len) return self.items.at(i);
+            i -= self.items.len;
 
-    pub fn lastToken(self: &NodeSwitchElse) Token {
-        return self.token;
-    }
-};
+            if (self.payload) |payload| {
+                if (i < 1) return payload;
+                i -= 1;
+            }
 
-pub const NodeWhile = struct {
-    base: Node,
-    label: ?Token,
-    inline_token: ?Token,
-    while_token: Token,
-    condition: &Node,
-    payload: ?&Node,
-    continue_expr: ?&Node,
-    body: &Node,
-    @"else": ?&NodeElse,
-
-    pub fn iterate(self: &NodeWhile, index: usize) ?&Node {
-        var i = index;
-
-        if (i < 1) return self.condition;
-        i -= 1;
-
-        if (self.payload) |payload| {
-            if (i < 1) return payload;
+            if (i < 1) return self.expr;
             i -= 1;
-        }
 
-        if (self.continue_expr) |continue_expr| {
-            if (i < 1) return continue_expr;
-            i -= 1;
+            return null;
         }
 
-        if (i < 1) return self.body;
-        i -= 1;
+        pub fn firstToken(self: &SwitchCase) Token {
+            return self.items.at(0).firstToken();
+        }
 
-        if (self.@"else") |@"else"| {
-            if (i < 1) return &@"else".base;
-            i -= 1;
+        pub fn lastToken(self: &SwitchCase) Token {
+            return self.expr.lastToken();
         }
+    };
 
-        return null;
-    }
+    pub const SwitchElse = struct {
+        base: Node,
+        token: Token,
 
-    pub fn firstToken(self: &NodeWhile) Token {
-        if (self.label) |label| {
-            return label;
+        pub fn iterate(self: &SwitchElse, index: usize) ?&Node {
+            return null;
         }
 
-        if (self.inline_token) |inline_token| {
-            return inline_token;
+        pub fn firstToken(self: &SwitchElse) Token {
+            return self.token;
         }
 
-        return self.while_token;
-    }
-
-    pub fn lastToken(self: &NodeWhile) Token {
-        if (self.@"else") |@"else"| {
-            return @"else".body.lastToken();
+        pub fn lastToken(self: &SwitchElse) Token {
+            return self.token;
         }
+    };
 
-        return self.body.lastToken();
-    }
-};
-
-pub const NodeFor = struct {
-    base: Node,
-    label: ?Token,
-    inline_token: ?Token,
-    for_token: Token,
-    array_expr: &Node,
-    payload: ?&Node,
-    body: &Node,
-    @"else": ?&NodeElse,
+    pub const While = struct {
+        base: Node,
+        label: ?Token,
+        inline_token: ?Token,
+        while_token: Token,
+        condition: &Node,
+        payload: ?&Node,
+        continue_expr: ?&Node,
+        body: &Node,
+        @"else": ?&Else,
+
+        pub fn iterate(self: &While, index: usize) ?&Node {
+            var i = index;
+
+            if (i < 1) return self.condition;
+            i -= 1;
 
-    pub fn iterate(self: &NodeFor, index: usize) ?&Node {
-        var i = index;
+            if (self.payload) |payload| {
+                if (i < 1) return payload;
+                i -= 1;
+            }
 
-        if (i < 1) return self.array_expr;
-        i -= 1;
+            if (self.continue_expr) |continue_expr| {
+                if (i < 1) return continue_expr;
+                i -= 1;
+            }
 
-        if (self.payload) |payload| {
-            if (i < 1) return payload;
+            if (i < 1) return self.body;
             i -= 1;
-        }
 
-        if (i < 1) return self.body;
-        i -= 1;
+            if (self.@"else") |@"else"| {
+                if (i < 1) return &@"else".base;
+                i -= 1;
+            }
 
-        if (self.@"else") |@"else"| {
-            if (i < 1) return &@"else".base;
-            i -= 1;
+            return null;
         }
 
-        return null;
-    }
+        pub fn firstToken(self: &While) Token {
+            if (self.label) |label| {
+                return label;
+            }
 
-    pub fn firstToken(self: &NodeFor) Token {
-        if (self.label) |label| {
-            return label;
-        }
+            if (self.inline_token) |inline_token| {
+                return inline_token;
+            }
 
-        if (self.inline_token) |inline_token| {
-            return inline_token;
+            return self.while_token;
         }
 
-        return self.for_token;
-    }
+        pub fn lastToken(self: &While) Token {
+            if (self.@"else") |@"else"| {
+                return @"else".body.lastToken();
+            }
 
-    pub fn lastToken(self: &NodeFor) Token {
-        if (self.@"else") |@"else"| {
-            return @"else".body.lastToken();
+            return self.body.lastToken();
         }
+    };
 
-        return self.body.lastToken();
-    }
-};
+    pub const For = struct {
+        base: Node,
+        label: ?Token,
+        inline_token: ?Token,
+        for_token: Token,
+        array_expr: &Node,
+        payload: ?&Node,
+        body: &Node,
+        @"else": ?&Else,
 
-pub const NodeIf = struct {
-    base: Node,
-    if_token: Token,
-    condition: &Node,
-    payload: ?&Node,
-    body: &Node,
-    @"else": ?&NodeElse,
+        pub fn iterate(self: &For, index: usize) ?&Node {
+            var i = index;
 
-    pub fn iterate(self: &NodeIf, index: usize) ?&Node {
-        var i = index;
+            if (i < 1) return self.array_expr;
+            i -= 1;
 
-        if (i < 1) return self.condition;
-        i -= 1;
+            if (self.payload) |payload| {
+                if (i < 1) return payload;
+                i -= 1;
+            }
 
-        if (self.payload) |payload| {
-            if (i < 1) return payload;
+            if (i < 1) return self.body;
             i -= 1;
-        }
 
-        if (i < 1) return self.body;
-        i -= 1;
+            if (self.@"else") |@"else"| {
+                if (i < 1) return &@"else".base;
+                i -= 1;
+            }
 
-        if (self.@"else") |@"else"| {
-            if (i < 1) return &@"else".base;
-            i -= 1;
+            return null;
         }
 
-        return null;
-    }
+        pub fn firstToken(self: &For) Token {
+            if (self.label) |label| {
+                return label;
+            }
 
-    pub fn firstToken(self: &NodeIf) Token {
-        return self.if_token;
-    }
+            if (self.inline_token) |inline_token| {
+                return inline_token;
+            }
 
-    pub fn lastToken(self: &NodeIf) Token {
-        if (self.@"else") |@"else"| {
-            return @"else".body.lastToken();
+            return self.for_token;
         }
 
-        return self.body.lastToken();
-    }
-};
+        pub fn lastToken(self: &For) Token {
+            if (self.@"else") |@"else"| {
+                return @"else".body.lastToken();
+            }
 
-pub const NodeInfixOp = struct {
-    base: Node,
-    op_token: Token,
-    lhs: &Node,
-    op: InfixOp,
-    rhs: &Node,
-
-    const InfixOp = union(enum) {
-        Add,
-        AddWrap,
-        ArrayCat,
-        ArrayMult,
-        Assign,
-        AssignBitAnd,
-        AssignBitOr,
-        AssignBitShiftLeft,
-        AssignBitShiftRight,
-        AssignBitXor,
-        AssignDiv,
-        AssignMinus,
-        AssignMinusWrap,
-        AssignMod,
-        AssignPlus,
-        AssignPlusWrap,
-        AssignTimes,
-        AssignTimesWarp,
-        BangEqual,
-        BitAnd,
-        BitOr,
-        BitShiftLeft,
-        BitShiftRight,
-        BitXor,
-        BoolAnd,
-        BoolOr,
-        Catch: ?&Node,
-        Div,
-        EqualEqual,
-        ErrorUnion,
-        GreaterOrEqual,
-        GreaterThan,
-        LessOrEqual,
-        LessThan,
-        MergeErrorSets,
-        Mod,
-        Mult,
-        MultWrap,
-        Period,
-        Range,
-        Sub,
-        SubWrap,
-        UnwrapMaybe,
+            return self.body.lastToken();
+        }
     };
 
-    pub fn iterate(self: &NodeInfixOp, index: usize) ?&Node {
-        var i = index;
+    pub const If = struct {
+        base: Node,
+        if_token: Token,
+        condition: &Node,
+        payload: ?&Node,
+        body: &Node,
+        @"else": ?&Else,
 
-        if (i < 1) return self.lhs;
-        i -= 1;
+        pub fn iterate(self: &If, index: usize) ?&Node {
+            var i = index;
 
-        switch (self.op) {
-            InfixOp.Catch => |maybe_payload| {
-                if (maybe_payload) |payload| {
-                    if (i < 1) return payload;
-                    i -= 1;
-                }
-            },
-
-            InfixOp.Add,
-            InfixOp.AddWrap,
-            InfixOp.ArrayCat,
-            InfixOp.ArrayMult,
-            InfixOp.Assign,
-            InfixOp.AssignBitAnd,
-            InfixOp.AssignBitOr,
-            InfixOp.AssignBitShiftLeft,
-            InfixOp.AssignBitShiftRight,
-            InfixOp.AssignBitXor,
-            InfixOp.AssignDiv,
-            InfixOp.AssignMinus,
-            InfixOp.AssignMinusWrap,
-            InfixOp.AssignMod,
-            InfixOp.AssignPlus,
-            InfixOp.AssignPlusWrap,
-            InfixOp.AssignTimes,
-            InfixOp.AssignTimesWarp,
-            InfixOp.BangEqual,
-            InfixOp.BitAnd,
-            InfixOp.BitOr,
-            InfixOp.BitShiftLeft,
-            InfixOp.BitShiftRight,
-            InfixOp.BitXor,
-            InfixOp.BoolAnd,
-            InfixOp.BoolOr,
-            InfixOp.Div,
-            InfixOp.EqualEqual,
-            InfixOp.ErrorUnion,
-            InfixOp.GreaterOrEqual,
-            InfixOp.GreaterThan,
-            InfixOp.LessOrEqual,
-            InfixOp.LessThan,
-            InfixOp.MergeErrorSets,
-            InfixOp.Mod,
-            InfixOp.Mult,
-            InfixOp.MultWrap,
-            InfixOp.Period,
-            InfixOp.Range,
-            InfixOp.Sub,
-            InfixOp.SubWrap,
-            InfixOp.UnwrapMaybe => {},
-        }
-
-        if (i < 1) return self.rhs;
-        i -= 1;
-
-        return null;
-    }
+            if (i < 1) return self.condition;
+            i -= 1;
 
-    pub fn firstToken(self: &NodeInfixOp) Token {
-        return self.lhs.firstToken();
-    }
+            if (self.payload) |payload| {
+                if (i < 1) return payload;
+                i -= 1;
+            }
 
-    pub fn lastToken(self: &NodeInfixOp) Token {
-        return self.rhs.lastToken();
-    }
-};
+            if (i < 1) return self.body;
+            i -= 1;
 
-pub const NodePrefixOp = struct {
-    base: Node,
-    op_token: Token,
-    op: PrefixOp,
-    rhs: &Node,
-
-    const PrefixOp = union(enum) {
-        AddrOf: AddrOfInfo,
-        ArrayType: &Node,
-        Await,
-        BitNot,
-        BoolNot,
-        Cancel,
-        Deref,
-        MaybeType,
-        Negation,
-        NegationWrap,
-        Resume,
-        SliceType: AddrOfInfo,
-        Try,
-        UnwrapMaybe,
-    };
+            if (self.@"else") |@"else"| {
+                if (i < 1) return &@"else".base;
+                i -= 1;
+            }
 
-    const AddrOfInfo = struct {
-        align_expr: ?&Node,
-        bit_offset_start_token: ?Token,
-        bit_offset_end_token: ?Token,
-        const_token: ?Token,
-        volatile_token: ?Token,
-    };
+            return null;
+        }
 
-    pub fn iterate(self: &NodePrefixOp, index: usize) ?&Node {
-        var i = index;
+        pub fn firstToken(self: &If) Token {
+            return self.if_token;
+        }
 
-        switch (self.op) {
-            PrefixOp.SliceType => |addr_of_info| {
-                if (addr_of_info.align_expr) |align_expr| {
-                    if (i < 1) return align_expr;
-                    i -= 1;
-                }
-            },
-            PrefixOp.AddrOf => |addr_of_info| {
-                if (addr_of_info.align_expr) |align_expr| {
-                    if (i < 1) return align_expr;
-                    i -= 1;
-                }
-            },
-            PrefixOp.ArrayType => |size_expr| {
-                if (i < 1) return size_expr;
-                i -= 1;
-            },
-            PrefixOp.Await,
-            PrefixOp.BitNot,
-            PrefixOp.BoolNot,
-            PrefixOp.Cancel,
-            PrefixOp.Deref,
-            PrefixOp.MaybeType,
-            PrefixOp.Negation,
-            PrefixOp.NegationWrap,
-            PrefixOp.Try,
-            PrefixOp.Resume,
-            PrefixOp.UnwrapMaybe => {},
-        }
-
-        if (i < 1) return self.rhs;
-        i -= 1;
-
-        return null;
-    }
+        pub fn lastToken(self: &If) Token {
+            if (self.@"else") |@"else"| {
+                return @"else".body.lastToken();
+            }
 
-    pub fn firstToken(self: &NodePrefixOp) Token {
-        return self.op_token;
-    }
+            return self.body.lastToken();
+        }
+    };
 
-    pub fn lastToken(self: &NodePrefixOp) Token {
-        return self.rhs.lastToken();
-    }
-};
+    pub const InfixOp = struct {
+        base: Node,
+        op_token: Token,
+        lhs: &Node,
+        op: Op,
+        rhs: &Node,
+
+        pub const Op = union(enum) {
+            Add,
+            AddWrap,
+            ArrayCat,
+            ArrayMult,
+            Assign,
+            AssignBitAnd,
+            AssignBitOr,
+            AssignBitShiftLeft,
+            AssignBitShiftRight,
+            AssignBitXor,
+            AssignDiv,
+            AssignMinus,
+            AssignMinusWrap,
+            AssignMod,
+            AssignPlus,
+            AssignPlusWrap,
+            AssignTimes,
+            AssignTimesWarp,
+            BangEqual,
+            BitAnd,
+            BitOr,
+            BitShiftLeft,
+            BitShiftRight,
+            BitXor,
+            BoolAnd,
+            BoolOr,
+            Catch: ?&Node,
+            Div,
+            EqualEqual,
+            ErrorUnion,
+            GreaterOrEqual,
+            GreaterThan,
+            LessOrEqual,
+            LessThan,
+            MergeErrorSets,
+            Mod,
+            Mult,
+            MultWrap,
+            Period,
+            Range,
+            Sub,
+            SubWrap,
+            UnwrapMaybe,
+        };
 
-pub const NodeFieldInitializer = struct {
-    base: Node,
-    period_token: Token,
-    name_token: Token,
-    expr: &Node,
+        pub fn iterate(self: &InfixOp, index: usize) ?&Node {
+            var i = index;
 
-    pub fn iterate(self: &NodeFieldInitializer, index: usize) ?&Node {
-        var i = index;
+            if (i < 1) return self.lhs;
+            i -= 1;
 
-        if (i < 1) return self.expr;
-        i -= 1;
+            switch (self.op) {
+                Op.Catch => |maybe_payload| {
+                    if (maybe_payload) |payload| {
+                        if (i < 1) return payload;
+                        i -= 1;
+                    }
+                },
+
+                Op.Add,
+                Op.AddWrap,
+                Op.ArrayCat,
+                Op.ArrayMult,
+                Op.Assign,
+                Op.AssignBitAnd,
+                Op.AssignBitOr,
+                Op.AssignBitShiftLeft,
+                Op.AssignBitShiftRight,
+                Op.AssignBitXor,
+                Op.AssignDiv,
+                Op.AssignMinus,
+                Op.AssignMinusWrap,
+                Op.AssignMod,
+                Op.AssignPlus,
+                Op.AssignPlusWrap,
+                Op.AssignTimes,
+                Op.AssignTimesWarp,
+                Op.BangEqual,
+                Op.BitAnd,
+                Op.BitOr,
+                Op.BitShiftLeft,
+                Op.BitShiftRight,
+                Op.BitXor,
+                Op.BoolAnd,
+                Op.BoolOr,
+                Op.Div,
+                Op.EqualEqual,
+                Op.ErrorUnion,
+                Op.GreaterOrEqual,
+                Op.GreaterThan,
+                Op.LessOrEqual,
+                Op.LessThan,
+                Op.MergeErrorSets,
+                Op.Mod,
+                Op.Mult,
+                Op.MultWrap,
+                Op.Period,
+                Op.Range,
+                Op.Sub,
+                Op.SubWrap,
+                Op.UnwrapMaybe => {},
+            }
 
-        return null;
-    }
+            if (i < 1) return self.rhs;
+            i -= 1;
 
-    pub fn firstToken(self: &NodeFieldInitializer) Token {
-        return self.period_token;
-    }
+            return null;
+        }
 
-    pub fn lastToken(self: &NodeFieldInitializer) Token {
-        return self.expr.lastToken();
-    }
-};
+        pub fn firstToken(self: &InfixOp) Token {
+            return self.lhs.firstToken();
+        }
 
-pub const NodeSuffixOp = struct {
-    base: Node,
-    lhs: &Node,
-    op: SuffixOp,
-    rtoken: Token,
-
-    const SuffixOp = union(enum) {
-        Call: CallInfo,
-        ArrayAccess: &Node,
-        Slice: SliceRange,
-        ArrayInitializer: ArrayList(&Node),
-        StructInitializer: ArrayList(&NodeFieldInitializer),
+        pub fn lastToken(self: &InfixOp) Token {
+            return self.rhs.lastToken();
+        }
     };
 
-    const CallInfo = struct {
-        params: ArrayList(&Node),
-        async_attr: ?&NodeAsyncAttribute,
-    };
+    pub const PrefixOp = struct {
+        base: Node,
+        op_token: Token,
+        op: Op,
+        rhs: &Node,
+
+        const Op = union(enum) {
+            AddrOf: AddrOfInfo,
+            ArrayType: &Node,
+            Await,
+            BitNot,
+            BoolNot,
+            Cancel,
+            Deref,
+            MaybeType,
+            Negation,
+            NegationWrap,
+            Resume,
+            SliceType: AddrOfInfo,
+            Try,
+            UnwrapMaybe,
+        };
 
-    const SliceRange = struct {
-        start: &Node,
-        end: ?&Node,
-    };
+        const AddrOfInfo = struct {
+            align_expr: ?&Node,
+            bit_offset_start_token: ?Token,
+            bit_offset_end_token: ?Token,
+            const_token: ?Token,
+            volatile_token: ?Token,
+        };
 
-    pub fn iterate(self: &NodeSuffixOp, index: usize) ?&Node {
-        var i = index;
+        pub fn iterate(self: &PrefixOp, index: usize) ?&Node {
+            var i = index;
+
+            switch (self.op) {
+                Op.SliceType => |addr_of_info| {
+                    if (addr_of_info.align_expr) |align_expr| {
+                        if (i < 1) return align_expr;
+                        i -= 1;
+                    }
+                },
+                Op.AddrOf => |addr_of_info| {
+                    if (addr_of_info.align_expr) |align_expr| {
+                        if (i < 1) return align_expr;
+                        i -= 1;
+                    }
+                },
+                Op.ArrayType => |size_expr| {
+                    if (i < 1) return size_expr;
+                    i -= 1;
+                },
+                Op.Await,
+                Op.BitNot,
+                Op.BoolNot,
+                Op.Cancel,
+                Op.Deref,
+                Op.MaybeType,
+                Op.Negation,
+                Op.NegationWrap,
+                Op.Try,
+                Op.Resume,
+                Op.UnwrapMaybe => {},
+            }
 
-        if (i < 1) return self.lhs;
-        i -= 1;
+            if (i < 1) return self.rhs;
+            i -= 1;
 
-        switch (self.op) {
-            SuffixOp.Call => |call_info| {
-                if (i < call_info.params.len) return call_info.params.at(i);
-                i -= call_info.params.len;
-            },
-            SuffixOp.ArrayAccess => |index_expr| {
-                if (i < 1) return index_expr;
-                i -= 1;
-            },
-            SuffixOp.Slice => |range| {
-                if (i < 1) return range.start;
-                i -= 1;
+            return null;
+        }
 
-                if (range.end) |end| {
-                    if (i < 1) return end;
-                    i -= 1;
-                }
-            },
-            SuffixOp.ArrayInitializer => |exprs| {
-                if (i < exprs.len) return exprs.at(i);
-                i -= exprs.len;
-            },
-            SuffixOp.StructInitializer => |fields| {
-                if (i < fields.len) return &fields.at(i).base;
-                i -= fields.len;
-            },
-        }
-
-        return null;
-    }
+        pub fn firstToken(self: &PrefixOp) Token {
+            return self.op_token;
+        }
 
-    pub fn firstToken(self: &NodeSuffixOp) Token {
-        return self.lhs.firstToken();
-    }
+        pub fn lastToken(self: &PrefixOp) Token {
+            return self.rhs.lastToken();
+        }
+    };
 
-    pub fn lastToken(self: &NodeSuffixOp) Token {
-        return self.rtoken;
-    }
-};
+    pub const FieldInitializer = struct {
+        base: Node,
+        period_token: Token,
+        name_token: Token,
+        expr: &Node,
 
-pub const NodeGroupedExpression = struct {
-    base: Node,
-    lparen: Token,
-    expr: &Node,
-    rparen: Token,
+        pub fn iterate(self: &FieldInitializer, index: usize) ?&Node {
+            var i = index;
 
-    pub fn iterate(self: &NodeGroupedExpression, index: usize) ?&Node {
-        var i = index;
+            if (i < 1) return self.expr;
+            i -= 1;
 
-        if (i < 1) return self.expr;
-        i -= 1;
+            return null;
+        }
 
-        return null;
-    }
+        pub fn firstToken(self: &FieldInitializer) Token {
+            return self.period_token;
+        }
 
-    pub fn firstToken(self: &NodeGroupedExpression) Token {
-        return self.lparen;
-    }
+        pub fn lastToken(self: &FieldInitializer) Token {
+            return self.expr.lastToken();
+        }
+    };
 
-    pub fn lastToken(self: &NodeGroupedExpression) Token {
-        return self.rparen;
-    }
-};
+    pub const SuffixOp = struct {
+        base: Node,
+        lhs: &Node,
+        op: Op,
+        rtoken: Token,
+
+        const Op = union(enum) {
+            Call: CallInfo,
+            ArrayAccess: &Node,
+            Slice: SliceRange,
+            ArrayInitializer: ArrayList(&Node),
+            StructInitializer: ArrayList(&FieldInitializer),
+        };
+
+        const CallInfo = struct {
+            params: ArrayList(&Node),
+            async_attr: ?&AsyncAttribute,
+        };
 
-pub const NodeControlFlowExpression = struct {
-    base: Node,
-    ltoken: Token,
-    kind: Kind,
-    rhs: ?&Node,
+        const SliceRange = struct {
+            start: &Node,
+            end: ?&Node,
+        };
 
-    const Kind = union(enum) {
-        Break: ?&Node,
-        Continue: ?&Node,
-        Return,
-    };
+        pub fn iterate(self: &SuffixOp, index: usize) ?&Node {
+            var i = index;
 
-    pub fn iterate(self: &NodeControlFlowExpression, index: usize) ?&Node {
-        var i = index;
+            if (i < 1) return self.lhs;
+            i -= 1;
 
-        switch (self.kind) {
-            Kind.Break => |maybe_label| {
-                if (maybe_label) |label| {
-                    if (i < 1) return label;
+            switch (self.op) {
+                Op.Call => |call_info| {
+                    if (i < call_info.params.len) return call_info.params.at(i);
+                    i -= call_info.params.len;
+                },
+                Op.ArrayAccess => |index_expr| {
+                    if (i < 1) return index_expr;
                     i -= 1;
-                }
-            },
-            Kind.Continue => |maybe_label| {
-                if (maybe_label) |label| {
-                    if (i < 1) return label;
+                },
+                Op.Slice => |range| {
+                    if (i < 1) return range.start;
                     i -= 1;
-                }
-            },
-            Kind.Return => {},
+
+                    if (range.end) |end| {
+                        if (i < 1) return end;
+                        i -= 1;
+                    }
+                },
+                Op.ArrayInitializer => |exprs| {
+                    if (i < exprs.len) return exprs.at(i);
+                    i -= exprs.len;
+                },
+                Op.StructInitializer => |fields| {
+                    if (i < fields.len) return &fields.at(i).base;
+                    i -= fields.len;
+                },
+            }
+
+            return null;
         }
 
-        if (self.rhs) |rhs| {
-            if (i < 1) return rhs;
-            i -= 1;
+        pub fn firstToken(self: &SuffixOp) Token {
+            return self.lhs.firstToken();
         }
 
-        return null;
-    }
+        pub fn lastToken(self: &SuffixOp) Token {
+            return self.rtoken;
+        }
+    };
 
-    pub fn firstToken(self: &NodeControlFlowExpression) Token {
-        return self.ltoken;
-    }
+    pub const GroupedExpression = struct {
+        base: Node,
+        lparen: Token,
+        expr: &Node,
+        rparen: Token,
+
+        pub fn iterate(self: &GroupedExpression, index: usize) ?&Node {
+            var i = index;
 
-    pub fn lastToken(self: &NodeControlFlowExpression) Token {
-        if (self.rhs) |rhs| {
-            return rhs.lastToken();
+            if (i < 1) return self.expr;
+            i -= 1;
+
+            return null;
         }
 
-        switch (self.kind) {
-            Kind.Break => |maybe_label| {
-                if (maybe_label) |label| {
-                    return label.lastToken();
-                }
-            },
-            Kind.Continue => |maybe_label| {
-                if (maybe_label) |label| {
-                    return label.lastToken();
-                }
-            },
-            Kind.Return => return self.ltoken,
+        pub fn firstToken(self: &GroupedExpression) Token {
+            return self.lparen;
         }
 
-        return self.ltoken;
-    }
-};
+        pub fn lastToken(self: &GroupedExpression) Token {
+            return self.rparen;
+        }
+    };
 
-pub const NodeSuspend = struct {
-    base: Node,
-    suspend_token: Token,
-    payload: ?&Node,
-    body: ?&Node,
+    pub const ControlFlowExpression = struct {
+        base: Node,
+        ltoken: Token,
+        kind: Kind,
+        rhs: ?&Node,
 
-    pub fn iterate(self: &NodeSuspend, index: usize) ?&Node {
-        var i = index;
+        const Kind = union(enum) {
+            Break: ?&Node,
+            Continue: ?&Node,
+            Return,
+        };
 
-        if (self.payload) |payload| {
-            if (i < 1) return payload;
-            i -= 1;
+        pub fn iterate(self: &ControlFlowExpression, index: usize) ?&Node {
+            var i = index;
+
+            switch (self.kind) {
+                Kind.Break => |maybe_label| {
+                    if (maybe_label) |label| {
+                        if (i < 1) return label;
+                        i -= 1;
+                    }
+                },
+                Kind.Continue => |maybe_label| {
+                    if (maybe_label) |label| {
+                        if (i < 1) return label;
+                        i -= 1;
+                    }
+                },
+                Kind.Return => {},
+            }
+
+            if (self.rhs) |rhs| {
+                if (i < 1) return rhs;
+                i -= 1;
+            }
+
+            return null;
         }
 
-        if (self.body) |body| {
-            if (i < 1) return body;
-            i -= 1;
+        pub fn firstToken(self: &ControlFlowExpression) Token {
+            return self.ltoken;
         }
 
-        return null;
-    }
+        pub fn lastToken(self: &ControlFlowExpression) Token {
+            if (self.rhs) |rhs| {
+                return rhs.lastToken();
+            }
 
-    pub fn firstToken(self: &NodeSuspend) Token {
-        return self.suspend_token;
-    }
+            switch (self.kind) {
+                Kind.Break => |maybe_label| {
+                    if (maybe_label) |label| {
+                        return label.lastToken();
+                    }
+                },
+                Kind.Continue => |maybe_label| {
+                    if (maybe_label) |label| {
+                        return label.lastToken();
+                    }
+                },
+                Kind.Return => return self.ltoken,
+            }
 
-    pub fn lastToken(self: &NodeSuspend) Token {
-        if (self.body) |body| {
-            return body.lastToken();
+            return self.ltoken;
         }
+    };
+
+    pub const Suspend = struct {
+        base: Node,
+        suspend_token: Token,
+        payload: ?&Node,
+        body: ?&Node,
+
+        pub fn iterate(self: &Suspend, index: usize) ?&Node {
+            var i = index;
+
+            if (self.payload) |payload| {
+                if (i < 1) return payload;
+                i -= 1;
+            }
 
-        if (self.payload) |payload| {
-            return payload.lastToken();
+            if (self.body) |body| {
+                if (i < 1) return body;
+                i -= 1;
+            }
+
+            return null;
         }
 
-        return self.suspend_token;
-    }
-};
+        pub fn firstToken(self: &Suspend) Token {
+            return self.suspend_token;
+        }
 
-pub const NodeIntegerLiteral = struct {
-    base: Node,
-    token: Token,
+        pub fn lastToken(self: &Suspend) Token {
+            if (self.body) |body| {
+                return body.lastToken();
+            }
 
-    pub fn iterate(self: &NodeIntegerLiteral, index: usize) ?&Node {
-        return null;
-    }
+            if (self.payload) |payload| {
+                return payload.lastToken();
+            }
 
-    pub fn firstToken(self: &NodeIntegerLiteral) Token {
-        return self.token;
-    }
+            return self.suspend_token;
+        }
+    };
 
-    pub fn lastToken(self: &NodeIntegerLiteral) Token {
-        return self.token;
-    }
-};
+    pub const IntegerLiteral = struct {
+        base: Node,
+        token: Token,
 
-pub const NodeFloatLiteral = struct {
-    base: Node,
-    token: Token,
+        pub fn iterate(self: &IntegerLiteral, index: usize) ?&Node {
+            return null;
+        }
 
-    pub fn iterate(self: &NodeFloatLiteral, index: usize) ?&Node {
-        return null;
-    }
+        pub fn firstToken(self: &IntegerLiteral) Token {
+            return self.token;
+        }
 
-    pub fn firstToken(self: &NodeFloatLiteral) Token {
-        return self.token;
-    }
+        pub fn lastToken(self: &IntegerLiteral) Token {
+            return self.token;
+        }
+    };
 
-    pub fn lastToken(self: &NodeFloatLiteral) Token {
-        return self.token;
-    }
-};
+    pub const FloatLiteral = struct {
+        base: Node,
+        token: Token,
 
-pub const NodeBuiltinCall = struct {
-    base: Node,
-    builtin_token: Token,
-    params: ArrayList(&Node),
-    rparen_token: Token,
+        pub fn iterate(self: &FloatLiteral, index: usize) ?&Node {
+            return null;
+        }
 
-    pub fn iterate(self: &NodeBuiltinCall, index: usize) ?&Node {
-        var i = index;
+        pub fn firstToken(self: &FloatLiteral) Token {
+            return self.token;
+        }
 
-        if (i < self.params.len) return self.params.at(i);
-        i -= self.params.len;
+        pub fn lastToken(self: &FloatLiteral) Token {
+            return self.token;
+        }
+    };
 
-        return null;
-    }
+    pub const BuiltinCall = struct {
+        base: Node,
+        builtin_token: Token,
+        params: ArrayList(&Node),
+        rparen_token: Token,
 
-    pub fn firstToken(self: &NodeBuiltinCall) Token {
-        return self.builtin_token;
-    }
+        pub fn iterate(self: &BuiltinCall, index: usize) ?&Node {
+            var i = index;
 
-    pub fn lastToken(self: &NodeBuiltinCall) Token {
-        return self.rparen_token;
-    }
-};
+            if (i < self.params.len) return self.params.at(i);
+            i -= self.params.len;
 
-pub const NodeStringLiteral = struct {
-    base: Node,
-    token: Token,
+            return null;
+        }
 
-    pub fn iterate(self: &NodeStringLiteral, index: usize) ?&Node {
-        return null;
-    }
+        pub fn firstToken(self: &BuiltinCall) Token {
+            return self.builtin_token;
+        }
 
-    pub fn firstToken(self: &NodeStringLiteral) Token {
-        return self.token;
-    }
+        pub fn lastToken(self: &BuiltinCall) Token {
+            return self.rparen_token;
+        }
+    };
 
-    pub fn lastToken(self: &NodeStringLiteral) Token {
-        return self.token;
-    }
-};
+    pub const StringLiteral = struct {
+        base: Node,
+        token: Token,
 
-pub const NodeMultilineStringLiteral = struct {
-    base: Node,
-    tokens: ArrayList(Token),
+        pub fn iterate(self: &StringLiteral, index: usize) ?&Node {
+            return null;
+        }
 
-    pub fn iterate(self: &NodeMultilineStringLiteral, index: usize) ?&Node {
-        return null;
-    }
+        pub fn firstToken(self: &StringLiteral) Token {
+            return self.token;
+        }
 
-    pub fn firstToken(self: &NodeMultilineStringLiteral) Token {
-        return self.tokens.at(0);
-    }
+        pub fn lastToken(self: &StringLiteral) Token {
+            return self.token;
+        }
+    };
 
-    pub fn lastToken(self: &NodeMultilineStringLiteral) Token {
-        return self.tokens.at(self.tokens.len - 1);
-    }
-};
+    pub const MultilineStringLiteral = struct {
+        base: Node,
+        tokens: ArrayList(Token),
 
-pub const NodeCharLiteral = struct {
-    base: Node,
-    token: Token,
+        pub fn iterate(self: &MultilineStringLiteral, index: usize) ?&Node {
+            return null;
+        }
 
-    pub fn iterate(self: &NodeCharLiteral, index: usize) ?&Node {
-        return null;
-    }
+        pub fn firstToken(self: &MultilineStringLiteral) Token {
+            return self.tokens.at(0);
+        }
 
-    pub fn firstToken(self: &NodeCharLiteral) Token {
-        return self.token;
-    }
+        pub fn lastToken(self: &MultilineStringLiteral) Token {
+            return self.tokens.at(self.tokens.len - 1);
+        }
+    };
 
-    pub fn lastToken(self: &NodeCharLiteral) Token {
-        return self.token;
-    }
-};
+    pub const CharLiteral = struct {
+        base: Node,
+        token: Token,
 
-pub const NodeBoolLiteral = struct {
-    base: Node,
-    token: Token,
+        pub fn iterate(self: &CharLiteral, index: usize) ?&Node {
+            return null;
+        }
 
-    pub fn iterate(self: &NodeBoolLiteral, index: usize) ?&Node {
-        return null;
-    }
+        pub fn firstToken(self: &CharLiteral) Token {
+            return self.token;
+        }
 
-    pub fn firstToken(self: &NodeBoolLiteral) Token {
-        return self.token;
-    }
+        pub fn lastToken(self: &CharLiteral) Token {
+            return self.token;
+        }
+    };
 
-    pub fn lastToken(self: &NodeBoolLiteral) Token {
-        return self.token;
-    }
-};
+    pub const BoolLiteral = struct {
+        base: Node,
+        token: Token,
 
-pub const NodeNullLiteral = struct {
-    base: Node,
-    token: Token,
+        pub fn iterate(self: &BoolLiteral, index: usize) ?&Node {
+            return null;
+        }
 
-    pub fn iterate(self: &NodeNullLiteral, index: usize) ?&Node {
-        return null;
-    }
+        pub fn firstToken(self: &BoolLiteral) Token {
+            return self.token;
+        }
 
-    pub fn firstToken(self: &NodeNullLiteral) Token {
-        return self.token;
-    }
+        pub fn lastToken(self: &BoolLiteral) Token {
+            return self.token;
+        }
+    };
 
-    pub fn lastToken(self: &NodeNullLiteral) Token {
-        return self.token;
-    }
-};
+    pub const NullLiteral = struct {
+        base: Node,
+        token: Token,
 
-pub const NodeUndefinedLiteral = struct {
-    base: Node,
-    token: Token,
+        pub fn iterate(self: &NullLiteral, index: usize) ?&Node {
+            return null;
+        }
 
-    pub fn iterate(self: &NodeUndefinedLiteral, index: usize) ?&Node {
-        return null;
-    }
+        pub fn firstToken(self: &NullLiteral) Token {
+            return self.token;
+        }
 
-    pub fn firstToken(self: &NodeUndefinedLiteral) Token {
-        return self.token;
-    }
+        pub fn lastToken(self: &NullLiteral) Token {
+            return self.token;
+        }
+    };
 
-    pub fn lastToken(self: &NodeUndefinedLiteral) Token {
-        return self.token;
-    }
-};
+    pub const UndefinedLiteral = struct {
+        base: Node,
+        token: Token,
 
-pub const NodeThisLiteral = struct {
-    base: Node,
-    token: Token,
+        pub fn iterate(self: &UndefinedLiteral, index: usize) ?&Node {
+            return null;
+        }
 
-    pub fn iterate(self: &NodeThisLiteral, index: usize) ?&Node {
-        return null;
-    }
+        pub fn firstToken(self: &UndefinedLiteral) Token {
+            return self.token;
+        }
 
-    pub fn firstToken(self: &NodeThisLiteral) Token {
-        return self.token;
-    }
+        pub fn lastToken(self: &UndefinedLiteral) Token {
+            return self.token;
+        }
+    };
 
-    pub fn lastToken(self: &NodeThisLiteral) Token {
-        return self.token;
-    }
-};
+    pub const ThisLiteral = struct {
+        base: Node,
+        token: Token,
 
-pub const NodeAsmOutput = struct {
-    base: Node,
-    symbolic_name: &Node,
-    constraint: &Node,
-    kind: Kind,
+        pub fn iterate(self: &ThisLiteral, index: usize) ?&Node {
+            return null;
+        }
 
-    const Kind = union(enum) {
-        Variable: &NodeIdentifier,
-        Return: &Node
+        pub fn firstToken(self: &ThisLiteral) Token {
+            return self.token;
+        }
+
+        pub fn lastToken(self: &ThisLiteral) Token {
+            return self.token;
+        }
     };
 
-    pub fn iterate(self: &NodeAsmOutput, index: usize) ?&Node {
-        var i = index;
+    pub const AsmOutput = struct {
+        base: Node,
+        symbolic_name: &Node,
+        constraint: &Node,
+        kind: Kind,
 
-        if (i < 1) return self.symbolic_name;
-        i -= 1;
+        const Kind = union(enum) {
+            Variable: &Identifier,
+            Return: &Node
+        };
 
-        if (i < 1) return self.constraint;
-        i -= 1;
+        pub fn iterate(self: &AsmOutput, index: usize) ?&Node {
+            var i = index;
 
-        switch (self.kind) {
-            Kind.Variable => |variable_name| {
-                if (i < 1) return &variable_name.base;
-                i -= 1;
-            },
-            Kind.Return => |return_type| {
-                if (i < 1) return return_type;
-                i -= 1;
+            if (i < 1) return self.symbolic_name;
+            i -= 1;
+
+            if (i < 1) return self.constraint;
+            i -= 1;
+
+            switch (self.kind) {
+                Kind.Variable => |variable_name| {
+                    if (i < 1) return &variable_name.base;
+                    i -= 1;
+                },
+                Kind.Return => |return_type| {
+                    if (i < 1) return return_type;
+                    i -= 1;
+                }
             }
-        }
 
-        return null;
-    }
+            return null;
+        }
 
-    pub fn firstToken(self: &NodeAsmOutput) Token {
-        return self.symbolic_name.firstToken();
-    }
+        pub fn firstToken(self: &AsmOutput) Token {
+            return self.symbolic_name.firstToken();
+        }
 
-    pub fn lastToken(self: &NodeAsmOutput) Token {
-        return switch (self.kind) {
-            Kind.Variable => |variable_name| variable_name.lastToken(),
-            Kind.Return => |return_type| return_type.lastToken(),
-        };
-    }
-};
+        pub fn lastToken(self: &AsmOutput) Token {
+            return switch (self.kind) {
+                Kind.Variable => |variable_name| variable_name.lastToken(),
+                Kind.Return => |return_type| return_type.lastToken(),
+            };
+        }
+    };
 
-pub const NodeAsmInput = struct {
-    base: Node,
-    symbolic_name: &Node,
-    constraint: &Node,
-    expr: &Node,
+    pub const AsmInput = struct {
+        base: Node,
+        symbolic_name: &Node,
+        constraint: &Node,
+        expr: &Node,
 
-    pub fn iterate(self: &NodeAsmInput, index: usize) ?&Node {
-        var i = index;
+        pub fn iterate(self: &AsmInput, index: usize) ?&Node {
+            var i = index;
 
-        if (i < 1) return self.symbolic_name;
-        i -= 1;
+            if (i < 1) return self.symbolic_name;
+            i -= 1;
 
-        if (i < 1) return self.constraint;
-        i -= 1;
+            if (i < 1) return self.constraint;
+            i -= 1;
 
-        if (i < 1) return self.expr;
-        i -= 1;
+            if (i < 1) return self.expr;
+            i -= 1;
 
-        return null;
-    }
+            return null;
+        }
 
-    pub fn firstToken(self: &NodeAsmInput) Token {
-        return self.symbolic_name.firstToken();
-    }
+        pub fn firstToken(self: &AsmInput) Token {
+            return self.symbolic_name.firstToken();
+        }
 
-    pub fn lastToken(self: &NodeAsmInput) Token {
-        return self.expr.lastToken();
-    }
-};
+        pub fn lastToken(self: &AsmInput) Token {
+            return self.expr.lastToken();
+        }
+    };
 
-pub const NodeAsm = struct {
-    base: Node,
-    asm_token: Token,
-    volatile_token: ?Token,
-    template: &Node,
-    //tokens: ArrayList(AsmToken),
-    outputs: ArrayList(&NodeAsmOutput),
-    inputs: ArrayList(&NodeAsmInput),
-    cloppers: ArrayList(&Node),
-    rparen: Token,
+    pub const Asm = struct {
+        base: Node,
+        asm_token: Token,
+        volatile_token: ?Token,
+        template: &Node,
+        //tokens: ArrayList(AsmToken),
+        outputs: ArrayList(&AsmOutput),
+        inputs: ArrayList(&AsmInput),
+        cloppers: ArrayList(&Node),
+        rparen: Token,
 
-    pub fn iterate(self: &NodeAsm, index: usize) ?&Node {
-        var i = index;
+        pub fn iterate(self: &Asm, index: usize) ?&Node {
+            var i = index;
 
-        if (i < self.outputs.len) return &self.outputs.at(index).base;
-        i -= self.outputs.len;
+            if (i < self.outputs.len) return &self.outputs.at(index).base;
+            i -= self.outputs.len;
 
-        if (i < self.inputs.len) return &self.inputs.at(index).base;
-        i -= self.inputs.len;
+            if (i < self.inputs.len) return &self.inputs.at(index).base;
+            i -= self.inputs.len;
 
-        if (i < self.cloppers.len) return self.cloppers.at(index);
-        i -= self.cloppers.len;
+            if (i < self.cloppers.len) return self.cloppers.at(index);
+            i -= self.cloppers.len;
 
-        return null;
-    }
+            return null;
+        }
 
-    pub fn firstToken(self: &NodeAsm) Token {
-        return self.asm_token;
-    }
+        pub fn firstToken(self: &Asm) Token {
+            return self.asm_token;
+        }
 
-    pub fn lastToken(self: &NodeAsm) Token {
-        return self.rparen;
-    }
-};
+        pub fn lastToken(self: &Asm) Token {
+            return self.rparen;
+        }
+    };
 
-pub const NodeUnreachable = struct {
-    base: Node,
-    token: Token,
+    pub const Unreachable = struct {
+        base: Node,
+        token: Token,
 
-    pub fn iterate(self: &NodeUnreachable, index: usize) ?&Node {
-        return null;
-    }
+        pub fn iterate(self: &Unreachable, index: usize) ?&Node {
+            return null;
+        }
 
-    pub fn firstToken(self: &NodeUnreachable) Token {
-        return self.token;
-    }
+        pub fn firstToken(self: &Unreachable) Token {
+            return self.token;
+        }
 
-    pub fn lastToken(self: &NodeUnreachable) Token {
-        return self.token;
-    }
-};
+        pub fn lastToken(self: &Unreachable) Token {
+            return self.token;
+        }
+    };
 
-pub const NodeErrorType = struct {
-    base: Node,
-    token: Token,
+    pub const ErrorType = struct {
+        base: Node,
+        token: Token,
 
-    pub fn iterate(self: &NodeErrorType, index: usize) ?&Node {
-        return null;
-    }
+        pub fn iterate(self: &ErrorType, index: usize) ?&Node {
+            return null;
+        }
 
-    pub fn firstToken(self: &NodeErrorType) Token {
-        return self.token;
-    }
+        pub fn firstToken(self: &ErrorType) Token {
+            return self.token;
+        }
 
-    pub fn lastToken(self: &NodeErrorType) Token {
-        return self.token;
-    }
-};
+        pub fn lastToken(self: &ErrorType) Token {
+            return self.token;
+        }
+    };
 
-pub const NodeVarType = struct {
-    base: Node,
-    token: Token,
+    pub const VarType = struct {
+        base: Node,
+        token: Token,
 
-    pub fn iterate(self: &NodeVarType, index: usize) ?&Node {
-        return null;
-    }
+        pub fn iterate(self: &VarType, index: usize) ?&Node {
+            return null;
+        }
 
-    pub fn firstToken(self: &NodeVarType) Token {
-        return self.token;
-    }
+        pub fn firstToken(self: &VarType) Token {
+            return self.token;
+        }
 
-    pub fn lastToken(self: &NodeVarType) Token {
-        return self.token;
-    }
-};
+        pub fn lastToken(self: &VarType) Token {
+            return self.token;
+        }
+    };
 
-pub const NodeLineComment = struct {
-    base: Node,
-    lines: ArrayList(Token),
+    pub const LineComment = struct {
+        base: Node,
+        lines: ArrayList(Token),
 
-    pub fn iterate(self: &NodeLineComment, index: usize) ?&Node {
-        return null;
-    }
+        pub fn iterate(self: &LineComment, index: usize) ?&Node {
+            return null;
+        }
 
-    pub fn firstToken(self: &NodeLineComment) Token {
-        return self.lines.at(0);
-    }
+        pub fn firstToken(self: &LineComment) Token {
+            return self.lines.at(0);
+        }
 
-    pub fn lastToken(self: &NodeLineComment) Token {
-        return self.lines.at(self.lines.len - 1);
-    }
-};
+        pub fn lastToken(self: &LineComment) Token {
+            return self.lines.at(self.lines.len - 1);
+        }
+    };
 
-pub const NodeTestDecl = struct {
-    base: Node,
-    test_token: Token,
-    name: &Node,
-    body_node: &Node,
+    pub const TestDecl = struct {
+        base: Node,
+        comments: ?&LineComment,
+        test_token: Token,
+        name: &Node,
+        body_node: &Node,
 
-    pub fn iterate(self: &NodeTestDecl, index: usize) ?&Node {
-        var i = index;
+        pub fn iterate(self: &TestDecl, index: usize) ?&Node {
+            var i = index;
 
-        if (i < 1) return self.body_node;
-        i -= 1;
+            if (i < 1) return self.body_node;
+            i -= 1;
 
-        return null;
-    }
+            return null;
+        }
 
-    pub fn firstToken(self: &NodeTestDecl) Token {
-        return self.test_token;
-    }
+        pub fn firstToken(self: &TestDecl) Token {
+            return self.test_token;
+        }
 
-    pub fn lastToken(self: &NodeTestDecl) Token {
-        return self.body_node.lastToken();
-    }
+        pub fn lastToken(self: &TestDecl) Token {
+            return self.body_node.lastToken();
+        }
+    };
 };
+
std/zig/parser.zig
@@ -18,10 +18,10 @@ pub const Parser = struct {
     put_back_tokens: [2]Token,
     put_back_count: usize,
     source_file_name: []const u8,
-    pending_line_comment_node: ?&ast.NodeLineComment,
+    pending_line_comment_node: ?&ast.Node.LineComment,
 
     pub const Tree = struct {
-        root_node: &ast.NodeRoot,
+        root_node: &ast.Node.Root,
         arena_allocator: std.heap.ArenaAllocator,
 
         pub fn deinit(self: &Tree) void {
@@ -66,22 +66,24 @@ pub const Parser = struct {
         extern_export_token: ?Token,
         lib_name: ?&ast.Node,
         list: &ArrayList(&ast.Node),
+        comments: ?&ast.Node.LineComment,
     };
 
     const TopLevelExternOrFieldCtx = struct {
         visib_token: Token,
-        container_decl: &ast.NodeContainerDecl,
+        container_decl: &ast.Node.ContainerDecl,
     };
 
     const ExternTypeCtx = struct {
         opt_ctx: OptionalCtx,
         extern_token: Token,
+        comments: ?&ast.Node.LineComment,
     };
 
     const ContainerKindCtx = struct {
         opt_ctx: OptionalCtx,
         ltoken: Token,
-        layout: ast.NodeContainerDecl.Layout,
+        layout: ast.Node.ContainerDecl.Layout,
     };
 
     const ExpectTokenSave = struct {
@@ -132,7 +134,7 @@ pub const Parser = struct {
 
     const AsyncEndCtx = struct {
         ctx: OptionalCtx,
-        attribute: &ast.NodeAsyncAttribute,
+        attribute: &ast.Node.AsyncAttribute,
     };
 
     const ErrorTypeOrSetDeclCtx = struct {
@@ -141,13 +143,13 @@ pub const Parser = struct {
     };
 
     const ParamDeclEndCtx = struct {
-        fn_proto: &ast.NodeFnProto,
-        param_decl: &ast.NodeParamDecl,
+        fn_proto: &ast.Node.FnProto,
+        param_decl: &ast.Node.ParamDecl,
     };
 
     const ComptimeStatementCtx = struct {
         comptime_token: Token,
-        block: &ast.NodeBlock,
+        block: &ast.Node.Block,
     };
 
     const OptionalCtx = union(enum) {
@@ -190,24 +192,24 @@ pub const Parser = struct {
         TopLevelExternOrField: TopLevelExternOrFieldCtx,
 
         ContainerKind: ContainerKindCtx,
-        ContainerInitArgStart: &ast.NodeContainerDecl,
-        ContainerInitArg: &ast.NodeContainerDecl,
-        ContainerDecl: &ast.NodeContainerDecl,
+        ContainerInitArgStart: &ast.Node.ContainerDecl,
+        ContainerInitArg: &ast.Node.ContainerDecl,
+        ContainerDecl: &ast.Node.ContainerDecl,
 
         VarDecl: VarDeclCtx,
-        VarDeclAlign: &ast.NodeVarDecl,
-        VarDeclEq: &ast.NodeVarDecl,
+        VarDeclAlign: &ast.Node.VarDecl,
+        VarDeclEq: &ast.Node.VarDecl,
 
-        FnDef: &ast.NodeFnProto,
-        FnProto: &ast.NodeFnProto,
-        FnProtoAlign: &ast.NodeFnProto,
-        FnProtoReturnType: &ast.NodeFnProto,
+        FnDef: &ast.Node.FnProto,
+        FnProto: &ast.Node.FnProto,
+        FnProtoAlign: &ast.Node.FnProto,
+        FnProtoReturnType: &ast.Node.FnProto,
 
-        ParamDecl: &ast.NodeFnProto,
-        ParamDeclAliasOrComptime: &ast.NodeParamDecl,
-        ParamDeclName: &ast.NodeParamDecl,
+        ParamDecl: &ast.Node.FnProto,
+        ParamDeclAliasOrComptime: &ast.Node.ParamDecl,
+        ParamDeclName: &ast.Node.ParamDecl,
         ParamDeclEnd: ParamDeclEndCtx,
-        ParamDeclComma: &ast.NodeFnProto,
+        ParamDeclComma: &ast.Node.FnProto,
 
         MaybeLabeledExpression: MaybeLabeledExpressionCtx,
         LabeledExpression: LabelCtx,
@@ -215,39 +217,39 @@ pub const Parser = struct {
         While: LoopCtx,
         WhileContinueExpr: &?&ast.Node,
         For: LoopCtx,
-        Else: &?&ast.NodeElse,
+        Else: &?&ast.Node.Else,
 
-        Block: &ast.NodeBlock,
-        Statement: &ast.NodeBlock,
+        Block: &ast.Node.Block,
+        Statement: &ast.Node.Block,
         ComptimeStatement: ComptimeStatementCtx,
         Semicolon: &&ast.Node,
 
-        AsmOutputItems: &ArrayList(&ast.NodeAsmOutput),
-        AsmOutputReturnOrType: &ast.NodeAsmOutput,
-        AsmInputItems: &ArrayList(&ast.NodeAsmInput),
+        AsmOutputItems: &ArrayList(&ast.Node.AsmOutput),
+        AsmOutputReturnOrType: &ast.Node.AsmOutput,
+        AsmInputItems: &ArrayList(&ast.Node.AsmInput),
         AsmClopperItems: &ArrayList(&ast.Node),
 
         ExprListItemOrEnd: ExprListCtx,
         ExprListCommaOrEnd: ExprListCtx,
-        FieldInitListItemOrEnd: ListSave(&ast.NodeFieldInitializer),
-        FieldInitListCommaOrEnd: ListSave(&ast.NodeFieldInitializer),
-        FieldListCommaOrEnd: &ast.NodeContainerDecl,
+        FieldInitListItemOrEnd: ListSave(&ast.Node.FieldInitializer),
+        FieldInitListCommaOrEnd: ListSave(&ast.Node.FieldInitializer),
+        FieldListCommaOrEnd: &ast.Node.ContainerDecl,
         IdentifierListItemOrEnd: ListSave(&ast.Node),
         IdentifierListCommaOrEnd: ListSave(&ast.Node),
-        SwitchCaseOrEnd: ListSave(&ast.NodeSwitchCase),
-        SwitchCaseCommaOrEnd: ListSave(&ast.NodeSwitchCase),
+        SwitchCaseOrEnd: ListSave(&ast.Node.SwitchCase),
+        SwitchCaseCommaOrEnd: ListSave(&ast.Node.SwitchCase),
         SwitchCaseFirstItem: &ArrayList(&ast.Node),
         SwitchCaseItem: &ArrayList(&ast.Node),
         SwitchCaseItemCommaOrEnd: &ArrayList(&ast.Node),
 
-        SuspendBody: &ast.NodeSuspend,
-        AsyncAllocator: &ast.NodeAsyncAttribute,
+        SuspendBody: &ast.Node.Suspend,
+        AsyncAllocator: &ast.Node.AsyncAttribute,
         AsyncEnd: AsyncEndCtx,
 
         ExternType: ExternTypeCtx,
-        SliceOrArrayAccess: &ast.NodeSuffixOp,
-        SliceOrArrayType: &ast.NodePrefixOp,
-        AddrOfModifiers: &ast.NodePrefixOp.AddrOfInfo,
+        SliceOrArrayAccess: &ast.Node.SuffixOp,
+        SliceOrArrayType: &ast.Node.PrefixOp,
+        AddrOfModifiers: &ast.Node.PrefixOp.AddrOfInfo,
 
         Payload: OptionalCtx,
         PointerPayload: OptionalCtx,
@@ -310,8 +312,8 @@ pub const Parser = struct {
         errdefer arena_allocator.deinit();
 
         const arena = &arena_allocator.allocator;
-        const root_node = try self.createNode(arena, ast.NodeRoot,
-            ast.NodeRoot {
+        const root_node = try self.createNode(arena, ast.Node.Root,
+            ast.Node.Root {
                 .base = undefined,
                 .decls = ArrayList(&ast.Node).init(arena),
                 // initialized when we get the eof token
@@ -334,43 +336,19 @@ pub const Parser = struct {
             //    warn("\n");
             //}
 
-            // look for line comments
-            while (true) {
-                if (self.eatToken(Token.Id.LineComment)) |line_comment| {
-                    const node = blk: {
-                        if (self.pending_line_comment_node) |comment_node| {
-                            break :blk comment_node;
-                        } else {
-                            const comment_node = try arena.create(ast.NodeLineComment);
-                            *comment_node = ast.NodeLineComment {
-                                .base = ast.Node {
-                                    .id = ast.Node.Id.LineComment,
-                                    .comment = null,
-                                },
-                                .lines = ArrayList(Token).init(arena),
-                            };
-                            self.pending_line_comment_node = comment_node;
-                            break :blk comment_node;
-                        }
-                    };
-                    try node.lines.append(line_comment);
-                    continue;
-                }
-                break;
-            }
-
             // This gives us 1 free append that can't fail
             const state = stack.pop();
 
             switch (state) {
                 State.TopLevel => {
+                    const comments = try self.eatComments(arena);
                     const token = self.getNextToken();
                     switch (token.id) {
                         Token.Id.Keyword_test => {
                             stack.append(State.TopLevel) catch unreachable;
 
-                            const block = try self.createNode(arena, ast.NodeBlock,
-                                ast.NodeBlock {
+                            const block = try self.createNode(arena, ast.Node.Block,
+                                ast.Node.Block {
                                     .base = undefined,
                                     .label = null,
                                     .lbrace = undefined,
@@ -378,9 +356,10 @@ pub const Parser = struct {
                                     .rbrace = undefined,
                                 }
                             );
-                            const test_node = try self.createAttachNode(arena, &root_node.decls, ast.NodeTestDecl,
-                                ast.NodeTestDecl {
+                            const test_node = try self.createAttachNode(arena, &root_node.decls, ast.Node.TestDecl,
+                                ast.Node.TestDecl {
                                     .base = undefined,
+                                    .comments = comments,
                                     .test_token = token,
                                     .name = undefined,
                                     .body_node = &block.base,
@@ -413,8 +392,8 @@ pub const Parser = struct {
                             continue;
                         },
                         Token.Id.Keyword_comptime => {
-                            const block = try self.createNode(arena, ast.NodeBlock,
-                                ast.NodeBlock {
+                            const block = try self.createNode(arena, ast.Node.Block,
+                                ast.Node.Block {
                                     .base = undefined,
                                     .label = null,
                                     .lbrace = undefined,
@@ -422,8 +401,8 @@ pub const Parser = struct {
                                     .rbrace = undefined,
                                 }
                             );
-                            const node = try self.createAttachNode(arena, &root_node.decls, ast.NodeComptime,
-                                ast.NodeComptime {
+                            const node = try self.createAttachNode(arena, &root_node.decls, ast.Node.Comptime,
+                                ast.Node.Comptime {
                                     .base = undefined,
                                     .comptime_token = token,
                                     .expr = &block.base,
@@ -506,6 +485,7 @@ pub const Parser = struct {
                     continue;
                 },
                 State.TopLevelDecl => |ctx| {
+                    const comments = try self.eatComments(arena);
                     const token = self.getNextToken();
                     switch (token.id) {
                         Token.Id.Keyword_use => {
@@ -513,8 +493,8 @@ pub const Parser = struct {
                                 return self.parseError(token, "Invalid token {}", @tagName((??ctx.extern_export_inline_token).id));
                             }
 
-                            const node = try self.createAttachNode(arena, ctx.decls, ast.NodeUse,
-                                ast.NodeUse {
+                            const node = try self.createAttachNode(arena, ctx.decls, ast.Node.Use,
+                                ast.Node.Use {
                                     .base = undefined,
                                     .visib_token = ctx.visib_token,
                                     .expr = undefined,
@@ -539,6 +519,7 @@ pub const Parser = struct {
 
                             stack.append(State {
                                 .VarDecl = VarDeclCtx {
+                                    .comments = comments,
                                     .visib_token = ctx.visib_token,
                                     .lib_name = ctx.lib_name,
                                     .comptime_token = null,
@@ -551,9 +532,10 @@ pub const Parser = struct {
                         },
                         Token.Id.Keyword_fn, Token.Id.Keyword_nakedcc,
                         Token.Id.Keyword_stdcallcc, Token.Id.Keyword_async => {
-                            const fn_proto = try self.createAttachNode(arena, ctx.decls, ast.NodeFnProto,
-                                ast.NodeFnProto {
+                            const fn_proto = try self.createAttachNode(arena, ctx.decls, ast.Node.FnProto,
+                                ast.Node.FnProto {
                                     .base = undefined,
+                                    .comments = comments,
                                     .visib_token = ctx.visib_token,
                                     .name_token = null,
                                     .fn_token = undefined,
@@ -583,8 +565,8 @@ pub const Parser = struct {
                                     continue;
                                 },
                                 Token.Id.Keyword_async => {
-                                    const async_node = try self.createNode(arena, ast.NodeAsyncAttribute,
-                                        ast.NodeAsyncAttribute {
+                                    const async_node = try self.createNode(arena, ast.Node.AsyncAttribute,
+                                        ast.Node.AsyncAttribute {
                                             .base = undefined,
                                             .async_token = token,
                                             .allocator_type = null,
@@ -616,9 +598,9 @@ pub const Parser = struct {
                 },
                 State.TopLevelExternOrField => |ctx| {
                     if (self.eatToken(Token.Id.Identifier)) |identifier| {
-                        std.debug.assert(ctx.container_decl.kind == ast.NodeContainerDecl.Kind.Struct);
-                        const node = try self.createAttachNode(arena, &ctx.container_decl.fields_and_decls, ast.NodeStructField,
-                            ast.NodeStructField {
+                        std.debug.assert(ctx.container_decl.kind == ast.Node.ContainerDecl.Kind.Struct);
+                        const node = try self.createAttachNode(arena, &ctx.container_decl.fields_and_decls, ast.Node.StructField,
+                            ast.Node.StructField {
                                 .base = undefined,
                                 .visib_token = ctx.visib_token,
                                 .name_token = identifier,
@@ -647,15 +629,15 @@ pub const Parser = struct {
 
                 State.ContainerKind => |ctx| {
                     const token = self.getNextToken();
-                    const node = try self.createToCtxNode(arena, ctx.opt_ctx, ast.NodeContainerDecl,
-                        ast.NodeContainerDecl {
+                    const node = try self.createToCtxNode(arena, ctx.opt_ctx, ast.Node.ContainerDecl,
+                        ast.Node.ContainerDecl {
                             .base = undefined,
                             .ltoken = ctx.ltoken,
                             .layout = ctx.layout,
                             .kind = switch (token.id) {
-                                Token.Id.Keyword_struct => ast.NodeContainerDecl.Kind.Struct,
-                                Token.Id.Keyword_union => ast.NodeContainerDecl.Kind.Union,
-                                Token.Id.Keyword_enum => ast.NodeContainerDecl.Kind.Enum,
+                                Token.Id.Keyword_struct => ast.Node.ContainerDecl.Kind.Struct,
+                                Token.Id.Keyword_union => ast.Node.ContainerDecl.Kind.Union,
+                                Token.Id.Keyword_enum => ast.Node.ContainerDecl.Kind.Enum,
                                 else => {
                                     return self.parseError(token, "expected {}, {} or {}, found {}",
                                         @tagName(Token.Id.Keyword_struct),
@@ -664,7 +646,7 @@ pub const Parser = struct {
                                         @tagName(token.id));
                                 },
                             },
-                            .init_arg_expr = ast.NodeContainerDecl.InitArg.None,
+                            .init_arg_expr = ast.Node.ContainerDecl.InitArg.None,
                             .fields_and_decls = ArrayList(&ast.Node).init(arena),
                             .rbrace_token = undefined,
                         }
@@ -690,11 +672,11 @@ pub const Parser = struct {
                     const init_arg_token = self.getNextToken();
                     switch (init_arg_token.id) {
                         Token.Id.Keyword_enum => {
-                            container_decl.init_arg_expr = ast.NodeContainerDecl.InitArg.Enum;
+                            container_decl.init_arg_expr = ast.Node.ContainerDecl.InitArg.Enum;
                         },
                         else => {
                             self.putBackToken(init_arg_token);
-                            container_decl.init_arg_expr = ast.NodeContainerDecl.InitArg { .Type = undefined };
+                            container_decl.init_arg_expr = ast.Node.ContainerDecl.InitArg { .Type = undefined };
                             stack.append(State { .Expression = OptionalCtx { .Required = &container_decl.init_arg_expr.Type } }) catch unreachable;
                         },
                     }
@@ -705,9 +687,9 @@ pub const Parser = struct {
                     switch (token.id) {
                         Token.Id.Identifier => {
                             switch (container_decl.kind) {
-                                ast.NodeContainerDecl.Kind.Struct => {
-                                    const node = try self.createAttachNode(arena, &container_decl.fields_and_decls, ast.NodeStructField,
-                                        ast.NodeStructField {
+                                ast.Node.ContainerDecl.Kind.Struct => {
+                                    const node = try self.createAttachNode(arena, &container_decl.fields_and_decls, ast.Node.StructField,
+                                        ast.Node.StructField {
                                             .base = undefined,
                                             .visib_token = null,
                                             .name_token = token,
@@ -720,9 +702,9 @@ pub const Parser = struct {
                                     try stack.append(State { .ExpectToken = Token.Id.Colon });
                                     continue;
                                 },
-                                ast.NodeContainerDecl.Kind.Union => {
-                                    const node = try self.createAttachNode(arena, &container_decl.fields_and_decls, ast.NodeUnionTag,
-                                        ast.NodeUnionTag {
+                                ast.Node.ContainerDecl.Kind.Union => {
+                                    const node = try self.createAttachNode(arena, &container_decl.fields_and_decls, ast.Node.UnionTag,
+                                        ast.Node.UnionTag {
                                             .base = undefined,
                                             .name_token = token,
                                             .type_expr = null,
@@ -734,9 +716,9 @@ pub const Parser = struct {
                                     try stack.append(State { .IfToken = Token.Id.Colon });
                                     continue;
                                 },
-                                ast.NodeContainerDecl.Kind.Enum => {
-                                    const node = try self.createAttachNode(arena, &container_decl.fields_and_decls, ast.NodeEnumTag,
-                                        ast.NodeEnumTag {
+                                ast.Node.ContainerDecl.Kind.Enum => {
+                                    const node = try self.createAttachNode(arena, &container_decl.fields_and_decls, ast.Node.EnumTag,
+                                        ast.Node.EnumTag {
                                             .base = undefined,
                                             .name_token = token,
                                             .value = null,
@@ -752,7 +734,7 @@ pub const Parser = struct {
                         },
                         Token.Id.Keyword_pub => {
                             switch (container_decl.kind) {
-                                ast.NodeContainerDecl.Kind.Struct => {
+                                ast.Node.ContainerDecl.Kind.Struct => {
                                     try stack.append(State {
                                         .TopLevelExternOrField = TopLevelExternOrFieldCtx {
                                             .visib_token = token,
@@ -809,9 +791,10 @@ pub const Parser = struct {
 
 
                 State.VarDecl => |ctx| {
-                    const var_decl = try self.createAttachNode(arena, ctx.list, ast.NodeVarDecl,
-                        ast.NodeVarDecl {
+                    const var_decl = try self.createAttachNode(arena, ctx.list, ast.Node.VarDecl,
+                        ast.Node.VarDecl {
                             .base = undefined,
+                            .comments = ctx.comments,
                             .visib_token = ctx.visib_token,
                             .mut_token = ctx.mut_token,
                             .comptime_token = ctx.comptime_token,
@@ -881,8 +864,8 @@ pub const Parser = struct {
                     const token = self.getNextToken();
                     switch(token.id) {
                         Token.Id.LBrace => {
-                            const block = try self.createNode(arena, ast.NodeBlock,
-                                ast.NodeBlock {
+                            const block = try self.createNode(arena, ast.Node.Block,
+                                ast.Node.Block {
                                     .base = undefined,
                                     .label = null,
                                     .lbrace = token,
@@ -924,7 +907,7 @@ pub const Parser = struct {
                     const token = self.getNextToken();
                     switch (token.id) {
                         Token.Id.Bang => {
-                            fn_proto.return_type = ast.NodeFnProto.ReturnType { .InferErrorSet = undefined };
+                            fn_proto.return_type = ast.Node.FnProto.ReturnType { .InferErrorSet = undefined };
                             stack.append(State {
                                 .TypeExprBegin = OptionalCtx { .Required = &fn_proto.return_type.InferErrorSet },
                             }) catch unreachable;
@@ -934,15 +917,15 @@ pub const Parser = struct {
                             // TODO: this is a special case. Remove this when #760 is fixed
                             if (token.id == Token.Id.Keyword_error) {
                                 if (self.isPeekToken(Token.Id.LBrace)) {
-                                    fn_proto.return_type = ast.NodeFnProto.ReturnType {
-                                        .Explicit = &(try self.createLiteral(arena, ast.NodeErrorType, token)).base
+                                    fn_proto.return_type = ast.Node.FnProto.ReturnType {
+                                        .Explicit = &(try self.createLiteral(arena, ast.Node.ErrorType, token)).base
                                     };
                                     continue;
                                 }
                             }
 
                             self.putBackToken(token);
-                            fn_proto.return_type = ast.NodeFnProto.ReturnType { .Explicit = undefined };
+                            fn_proto.return_type = ast.Node.FnProto.ReturnType { .Explicit = undefined };
                             stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &fn_proto.return_type.Explicit }, }) catch unreachable;
                             continue;
                         },
@@ -954,8 +937,8 @@ pub const Parser = struct {
                     if (self.eatToken(Token.Id.RParen)) |_| {
                         continue;
                     }
-                    const param_decl = try self.createAttachNode(arena, &fn_proto.params, ast.NodeParamDecl,
-                        ast.NodeParamDecl {
+                    const param_decl = try self.createAttachNode(arena, &fn_proto.params, ast.Node.ParamDecl,
+                        ast.Node.ParamDecl {
                             .base = undefined,
                             .comptime_token = null,
                             .noalias_token = null,
@@ -1026,15 +1009,15 @@ pub const Parser = struct {
                         continue;
                     }
 
-                    _ = try self.createToCtxLiteral(arena, ctx.opt_ctx, ast.NodeIdentifier, ctx.label);
+                    _ = try self.createToCtxLiteral(arena, ctx.opt_ctx, ast.Node.Identifier, ctx.label);
                     continue;
                 },
                 State.LabeledExpression => |ctx| {
                     const token = self.getNextToken();
                     switch (token.id) {
                         Token.Id.LBrace => {
-                            const block = try self.createToCtxNode(arena, ctx.opt_ctx, ast.NodeBlock,
-                                ast.NodeBlock {
+                            const block = try self.createToCtxNode(arena, ctx.opt_ctx, ast.Node.Block,
+                                ast.Node.Block {
                                     .base = undefined,
                                     .label = ctx.label,
                                     .lbrace = token,
@@ -1123,8 +1106,8 @@ pub const Parser = struct {
                     }
                 },
                 State.While => |ctx| {
-                    const node = try self.createToCtxNode(arena, ctx.opt_ctx, ast.NodeWhile,
-                        ast.NodeWhile {
+                    const node = try self.createToCtxNode(arena, ctx.opt_ctx, ast.Node.While,
+                        ast.Node.While {
                             .base = undefined,
                             .label = ctx.label,
                             .inline_token = ctx.inline_token,
@@ -1153,8 +1136,8 @@ pub const Parser = struct {
                     continue;
                 },
                 State.For => |ctx| {
-                    const node = try self.createToCtxNode(arena, ctx.opt_ctx, ast.NodeFor,
-                        ast.NodeFor {
+                    const node = try self.createToCtxNode(arena, ctx.opt_ctx, ast.Node.For,
+                        ast.Node.For {
                             .base = undefined,
                             .label = ctx.label,
                             .inline_token = ctx.inline_token,
@@ -1175,8 +1158,8 @@ pub const Parser = struct {
                 },
                 State.Else => |dest| {
                     if (self.eatToken(Token.Id.Keyword_else)) |else_token| {
-                        const node = try self.createNode(arena, ast.NodeElse,
-                            ast.NodeElse {
+                        const node = try self.createNode(arena, ast.Node.Else,
+                            ast.Node.Else {
                                 .base = undefined,
                                 .else_token = else_token,
                                 .payload = null,
@@ -1210,6 +1193,7 @@ pub const Parser = struct {
                     }
                 },
                 State.Statement => |block| {
+                    const comments = try self.eatComments(arena);
                     const token = self.getNextToken();
                     switch (token.id) {
                         Token.Id.Keyword_comptime => {
@@ -1224,6 +1208,7 @@ pub const Parser = struct {
                         Token.Id.Keyword_var, Token.Id.Keyword_const => {
                             stack.append(State {
                                 .VarDecl = VarDeclCtx {
+                                    .comments = comments,
                                     .visib_token = null,
                                     .comptime_token = null,
                                     .extern_export_token = null,
@@ -1235,13 +1220,13 @@ pub const Parser = struct {
                             continue;
                         },
                         Token.Id.Keyword_defer, Token.Id.Keyword_errdefer => {
-                            const node = try self.createAttachNode(arena, &block.statements, ast.NodeDefer,
-                                ast.NodeDefer {
+                            const node = try self.createAttachNode(arena, &block.statements, ast.Node.Defer,
+                                ast.Node.Defer {
                                     .base = undefined,
                                     .defer_token = token,
                                     .kind = switch (token.id) {
-                                        Token.Id.Keyword_defer => ast.NodeDefer.Kind.Unconditional,
-                                        Token.Id.Keyword_errdefer => ast.NodeDefer.Kind.Error,
+                                        Token.Id.Keyword_defer => ast.Node.Defer.Kind.Unconditional,
+                                        Token.Id.Keyword_errdefer => ast.Node.Defer.Kind.Error,
                                         else => unreachable,
                                     },
                                     .expr = undefined,
@@ -1252,8 +1237,8 @@ pub const Parser = struct {
                             continue;
                         },
                         Token.Id.LBrace => {
-                            const inner_block = try self.createAttachNode(arena, &block.statements, ast.NodeBlock,
-                                ast.NodeBlock {
+                            const inner_block = try self.createAttachNode(arena, &block.statements, ast.Node.Block,
+                                ast.Node.Block {
                                     .base = undefined,
                                     .label = null,
                                     .lbrace = token,
@@ -1274,11 +1259,13 @@ pub const Parser = struct {
                     }
                 },
                 State.ComptimeStatement => |ctx| {
+                    const comments = try self.eatComments(arena);
                     const token = self.getNextToken();
                     switch (token.id) {
                         Token.Id.Keyword_var, Token.Id.Keyword_const => {
                             stack.append(State {
                                 .VarDecl = VarDeclCtx {
+                                    .comments = comments,
                                     .visib_token = null,
                                     .comptime_token = ctx.comptime_token,
                                     .extern_export_token = null,
@@ -1316,8 +1303,8 @@ pub const Parser = struct {
                         continue;
                     }
 
-                    const node = try self.createNode(arena, ast.NodeAsmOutput,
-                        ast.NodeAsmOutput {
+                    const node = try self.createNode(arena, ast.Node.AsmOutput,
+                        ast.Node.AsmOutput {
                             .base = undefined,
                             .symbolic_name = undefined,
                             .constraint = undefined,
@@ -1340,11 +1327,11 @@ pub const Parser = struct {
                     const token = self.getNextToken();
                     switch (token.id) {
                         Token.Id.Identifier => {
-                            node.kind = ast.NodeAsmOutput.Kind { .Variable = try self.createLiteral(arena, ast.NodeIdentifier, token) };
+                            node.kind = ast.Node.AsmOutput.Kind { .Variable = try self.createLiteral(arena, ast.Node.Identifier, token) };
                             continue;
                         },
                         Token.Id.Arrow => {
-                            node.kind = ast.NodeAsmOutput.Kind { .Return = undefined };
+                            node.kind = ast.Node.AsmOutput.Kind { .Return = undefined };
                             try stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.kind.Return } });
                             continue;
                         },
@@ -1362,8 +1349,8 @@ pub const Parser = struct {
                         continue;
                     }
 
-                    const node = try self.createNode(arena, ast.NodeAsmInput,
-                        ast.NodeAsmInput {
+                    const node = try self.createNode(arena, ast.Node.AsmInput,
+                        ast.Node.AsmInput {
                             .base = undefined,
                             .symbolic_name = undefined,
                             .constraint = undefined,
@@ -1415,8 +1402,8 @@ pub const Parser = struct {
                         continue;
                     }
 
-                    const node = try self.createNode(arena, ast.NodeFieldInitializer,
-                        ast.NodeFieldInitializer {
+                    const node = try self.createNode(arena, ast.Node.FieldInitializer,
+                        ast.Node.FieldInitializer {
                             .base = undefined,
                             .period_token = undefined,
                             .name_token = undefined,
@@ -1485,8 +1472,8 @@ pub const Parser = struct {
                         continue;
                     }
 
-                    const node = try self.createNode(arena, ast.NodeSwitchCase,
-                        ast.NodeSwitchCase {
+                    const node = try self.createNode(arena, ast.Node.SwitchCase,
+                        ast.Node.SwitchCase {
                             .base = undefined,
                             .items = ArrayList(&ast.Node).init(arena),
                             .payload = null,
@@ -1512,8 +1499,8 @@ pub const Parser = struct {
                 State.SwitchCaseFirstItem => |case_items| {
                     const token = self.getNextToken();
                     if (token.id == Token.Id.Keyword_else) {
-                        const else_node = try self.createAttachNode(arena, case_items, ast.NodeSwitchElse,
-                            ast.NodeSwitchElse {
+                        const else_node = try self.createAttachNode(arena, case_items, ast.Node.SwitchElse,
+                            ast.Node.SwitchElse {
                                 .base = undefined,
                                 .token = token,
                             }
@@ -1564,24 +1551,24 @@ pub const Parser = struct {
 
                     switch (node.id) {
                         ast.Node.Id.FnProto => {
-                            const fn_proto = @fieldParentPtr(ast.NodeFnProto, "base", node);
+                            const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", node);
                             fn_proto.async_attr = ctx.attribute;
                             continue;
                         },
                         ast.Node.Id.SuffixOp => {
-                            const suffix_op = @fieldParentPtr(ast.NodeSuffixOp, "base", node);
-                            if (suffix_op.op == ast.NodeSuffixOp.SuffixOp.Call) {
+                            const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", node);
+                            if (suffix_op.op == ast.Node.SuffixOp.Op.Call) {
                                 suffix_op.op.Call.async_attr = ctx.attribute;
                                 continue;
                             }
 
                             return self.parseError(node.firstToken(), "expected {}, found {}.",
-                                @tagName(ast.NodeSuffixOp.SuffixOp.Call),
+                                @tagName(ast.Node.SuffixOp.Op.Call),
                                 @tagName(suffix_op.op));
                         },
                         else => {
                             return self.parseError(node.firstToken(), "expected {} or {}, found {}.",
-                                @tagName(ast.NodeSuffixOp.SuffixOp.Call),
+                                @tagName(ast.Node.SuffixOp.Op.Call),
                                 @tagName(ast.Node.Id.FnProto),
                                 @tagName(node.id));
                         }
@@ -1591,9 +1578,10 @@ pub const Parser = struct {
 
                 State.ExternType => |ctx| {
                     if (self.eatToken(Token.Id.Keyword_fn)) |fn_token| {
-                        const fn_proto = try self.createToCtxNode(arena, ctx.opt_ctx, ast.NodeFnProto,
-                            ast.NodeFnProto {
+                        const fn_proto = try self.createToCtxNode(arena, ctx.opt_ctx, ast.Node.FnProto,
+                            ast.Node.FnProto {
                                 .base = undefined,
+                                .comments = ctx.comments,
                                 .visib_token = null,
                                 .name_token = null,
                                 .fn_token = fn_token,
@@ -1616,7 +1604,7 @@ pub const Parser = struct {
                         .ContainerKind = ContainerKindCtx {
                             .opt_ctx = ctx.opt_ctx,
                             .ltoken = ctx.extern_token,
-                            .layout = ast.NodeContainerDecl.Layout.Extern,
+                            .layout = ast.Node.ContainerDecl.Layout.Extern,
                         },
                     }) catch unreachable;
                     continue;
@@ -1626,8 +1614,8 @@ pub const Parser = struct {
                     switch (token.id) {
                         Token.Id.Ellipsis2 => {
                             const start = node.op.ArrayAccess;
-                            node.op = ast.NodeSuffixOp.SuffixOp {
-                                .Slice = ast.NodeSuffixOp.SliceRange {
+                            node.op = ast.Node.SuffixOp.Op {
+                                .Slice = ast.Node.SuffixOp.SliceRange {
                                     .start = start,
                                     .end = null,
                                 }
@@ -1653,8 +1641,8 @@ pub const Parser = struct {
                 },
                 State.SliceOrArrayType => |node| {
                     if (self.eatToken(Token.Id.RBracket)) |_| {
-                        node.op = ast.NodePrefixOp.PrefixOp {
-                            .SliceType = ast.NodePrefixOp.AddrOfInfo {
+                        node.op = ast.Node.PrefixOp.Op {
+                            .SliceType = ast.Node.PrefixOp.AddrOfInfo {
                                 .align_expr = null,
                                 .bit_offset_start_token = null,
                                 .bit_offset_end_token = null,
@@ -1667,7 +1655,7 @@ pub const Parser = struct {
                         continue;
                     }
 
-                    node.op = ast.NodePrefixOp.PrefixOp { .ArrayType = undefined };
+                    node.op = ast.Node.PrefixOp.Op { .ArrayType = undefined };
                     stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
                     try stack.append(State { .ExpectToken = Token.Id.RBracket });
                     try stack.append(State { .Expression = OptionalCtx { .Required = &node.op.ArrayType } });
@@ -1723,8 +1711,8 @@ pub const Parser = struct {
                         continue;
                     }
 
-                    const node = try self.createToCtxNode(arena, opt_ctx, ast.NodePayload,
-                        ast.NodePayload {
+                    const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.Payload,
+                        ast.Node.Payload {
                             .base = undefined,
                             .lpipe = token,
                             .error_symbol = undefined,
@@ -1754,8 +1742,8 @@ pub const Parser = struct {
                         continue;
                     }
 
-                    const node = try self.createToCtxNode(arena, opt_ctx, ast.NodePointerPayload,
-                        ast.NodePointerPayload {
+                    const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.PointerPayload,
+                        ast.Node.PointerPayload {
                             .base = undefined,
                             .lpipe = token,
                             .ptr_token = null,
@@ -1792,8 +1780,8 @@ pub const Parser = struct {
                         continue;
                     }
 
-                    const node = try self.createToCtxNode(arena, opt_ctx, ast.NodePointerIndexPayload,
-                        ast.NodePointerIndexPayload {
+                    const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.PointerIndexPayload,
+                        ast.Node.PointerIndexPayload {
                             .base = undefined,
                             .lpipe = token,
                             .ptr_token = null,
@@ -1826,8 +1814,8 @@ pub const Parser = struct {
                     const token = self.getNextToken();
                     switch (token.id) {
                         Token.Id.Keyword_return, Token.Id.Keyword_break, Token.Id.Keyword_continue => {
-                            const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeControlFlowExpression,
-                                ast.NodeControlFlowExpression {
+                            const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.ControlFlowExpression,
+                                ast.Node.ControlFlowExpression {
                                     .base = undefined,
                                     .ltoken = token,
                                     .kind = undefined,
@@ -1839,31 +1827,31 @@ pub const Parser = struct {
 
                             switch (token.id) {
                                 Token.Id.Keyword_break => {
-                                    node.kind = ast.NodeControlFlowExpression.Kind { .Break = null };
+                                    node.kind = ast.Node.ControlFlowExpression.Kind { .Break = null };
                                     try stack.append(State { .Identifier = OptionalCtx { .RequiredNull = &node.kind.Break } });
                                     try stack.append(State { .IfToken = Token.Id.Colon });
                                 },
                                 Token.Id.Keyword_continue => {
-                                    node.kind = ast.NodeControlFlowExpression.Kind { .Continue = null };
+                                    node.kind = ast.Node.ControlFlowExpression.Kind { .Continue = null };
                                     try stack.append(State { .Identifier = OptionalCtx { .RequiredNull = &node.kind.Continue } });
                                     try stack.append(State { .IfToken = Token.Id.Colon });
                                 },
                                 Token.Id.Keyword_return => {
-                                    node.kind = ast.NodeControlFlowExpression.Kind.Return;
+                                    node.kind = ast.Node.ControlFlowExpression.Kind.Return;
                                 },
                                 else => unreachable,
                             }
                             continue;
                         },
                         Token.Id.Keyword_try, Token.Id.Keyword_cancel, Token.Id.Keyword_resume => {
-                            const node = try self.createToCtxNode(arena, opt_ctx, ast.NodePrefixOp,
-                                ast.NodePrefixOp {
+                            const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.PrefixOp,
+                                ast.Node.PrefixOp {
                                     .base = undefined,
                                     .op_token = token,
                                     .op = switch (token.id) {
-                                        Token.Id.Keyword_try => ast.NodePrefixOp.PrefixOp { .Try = void{} },
-                                        Token.Id.Keyword_cancel => ast.NodePrefixOp.PrefixOp { .Cancel = void{} },
-                                        Token.Id.Keyword_resume => ast.NodePrefixOp.PrefixOp { .Resume = void{} },
+                                        Token.Id.Keyword_try => ast.Node.PrefixOp.Op { .Try = void{} },
+                                        Token.Id.Keyword_cancel => ast.Node.PrefixOp.Op { .Cancel = void{} },
+                                        Token.Id.Keyword_resume => ast.Node.PrefixOp.Op { .Resume = void{} },
                                         else => unreachable,
                                     },
                                     .rhs = undefined,
@@ -1891,12 +1879,12 @@ pub const Parser = struct {
                     const lhs = opt_ctx.get() ?? continue;
 
                     if (self.eatToken(Token.Id.Ellipsis3)) |ellipsis3| {
-                        const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
-                            ast.NodeInfixOp {
+                        const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
+                            ast.Node.InfixOp {
                                 .base = undefined,
                                 .lhs = lhs,
                                 .op_token = ellipsis3,
-                                .op = ast.NodeInfixOp.InfixOp.Range,
+                                .op = ast.Node.InfixOp.Op.Range,
                                 .rhs = undefined,
                             }
                         );
@@ -1915,8 +1903,8 @@ pub const Parser = struct {
 
                     const token = self.getNextToken();
                     if (tokenIdToAssignment(token.id)) |ass_id| {
-                        const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
-                            ast.NodeInfixOp {
+                        const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
+                            ast.Node.InfixOp {
                                 .base = undefined,
                                 .lhs = lhs,
                                 .op_token = token,
@@ -1944,8 +1932,8 @@ pub const Parser = struct {
 
                     const token = self.getNextToken();
                     if (tokenIdToUnwrapExpr(token.id)) |unwrap_id| {
-                        const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
-                            ast.NodeInfixOp {
+                        const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
+                            ast.Node.InfixOp {
                                 .base = undefined,
                                 .lhs = lhs,
                                 .op_token = token,
@@ -1957,7 +1945,7 @@ pub const Parser = struct {
                         stack.append(State { .UnwrapExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
                         try stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } });
 
-                        if (node.op == ast.NodeInfixOp.InfixOp.Catch) {
+                        if (node.op == ast.Node.InfixOp.Op.Catch) {
                             try stack.append(State { .Payload = OptionalCtx { .Optional = &node.op.Catch } });
                         }
                         continue;
@@ -1977,12 +1965,12 @@ pub const Parser = struct {
                     const lhs = opt_ctx.get() ?? continue;
 
                     if (self.eatToken(Token.Id.Keyword_or)) |or_token| {
-                        const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
-                            ast.NodeInfixOp {
+                        const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
+                            ast.Node.InfixOp {
                                 .base = undefined,
                                 .lhs = lhs,
                                 .op_token = or_token,
-                                .op = ast.NodeInfixOp.InfixOp.BoolOr,
+                                .op = ast.Node.InfixOp.Op.BoolOr,
                                 .rhs = undefined,
                             }
                         );
@@ -2002,12 +1990,12 @@ pub const Parser = struct {
                     const lhs = opt_ctx.get() ?? continue;
 
                     if (self.eatToken(Token.Id.Keyword_and)) |and_token| {
-                        const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
-                            ast.NodeInfixOp {
+                        const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
+                            ast.Node.InfixOp {
                                 .base = undefined,
                                 .lhs = lhs,
                                 .op_token = and_token,
-                                .op = ast.NodeInfixOp.InfixOp.BoolAnd,
+                                .op = ast.Node.InfixOp.Op.BoolAnd,
                                 .rhs = undefined,
                             }
                         );
@@ -2028,8 +2016,8 @@ pub const Parser = struct {
 
                     const token = self.getNextToken();
                     if (tokenIdToComparison(token.id)) |comp_id| {
-                        const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
-                            ast.NodeInfixOp {
+                        const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
+                            ast.Node.InfixOp {
                                 .base = undefined,
                                 .lhs = lhs,
                                 .op_token = token,
@@ -2056,12 +2044,12 @@ pub const Parser = struct {
                     const lhs = opt_ctx.get() ?? continue;
 
                     if (self.eatToken(Token.Id.Pipe)) |pipe| {
-                        const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
-                            ast.NodeInfixOp {
+                        const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
+                            ast.Node.InfixOp {
                                 .base = undefined,
                                 .lhs = lhs,
                                 .op_token = pipe,
-                                .op = ast.NodeInfixOp.InfixOp.BitOr,
+                                .op = ast.Node.InfixOp.Op.BitOr,
                                 .rhs = undefined,
                             }
                         );
@@ -2081,12 +2069,12 @@ pub const Parser = struct {
                     const lhs = opt_ctx.get() ?? continue;
 
                     if (self.eatToken(Token.Id.Caret)) |caret| {
-                        const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
-                            ast.NodeInfixOp {
+                        const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
+                            ast.Node.InfixOp {
                                 .base = undefined,
                                 .lhs = lhs,
                                 .op_token = caret,
-                                .op = ast.NodeInfixOp.InfixOp.BitXor,
+                                .op = ast.Node.InfixOp.Op.BitXor,
                                 .rhs = undefined,
                             }
                         );
@@ -2106,12 +2094,12 @@ pub const Parser = struct {
                     const lhs = opt_ctx.get() ?? continue;
 
                     if (self.eatToken(Token.Id.Ampersand)) |ampersand| {
-                        const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
-                            ast.NodeInfixOp {
+                        const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
+                            ast.Node.InfixOp {
                                 .base = undefined,
                                 .lhs = lhs,
                                 .op_token = ampersand,
-                                .op = ast.NodeInfixOp.InfixOp.BitAnd,
+                                .op = ast.Node.InfixOp.Op.BitAnd,
                                 .rhs = undefined,
                             }
                         );
@@ -2132,8 +2120,8 @@ pub const Parser = struct {
 
                     const token = self.getNextToken();
                     if (tokenIdToBitShift(token.id)) |bitshift_id| {
-                        const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
-                            ast.NodeInfixOp {
+                        const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
+                            ast.Node.InfixOp {
                                 .base = undefined,
                                 .lhs = lhs,
                                 .op_token = token,
@@ -2161,8 +2149,8 @@ pub const Parser = struct {
 
                     const token = self.getNextToken();
                     if (tokenIdToAddition(token.id)) |add_id| {
-                        const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
-                            ast.NodeInfixOp {
+                        const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
+                            ast.Node.InfixOp {
                                 .base = undefined,
                                 .lhs = lhs,
                                 .op_token = token,
@@ -2190,8 +2178,8 @@ pub const Parser = struct {
 
                     const token = self.getNextToken();
                     if (tokenIdToMultiply(token.id)) |mult_id| {
-                        const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
-                            ast.NodeInfixOp {
+                        const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
+                            ast.Node.InfixOp {
                                 .base = undefined,
                                 .lhs = lhs,
                                 .op_token = token,
@@ -2219,12 +2207,12 @@ pub const Parser = struct {
                     const lhs = opt_ctx.get() ?? continue;
 
                     if (self.isPeekToken(Token.Id.Period)) {
-                        const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeSuffixOp,
-                            ast.NodeSuffixOp {
+                        const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,
+                            ast.Node.SuffixOp {
                                 .base = undefined,
                                 .lhs = lhs,
-                                .op = ast.NodeSuffixOp.SuffixOp {
-                                    .StructInitializer = ArrayList(&ast.NodeFieldInitializer).init(arena),
+                                .op = ast.Node.SuffixOp.Op {
+                                    .StructInitializer = ArrayList(&ast.Node.FieldInitializer).init(arena),
                                 },
                                 .rtoken = undefined,
                             }
@@ -2232,7 +2220,7 @@ pub const Parser = struct {
                         stack.append(State { .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
                         try stack.append(State { .IfToken = Token.Id.LBrace });
                         try stack.append(State {
-                            .FieldInitListItemOrEnd = ListSave(&ast.NodeFieldInitializer) {
+                            .FieldInitListItemOrEnd = ListSave(&ast.Node.FieldInitializer) {
                                 .list = &node.op.StructInitializer,
                                 .ptr = &node.rtoken,
                             }
@@ -2240,11 +2228,11 @@ pub const Parser = struct {
                         continue;
                     }
 
-                    const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeSuffixOp,
-                        ast.NodeSuffixOp {
+                    const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,
+                        ast.Node.SuffixOp {
                             .base = undefined,
                             .lhs = lhs,
-                            .op = ast.NodeSuffixOp.SuffixOp {
+                            .op = ast.Node.SuffixOp.Op {
                                 .ArrayInitializer = ArrayList(&ast.Node).init(arena),
                             },
                             .rtoken = undefined,
@@ -2272,12 +2260,12 @@ pub const Parser = struct {
                     const lhs = opt_ctx.get() ?? continue;
 
                     if (self.eatToken(Token.Id.Bang)) |bang| {
-                        const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
-                            ast.NodeInfixOp {
+                        const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
+                            ast.Node.InfixOp {
                                 .base = undefined,
                                 .lhs = lhs,
                                 .op_token = bang,
-                                .op = ast.NodeInfixOp.InfixOp.ErrorUnion,
+                                .op = ast.Node.InfixOp.Op.ErrorUnion,
                                 .rhs = undefined,
                             }
                         );
@@ -2290,8 +2278,8 @@ pub const Parser = struct {
                 State.PrefixOpExpression => |opt_ctx| {
                     const token = self.getNextToken();
                     if (tokenIdToPrefixOp(token.id)) |prefix_id| {
-                        var node = try self.createToCtxNode(arena, opt_ctx, ast.NodePrefixOp,
-                            ast.NodePrefixOp {
+                        var node = try self.createToCtxNode(arena, opt_ctx, ast.Node.PrefixOp,
+                            ast.Node.PrefixOp {
                                 .base = undefined,
                                 .op_token = token,
                                 .op = prefix_id,
@@ -2301,8 +2289,8 @@ pub const Parser = struct {
 
                         // Treat '**' token as two derefs
                         if (token.id == Token.Id.AsteriskAsterisk) {
-                            const child = try self.createNode(arena, ast.NodePrefixOp,
-                                ast.NodePrefixOp {
+                            const child = try self.createNode(arena, ast.Node.PrefixOp,
+                                ast.Node.PrefixOp {
                                     .base = undefined,
                                     .op_token = token,
                                     .op = prefix_id,
@@ -2314,7 +2302,7 @@ pub const Parser = struct {
                         }
 
                         stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
-                        if (node.op == ast.NodePrefixOp.PrefixOp.AddrOf) {
+                        if (node.op == ast.Node.PrefixOp.Op.AddrOf) {
                             try stack.append(State { .AddrOfModifiers = &node.op.AddrOf });
                         }
                         continue;
@@ -2327,8 +2315,8 @@ pub const Parser = struct {
 
                 State.SuffixOpExpressionBegin => |opt_ctx| {
                     if (self.eatToken(Token.Id.Keyword_async)) |async_token| {
-                        const async_node = try self.createNode(arena, ast.NodeAsyncAttribute,
-                            ast.NodeAsyncAttribute {
+                        const async_node = try self.createNode(arena, ast.Node.AsyncAttribute,
+                            ast.Node.AsyncAttribute {
                                 .base = undefined,
                                 .async_token = async_token,
                                 .allocator_type = null,
@@ -2358,12 +2346,12 @@ pub const Parser = struct {
                     const token = self.getNextToken();
                     switch (token.id) {
                         Token.Id.LParen => {
-                            const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeSuffixOp,
-                                ast.NodeSuffixOp {
+                            const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,
+                                ast.Node.SuffixOp {
                                     .base = undefined,
                                     .lhs = lhs,
-                                    .op = ast.NodeSuffixOp.SuffixOp {
-                                        .Call = ast.NodeSuffixOp.CallInfo {
+                                    .op = ast.Node.SuffixOp.Op {
+                                        .Call = ast.Node.SuffixOp.CallInfo {
                                             .params = ArrayList(&ast.Node).init(arena),
                                             .async_attr = null,
                                         }
@@ -2382,11 +2370,11 @@ pub const Parser = struct {
                             continue;
                         },
                         Token.Id.LBracket => {
-                            const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeSuffixOp,
-                                ast.NodeSuffixOp {
+                            const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,
+                                ast.Node.SuffixOp {
                                     .base = undefined,
                                     .lhs = lhs,
-                                    .op = ast.NodeSuffixOp.SuffixOp {
+                                    .op = ast.Node.SuffixOp.Op {
                                         .ArrayAccess = undefined,
                                     },
                                     .rtoken = undefined
@@ -2398,12 +2386,12 @@ pub const Parser = struct {
                             continue;
                         },
                         Token.Id.Period => {
-                            const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
-                                ast.NodeInfixOp {
+                            const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
+                                ast.Node.InfixOp {
                                     .base = undefined,
                                     .lhs = lhs,
                                     .op_token = token,
-                                    .op = ast.NodeInfixOp.InfixOp.Period,
+                                    .op = ast.Node.InfixOp.Op.Period,
                                     .rhs = undefined,
                                 }
                             );
@@ -2422,39 +2410,39 @@ pub const Parser = struct {
                     const token = self.getNextToken();
                     switch (token.id) {
                         Token.Id.IntegerLiteral => {
-                            _ = try self.createToCtxLiteral(arena, opt_ctx, ast.NodeStringLiteral, token);
+                            _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.StringLiteral, token);
                             continue;
                         },
                         Token.Id.FloatLiteral => {
-                            _ = try self.createToCtxLiteral(arena, opt_ctx, ast.NodeFloatLiteral, token);
+                            _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.FloatLiteral, token);
                             continue;
                         },
                         Token.Id.CharLiteral => {
-                            _ = try self.createToCtxLiteral(arena, opt_ctx, ast.NodeCharLiteral, token);
+                            _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.CharLiteral, token);
                             continue;
                         },
                         Token.Id.Keyword_undefined => {
-                            _ = try self.createToCtxLiteral(arena, opt_ctx, ast.NodeUndefinedLiteral, token);
+                            _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.UndefinedLiteral, token);
                             continue;
                         },
                         Token.Id.Keyword_true, Token.Id.Keyword_false => {
-                            _ = try self.createToCtxLiteral(arena, opt_ctx, ast.NodeBoolLiteral, token);
+                            _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.BoolLiteral, token);
                             continue;
                         },
                         Token.Id.Keyword_null => {
-                            _ = try self.createToCtxLiteral(arena, opt_ctx, ast.NodeNullLiteral, token);
+                            _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.NullLiteral, token);
                             continue;
                         },
                         Token.Id.Keyword_this => {
-                            _ = try self.createToCtxLiteral(arena, opt_ctx, ast.NodeThisLiteral, token);
+                            _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.ThisLiteral, token);
                             continue;
                         },
                         Token.Id.Keyword_var => {
-                            _ = try self.createToCtxLiteral(arena, opt_ctx, ast.NodeVarType, token);
+                            _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.VarType, token);
                             continue;
                         },
                         Token.Id.Keyword_unreachable => {
-                            _ = try self.createToCtxLiteral(arena, opt_ctx, ast.NodeUnreachable, token);
+                            _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.Unreachable, token);
                             continue;
                         },
                         Token.Id.StringLiteral, Token.Id.MultilineStringLiteralLine => {
@@ -2462,8 +2450,8 @@ pub const Parser = struct {
                             continue;
                         },
                         Token.Id.LParen => {
-                            const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeGroupedExpression,
-                                ast.NodeGroupedExpression {
+                            const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.GroupedExpression,
+                                ast.Node.GroupedExpression {
                                     .base = undefined,
                                     .lparen = token,
                                     .expr = undefined,
@@ -2480,8 +2468,8 @@ pub const Parser = struct {
                             continue;
                         },
                         Token.Id.Builtin => {
-                            const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeBuiltinCall,
-                                ast.NodeBuiltinCall {
+                            const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.BuiltinCall,
+                                ast.Node.BuiltinCall {
                                     .base = undefined,
                                     .builtin_token = token,
                                     .params = ArrayList(&ast.Node).init(arena),
@@ -2499,8 +2487,8 @@ pub const Parser = struct {
                             continue;
                         },
                         Token.Id.LBracket => {
-                            const node = try self.createToCtxNode(arena, opt_ctx, ast.NodePrefixOp,
-                                ast.NodePrefixOp {
+                            const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.PrefixOp,
+                                ast.Node.PrefixOp {
                                     .base = undefined,
                                     .op_token = token,
                                     .op = undefined,
@@ -2524,7 +2512,7 @@ pub const Parser = struct {
                                 .ContainerKind = ContainerKindCtx {
                                     .opt_ctx = opt_ctx,
                                     .ltoken = token,
-                                    .layout = ast.NodeContainerDecl.Layout.Packed,
+                                    .layout = ast.Node.ContainerDecl.Layout.Packed,
                                 },
                             }) catch unreachable;
                             continue;
@@ -2534,6 +2522,7 @@ pub const Parser = struct {
                                 .ExternType = ExternTypeCtx {
                                     .opt_ctx = opt_ctx,
                                     .extern_token = token,
+                                    .comments = null,
                                 },
                             }) catch unreachable;
                             continue;
@@ -2544,7 +2533,7 @@ pub const Parser = struct {
                                 .ContainerKind = ContainerKindCtx {
                                     .opt_ctx = opt_ctx,
                                     .ltoken = token,
-                                    .layout = ast.NodeContainerDecl.Layout.Auto,
+                                    .layout = ast.Node.ContainerDecl.Layout.Auto,
                                 },
                             }) catch unreachable;
                             continue;
@@ -2559,9 +2548,10 @@ pub const Parser = struct {
                             continue;
                         },
                         Token.Id.Keyword_fn => {
-                            const fn_proto = try self.createToCtxNode(arena, opt_ctx, ast.NodeFnProto,
-                                ast.NodeFnProto {
+                            const fn_proto = try self.createToCtxNode(arena, opt_ctx, ast.Node.FnProto,
+                                ast.Node.FnProto {
                                     .base = undefined,
+                                    .comments = null,
                                     .visib_token = null,
                                     .name_token = null,
                                     .fn_token = token,
@@ -2580,9 +2570,10 @@ pub const Parser = struct {
                             continue;
                         },
                         Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
-                            const fn_proto = try self.createToCtxNode(arena, opt_ctx, ast.NodeFnProto,
-                                ast.NodeFnProto {
+                            const fn_proto = try self.createToCtxNode(arena, opt_ctx, ast.Node.FnProto,
+                                ast.Node.FnProto {
                                     .base = undefined,
+                                    .comments = null,
                                     .visib_token = null,
                                     .name_token = null,
                                     .fn_token = undefined,
@@ -2607,15 +2598,15 @@ pub const Parser = struct {
                             continue;
                         },
                         Token.Id.Keyword_asm => {
-                            const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeAsm,
-                                ast.NodeAsm {
+                            const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.Asm,
+                                ast.Node.Asm {
                                     .base = undefined,
                                     .asm_token = token,
                                     .volatile_token = null,
                                     .template = undefined,
-                                    //.tokens = ArrayList(ast.NodeAsm.AsmToken).init(arena),
-                                    .outputs = ArrayList(&ast.NodeAsmOutput).init(arena),
-                                    .inputs = ArrayList(&ast.NodeAsmInput).init(arena),
+                                    //.tokens = ArrayList(ast.Node.Asm.AsmToken).init(arena),
+                                    .outputs = ArrayList(&ast.Node.AsmOutput).init(arena),
+                                    .inputs = ArrayList(&ast.Node.AsmInput).init(arena),
                                     .cloppers = ArrayList(&ast.Node).init(arena),
                                     .rparen = undefined,
                                 }
@@ -2666,12 +2657,12 @@ pub const Parser = struct {
 
                 State.ErrorTypeOrSetDecl => |ctx| {
                     if (self.eatToken(Token.Id.LBrace) == null) {
-                        _ = try self.createToCtxLiteral(arena, ctx.opt_ctx, ast.NodeErrorType, ctx.error_token);
+                        _ = try self.createToCtxLiteral(arena, ctx.opt_ctx, ast.Node.ErrorType, ctx.error_token);
                         continue;
                     }
 
-                    const node = try self.createToCtxNode(arena, ctx.opt_ctx, ast.NodeErrorSetDecl,
-                        ast.NodeErrorSetDecl {
+                    const node = try self.createToCtxNode(arena, ctx.opt_ctx, ast.Node.ErrorSetDecl,
+                        ast.Node.ErrorSetDecl {
                             .base = undefined,
                             .error_token = ctx.error_token,
                             .decls = ArrayList(&ast.Node).init(arena),
@@ -2702,7 +2693,7 @@ pub const Parser = struct {
                 },
                 State.Identifier => |opt_ctx| {
                     if (self.eatToken(Token.Id.Identifier)) |ident_token| {
-                        _ = try self.createToCtxLiteral(arena, opt_ctx, ast.NodeIdentifier, ident_token);
+                        _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.Identifier, ident_token);
                         continue;
                     }
 
@@ -2750,6 +2741,33 @@ pub const Parser = struct {
         }
     }
 
+    fn eatComments(self: &Parser, arena: &mem.Allocator) !?&ast.Node.LineComment {
+        var result: ?&ast.Node.LineComment = null;
+        while (true) {
+            if (self.eatToken(Token.Id.LineComment)) |line_comment| {
+                const node = blk: {
+                    if (result) |comment_node| {
+                        break :blk comment_node;
+                    } else {
+                        const comment_node = try arena.create(ast.Node.LineComment);
+                        *comment_node = ast.Node.LineComment {
+                            .base = ast.Node {
+                                .id = ast.Node.Id.LineComment,
+                            },
+                            .lines = ArrayList(Token).init(arena),
+                        };
+                        result = comment_node;
+                        break :blk comment_node;
+                    }
+                };
+                try node.lines.append(line_comment);
+                continue;
+            }
+            break;
+        }
+        return result;
+    }
+
     fn requireSemiColon(node: &const ast.Node) bool {
         var n = node;
         while (true) {
@@ -2770,7 +2788,7 @@ pub const Parser = struct {
                 ast.Node.Id.LineComment,
                 ast.Node.Id.TestDecl => return false,
                 ast.Node.Id.While => {
-                    const while_node = @fieldParentPtr(ast.NodeWhile, "base", n);
+                    const while_node = @fieldParentPtr(ast.Node.While, "base", n);
                     if (while_node.@"else") |@"else"| {
                         n = @"else".base;
                         continue;
@@ -2779,7 +2797,7 @@ pub const Parser = struct {
                     return while_node.body.id != ast.Node.Id.Block;
                 },
                 ast.Node.Id.For => {
-                    const for_node = @fieldParentPtr(ast.NodeFor, "base", n);
+                    const for_node = @fieldParentPtr(ast.Node.For, "base", n);
                     if (for_node.@"else") |@"else"| {
                         n = @"else".base;
                         continue;
@@ -2788,7 +2806,7 @@ pub const Parser = struct {
                     return for_node.body.id != ast.Node.Id.Block;
                 },
                 ast.Node.Id.If => {
-                    const if_node = @fieldParentPtr(ast.NodeIf, "base", n);
+                    const if_node = @fieldParentPtr(ast.Node.If, "base", n);
                     if (if_node.@"else") |@"else"| {
                         n = @"else".base;
                         continue;
@@ -2797,20 +2815,20 @@ pub const Parser = struct {
                     return if_node.body.id != ast.Node.Id.Block;
                 },
                 ast.Node.Id.Else => {
-                    const else_node = @fieldParentPtr(ast.NodeElse, "base", n);
+                    const else_node = @fieldParentPtr(ast.Node.Else, "base", n);
                     n = else_node.body;
                     continue;
                 },
                 ast.Node.Id.Defer => {
-                    const defer_node = @fieldParentPtr(ast.NodeDefer, "base", n);
+                    const defer_node = @fieldParentPtr(ast.Node.Defer, "base", n);
                     return defer_node.expr.id != ast.Node.Id.Block;
                 },
                 ast.Node.Id.Comptime => {
-                    const comptime_node = @fieldParentPtr(ast.NodeComptime, "base", n);
+                    const comptime_node = @fieldParentPtr(ast.Node.Comptime, "base", n);
                     return comptime_node.expr.id != ast.Node.Id.Block;
                 },
                 ast.Node.Id.Suspend => {
-                    const suspend_node = @fieldParentPtr(ast.NodeSuspend, "base", n);
+                    const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", n);
                     if (suspend_node.body) |body| {
                         return body.id != ast.Node.Id.Block;
                     }
@@ -2825,11 +2843,11 @@ pub const Parser = struct {
     fn parseStringLiteral(self: &Parser, arena: &mem.Allocator, token: &const Token) !?&ast.Node {
         switch (token.id) {
             Token.Id.StringLiteral => {
-                return &(try self.createLiteral(arena, ast.NodeStringLiteral, token)).base;
+                return &(try self.createLiteral(arena, ast.Node.StringLiteral, token)).base;
             },
             Token.Id.MultilineStringLiteralLine => {
-                const node = try self.createNode(arena, ast.NodeMultilineStringLiteral,
-                    ast.NodeMultilineStringLiteral {
+                const node = try self.createNode(arena, ast.Node.MultilineStringLiteral,
+                    ast.Node.MultilineStringLiteral {
                         .base = undefined,
                         .tokens = ArrayList(Token).init(arena),
                     }
@@ -2856,8 +2874,8 @@ pub const Parser = struct {
     fn parseBlockExpr(self: &Parser, stack: &ArrayList(State), arena: &mem.Allocator, ctx: &const OptionalCtx, token: &const Token) !bool {
         switch (token.id) {
             Token.Id.Keyword_suspend => {
-                const node = try self.createToCtxNode(arena, ctx, ast.NodeSuspend,
-                    ast.NodeSuspend {
+                const node = try self.createToCtxNode(arena, ctx, ast.Node.Suspend,
+                    ast.Node.Suspend {
                         .base = undefined,
                         .suspend_token = *token,
                         .payload = null,
@@ -2870,8 +2888,8 @@ pub const Parser = struct {
                 return true;
             },
             Token.Id.Keyword_if => {
-                const node = try self.createToCtxNode(arena, ctx, ast.NodeIf,
-                    ast.NodeIf {
+                const node = try self.createToCtxNode(arena, ctx, ast.Node.If,
+                    ast.Node.If {
                         .base = undefined,
                         .if_token = *token,
                         .condition = undefined,
@@ -2912,18 +2930,18 @@ pub const Parser = struct {
                 return true;
             },
             Token.Id.Keyword_switch => {
-                const node = try self.createToCtxNode(arena, ctx, ast.NodeSwitch,
-                    ast.NodeSwitch {
+                const node = try self.createToCtxNode(arena, ctx, ast.Node.Switch,
+                    ast.Node.Switch {
                         .base = undefined,
                         .switch_token = *token,
                         .expr = undefined,
-                        .cases = ArrayList(&ast.NodeSwitchCase).init(arena),
+                        .cases = ArrayList(&ast.Node.SwitchCase).init(arena),
                         .rbrace = undefined,
                     }
                 );
 
                 stack.append(State {
-                    .SwitchCaseOrEnd = ListSave(&ast.NodeSwitchCase) {
+                    .SwitchCaseOrEnd = ListSave(&ast.Node.SwitchCase) {
                         .list = &node.cases,
                         .ptr = &node.rbrace,
                     },
@@ -2935,8 +2953,8 @@ pub const Parser = struct {
                 return true;
             },
             Token.Id.Keyword_comptime => {
-                const node = try self.createToCtxNode(arena, ctx, ast.NodeComptime,
-                    ast.NodeComptime {
+                const node = try self.createToCtxNode(arena, ctx, ast.Node.Comptime,
+                    ast.Node.Comptime {
                         .base = undefined,
                         .comptime_token = *token,
                         .expr = undefined,
@@ -2946,8 +2964,8 @@ pub const Parser = struct {
                 return true;
             },
             Token.Id.LBrace => {
-                const block = try self.createToCtxNode(arena, ctx, ast.NodeBlock,
-                    ast.NodeBlock {
+                const block = try self.createToCtxNode(arena, ctx, ast.Node.Block,
+                    ast.Node.Block {
                         .base = undefined,
                         .label = null,
                         .lbrace = *token,
@@ -2978,88 +2996,88 @@ pub const Parser = struct {
         }
     }
 
-    fn tokenIdToAssignment(id: &const Token.Id) ?ast.NodeInfixOp.InfixOp {
+    fn tokenIdToAssignment(id: &const Token.Id) ?ast.Node.InfixOp.Op {
         // TODO: We have to cast all cases because of this:
         // error: expected type '?InfixOp', found '?@TagType(InfixOp)'
         return switch (*id) {
-            Token.Id.AmpersandEqual => ast.NodeInfixOp.InfixOp { .AssignBitAnd = void{} },
-            Token.Id.AngleBracketAngleBracketLeftEqual => ast.NodeInfixOp.InfixOp { .AssignBitShiftLeft = void{} },
-            Token.Id.AngleBracketAngleBracketRightEqual => ast.NodeInfixOp.InfixOp { .AssignBitShiftRight = void{} },
-            Token.Id.AsteriskEqual => ast.NodeInfixOp.InfixOp { .AssignTimes = void{} },
-            Token.Id.AsteriskPercentEqual => ast.NodeInfixOp.InfixOp { .AssignTimesWarp = void{} },
-            Token.Id.CaretEqual => ast.NodeInfixOp.InfixOp { .AssignBitXor = void{} },
-            Token.Id.Equal => ast.NodeInfixOp.InfixOp { .Assign = void{} },
-            Token.Id.MinusEqual => ast.NodeInfixOp.InfixOp { .AssignMinus = void{} },
-            Token.Id.MinusPercentEqual => ast.NodeInfixOp.InfixOp { .AssignMinusWrap = void{} },
-            Token.Id.PercentEqual => ast.NodeInfixOp.InfixOp { .AssignMod = void{} },
-            Token.Id.PipeEqual => ast.NodeInfixOp.InfixOp { .AssignBitOr = void{} },
-            Token.Id.PlusEqual => ast.NodeInfixOp.InfixOp { .AssignPlus = void{} },
-            Token.Id.PlusPercentEqual => ast.NodeInfixOp.InfixOp { .AssignPlusWrap = void{} },
-            Token.Id.SlashEqual => ast.NodeInfixOp.InfixOp { .AssignDiv = void{} },
+            Token.Id.AmpersandEqual => ast.Node.InfixOp.Op { .AssignBitAnd = void{} },
+            Token.Id.AngleBracketAngleBracketLeftEqual => ast.Node.InfixOp.Op { .AssignBitShiftLeft = void{} },
+            Token.Id.AngleBracketAngleBracketRightEqual => ast.Node.InfixOp.Op { .AssignBitShiftRight = void{} },
+            Token.Id.AsteriskEqual => ast.Node.InfixOp.Op { .AssignTimes = void{} },
+            Token.Id.AsteriskPercentEqual => ast.Node.InfixOp.Op { .AssignTimesWarp = void{} },
+            Token.Id.CaretEqual => ast.Node.InfixOp.Op { .AssignBitXor = void{} },
+            Token.Id.Equal => ast.Node.InfixOp.Op { .Assign = void{} },
+            Token.Id.MinusEqual => ast.Node.InfixOp.Op { .AssignMinus = void{} },
+            Token.Id.MinusPercentEqual => ast.Node.InfixOp.Op { .AssignMinusWrap = void{} },
+            Token.Id.PercentEqual => ast.Node.InfixOp.Op { .AssignMod = void{} },
+            Token.Id.PipeEqual => ast.Node.InfixOp.Op { .AssignBitOr = void{} },
+            Token.Id.PlusEqual => ast.Node.InfixOp.Op { .AssignPlus = void{} },
+            Token.Id.PlusPercentEqual => ast.Node.InfixOp.Op { .AssignPlusWrap = void{} },
+            Token.Id.SlashEqual => ast.Node.InfixOp.Op { .AssignDiv = void{} },
             else => null,
         };
     }
 
-    fn tokenIdToUnwrapExpr(id: @TagType(Token.Id)) ?ast.NodeInfixOp.InfixOp {
+    fn tokenIdToUnwrapExpr(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
         return switch (id) {
-            Token.Id.Keyword_catch => ast.NodeInfixOp.InfixOp { .Catch = null },
-            Token.Id.QuestionMarkQuestionMark => ast.NodeInfixOp.InfixOp { .UnwrapMaybe = void{} },
+            Token.Id.Keyword_catch => ast.Node.InfixOp.Op { .Catch = null },
+            Token.Id.QuestionMarkQuestionMark => ast.Node.InfixOp.Op { .UnwrapMaybe = void{} },
             else => null,
         };
     }
 
-    fn tokenIdToComparison(id: @TagType(Token.Id)) ?ast.NodeInfixOp.InfixOp {
+    fn tokenIdToComparison(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
         return switch (id) {
-            Token.Id.BangEqual => ast.NodeInfixOp.InfixOp { .BangEqual = void{} },
-            Token.Id.EqualEqual => ast.NodeInfixOp.InfixOp { .EqualEqual = void{} },
-            Token.Id.AngleBracketLeft => ast.NodeInfixOp.InfixOp { .LessThan = void{} },
-            Token.Id.AngleBracketLeftEqual => ast.NodeInfixOp.InfixOp { .LessOrEqual = void{} },
-            Token.Id.AngleBracketRight => ast.NodeInfixOp.InfixOp { .GreaterThan = void{} },
-            Token.Id.AngleBracketRightEqual => ast.NodeInfixOp.InfixOp { .GreaterOrEqual = void{} },
+            Token.Id.BangEqual => ast.Node.InfixOp.Op { .BangEqual = void{} },
+            Token.Id.EqualEqual => ast.Node.InfixOp.Op { .EqualEqual = void{} },
+            Token.Id.AngleBracketLeft => ast.Node.InfixOp.Op { .LessThan = void{} },
+            Token.Id.AngleBracketLeftEqual => ast.Node.InfixOp.Op { .LessOrEqual = void{} },
+            Token.Id.AngleBracketRight => ast.Node.InfixOp.Op { .GreaterThan = void{} },
+            Token.Id.AngleBracketRightEqual => ast.Node.InfixOp.Op { .GreaterOrEqual = void{} },
             else => null,
         };
     }
 
-    fn tokenIdToBitShift(id: @TagType(Token.Id)) ?ast.NodeInfixOp.InfixOp {
+    fn tokenIdToBitShift(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
         return switch (id) {
-            Token.Id.AngleBracketAngleBracketLeft => ast.NodeInfixOp.InfixOp { .BitShiftLeft = void{} },
-            Token.Id.AngleBracketAngleBracketRight => ast.NodeInfixOp.InfixOp { .BitShiftRight = void{} },
+            Token.Id.AngleBracketAngleBracketLeft => ast.Node.InfixOp.Op { .BitShiftLeft = void{} },
+            Token.Id.AngleBracketAngleBracketRight => ast.Node.InfixOp.Op { .BitShiftRight = void{} },
             else => null,
         };
     }
 
-    fn tokenIdToAddition(id: @TagType(Token.Id)) ?ast.NodeInfixOp.InfixOp {
+    fn tokenIdToAddition(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
         return switch (id) {
-            Token.Id.Minus => ast.NodeInfixOp.InfixOp { .Sub = void{} },
-            Token.Id.MinusPercent => ast.NodeInfixOp.InfixOp { .SubWrap = void{} },
-            Token.Id.Plus => ast.NodeInfixOp.InfixOp { .Add = void{} },
-            Token.Id.PlusPercent => ast.NodeInfixOp.InfixOp { .AddWrap = void{} },
-            Token.Id.PlusPlus => ast.NodeInfixOp.InfixOp { .ArrayCat = void{} },
+            Token.Id.Minus => ast.Node.InfixOp.Op { .Sub = void{} },
+            Token.Id.MinusPercent => ast.Node.InfixOp.Op { .SubWrap = void{} },
+            Token.Id.Plus => ast.Node.InfixOp.Op { .Add = void{} },
+            Token.Id.PlusPercent => ast.Node.InfixOp.Op { .AddWrap = void{} },
+            Token.Id.PlusPlus => ast.Node.InfixOp.Op { .ArrayCat = void{} },
             else => null,
         };
     }
 
-    fn tokenIdToMultiply(id: @TagType(Token.Id)) ?ast.NodeInfixOp.InfixOp {
+    fn tokenIdToMultiply(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
         return switch (id) {
-            Token.Id.Slash => ast.NodeInfixOp.InfixOp { .Div = void{} },
-            Token.Id.Asterisk => ast.NodeInfixOp.InfixOp { .Mult = void{} },
-            Token.Id.AsteriskAsterisk => ast.NodeInfixOp.InfixOp { .ArrayMult = void{} },
-            Token.Id.AsteriskPercent => ast.NodeInfixOp.InfixOp { .MultWrap = void{} },
-            Token.Id.Percent => ast.NodeInfixOp.InfixOp { .Mod = void{} },
-            Token.Id.PipePipe => ast.NodeInfixOp.InfixOp { .MergeErrorSets = void{} },
+            Token.Id.Slash => ast.Node.InfixOp.Op { .Div = void{} },
+            Token.Id.Asterisk => ast.Node.InfixOp.Op { .Mult = void{} },
+            Token.Id.AsteriskAsterisk => ast.Node.InfixOp.Op { .ArrayMult = void{} },
+            Token.Id.AsteriskPercent => ast.Node.InfixOp.Op { .MultWrap = void{} },
+            Token.Id.Percent => ast.Node.InfixOp.Op { .Mod = void{} },
+            Token.Id.PipePipe => ast.Node.InfixOp.Op { .MergeErrorSets = void{} },
             else => null,
         };
     }
 
-    fn tokenIdToPrefixOp(id: @TagType(Token.Id)) ?ast.NodePrefixOp.PrefixOp {
+    fn tokenIdToPrefixOp(id: @TagType(Token.Id)) ?ast.Node.PrefixOp.Op {
         return switch (id) {
-            Token.Id.Bang => ast.NodePrefixOp.PrefixOp { .BoolNot = void{} },
-            Token.Id.Tilde => ast.NodePrefixOp.PrefixOp { .BitNot = void{} },
-            Token.Id.Minus => ast.NodePrefixOp.PrefixOp { .Negation = void{} },
-            Token.Id.MinusPercent => ast.NodePrefixOp.PrefixOp { .NegationWrap = void{} },
-            Token.Id.Asterisk, Token.Id.AsteriskAsterisk => ast.NodePrefixOp.PrefixOp { .Deref = void{} },
-            Token.Id.Ampersand => ast.NodePrefixOp.PrefixOp {
-                .AddrOf = ast.NodePrefixOp.AddrOfInfo {
+            Token.Id.Bang => ast.Node.PrefixOp.Op { .BoolNot = void{} },
+            Token.Id.Tilde => ast.Node.PrefixOp.Op { .BitNot = void{} },
+            Token.Id.Minus => ast.Node.PrefixOp.Op { .Negation = void{} },
+            Token.Id.MinusPercent => ast.Node.PrefixOp.Op { .NegationWrap = void{} },
+            Token.Id.Asterisk, Token.Id.AsteriskAsterisk => ast.Node.PrefixOp.Op { .Deref = void{} },
+            Token.Id.Ampersand => ast.Node.PrefixOp.Op {
+                .AddrOf = ast.Node.PrefixOp.AddrOfInfo {
                     .align_expr = null,
                     .bit_offset_start_token = null,
                     .bit_offset_end_token = null,
@@ -3067,10 +3085,10 @@ pub const Parser = struct {
                     .volatile_token = null,
                 },
             },
-            Token.Id.QuestionMark => ast.NodePrefixOp.PrefixOp { .MaybeType = void{} },
-            Token.Id.QuestionMarkQuestionMark => ast.NodePrefixOp.PrefixOp { .UnwrapMaybe = void{} },
-            Token.Id.Keyword_await => ast.NodePrefixOp.PrefixOp { .Await = void{} },
-            Token.Id.Keyword_try => ast.NodePrefixOp.PrefixOp { .Try = void{ } },
+            Token.Id.QuestionMark => ast.Node.PrefixOp.Op { .MaybeType = void{} },
+            Token.Id.QuestionMarkQuestionMark => ast.Node.PrefixOp.Op { .UnwrapMaybe = void{} },
+            Token.Id.Keyword_await => ast.Node.PrefixOp.Op { .Await = void{} },
+            Token.Id.Keyword_try => ast.Node.PrefixOp.Op { .Try = void{ } },
             else => null,
         };
     }
@@ -3080,11 +3098,7 @@ pub const Parser = struct {
         *node = *init_to;
         node.base = blk: {
             const id = ast.Node.typeToId(T);
-            if (self.pending_line_comment_node) |comment_node| {
-                self.pending_line_comment_node = null;
-                break :blk ast.Node {.id = id, .comment = comment_node};
-            }
-            break :blk ast.Node {.id = id, .comment = null };
+            break :blk ast.Node {.id = id};
         };
 
         return node;
@@ -3183,7 +3197,7 @@ pub const Parser = struct {
         indent: usize,
     };
 
-    pub fn renderAst(self: &Parser, stream: var, root_node: &ast.NodeRoot) !void {
+    pub fn renderAst(self: &Parser, stream: var, root_node: &ast.Node.Root) !void {
         var stack = self.initUtilityArrayList(RenderAstFrame);
         defer self.deinitUtilityArrayList(stack);
 
@@ -3215,14 +3229,14 @@ pub const Parser = struct {
         ParamDecl: &ast.Node,
         Text: []const u8,
         Expression: &ast.Node,
-        VarDecl: &ast.NodeVarDecl,
+        VarDecl: &ast.Node.VarDecl,
         Statement: &ast.Node,
-        FieldInitializer: &ast.NodeFieldInitializer,
+        FieldInitializer: &ast.Node.FieldInitializer,
         PrintIndent,
         Indent: usize,
     };
 
-    pub fn renderSource(self: &Parser, stream: var, root_node: &ast.NodeRoot) !void {
+    pub fn renderSource(self: &Parser, stream: var, root_node: &ast.Node.Root) !void {
         var stack = self.initUtilityArrayList(RenderState);
         defer self.deinitUtilityArrayList(stack);
 
@@ -3256,7 +3270,8 @@ pub const Parser = struct {
                 RenderState.TopLevelDecl => |decl| {
                     switch (decl.id) {
                         ast.Node.Id.FnProto => {
-                            const fn_proto = @fieldParentPtr(ast.NodeFnProto, "base", decl);
+                            const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);
+                            try self.renderComments(stream, fn_proto, indent);
 
                             if (fn_proto.body_node) |body_node| {
                                 stack.append(RenderState { .Expression = body_node}) catch unreachable;
@@ -3268,7 +3283,7 @@ pub const Parser = struct {
                             try stack.append(RenderState { .Expression = decl });
                         },
                         ast.Node.Id.Use => {
-                            const use_decl = @fieldParentPtr(ast.NodeUse, "base", decl);
+                            const use_decl = @fieldParentPtr(ast.Node.Use, "base", decl);
                             if (use_decl.visib_token) |visib_token| {
                                 try stream.print("{} ", self.tokenizer.getTokenSlice(visib_token));
                             }
@@ -3277,18 +3292,19 @@ pub const Parser = struct {
                             try stack.append(RenderState { .Expression = use_decl.expr });
                         },
                         ast.Node.Id.VarDecl => {
-                            const var_decl = @fieldParentPtr(ast.NodeVarDecl, "base", decl);
+                            const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", decl);
                             try stack.append(RenderState { .VarDecl = var_decl});
                         },
                         ast.Node.Id.TestDecl => {
-                            const test_decl = @fieldParentPtr(ast.NodeTestDecl, "base", decl);
+                            const test_decl = @fieldParentPtr(ast.Node.TestDecl, "base", decl);
+                            try self.renderComments(stream, test_decl, indent);
                             try stream.print("test ");
                             try stack.append(RenderState { .Expression = test_decl.body_node });
                             try stack.append(RenderState { .Text = " " });
                             try stack.append(RenderState { .Expression = test_decl.name });
                         },
                         ast.Node.Id.StructField => {
-                            const field = @fieldParentPtr(ast.NodeStructField, "base", decl);
+                            const field = @fieldParentPtr(ast.Node.StructField, "base", decl);
                             if (field.visib_token) |visib_token| {
                                 try stream.print("{} ", self.tokenizer.getTokenSlice(visib_token));
                             }
@@ -3296,7 +3312,7 @@ pub const Parser = struct {
                             try stack.append(RenderState { .Expression = field.type_expr});
                         },
                         ast.Node.Id.UnionTag => {
-                            const tag = @fieldParentPtr(ast.NodeUnionTag, "base", decl);
+                            const tag = @fieldParentPtr(ast.Node.UnionTag, "base", decl);
                             try stream.print("{}", self.tokenizer.getTokenSlice(tag.name_token));
 
                             if (tag.type_expr) |type_expr| {
@@ -3305,7 +3321,7 @@ pub const Parser = struct {
                             }
                         },
                         ast.Node.Id.EnumTag => {
-                            const tag = @fieldParentPtr(ast.NodeEnumTag, "base", decl);
+                            const tag = @fieldParentPtr(ast.Node.EnumTag, "base", decl);
                             try stream.print("{}", self.tokenizer.getTokenSlice(tag.name_token));
 
                             if (tag.value) |value| {
@@ -3324,6 +3340,7 @@ pub const Parser = struct {
                 },
 
                 RenderState.FieldInitializer => |field_init| {
+                    //TODO try self.renderComments(stream, field_init, indent);
                     try stream.print(".{}", self.tokenizer.getTokenSlice(field_init.name_token));
                     try stream.print(" = ");
                     try stack.append(RenderState { .Expression = field_init.expr });
@@ -3369,7 +3386,8 @@ pub const Parser = struct {
                 },
 
                 RenderState.ParamDecl => |base| {
-                    const param_decl = @fieldParentPtr(ast.NodeParamDecl, "base", base);
+                    const param_decl = @fieldParentPtr(ast.Node.ParamDecl, "base", base);
+                    // TODO try self.renderComments(stream, param_decl, indent);
                     if (param_decl.comptime_token) |comptime_token| {
                         try stream.print("{} ", self.tokenizer.getTokenSlice(comptime_token));
                     }
@@ -3390,11 +3408,11 @@ pub const Parser = struct {
                 },
                 RenderState.Expression => |base| switch (base.id) {
                     ast.Node.Id.Identifier => {
-                        const identifier = @fieldParentPtr(ast.NodeIdentifier, "base", base);
+                        const identifier = @fieldParentPtr(ast.Node.Identifier, "base", base);
                         try stream.print("{}", self.tokenizer.getTokenSlice(identifier.token));
                     },
                     ast.Node.Id.Block => {
-                        const block = @fieldParentPtr(ast.NodeBlock, "base", base);
+                        const block = @fieldParentPtr(ast.Node.Block, "base", base);
                         if (block.label) |label| {
                             try stream.print("{}: ", self.tokenizer.getTokenSlice(label));
                         }
@@ -3430,17 +3448,17 @@ pub const Parser = struct {
                         }
                     },
                     ast.Node.Id.Defer => {
-                        const defer_node = @fieldParentPtr(ast.NodeDefer, "base", base);
+                        const defer_node = @fieldParentPtr(ast.Node.Defer, "base", base);
                         try stream.print("{} ", self.tokenizer.getTokenSlice(defer_node.defer_token));
                         try stack.append(RenderState { .Expression = defer_node.expr });
                     },
                     ast.Node.Id.Comptime => {
-                        const comptime_node = @fieldParentPtr(ast.NodeComptime, "base", base);
+                        const comptime_node = @fieldParentPtr(ast.Node.Comptime, "base", base);
                         try stream.print("{} ", self.tokenizer.getTokenSlice(comptime_node.comptime_token));
                         try stack.append(RenderState { .Expression = comptime_node.expr });
                     },
                     ast.Node.Id.AsyncAttribute => {
-                        const async_attr = @fieldParentPtr(ast.NodeAsyncAttribute, "base", base);
+                        const async_attr = @fieldParentPtr(ast.Node.AsyncAttribute, "base", base);
                         try stream.print("{}", self.tokenizer.getTokenSlice(async_attr.async_token));
 
                         if (async_attr.allocator_type) |allocator_type| {
@@ -3450,7 +3468,7 @@ pub const Parser = struct {
                         }
                     },
                     ast.Node.Id.Suspend => {
-                        const suspend_node = @fieldParentPtr(ast.NodeSuspend, "base", base);
+                        const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base);
                         try stream.print("{}", self.tokenizer.getTokenSlice(suspend_node.suspend_token));
 
                         if (suspend_node.body) |body| {
@@ -3464,10 +3482,10 @@ pub const Parser = struct {
                         }
                     },
                     ast.Node.Id.InfixOp => {
-                        const prefix_op_node = @fieldParentPtr(ast.NodeInfixOp, "base", base);
+                        const prefix_op_node = @fieldParentPtr(ast.Node.InfixOp, "base", base);
                         try stack.append(RenderState { .Expression = prefix_op_node.rhs });
 
-                        if (prefix_op_node.op == ast.NodeInfixOp.InfixOp.Catch) {
+                        if (prefix_op_node.op == ast.Node.InfixOp.Op.Catch) {
                             if (prefix_op_node.op.Catch) |payload| {
                             try stack.append(RenderState { .Text = " " });
                                 try stack.append(RenderState { .Expression = payload });
@@ -3475,49 +3493,49 @@ pub const Parser = struct {
                             try stack.append(RenderState { .Text = " catch " });
                         } else {
                             const text = switch (prefix_op_node.op) {
-                                ast.NodeInfixOp.InfixOp.Add => " + ",
-                                ast.NodeInfixOp.InfixOp.AddWrap => " +% ",
-                                ast.NodeInfixOp.InfixOp.ArrayCat => " ++ ",
-                                ast.NodeInfixOp.InfixOp.ArrayMult => " ** ",
-                                ast.NodeInfixOp.InfixOp.Assign => " = ",
-                                ast.NodeInfixOp.InfixOp.AssignBitAnd => " &= ",
-                                ast.NodeInfixOp.InfixOp.AssignBitOr => " |= ",
-                                ast.NodeInfixOp.InfixOp.AssignBitShiftLeft => " <<= ",
-                                ast.NodeInfixOp.InfixOp.AssignBitShiftRight => " >>= ",
-                                ast.NodeInfixOp.InfixOp.AssignBitXor => " ^= ",
-                                ast.NodeInfixOp.InfixOp.AssignDiv => " /= ",
-                                ast.NodeInfixOp.InfixOp.AssignMinus => " -= ",
-                                ast.NodeInfixOp.InfixOp.AssignMinusWrap => " -%= ",
-                                ast.NodeInfixOp.InfixOp.AssignMod => " %= ",
-                                ast.NodeInfixOp.InfixOp.AssignPlus => " += ",
-                                ast.NodeInfixOp.InfixOp.AssignPlusWrap => " +%= ",
-                                ast.NodeInfixOp.InfixOp.AssignTimes => " *= ",
-                                ast.NodeInfixOp.InfixOp.AssignTimesWarp => " *%= ",
-                                ast.NodeInfixOp.InfixOp.BangEqual => " != ",
-                                ast.NodeInfixOp.InfixOp.BitAnd => " & ",
-                                ast.NodeInfixOp.InfixOp.BitOr => " | ",
-                                ast.NodeInfixOp.InfixOp.BitShiftLeft => " << ",
-                                ast.NodeInfixOp.InfixOp.BitShiftRight => " >> ",
-                                ast.NodeInfixOp.InfixOp.BitXor => " ^ ",
-                                ast.NodeInfixOp.InfixOp.BoolAnd => " and ",
-                                ast.NodeInfixOp.InfixOp.BoolOr => " or ",
-                                ast.NodeInfixOp.InfixOp.Div => " / ",
-                                ast.NodeInfixOp.InfixOp.EqualEqual => " == ",
-                                ast.NodeInfixOp.InfixOp.ErrorUnion => "!",
-                                ast.NodeInfixOp.InfixOp.GreaterOrEqual => " >= ",
-                                ast.NodeInfixOp.InfixOp.GreaterThan => " > ",
-                                ast.NodeInfixOp.InfixOp.LessOrEqual => " <= ",
-                                ast.NodeInfixOp.InfixOp.LessThan => " < ",
-                                ast.NodeInfixOp.InfixOp.MergeErrorSets => " || ",
-                                ast.NodeInfixOp.InfixOp.Mod => " % ",
-                                ast.NodeInfixOp.InfixOp.Mult => " * ",
-                                ast.NodeInfixOp.InfixOp.MultWrap => " *% ",
-                                ast.NodeInfixOp.InfixOp.Period => ".",
-                                ast.NodeInfixOp.InfixOp.Sub => " - ",
-                                ast.NodeInfixOp.InfixOp.SubWrap => " -% ",
-                                ast.NodeInfixOp.InfixOp.UnwrapMaybe => " ?? ",
-                                ast.NodeInfixOp.InfixOp.Range => " ... ",
-                                ast.NodeInfixOp.InfixOp.Catch => unreachable,
+                                ast.Node.InfixOp.Op.Add => " + ",
+                                ast.Node.InfixOp.Op.AddWrap => " +% ",
+                                ast.Node.InfixOp.Op.ArrayCat => " ++ ",
+                                ast.Node.InfixOp.Op.ArrayMult => " ** ",
+                                ast.Node.InfixOp.Op.Assign => " = ",
+                                ast.Node.InfixOp.Op.AssignBitAnd => " &= ",
+                                ast.Node.InfixOp.Op.AssignBitOr => " |= ",
+                                ast.Node.InfixOp.Op.AssignBitShiftLeft => " <<= ",
+                                ast.Node.InfixOp.Op.AssignBitShiftRight => " >>= ",
+                                ast.Node.InfixOp.Op.AssignBitXor => " ^= ",
+                                ast.Node.InfixOp.Op.AssignDiv => " /= ",
+                                ast.Node.InfixOp.Op.AssignMinus => " -= ",
+                                ast.Node.InfixOp.Op.AssignMinusWrap => " -%= ",
+                                ast.Node.InfixOp.Op.AssignMod => " %= ",
+                                ast.Node.InfixOp.Op.AssignPlus => " += ",
+                                ast.Node.InfixOp.Op.AssignPlusWrap => " +%= ",
+                                ast.Node.InfixOp.Op.AssignTimes => " *= ",
+                                ast.Node.InfixOp.Op.AssignTimesWarp => " *%= ",
+                                ast.Node.InfixOp.Op.BangEqual => " != ",
+                                ast.Node.InfixOp.Op.BitAnd => " & ",
+                                ast.Node.InfixOp.Op.BitOr => " | ",
+                                ast.Node.InfixOp.Op.BitShiftLeft => " << ",
+                                ast.Node.InfixOp.Op.BitShiftRight => " >> ",
+                                ast.Node.InfixOp.Op.BitXor => " ^ ",
+                                ast.Node.InfixOp.Op.BoolAnd => " and ",
+                                ast.Node.InfixOp.Op.BoolOr => " or ",
+                                ast.Node.InfixOp.Op.Div => " / ",
+                                ast.Node.InfixOp.Op.EqualEqual => " == ",
+                                ast.Node.InfixOp.Op.ErrorUnion => "!",
+                                ast.Node.InfixOp.Op.GreaterOrEqual => " >= ",
+                                ast.Node.InfixOp.Op.GreaterThan => " > ",
+                                ast.Node.InfixOp.Op.LessOrEqual => " <= ",
+                                ast.Node.InfixOp.Op.LessThan => " < ",
+                                ast.Node.InfixOp.Op.MergeErrorSets => " || ",
+                                ast.Node.InfixOp.Op.Mod => " % ",
+                                ast.Node.InfixOp.Op.Mult => " * ",
+                                ast.Node.InfixOp.Op.MultWrap => " *% ",
+                                ast.Node.InfixOp.Op.Period => ".",
+                                ast.Node.InfixOp.Op.Sub => " - ",
+                                ast.Node.InfixOp.Op.SubWrap => " -% ",
+                                ast.Node.InfixOp.Op.UnwrapMaybe => " ?? ",
+                                ast.Node.InfixOp.Op.Range => " ... ",
+                                ast.Node.InfixOp.Op.Catch => unreachable,
                             };
 
                             try stack.append(RenderState { .Text = text });
@@ -3525,10 +3543,10 @@ pub const Parser = struct {
                         try stack.append(RenderState { .Expression = prefix_op_node.lhs });
                     },
                     ast.Node.Id.PrefixOp => {
-                        const prefix_op_node = @fieldParentPtr(ast.NodePrefixOp, "base", base);
+                        const prefix_op_node = @fieldParentPtr(ast.Node.PrefixOp, "base", base);
                         try stack.append(RenderState { .Expression = prefix_op_node.rhs });
                         switch (prefix_op_node.op) {
-                            ast.NodePrefixOp.PrefixOp.AddrOf => |addr_of_info| {
+                            ast.Node.PrefixOp.Op.AddrOf => |addr_of_info| {
                                 try stream.write("&");
                                 if (addr_of_info.volatile_token != null) {
                                     try stack.append(RenderState { .Text = "volatile "});
@@ -3542,7 +3560,7 @@ pub const Parser = struct {
                                     try stack.append(RenderState { .Expression = align_expr});
                                 }
                             },
-                            ast.NodePrefixOp.PrefixOp.SliceType => |addr_of_info| {
+                            ast.Node.PrefixOp.Op.SliceType => |addr_of_info| {
                                 try stream.write("[]");
                                 if (addr_of_info.volatile_token != null) {
                                     try stack.append(RenderState { .Text = "volatile "});
@@ -3556,29 +3574,29 @@ pub const Parser = struct {
                                     try stack.append(RenderState { .Expression = align_expr});
                                 }
                             },
-                            ast.NodePrefixOp.PrefixOp.ArrayType => |array_index| {
+                            ast.Node.PrefixOp.Op.ArrayType => |array_index| {
                                 try stack.append(RenderState { .Text = "]"});
                                 try stack.append(RenderState { .Expression = array_index});
                                 try stack.append(RenderState { .Text = "["});
                             },
-                            ast.NodePrefixOp.PrefixOp.BitNot => try stream.write("~"),
-                            ast.NodePrefixOp.PrefixOp.BoolNot => try stream.write("!"),
-                            ast.NodePrefixOp.PrefixOp.Deref => try stream.write("*"),
-                            ast.NodePrefixOp.PrefixOp.Negation => try stream.write("-"),
-                            ast.NodePrefixOp.PrefixOp.NegationWrap => try stream.write("-%"),
-                            ast.NodePrefixOp.PrefixOp.Try => try stream.write("try "),
-                            ast.NodePrefixOp.PrefixOp.UnwrapMaybe => try stream.write("??"),
-                            ast.NodePrefixOp.PrefixOp.MaybeType => try stream.write("?"),
-                            ast.NodePrefixOp.PrefixOp.Await => try stream.write("await "),
-                            ast.NodePrefixOp.PrefixOp.Cancel => try stream.write("cancel "),
-                            ast.NodePrefixOp.PrefixOp.Resume => try stream.write("resume "),
+                            ast.Node.PrefixOp.Op.BitNot => try stream.write("~"),
+                            ast.Node.PrefixOp.Op.BoolNot => try stream.write("!"),
+                            ast.Node.PrefixOp.Op.Deref => try stream.write("*"),
+                            ast.Node.PrefixOp.Op.Negation => try stream.write("-"),
+                            ast.Node.PrefixOp.Op.NegationWrap => try stream.write("-%"),
+                            ast.Node.PrefixOp.Op.Try => try stream.write("try "),
+                            ast.Node.PrefixOp.Op.UnwrapMaybe => try stream.write("??"),
+                            ast.Node.PrefixOp.Op.MaybeType => try stream.write("?"),
+                            ast.Node.PrefixOp.Op.Await => try stream.write("await "),
+                            ast.Node.PrefixOp.Op.Cancel => try stream.write("cancel "),
+                            ast.Node.PrefixOp.Op.Resume => try stream.write("resume "),
                         }
                     },
                     ast.Node.Id.SuffixOp => {
-                        const suffix_op = @fieldParentPtr(ast.NodeSuffixOp, "base", base);
+                        const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", base);
 
                         switch (suffix_op.op) {
-                            ast.NodeSuffixOp.SuffixOp.Call => |call_info| {
+                            ast.Node.SuffixOp.Op.Call => |call_info| {
                                 try stack.append(RenderState { .Text = ")"});
                                 var i = call_info.params.len;
                                 while (i != 0) {
@@ -3597,13 +3615,13 @@ pub const Parser = struct {
                                     try stack.append(RenderState { .Expression = &async_attr.base });
                                 }
                             },
-                            ast.NodeSuffixOp.SuffixOp.ArrayAccess => |index_expr| {
+                            ast.Node.SuffixOp.Op.ArrayAccess => |index_expr| {
                                 try stack.append(RenderState { .Text = "]"});
                                 try stack.append(RenderState { .Expression = index_expr});
                                 try stack.append(RenderState { .Text = "["});
                                 try stack.append(RenderState { .Expression = suffix_op.lhs });
                             },
-                            ast.NodeSuffixOp.SuffixOp.Slice => |range| {
+                            ast.Node.SuffixOp.Op.Slice => |range| {
                                 try stack.append(RenderState { .Text = "]"});
                                 if (range.end) |end| {
                                     try stack.append(RenderState { .Expression = end});
@@ -3613,7 +3631,7 @@ pub const Parser = struct {
                                 try stack.append(RenderState { .Text = "["});
                                 try stack.append(RenderState { .Expression = suffix_op.lhs });
                             },
-                            ast.NodeSuffixOp.SuffixOp.StructInitializer => |field_inits| {
+                            ast.Node.SuffixOp.Op.StructInitializer => |field_inits| {
                                 if (field_inits.len == 0) {
                                     try stack.append(RenderState { .Text = "{}" });
                                     try stack.append(RenderState { .Expression = suffix_op.lhs });
@@ -3634,7 +3652,7 @@ pub const Parser = struct {
                                 try stack.append(RenderState { .Text = " {\n"});
                                 try stack.append(RenderState { .Expression = suffix_op.lhs });
                             },
-                            ast.NodeSuffixOp.SuffixOp.ArrayInitializer => |exprs| {
+                            ast.Node.SuffixOp.Op.ArrayInitializer => |exprs| {
                                 if (exprs.len == 0) {
                                     try stack.append(RenderState { .Text = "{}" });
                                     try stack.append(RenderState { .Expression = suffix_op.lhs });
@@ -3658,7 +3676,7 @@ pub const Parser = struct {
                         }
                     },
                     ast.Node.Id.ControlFlowExpression => {
-                        const flow_expr = @fieldParentPtr(ast.NodeControlFlowExpression, "base", base);
+                        const flow_expr = @fieldParentPtr(ast.Node.ControlFlowExpression, "base", base);
 
                         if (flow_expr.rhs) |rhs| {
                             try stack.append(RenderState { .Expression = rhs });
@@ -3666,34 +3684,34 @@ pub const Parser = struct {
                         }
 
                         switch (flow_expr.kind) {
-                            ast.NodeControlFlowExpression.Kind.Break => |maybe_label| {
+                            ast.Node.ControlFlowExpression.Kind.Break => |maybe_label| {
                                 try stream.print("break");
                                 if (maybe_label) |label| {
                                     try stream.print(" :");
                                     try stack.append(RenderState { .Expression = label });
                                 }
                             },
-                            ast.NodeControlFlowExpression.Kind.Continue => |maybe_label| {
+                            ast.Node.ControlFlowExpression.Kind.Continue => |maybe_label| {
                                 try stream.print("continue");
                                 if (maybe_label) |label| {
                                     try stream.print(" :");
                                     try stack.append(RenderState { .Expression = label });
                                 }
                             },
-                            ast.NodeControlFlowExpression.Kind.Return => {
+                            ast.Node.ControlFlowExpression.Kind.Return => {
                                 try stream.print("return");
                             },
 
                         }
                     },
                     ast.Node.Id.Payload => {
-                        const payload = @fieldParentPtr(ast.NodePayload, "base", base);
+                        const payload = @fieldParentPtr(ast.Node.Payload, "base", base);
                         try stack.append(RenderState { .Text = "|"});
                         try stack.append(RenderState { .Expression = payload.error_symbol });
                         try stack.append(RenderState { .Text = "|"});
                     },
                     ast.Node.Id.PointerPayload => {
-                        const payload = @fieldParentPtr(ast.NodePointerPayload, "base", base);
+                        const payload = @fieldParentPtr(ast.Node.PointerPayload, "base", base);
                         try stack.append(RenderState { .Text = "|"});
                         try stack.append(RenderState { .Expression = payload.value_symbol });
 
@@ -3704,7 +3722,7 @@ pub const Parser = struct {
                         try stack.append(RenderState { .Text = "|"});
                     },
                     ast.Node.Id.PointerIndexPayload => {
-                        const payload = @fieldParentPtr(ast.NodePointerIndexPayload, "base", base);
+                        const payload = @fieldParentPtr(ast.Node.PointerIndexPayload, "base", base);
                         try stack.append(RenderState { .Text = "|"});
 
                         if (payload.index_symbol) |index_symbol| {
@@ -3721,69 +3739,69 @@ pub const Parser = struct {
                         try stack.append(RenderState { .Text = "|"});
                     },
                     ast.Node.Id.GroupedExpression => {
-                        const grouped_expr = @fieldParentPtr(ast.NodeGroupedExpression, "base", base);
+                        const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", base);
                         try stack.append(RenderState { .Text = ")"});
                         try stack.append(RenderState { .Expression = grouped_expr.expr });
                         try stack.append(RenderState { .Text = "("});
                     },
                     ast.Node.Id.FieldInitializer => {
-                        const field_init = @fieldParentPtr(ast.NodeFieldInitializer, "base", base);
+                        const field_init = @fieldParentPtr(ast.Node.FieldInitializer, "base", base);
                         try stream.print(".{} = ", self.tokenizer.getTokenSlice(field_init.name_token));
                         try stack.append(RenderState { .Expression = field_init.expr });
                     },
                     ast.Node.Id.IntegerLiteral => {
-                        const integer_literal = @fieldParentPtr(ast.NodeIntegerLiteral, "base", base);
+                        const integer_literal = @fieldParentPtr(ast.Node.IntegerLiteral, "base", base);
                         try stream.print("{}", self.tokenizer.getTokenSlice(integer_literal.token));
                     },
                     ast.Node.Id.FloatLiteral => {
-                        const float_literal = @fieldParentPtr(ast.NodeFloatLiteral, "base", base);
+                        const float_literal = @fieldParentPtr(ast.Node.FloatLiteral, "base", base);
                         try stream.print("{}", self.tokenizer.getTokenSlice(float_literal.token));
                     },
                     ast.Node.Id.StringLiteral => {
-                        const string_literal = @fieldParentPtr(ast.NodeStringLiteral, "base", base);
+                        const string_literal = @fieldParentPtr(ast.Node.StringLiteral, "base", base);
                         try stream.print("{}", self.tokenizer.getTokenSlice(string_literal.token));
                     },
                     ast.Node.Id.CharLiteral => {
-                        const char_literal = @fieldParentPtr(ast.NodeCharLiteral, "base", base);
+                        const char_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);
                         try stream.print("{}", self.tokenizer.getTokenSlice(char_literal.token));
                     },
                     ast.Node.Id.BoolLiteral => {
-                        const bool_literal = @fieldParentPtr(ast.NodeCharLiteral, "base", base);
+                        const bool_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);
                         try stream.print("{}", self.tokenizer.getTokenSlice(bool_literal.token));
                     },
                     ast.Node.Id.NullLiteral => {
-                        const null_literal = @fieldParentPtr(ast.NodeNullLiteral, "base", base);
+                        const null_literal = @fieldParentPtr(ast.Node.NullLiteral, "base", base);
                         try stream.print("{}", self.tokenizer.getTokenSlice(null_literal.token));
                     },
                     ast.Node.Id.ThisLiteral => {
-                        const this_literal = @fieldParentPtr(ast.NodeThisLiteral, "base", base);
+                        const this_literal = @fieldParentPtr(ast.Node.ThisLiteral, "base", base);
                         try stream.print("{}", self.tokenizer.getTokenSlice(this_literal.token));
                     },
                     ast.Node.Id.Unreachable => {
-                        const unreachable_node = @fieldParentPtr(ast.NodeUnreachable, "base", base);
+                        const unreachable_node = @fieldParentPtr(ast.Node.Unreachable, "base", base);
                         try stream.print("{}", self.tokenizer.getTokenSlice(unreachable_node.token));
                     },
                     ast.Node.Id.ErrorType => {
-                        const error_type = @fieldParentPtr(ast.NodeErrorType, "base", base);
+                        const error_type = @fieldParentPtr(ast.Node.ErrorType, "base", base);
                         try stream.print("{}", self.tokenizer.getTokenSlice(error_type.token));
                     },
                     ast.Node.Id.VarType => {
-                        const var_type = @fieldParentPtr(ast.NodeVarType, "base", base);
+                        const var_type = @fieldParentPtr(ast.Node.VarType, "base", base);
                         try stream.print("{}", self.tokenizer.getTokenSlice(var_type.token));
                     },
                     ast.Node.Id.ContainerDecl => {
-                        const container_decl = @fieldParentPtr(ast.NodeContainerDecl, "base", base);
+                        const container_decl = @fieldParentPtr(ast.Node.ContainerDecl, "base", base);
 
                         switch (container_decl.layout) {
-                            ast.NodeContainerDecl.Layout.Packed => try stream.print("packed "),
-                            ast.NodeContainerDecl.Layout.Extern => try stream.print("extern "),
-                            ast.NodeContainerDecl.Layout.Auto => { },
+                            ast.Node.ContainerDecl.Layout.Packed => try stream.print("packed "),
+                            ast.Node.ContainerDecl.Layout.Extern => try stream.print("extern "),
+                            ast.Node.ContainerDecl.Layout.Auto => { },
                         }
 
                         switch (container_decl.kind) {
-                            ast.NodeContainerDecl.Kind.Struct => try stream.print("struct"),
-                            ast.NodeContainerDecl.Kind.Enum => try stream.print("enum"),
-                            ast.NodeContainerDecl.Kind.Union => try stream.print("union"),
+                            ast.Node.ContainerDecl.Kind.Struct => try stream.print("struct"),
+                            ast.Node.ContainerDecl.Kind.Enum => try stream.print("enum"),
+                            ast.Node.ContainerDecl.Kind.Union => try stream.print("union"),
                         }
 
                         try stack.append(RenderState { .Text = "}"});
@@ -3823,9 +3841,9 @@ pub const Parser = struct {
                         try stack.append(RenderState { .Text = "{"});
 
                         switch (container_decl.init_arg_expr) {
-                            ast.NodeContainerDecl.InitArg.None => try stack.append(RenderState { .Text = " "}),
-                            ast.NodeContainerDecl.InitArg.Enum => try stack.append(RenderState { .Text = "(enum) "}),
-                            ast.NodeContainerDecl.InitArg.Type => |type_expr| {
+                            ast.Node.ContainerDecl.InitArg.None => try stack.append(RenderState { .Text = " "}),
+                            ast.Node.ContainerDecl.InitArg.Enum => try stack.append(RenderState { .Text = "(enum) "}),
+                            ast.Node.ContainerDecl.InitArg.Type => |type_expr| {
                                 try stack.append(RenderState { .Text = ") "});
                                 try stack.append(RenderState { .Expression = type_expr});
                                 try stack.append(RenderState { .Text = "("});
@@ -3833,7 +3851,7 @@ pub const Parser = struct {
                         }
                     },
                     ast.Node.Id.ErrorSetDecl => {
-                        const err_set_decl = @fieldParentPtr(ast.NodeErrorSetDecl, "base", base);
+                        const err_set_decl = @fieldParentPtr(ast.Node.ErrorSetDecl, "base", base);
                         try stream.print("error ");
 
                         try stack.append(RenderState { .Text = "}"});
@@ -3866,7 +3884,7 @@ pub const Parser = struct {
                         try stack.append(RenderState { .Text = "{"});
                     },
                     ast.Node.Id.MultilineStringLiteral => {
-                        const multiline_str_literal = @fieldParentPtr(ast.NodeMultilineStringLiteral, "base", base);
+                        const multiline_str_literal = @fieldParentPtr(ast.Node.MultilineStringLiteral, "base", base);
                         try stream.print("\n");
 
                         var i : usize = 0;
@@ -3878,11 +3896,11 @@ pub const Parser = struct {
                         try stream.writeByteNTimes(' ', indent + indent_delta);
                     },
                     ast.Node.Id.UndefinedLiteral => {
-                        const undefined_literal = @fieldParentPtr(ast.NodeUndefinedLiteral, "base", base);
+                        const undefined_literal = @fieldParentPtr(ast.Node.UndefinedLiteral, "base", base);
                         try stream.print("{}", self.tokenizer.getTokenSlice(undefined_literal.token));
                     },
                     ast.Node.Id.BuiltinCall => {
-                        const builtin_call = @fieldParentPtr(ast.NodeBuiltinCall, "base", base);
+                        const builtin_call = @fieldParentPtr(ast.Node.BuiltinCall, "base", base);
                         try stream.print("{}(", self.tokenizer.getTokenSlice(builtin_call.builtin_token));
                         try stack.append(RenderState { .Text = ")"});
                         var i = builtin_call.params.len;
@@ -3896,13 +3914,13 @@ pub const Parser = struct {
                         }
                     },
                     ast.Node.Id.FnProto => {
-                        const fn_proto = @fieldParentPtr(ast.NodeFnProto, "base", base);
+                        const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", base);
 
                         switch (fn_proto.return_type) {
-                            ast.NodeFnProto.ReturnType.Explicit => |node| {
+                            ast.Node.FnProto.ReturnType.Explicit => |node| {
                                 try stack.append(RenderState { .Expression = node});
                             },
-                            ast.NodeFnProto.ReturnType.InferErrorSet => |node| {
+                            ast.Node.FnProto.ReturnType.InferErrorSet => |node| {
                                 try stack.append(RenderState { .Expression = node});
                                 try stack.append(RenderState { .Text = "!"});
                             },
@@ -3960,7 +3978,7 @@ pub const Parser = struct {
                     },
                     ast.Node.Id.LineComment => @panic("TODO render line comment in an expression"),
                     ast.Node.Id.Switch => {
-                        const switch_node = @fieldParentPtr(ast.NodeSwitch, "base", base);
+                        const switch_node = @fieldParentPtr(ast.Node.Switch, "base", base);
                         try stream.print("{} (", self.tokenizer.getTokenSlice(switch_node.switch_token));
 
                         try stack.append(RenderState { .Text = "}"});
@@ -3994,7 +4012,7 @@ pub const Parser = struct {
                         try stack.append(RenderState { .Expression = switch_node.expr });
                     },
                     ast.Node.Id.SwitchCase => {
-                        const switch_case = @fieldParentPtr(ast.NodeSwitchCase, "base", base);
+                        const switch_case = @fieldParentPtr(ast.Node.SwitchCase, "base", base);
 
                         try stack.append(RenderState { .Expression = switch_case.expr });
                         if (switch_case.payload) |payload| {
@@ -4016,11 +4034,11 @@ pub const Parser = struct {
                         }
                     },
                     ast.Node.Id.SwitchElse => {
-                        const switch_else = @fieldParentPtr(ast.NodeSwitchElse, "base", base);
+                        const switch_else = @fieldParentPtr(ast.Node.SwitchElse, "base", base);
                         try stream.print("{}", self.tokenizer.getTokenSlice(switch_else.token));
                     },
                     ast.Node.Id.Else => {
-                        const else_node = @fieldParentPtr(ast.NodeElse, "base", base);
+                        const else_node = @fieldParentPtr(ast.Node.Else, "base", base);
                         try stream.print("{}", self.tokenizer.getTokenSlice(else_node.else_token));
 
                         switch (else_node.body.id) {
@@ -4045,7 +4063,7 @@ pub const Parser = struct {
                         }
                     },
                     ast.Node.Id.While => {
-                        const while_node = @fieldParentPtr(ast.NodeWhile, "base", base);
+                        const while_node = @fieldParentPtr(ast.Node.While, "base", base);
                         if (while_node.label) |label| {
                             try stream.print("{}: ", self.tokenizer.getTokenSlice(label));
                         }
@@ -4095,7 +4113,7 @@ pub const Parser = struct {
                         try stack.append(RenderState { .Text = "(" });
                     },
                     ast.Node.Id.For => {
-                        const for_node = @fieldParentPtr(ast.NodeFor, "base", base);
+                        const for_node = @fieldParentPtr(ast.Node.For, "base", base);
                         if (for_node.label) |label| {
                             try stream.print("{}: ", self.tokenizer.getTokenSlice(label));
                         }
@@ -4138,7 +4156,7 @@ pub const Parser = struct {
                         try stack.append(RenderState { .Text = "(" });
                     },
                     ast.Node.Id.If => {
-                        const if_node = @fieldParentPtr(ast.NodeIf, "base", base);
+                        const if_node = @fieldParentPtr(ast.Node.If, "base", base);
                         try stream.print("{} ", self.tokenizer.getTokenSlice(if_node.if_token));
 
                         switch (if_node.body.id) {
@@ -4185,7 +4203,7 @@ pub const Parser = struct {
                         try stack.append(RenderState { .Text = "(" });
                     },
                     ast.Node.Id.Asm => {
-                        const asm_node = @fieldParentPtr(ast.NodeAsm, "base", base);
+                        const asm_node = @fieldParentPtr(ast.Node.Asm, "base", base);
                         try stream.print("{} ", self.tokenizer.getTokenSlice(asm_node.asm_token));
 
                         if (asm_node.volatile_token) |volatile_token| {
@@ -4272,7 +4290,7 @@ pub const Parser = struct {
                         try stack.append(RenderState { .Text = "(" });
                     },
                     ast.Node.Id.AsmInput => {
-                        const asm_input = @fieldParentPtr(ast.NodeAsmInput, "base", base);
+                        const asm_input = @fieldParentPtr(ast.Node.AsmInput, "base", base);
 
                         try stack.append(RenderState { .Text = ")"});
                         try stack.append(RenderState { .Expression = asm_input.expr});
@@ -4283,14 +4301,14 @@ pub const Parser = struct {
                         try stack.append(RenderState { .Text = "["});
                     },
                     ast.Node.Id.AsmOutput => {
-                        const asm_output = @fieldParentPtr(ast.NodeAsmOutput, "base", base);
+                        const asm_output = @fieldParentPtr(ast.Node.AsmOutput, "base", base);
 
                         try stack.append(RenderState { .Text = ")"});
                         switch (asm_output.kind) {
-                            ast.NodeAsmOutput.Kind.Variable => |variable_name| {
+                            ast.Node.AsmOutput.Kind.Variable => |variable_name| {
                                 try stack.append(RenderState { .Expression = &variable_name.base});
                             },
-                            ast.NodeAsmOutput.Kind.Return => |return_type| {
+                            ast.Node.AsmOutput.Kind.Return => |return_type| {
                                 try stack.append(RenderState { .Expression = return_type});
                                 try stack.append(RenderState { .Text = "-> "});
                             },
@@ -4312,15 +4330,10 @@ pub const Parser = struct {
                     ast.Node.Id.ParamDecl => unreachable,
                 },
                 RenderState.Statement => |base| {
-                    if (base.comment) |comment| {
-                        for (comment.lines.toSliceConst()) |line_token| {
-                            try stream.print("{}\n", self.tokenizer.getTokenSlice(line_token));
-                            try stream.writeByteNTimes(' ', indent);
-                        }
-                    }
                     switch (base.id) {
                         ast.Node.Id.VarDecl => {
-                            const var_decl = @fieldParentPtr(ast.NodeVarDecl, "base", base);
+                            const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", base);
+                            try self.renderComments(stream, var_decl, indent);
                             try stack.append(RenderState { .VarDecl = var_decl});
                         },
                         else => {
@@ -4337,6 +4350,14 @@ pub const Parser = struct {
         }
     }
 
+    fn renderComments(self: &Parser, stream: var, node: var, indent: usize) !void {
+        const comment = node.comments ?? return;
+        for (comment.lines.toSliceConst()) |line_token| {
+            try stream.print("{}\n", self.tokenizer.getTokenSlice(line_token));
+            try stream.writeByteNTimes(' ', indent);
+        }
+    }
+
     fn initUtilityArrayList(self: &Parser, comptime T: type) ArrayList(T) {
         const new_byte_count = self.utility_bytes.len - self.utility_bytes.len % @sizeOf(T);
         self.utility_bytes = self.util_allocator.alignedShrink(u8, utility_bytes_align, self.utility_bytes, new_byte_count);
@@ -4411,6 +4432,14 @@ fn testCanonical(source: []const u8) !void {
     }
 }
 
+test "zig fmt: preserve top level comments" {
+    try testCanonical(
+        \\// top level comment
+        \\test "hi" {}
+        \\
+    );
+}
+
 test "zig fmt: get stdout or fail" {
     try testCanonical(
         \\const std = @import("std");