Commit 206c0b8bdb

Jimmi Holst Christensen <jhc@liab.dk>
2018-04-12 16:08:23
std.zig.parser: Refactor, round 1: * Removed the Optional state * We now have an OptionalCtx instead of DestPtr * OptionalCtx simulated return, instead of reverting states * OptionalCtx is a lot less hacky, but is still a small footgun * Trying to avoid consuming more than one token per state * This is required, because of comments * The C++ compiler allows comments between all tokens * We therefor have to consume comment tokens between each state * Reordered states so they are grouped in some logical fasion
1 parent 0d8646d
Changed files (2)
std/zig/ast.zig
@@ -283,7 +283,7 @@ pub const NodeUse = struct {
 pub const NodeErrorSetDecl = struct {
     base: Node,
     error_token: Token,
-    decls: ArrayList(&NodeIdentifier),
+    decls: ArrayList(&Node),
     rbrace_token: Token,
 
     pub fn iterate(self: &NodeErrorSetDecl, index: usize) ?&Node {
@@ -676,13 +676,13 @@ pub const NodeComptime = struct {
 pub const NodePayload = struct {
     base: Node,
     lpipe: Token,
-    error_symbol: &NodeIdentifier,
+    error_symbol: &Node,
     rpipe: Token,
 
     pub fn iterate(self: &NodePayload, index: usize) ?&Node {
         var i = index;
 
-        if (i < 1) return &self.error_symbol.base;
+        if (i < 1) return self.error_symbol;
         i -= 1;
 
         return null;
@@ -700,14 +700,14 @@ pub const NodePayload = struct {
 pub const NodePointerPayload = struct {
     base: Node,
     lpipe: Token,
-    is_ptr: bool,
-    value_symbol: &NodeIdentifier,
+    ptr_token: ?Token,
+    value_symbol: &Node,
     rpipe: Token,
 
     pub fn iterate(self: &NodePointerPayload, index: usize) ?&Node {
         var i = index;
 
-        if (i < 1) return &self.value_symbol.base;
+        if (i < 1) return self.value_symbol;
         i -= 1;
 
         return null;
@@ -725,19 +725,19 @@ pub const NodePointerPayload = struct {
 pub const NodePointerIndexPayload = struct {
     base: Node,
     lpipe: Token,
-    is_ptr: bool,
-    value_symbol: &NodeIdentifier,
-    index_symbol: ?&NodeIdentifier,
+    ptr_token: ?Token,
+    value_symbol: &Node,
+    index_symbol: ?&Node,
     rpipe: Token,
 
     pub fn iterate(self: &NodePointerIndexPayload, index: usize) ?&Node {
         var i = index;
 
-        if (i < 1) return &self.value_symbol.base;
+        if (i < 1) return self.value_symbol;
         i -= 1;
 
         if (self.index_symbol) |index_symbol| {
-            if (i < 1) return &index_symbol.base;
+            if (i < 1) return index_symbol;
             i -= 1;
         }
 
@@ -756,7 +756,7 @@ pub const NodePointerIndexPayload = struct {
 pub const NodeElse = struct {
     base: Node,
     else_token: Token,
-    payload: ?&NodePayload,
+    payload: ?&Node,
     body: &Node,
 
     pub fn iterate(self: &NodeElse, index: usize) ?&Node {
@@ -813,7 +813,7 @@ pub const NodeSwitch = struct {
 pub const NodeSwitchCase = struct {
     base: Node,
     items: ArrayList(&Node),
-    payload: ?&NodePointerPayload,
+    payload: ?&Node,
     expr: &Node,
 
     pub fn iterate(self: &NodeSwitchCase, index: usize) ?&Node {
@@ -865,7 +865,7 @@ pub const NodeWhile = struct {
     inline_token: ?Token,
     while_token: Token,
     condition: &Node,
-    payload: ?&NodePointerPayload,
+    payload: ?&Node,
     continue_expr: ?&Node,
     body: &Node,
     @"else": ?&NodeElse,
@@ -924,7 +924,7 @@ pub const NodeFor = struct {
     inline_token: ?Token,
     for_token: Token,
     array_expr: &Node,
-    payload: ?&NodePointerIndexPayload,
+    payload: ?&Node,
     body: &Node,
     @"else": ?&NodeElse,
 
@@ -975,7 +975,7 @@ pub const NodeIf = struct {
     base: Node,
     if_token: Token,
     condition: &Node,
-    payload: ?&NodePointerPayload,
+    payload: ?&Node,
     body: &Node,
     @"else": ?&NodeElse,
 
@@ -1048,7 +1048,7 @@ pub const NodeInfixOp = struct {
         BitXor,
         BoolAnd,
         BoolOr,
-        Catch: ?&NodePayload,
+        Catch: ?&Node,
         Div,
         EqualEqual,
         ErrorUnion,
@@ -1344,14 +1344,30 @@ pub const NodeControlFlowExpression = struct {
     rhs: ?&Node,
 
     const Kind = union(enum) {
-        Break: ?Token,
-        Continue: ?Token,
+        Break: ?&Node,
+        Continue: ?&Node,
         Return,
     };
 
     pub fn iterate(self: &NodeControlFlowExpression, 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;
@@ -1370,14 +1386,14 @@ pub const NodeControlFlowExpression = struct {
         }
 
         switch (self.kind) {
-            Kind.Break => |maybe_blk_token| {
-                if (maybe_blk_token) |blk_token| {
-                    return blk_token;
+            Kind.Break => |maybe_label| {
+                if (maybe_label) |label| {
+                    return label.lastToken();
                 }
             },
-            Kind.Continue => |maybe_blk_token| {
-                if (maybe_blk_token) |blk_token| {
-                    return blk_token;
+            Kind.Continue => |maybe_label| {
+                if (maybe_label) |label| {
+                    return label.lastToken();
                 }
             },
             Kind.Return => return self.ltoken,
@@ -1390,7 +1406,7 @@ pub const NodeControlFlowExpression = struct {
 pub const NodeSuspend = struct {
     base: Node,
     suspend_token: Token,
-    payload: ?&NodePayload,
+    payload: ?&Node,
     body: ?&Node,
 
     pub fn iterate(self: &NodeSuspend, index: usize) ?&Node {
@@ -1605,7 +1621,7 @@ pub const NodeThisLiteral = struct {
 
 pub const NodeAsmOutput = struct {
     base: Node,
-    symbolic_name: &NodeIdentifier,
+    symbolic_name: &Node,
     constraint: &Node,
     kind: Kind,
 
@@ -1617,7 +1633,7 @@ pub const NodeAsmOutput = struct {
     pub fn iterate(self: &NodeAsmOutput, index: usize) ?&Node {
         var i = index;
 
-        if (i < 1) return &self.symbolic_name.base;
+        if (i < 1) return self.symbolic_name;
         i -= 1;
 
         if (i < 1) return self.constraint;
@@ -1651,14 +1667,14 @@ pub const NodeAsmOutput = struct {
 
 pub const NodeAsmInput = struct {
     base: Node,
-    symbolic_name: &NodeIdentifier,
+    symbolic_name: &Node,
     constraint: &Node,
     expr: &Node,
 
     pub fn iterate(self: &NodeAsmInput, index: usize) ?&Node {
         var i = index;
 
-        if (i < 1) return &self.symbolic_name.base;
+        if (i < 1) return self.symbolic_name;
         i -= 1;
 
         if (i < 1) return self.constraint;
@@ -1682,7 +1698,7 @@ pub const NodeAsmInput = struct {
 pub const NodeAsm = struct {
     base: Node,
     asm_token: Token,
-    is_volatile: bool,
+    volatile_token: ?Token,
     template: &Node,
     //tokens: ArrayList(AsmToken),
     outputs: ArrayList(&NodeAsmOutput),
std/zig/parser.zig
@@ -59,36 +59,27 @@ pub const Parser = struct {
         lib_name: ?&ast.Node,
     };
 
+    const TopLevelExternOrFieldCtx = struct {
+        visib_token: Token,
+        container_decl: &ast.NodeContainerDecl,
+    };
+
     const ContainerExternCtx = struct {
-        dest_ptr: DestPtr,
+        opt_ctx: OptionalCtx,
         ltoken: Token,
         layout: ast.NodeContainerDecl.Layout,
     };
 
-    const DestPtr = union(enum) {
-        Field: &&ast.Node,
-        NullableField: &?&ast.Node,
-
-        pub fn store(self: &const DestPtr, value: &ast.Node) void {
-            switch (*self) {
-                DestPtr.Field => |ptr| *ptr = value,
-                DestPtr.NullableField => |ptr| *ptr = value,
-            }
-        }
-
-        pub fn get(self: &const DestPtr) &ast.Node {
-            switch (*self) {
-                DestPtr.Field => |ptr| return *ptr,
-                DestPtr.NullableField => |ptr| return ??*ptr,
-            }
-        }
-    };
-
     const ExpectTokenSave = struct {
         id: Token.Id,
         ptr: &Token,
     };
 
+    const OptionalTokenSave = struct {
+        id: Token.Id,
+        ptr: &?Token,
+    };
+
     const RevertState = struct {
         parser: Parser,
         tokenizer: Tokenizer,
@@ -104,11 +95,6 @@ pub const Parser = struct {
         ptr: &Token,
     };
 
-    const ElseCtx = struct {
-        payload: ?DestPtr,
-        body: DestPtr,
-    };
-
     fn ListSave(comptime T: type) type {
         return struct {
             list: &ArrayList(T),
@@ -118,118 +104,187 @@ pub const Parser = struct {
 
     const LabelCtx = struct {
         label: ?Token,
-        dest_ptr: DestPtr,
+        opt_ctx: OptionalCtx,
     };
 
     const InlineCtx = struct {
         label: ?Token,
         inline_token: ?Token,
-        dest_ptr: DestPtr,
+        opt_ctx: OptionalCtx,
     };
 
     const LoopCtx = struct {
         label: ?Token,
         inline_token: ?Token,
         loop_token: Token,
-        dest_ptr: DestPtr,
+        opt_ctx: OptionalCtx,
     };
 
     const AsyncEndCtx = struct {
-        dest_ptr: DestPtr,
+        ctx: OptionalCtx,
         attribute: &ast.NodeAsyncAttribute,
     };
 
+    const ErrorTypeOrSetDeclCtx = struct {
+        opt_ctx: OptionalCtx,
+        error_token: Token,
+    };
+
+    const ParamDeclEndCtx = struct {
+        fn_proto: &ast.NodeFnProto,
+        param_decl: &ast.NodeParamDecl,
+    };
+
+    const ComptimeStatementCtx = struct {
+        comptime_token: Token,
+        block: &ast.NodeBlock,
+    };
+
+    const OptionalCtx = union(enum) {
+        Optional: &?&ast.Node,
+        RequiredNull: &?&ast.Node,
+        Required: &&ast.Node,
+
+        pub fn store(self: &const OptionalCtx, value: &ast.Node) void {
+            switch (*self) {
+                OptionalCtx.Optional => |ptr| *ptr = value,
+                OptionalCtx.RequiredNull => |ptr| *ptr = value,
+                OptionalCtx.Required => |ptr| *ptr = value,
+            }
+        }
+
+        pub fn get(self: &const OptionalCtx) ?&ast.Node {
+            switch (*self) {
+                OptionalCtx.Optional => |ptr| return *ptr,
+                OptionalCtx.RequiredNull => |ptr| return ??*ptr,
+                OptionalCtx.Required => |ptr| return *ptr,
+            }
+        }
+
+        pub fn toRequired(self: &const OptionalCtx) OptionalCtx {
+            switch (*self) {
+                OptionalCtx.Optional => |ptr| {
+                    return OptionalCtx { .RequiredNull = ptr };
+                },
+                OptionalCtx.RequiredNull => |ptr| return *self,
+                OptionalCtx.Required => |ptr| return *self,
+            }
+        }
+    };
+
     const State = union(enum) {
         TopLevel,
         TopLevelExtern: TopLevelDeclCtx,
         TopLevelLibname: TopLevelDeclCtx,
         TopLevelDecl: TopLevelDeclCtx,
+        TopLevelExternOrField: TopLevelExternOrFieldCtx,
+
         ContainerExtern: ContainerExternCtx,
+        ContainerInitArgStart: &ast.NodeContainerDecl,
+        ContainerInitArg: &ast.NodeContainerDecl,
         ContainerDecl: &ast.NodeContainerDecl,
-        SliceOrArrayAccess: &ast.NodeSuffixOp,
-        AddrOfModifiers: &ast.NodePrefixOp.AddrOfInfo,
+
         VarDecl: &ast.NodeVarDecl,
         VarDeclAlign: &ast.NodeVarDecl,
         VarDeclEq: &ast.NodeVarDecl,
-        IfToken: @TagType(Token.Id),
-        IfTokenSave: ExpectTokenSave,
-        ExpectToken: @TagType(Token.Id),
-        ExpectTokenSave: ExpectTokenSave,
+
+        FnDef: &ast.NodeFnProto,
         FnProto: &ast.NodeFnProto,
         FnProtoAlign: &ast.NodeFnProto,
         FnProtoReturnType: &ast.NodeFnProto,
+
         ParamDecl: &ast.NodeFnProto,
-        ParamDeclComma,
-        FnDef: &ast.NodeFnProto,
+        ParamDeclAliasOrComptime: &ast.NodeParamDecl,
+        ParamDeclName: &ast.NodeParamDecl,
+        ParamDeclEnd: ParamDeclEndCtx,
+        ParamDeclComma: &ast.NodeFnProto,
+
         LabeledExpression: LabelCtx,
         Inline: InlineCtx,
         While: LoopCtx,
+        WhileContinueExpr: &?&ast.Node,
         For: LoopCtx,
-        Block: &ast.NodeBlock,
         Else: &?&ast.NodeElse,
-        WhileContinueExpr: &?&ast.Node,
+
+        Block: &ast.NodeBlock,
         Statement: &ast.NodeBlock,
+        ComptimeStatement: ComptimeStatementCtx,
         Semicolon: &const &const ast.Node,
+
         AsmOutputItems: &ArrayList(&ast.NodeAsmOutput),
+        AsmOutputReturnOrType: &ast.NodeAsmOutput,
         AsmInputItems: &ArrayList(&ast.NodeAsmInput),
         AsmClopperItems: &ArrayList(&ast.Node),
+
         ExprListItemOrEnd: ExprListCtx,
         ExprListCommaOrEnd: ExprListCtx,
         FieldInitListItemOrEnd: ListSave(&ast.NodeFieldInitializer),
         FieldInitListCommaOrEnd: ListSave(&ast.NodeFieldInitializer),
         FieldListCommaOrEnd: &ast.NodeContainerDecl,
-        IdentifierListItemOrEnd: ListSave(&ast.NodeIdentifier),
-        IdentifierListCommaOrEnd: ListSave(&ast.NodeIdentifier),
+        IdentifierListItemOrEnd: ListSave(&ast.Node),
+        IdentifierListCommaOrEnd: ListSave(&ast.Node),
         SwitchCaseOrEnd: ListSave(&ast.NodeSwitchCase),
-        SuspendBody: &ast.NodeSuspend,
-        AsyncEnd: AsyncEndCtx,
-        Payload: &?&ast.NodePayload,
-        PointerPayload: &?&ast.NodePointerPayload,
-        PointerIndexPayload: &?&ast.NodePointerIndexPayload,
         SwitchCaseCommaOrEnd: ListSave(&ast.NodeSwitchCase),
+        SwitchCaseFirstItem: &ArrayList(&ast.Node),
         SwitchCaseItem: &ArrayList(&ast.Node),
         SwitchCaseItemCommaOrEnd: &ArrayList(&ast.Node),
 
-        /// A state that can be appended before any other State. If an error occures,
-        /// the parser will first try looking for the closest optional state. If an
-        /// optional state is found, the parser will revert to the state it was in
-        /// when the optional was added. This will polute the arena allocator with
-        /// "leaked" nodes. TODO: Figure out if it's nessesary to handle leaked nodes.
-        Optional: RevertState,
-
-        Expression: DestPtr,
-        RangeExpressionBegin: DestPtr,
-        RangeExpressionEnd: DestPtr,
-        AssignmentExpressionBegin: DestPtr,
-        AssignmentExpressionEnd: DestPtr,
-        UnwrapExpressionBegin: DestPtr,
-        UnwrapExpressionEnd: DestPtr,
-        BoolOrExpressionBegin: DestPtr,
-        BoolOrExpressionEnd: DestPtr,
-        BoolAndExpressionBegin: DestPtr,
-        BoolAndExpressionEnd: DestPtr,
-        ComparisonExpressionBegin: DestPtr,
-        ComparisonExpressionEnd: DestPtr,
-        BinaryOrExpressionBegin: DestPtr,
-        BinaryOrExpressionEnd: DestPtr,
-        BinaryXorExpressionBegin: DestPtr,
-        BinaryXorExpressionEnd: DestPtr,
-        BinaryAndExpressionBegin: DestPtr,
-        BinaryAndExpressionEnd: DestPtr,
-        BitShiftExpressionBegin: DestPtr,
-        BitShiftExpressionEnd: DestPtr,
-        AdditionExpressionBegin: DestPtr,
-        AdditionExpressionEnd: DestPtr,
-        MultiplyExpressionBegin: DestPtr,
-        MultiplyExpressionEnd: DestPtr,
-        CurlySuffixExpressionBegin: DestPtr,
-        CurlySuffixExpressionEnd: DestPtr,
-        TypeExprBegin: DestPtr,
-        TypeExprEnd: DestPtr,
-        PrefixOpExpression: DestPtr,
-        SuffixOpExpressionBegin: DestPtr,
-        SuffixOpExpressionEnd: DestPtr,
-        PrimaryExpression: DestPtr,
+        SuspendBody: &ast.NodeSuspend,
+        AsyncAllocator: &ast.NodeAsyncAttribute,
+        AsyncEnd: AsyncEndCtx,
+
+        SliceOrArrayAccess: &ast.NodeSuffixOp,
+        SliceOrArrayType: &ast.NodePrefixOp,
+        AddrOfModifiers: &ast.NodePrefixOp.AddrOfInfo,
+
+        Payload: OptionalCtx,
+        PointerPayload: OptionalCtx,
+        PointerIndexPayload: OptionalCtx,
+
+        Expression: OptionalCtx,
+        RangeExpressionBegin: OptionalCtx,
+        RangeExpressionEnd: OptionalCtx,
+        AssignmentExpressionBegin: OptionalCtx,
+        AssignmentExpressionEnd: OptionalCtx,
+        UnwrapExpressionBegin: OptionalCtx,
+        UnwrapExpressionEnd: OptionalCtx,
+        BoolOrExpressionBegin: OptionalCtx,
+        BoolOrExpressionEnd: OptionalCtx,
+        BoolAndExpressionBegin: OptionalCtx,
+        BoolAndExpressionEnd: OptionalCtx,
+        ComparisonExpressionBegin: OptionalCtx,
+        ComparisonExpressionEnd: OptionalCtx,
+        BinaryOrExpressionBegin: OptionalCtx,
+        BinaryOrExpressionEnd: OptionalCtx,
+        BinaryXorExpressionBegin: OptionalCtx,
+        BinaryXorExpressionEnd: OptionalCtx,
+        BinaryAndExpressionBegin: OptionalCtx,
+        BinaryAndExpressionEnd: OptionalCtx,
+        BitShiftExpressionBegin: OptionalCtx,
+        BitShiftExpressionEnd: OptionalCtx,
+        AdditionExpressionBegin: OptionalCtx,
+        AdditionExpressionEnd: OptionalCtx,
+        MultiplyExpressionBegin: OptionalCtx,
+        MultiplyExpressionEnd: OptionalCtx,
+        CurlySuffixExpressionBegin: OptionalCtx,
+        CurlySuffixExpressionEnd: OptionalCtx,
+        TypeExprBegin: OptionalCtx,
+        TypeExprEnd: OptionalCtx,
+        PrefixOpExpression: OptionalCtx,
+        SuffixOpExpressionBegin: OptionalCtx,
+        SuffixOpExpressionEnd: OptionalCtx,
+        PrimaryExpression: OptionalCtx,
+
+        ErrorTypeOrSetDecl: ErrorTypeOrSetDeclCtx,
+        StringLiteral: OptionalCtx,
+        Identifier: OptionalCtx,
+
+
+        IfToken: @TagType(Token.Id),
+        IfTokenSave: ExpectTokenSave,
+        ExpectToken: @TagType(Token.Id),
+        ExpectTokenSave: ExpectTokenSave,
+        OptionalTokenSave: OptionalTokenSave,
     };
 
     /// Returns an AST tree, allocated with the parser's allocator.
@@ -302,31 +357,31 @@ pub const Parser = struct {
                         Token.Id.Keyword_test => {
                             stack.append(State.TopLevel) catch unreachable;
 
-                            const name_token = self.getNextToken();
-                            const name = (try self.parseStringLiteral(arena, name_token)) ?? {
-                                try self.parseError(&stack, name_token, "expected string literal, found {}", @tagName(name_token.id));
-                                continue;
-                            };
-                            const lbrace = (try self.expectToken(&stack, Token.Id.LBrace)) ?? continue;
-
                             const block = try self.createNode(arena, ast.NodeBlock,
                                 ast.NodeBlock {
                                     .base = undefined,
                                     .label = null,
-                                    .lbrace = lbrace,
+                                    .lbrace = undefined,
                                     .statements = ArrayList(&ast.Node).init(arena),
                                     .rbrace = undefined,
                                 }
                             );
-                            _ = try self.createAttachNode(arena, &root_node.decls, ast.NodeTestDecl,
+                            const test_node = try self.createAttachNode(arena, &root_node.decls, ast.NodeTestDecl,
                                 ast.NodeTestDecl {
                                     .base = undefined,
                                     .test_token = token,
-                                    .name = name,
+                                    .name = undefined,
                                     .body_node = &block.base,
                                 }
                             );
                             stack.append(State { .Block = block }) catch unreachable;
+                            try stack.append(State {
+                                .ExpectTokenSave = ExpectTokenSave {
+                                    .id = Token.Id.LBrace,
+                                    .ptr = &block.rbrace,
+                                }
+                            });
+                            try stack.append(State { .StringLiteral = OptionalCtx { .Required = &test_node.name } });
                             continue;
                         },
                         Token.Id.Eof => {
@@ -346,15 +401,30 @@ pub const Parser = struct {
                             continue;
                         },
                         Token.Id.Keyword_comptime => {
+                            const block = try self.createNode(arena, ast.NodeBlock,
+                                ast.NodeBlock {
+                                    .base = undefined,
+                                    .label = null,
+                                    .lbrace = undefined,
+                                    .statements = ArrayList(&ast.Node).init(arena),
+                                    .rbrace = undefined,
+                                }
+                            );
                             const node = try self.createAttachNode(arena, &root_node.decls, ast.NodeComptime,
                                 ast.NodeComptime {
                                     .base = undefined,
                                     .comptime_token = token,
-                                    .expr = undefined,
+                                    .expr = &block.base,
                                 }
                             );
                             stack.append(State.TopLevel) catch unreachable;
-                            try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
+                            try stack.append(State { .Block = block });
+                            try stack.append(State {
+                                .ExpectTokenSave = ExpectTokenSave {
+                                    .id = Token.Id.LBrace,
+                                    .ptr = &block.rbrace,
+                                }
+                            });
                             continue;
                         },
                         else => {
@@ -404,7 +474,6 @@ pub const Parser = struct {
                         }
                     }
                 },
-
                 State.TopLevelLibname => |ctx| {
                     const lib_name = blk: {
                         const lib_name_token = self.getNextToken();
@@ -423,14 +492,12 @@ pub const Parser = struct {
                         },
                     }) catch unreachable;
                 },
-
                 State.TopLevelDecl => |ctx| {
                     const token = self.getNextToken();
                     switch (token.id) {
                         Token.Id.Keyword_use => {
                             if (ctx.extern_export_inline_token != null) {
-                                try self.parseError(&stack, token, "Invalid token {}", @tagName((??ctx.extern_export_inline_token).id));
-                                continue;
+                                return self.parseError(token, "Invalid token {}", @tagName((??ctx.extern_export_inline_token).id));
                             }
 
                             const node = try self.createAttachNode(arena, ctx.decls, ast.NodeUse,
@@ -447,14 +514,13 @@ pub const Parser = struct {
                                     .ptr = &node.semicolon_token,
                                 }
                             }) catch unreachable;
-                            try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
+                            try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
                             continue;
                         },
                         Token.Id.Keyword_var, Token.Id.Keyword_const => {
                             if (ctx.extern_export_inline_token) |extern_export_inline_token| {
                                 if (extern_export_inline_token.id == Token.Id.Keyword_inline) {
-                                    try self.parseError(&stack, token, "Invalid token {}", @tagName(extern_export_inline_token.id));
-                                    continue;
+                                    return self.parseError(token, "Invalid token {}", @tagName(extern_export_inline_token.id));
                                 }
                             }
 
@@ -564,82 +630,48 @@ pub const Parser = struct {
                                 }
                             });
 
-                            const langle_bracket = self.getNextToken();
-                            if (langle_bracket.id != Token.Id.AngleBracketLeft) {
-                                self.putBackToken(langle_bracket);
-                                continue;
-                            }
-
-                            async_node.rangle_bracket = Token(undefined);
-                            try stack.append(State {
-                                .ExpectTokenSave = ExpectTokenSave {
-                                    .id = Token.Id.AngleBracketRight,
-                                    .ptr = &??async_node.rangle_bracket,
-                                }
-                            });
-                            try stack.append(State { .TypeExprBegin = DestPtr { .NullableField = &async_node.allocator_type } });
+                            try stack.append(State { .AsyncAllocator = async_node });
                             continue;
                         },
                         else => {
-                            try self.parseError(&stack, token, "expected variable declaration or function, found {}", @tagName(token.id));
-                            continue;
+                            return self.parseError(token, "expected variable declaration or function, found {}", @tagName(token.id));
                         },
                     }
                 },
-                State.VarDecl => |var_decl| {
-                    stack.append(State { .VarDeclAlign = var_decl }) catch unreachable;
-                    try stack.append(State { .TypeExprBegin = DestPtr {.NullableField = &var_decl.type_node} });
-                    try stack.append(State { .IfToken = Token.Id.Colon });
-                    try stack.append(State {
-                        .ExpectTokenSave = ExpectTokenSave {
-                            .id = Token.Id.Identifier,
-                            .ptr = &var_decl.name_token,
-                        }
-                    });
-                    continue;
-                },
-                State.VarDeclAlign => |var_decl| {
-                    stack.append(State { .VarDeclEq = var_decl }) catch unreachable;
+                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 {
+                                .base = undefined,
+                                .visib_token = ctx.visib_token,
+                                .name_token = identifier,
+                                .type_expr = undefined,
+                            }
+                        );
 
-                    const next_token = self.getNextToken();
-                    if (next_token.id == Token.Id.Keyword_align) {
-                        try stack.append(State { .ExpectToken = Token.Id.RParen });
-                        try stack.append(State { .Expression = DestPtr{.NullableField = &var_decl.align_node} });
-                        try stack.append(State { .ExpectToken = Token.Id.LParen });
+                        stack.append(State { .FieldListCommaOrEnd = ctx.container_decl }) catch unreachable;
+                        try stack.append(State { .Expression = OptionalCtx { .Required = &node.type_expr } });
+                        try stack.append(State { .ExpectToken = Token.Id.Colon });
                         continue;
                     }
 
-                    self.putBackToken(next_token);
-                    continue;
-                },
-                State.VarDeclEq => |var_decl| {
-                    const token = self.getNextToken();
-                    switch (token.id) {
-                        Token.Id.Equal => {
-                            var_decl.eq_token = token;
-                            stack.append(State {
-                                .ExpectTokenSave = ExpectTokenSave {
-                                    .id = Token.Id.Semicolon,
-                                    .ptr = &var_decl.semicolon_token,
-                                },
-                            }) catch unreachable;
-                            try stack.append(State { .Expression = DestPtr {.NullableField = &var_decl.init_node} });
-                            continue;
-                        },
-                        Token.Id.Semicolon => {
-                            var_decl.semicolon_token = token;
-                            continue;
-                        },
-                        else => {
-                            try self.parseError(&stack, token, "expected '=' or ';', found {}", @tagName(token.id));
-                            continue;
+                    stack.append(State{ .ContainerDecl = ctx.container_decl }) catch unreachable;
+                    try stack.append(State {
+                        .TopLevelExtern = TopLevelDeclCtx {
+                            .decls = &ctx.container_decl.fields_and_decls,
+                            .visib_token = ctx.visib_token,
+                            .extern_export_inline_token = null,
+                            .lib_name = null,
                         }
-                    }
+                    });
+                    continue;
                 },
 
+
                 State.ContainerExtern => |ctx| {
                     const token = self.getNextToken();
-                    const node = try self.createToDestNode(arena, ctx.dest_ptr, ast.NodeContainerDecl,
+                    const node = try self.createToCtxNode(arena, ctx.opt_ctx, ast.NodeContainerDecl,
                         ast.NodeContainerDecl {
                             .base = undefined,
                             .ltoken = ctx.ltoken,
@@ -649,15 +681,14 @@ pub const Parser = struct {
                                 Token.Id.Keyword_union => ast.NodeContainerDecl.Kind.Union,
                                 Token.Id.Keyword_enum => ast.NodeContainerDecl.Kind.Enum,
                                 else => {
-                                    try self.parseError(&stack, token, "expected {}, {} or {}, found {}",
+                                    return self.parseError(token, "expected {}, {} or {}, found {}",
                                         @tagName(Token.Id.Keyword_struct),
                                         @tagName(Token.Id.Keyword_union),
                                         @tagName(Token.Id.Keyword_enum),
                                         @tagName(token.id));
-                                    continue;
                                 },
                             },
-                            .init_arg_expr = undefined,
+                            .init_arg_expr = ast.NodeContainerDecl.InitArg.None,
                             .fields_and_decls = ArrayList(&ast.Node).init(arena),
                             .rbrace_token = undefined,
                         }
@@ -665,37 +696,34 @@ pub const Parser = struct {
 
                     stack.append(State { .ContainerDecl = node }) catch unreachable;
                     try stack.append(State { .ExpectToken = Token.Id.LBrace });
+                    try stack.append(State { .ContainerInitArgStart = node });
+                },
 
-                    const lparen = self.getNextToken();
-                    if (lparen.id != Token.Id.LParen) {
-                        self.putBackToken(lparen);
-                        node.init_arg_expr = ast.NodeContainerDecl.InitArg.None;
+                State.ContainerInitArgStart => |container_decl| {
+                    if (self.eatToken(Token.Id.LParen) == null) {
                         continue;
                     }
 
-                    try stack.append(State { .ExpectToken = Token.Id.RParen });
+                    stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
+                    try stack.append(State { .ContainerInitArg = container_decl });
+                },
 
+                State.ContainerInitArg => |container_decl| {
                     const init_arg_token = self.getNextToken();
                     switch (init_arg_token.id) {
                         Token.Id.Keyword_enum => {
-                            node.init_arg_expr = ast.NodeContainerDecl.InitArg.Enum;
+                            container_decl.init_arg_expr = ast.NodeContainerDecl.InitArg.Enum;
                         },
                         else => {
                             self.putBackToken(init_arg_token);
-                            node.init_arg_expr = ast.NodeContainerDecl.InitArg { .Type = undefined };
-                            try stack.append(State {
-                                .Expression = DestPtr {
-                                    .Field = &node.init_arg_expr.Type
-                                }
-                            });
+                            container_decl.init_arg_expr = ast.NodeContainerDecl.InitArg { .Type = undefined };
+                            stack.append(State { .Expression = OptionalCtx { .Required = &container_decl.init_arg_expr.Type } }) catch unreachable;
                         },
                     }
                     continue;
                 },
-
                 State.ContainerDecl => |container_decl| {
                     const token = self.getNextToken();
-
                     switch (token.id) {
                         Token.Id.Identifier => {
                             switch (container_decl.kind) {
@@ -710,7 +738,7 @@ pub const Parser = struct {
                                     );
 
                                     stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
-                                    try stack.append(State { .Expression = DestPtr { .Field = &node.type_expr } });
+                                    try stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.type_expr } });
                                     try stack.append(State { .ExpectToken = Token.Id.Colon });
                                     continue;
                                 },
@@ -724,14 +752,8 @@ pub const Parser = struct {
                                     );
 
                                     stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
-
-                                    const next = self.getNextToken();
-                                    if (next.id != Token.Id.Colon) {
-                                        self.putBackToken(next);
-                                        continue;
-                                    }
-
-                                    try stack.append(State { .Expression = DestPtr { .NullableField = &node.type_expr } });
+                                    try stack.append(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &node.type_expr } });
+                                    try stack.append(State { .IfToken = Token.Id.Colon });
                                     continue;
                                 },
                                 ast.NodeContainerDecl.Kind.Enum => {
@@ -744,52 +766,34 @@ pub const Parser = struct {
                                     );
 
                                     stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
-
-                                    const next = self.getNextToken();
-                                    if (next.id != Token.Id.Equal) {
-                                        self.putBackToken(next);
-                                        continue;
-                                    }
-
-                                    try stack.append(State { .Expression = DestPtr { .NullableField = &node.value } });
+                                    try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &node.value } });
+                                    try stack.append(State { .IfToken = Token.Id.Equal });
                                     continue;
                                 },
                             }
                         },
                         Token.Id.Keyword_pub => {
-                            if (self.eatToken(Token.Id.Identifier)) |identifier| {
-                                switch (container_decl.kind) {
-                                    ast.NodeContainerDecl.Kind.Struct => {
-                                        const node = try self.createAttachNode(arena, &container_decl.fields_and_decls, ast.NodeStructField,
-                                            ast.NodeStructField {
-                                                .base = undefined,
-                                                .visib_token = token,
-                                                .name_token = identifier,
-                                                .type_expr = undefined,
-                                            }
-                                        );
-
-                                        stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
-                                        try stack.append(State { .Expression = DestPtr { .Field = &node.type_expr } });
-                                        try stack.append(State { .ExpectToken = Token.Id.Colon });
-                                        continue;
-                                    },
-                                    else => {
-                                        self.putBackToken(identifier);
-                                    }
+                            switch (container_decl.kind) {
+                                ast.NodeContainerDecl.Kind.Struct => {
+                                    try stack.append(State {
+                                        .TopLevelExternOrField = TopLevelExternOrFieldCtx {
+                                            .visib_token = token,
+                                            .container_decl = container_decl,
+                                        }
+                                    });
+                                },
+                                else => {
+                                    stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
+                                    try stack.append(State {
+                                        .TopLevelExtern = TopLevelDeclCtx {
+                                            .decls = &container_decl.fields_and_decls,
+                                            .visib_token = token,
+                                            .extern_export_inline_token = null,
+                                            .lib_name = null,
+                                        }
+                                    });
                                 }
                             }
-
-                            stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
-                            try stack.append(State {
-                                .TopLevelExtern = TopLevelDeclCtx {
-                                    .decls = &container_decl.fields_and_decls,
-                                    .visib_token = token,
-                                    .extern_export_inline_token = null,
-                                    .lib_name = null,
-                                }
-                            });
-                            continue;
                         },
                         Token.Id.Keyword_export => {
                             stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
@@ -823,1883 +827,1947 @@ pub const Parser = struct {
                     }
                 },
 
-                State.ExpectToken => |token_id| {
-                    _ = (try self.expectToken(&stack, token_id)) ?? continue;
-                    continue;
-                },
-
-                State.ExpectTokenSave => |expect_token_save| {
-                    *expect_token_save.ptr = (try self.expectToken(&stack, expect_token_save.id)) ?? continue;
-                    continue;
-                },
 
-                State.IfToken => |token_id| {
-                    const token = self.getNextToken();
-                    if (@TagType(Token.Id)(token.id) != token_id) {
-                        self.putBackToken(token);
-                        _ = stack.pop();
-                        continue;
-                    }
+                State.VarDecl => |var_decl| {
+                    stack.append(State { .VarDeclAlign = var_decl }) catch unreachable;
+                    try stack.append(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &var_decl.type_node} });
+                    try stack.append(State { .IfToken = Token.Id.Colon });
+                    try stack.append(State {
+                        .ExpectTokenSave = ExpectTokenSave {
+                            .id = Token.Id.Identifier,
+                            .ptr = &var_decl.name_token,
+                        }
+                    });
                     continue;
                 },
+                State.VarDeclAlign => |var_decl| {
+                    stack.append(State { .VarDeclEq = var_decl }) catch unreachable;
 
-                State.IfTokenSave => |if_token_save| {
-                    const token = self.getNextToken();
-                    if (@TagType(Token.Id)(token.id) != if_token_save.id) {
-                        self.putBackToken(token);
-                        _ = stack.pop();
+                    const next_token = self.getNextToken();
+                    if (next_token.id == Token.Id.Keyword_align) {
+                        try stack.append(State { .ExpectToken = Token.Id.RParen });
+                        try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &var_decl.align_node} });
+                        try stack.append(State { .ExpectToken = Token.Id.LParen });
                         continue;
                     }
 
-                    *if_token_save.ptr = token;
+                    self.putBackToken(next_token);
                     continue;
                 },
-
-                State.Optional => { },
-
-                State.Expression => |dest_ptr| {
+                State.VarDeclEq => |var_decl| {
                     const token = self.getNextToken();
                     switch (token.id) {
-                        Token.Id.Keyword_return => {
-                            const node = try self.createToDestNode(arena, dest_ptr, ast.NodeControlFlowExpression,
-                                ast.NodeControlFlowExpression {
-                                    .base = undefined,
-                                    .ltoken = token,
-                                    .kind = ast.NodeControlFlowExpression.Kind.Return,
-                                    .rhs = undefined,
-                                }
-                            );
-
-                            // TODO: Find another way to do optional expressions
+                        Token.Id.Equal => {
+                            var_decl.eq_token = token;
                             stack.append(State {
-                                .Optional = RevertState {
-                                    .parser = *self,
-                                    .tokenizer = *self.tokenizer,
-                                    .ptr = &node.rhs,
-                                }
+                                .ExpectTokenSave = ExpectTokenSave {
+                                    .id = Token.Id.Semicolon,
+                                    .ptr = &var_decl.semicolon_token,
+                                },
                             }) catch unreachable;
-                            try stack.append(State { .Expression = DestPtr { .NullableField = &node.rhs } });
+                            try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &var_decl.init_node } });
                             continue;
                         },
-                        Token.Id.Keyword_break, Token.Id.Keyword_continue => {
-                            const label = blk: {
-                                const colon = self.getNextToken();
-                                if (colon.id != Token.Id.Colon) {
-                                    self.putBackToken(colon);
-                                    break :blk null;
-                                }
+                        Token.Id.Semicolon => {
+                            var_decl.semicolon_token = token;
+                            continue;
+                        },
+                        else => {
+                            return self.parseError(token, "expected '=' or ';', found {}", @tagName(token.id));
+                        }
+                    }
+                },
 
-                                break :blk (try self.expectToken(&stack, Token.Id.Identifier)) ?? continue;
-                            };
 
-                            const node = try self.createToDestNode(arena, dest_ptr, ast.NodeControlFlowExpression,
-                                ast.NodeControlFlowExpression {
-                                    .base = undefined,
-                                    .ltoken = token,
-                                    .kind = switch (token.id) {
-                                        Token.Id.Keyword_break => ast.NodeControlFlowExpression.Kind { .Break = label },
-                                        Token.Id.Keyword_continue => ast.NodeControlFlowExpression.Kind { .Continue = label },
-                                        else => unreachable,
-                                    },
-                                    .rhs = undefined,
-                                }
-                            );
-
-                            // TODO: Find another way to do optional expressions
-                            stack.append(State {
-                                .Optional = RevertState {
-                                    .parser = *self,
-                                    .tokenizer = *self.tokenizer,
-                                    .ptr = &node.rhs,
-                                }
-                            }) catch unreachable;
-                            try stack.append(State { .Expression = DestPtr { .NullableField = &node.rhs } });
-                            continue;
-                        },
-                        Token.Id.Keyword_try, Token.Id.Keyword_cancel, Token.Id.Keyword_resume => {
-                            const node = try self.createToDestNode(arena, dest_ptr, ast.NodePrefixOp,
-                                ast.NodePrefixOp {
+                State.FnDef => |fn_proto| {
+                    const token = self.getNextToken();
+                    switch(token.id) {
+                        Token.Id.LBrace => {
+                            const block = try self.createNode(arena, ast.NodeBlock,
+                                ast.NodeBlock {
                                     .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{} },
-                                        else => unreachable,
-                                    },
-                                    .rhs = undefined,
+                                    .label = null,
+                                    .lbrace = token,
+                                    .statements = ArrayList(&ast.Node).init(arena),
+                                    .rbrace = undefined,
                                 }
                             );
-
-                            stack.append(State { .Expression = DestPtr { .Field = &node.rhs } }) catch unreachable;
+                            fn_proto.body_node = &block.base;
+                            stack.append(State { .Block = block }) catch unreachable;
                             continue;
                         },
+                        Token.Id.Semicolon => continue,
                         else => {
-                            if (!try self.parseBlockExpr(&stack, arena, dest_ptr, token)) {
-                                self.putBackToken(token);
-                                stack.append(State { .UnwrapExpressionBegin = dest_ptr }) catch unreachable;
-                            }
-                            continue;
-                        }
+                            return self.parseError(token, "expected ';' or '{{', found {}", @tagName(token.id));
+                        },
                     }
                 },
+                State.FnProto => |fn_proto| {
+                    stack.append(State { .FnProtoAlign = fn_proto }) catch unreachable;
+                    try stack.append(State { .ParamDecl = fn_proto });
+                    try stack.append(State { .ExpectToken = Token.Id.LParen });
 
-                State.RangeExpressionBegin => |dest_ptr| {
-                    stack.append(State { .RangeExpressionEnd = dest_ptr }) catch unreachable;
-                    try stack.append(State { .Expression = dest_ptr });
-                    continue;
-                },
-
-                State.RangeExpressionEnd => |dest_ptr| {
-                    if (self.eatToken(Token.Id.Ellipsis3)) |ellipsis3| {
-                        const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
-                            ast.NodeInfixOp {
-                                .base = undefined,
-                                .lhs = dest_ptr.get(),
-                                .op_token = ellipsis3,
-                                .op = ast.NodeInfixOp.InfixOp.Range,
-                                .rhs = undefined,
-                            }
-                        );
-                        stack.append(State { .Expression = DestPtr { .Field = &node.rhs } }) catch unreachable;
+                    const next_token = self.getNextToken();
+                    if (next_token.id == Token.Id.Identifier) {
+                        fn_proto.name_token = next_token;
+                        continue;
                     }
-
-                    continue;
-                },
-
-                State.AssignmentExpressionBegin => |dest_ptr| {
-                    stack.append(State { .AssignmentExpressionEnd = dest_ptr }) catch unreachable;
-                    try stack.append(State { .Expression = dest_ptr });
+                    self.putBackToken(next_token);
                     continue;
                 },
+                State.FnProtoAlign => |fn_proto| {
+                    stack.append(State { .FnProtoReturnType = fn_proto }) catch unreachable;
 
-                State.AssignmentExpressionEnd => |dest_ptr| {
-                    const token = self.getNextToken();
-                    if (tokenIdToAssignment(token.id)) |ass_id| {
-                        const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
-                            ast.NodeInfixOp {
-                                .base = undefined,
-                                .lhs = dest_ptr.get(),
-                                .op_token = token,
-                                .op = ass_id,
-                                .rhs = undefined,
-                            }
-                        );
-                        stack.append(State { .AssignmentExpressionEnd = dest_ptr }) catch unreachable;
-                        try stack.append(State { .Expression = DestPtr { .Field = &node.rhs } });
-                        continue;
-                    } else {
-                        self.putBackToken(token);
-                        continue;
+                    if (self.eatToken(Token.Id.Keyword_align)) |align_token| {
+                        try stack.append(State { .ExpectToken = Token.Id.RParen });
+                        try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &fn_proto.align_expr } });
+                        try stack.append(State { .ExpectToken = Token.Id.LParen });
                     }
-                },
 
-                State.UnwrapExpressionBegin => |dest_ptr| {
-                    stack.append(State { .UnwrapExpressionEnd = dest_ptr }) catch unreachable;
-                    try stack.append(State { .BoolOrExpressionBegin = dest_ptr });
                     continue;
                 },
-
-                State.UnwrapExpressionEnd => |dest_ptr| {
+                State.FnProtoReturnType => |fn_proto| {
                     const token = self.getNextToken();
                     switch (token.id) {
-                        Token.Id.Keyword_catch, Token.Id.QuestionMarkQuestionMark => {
-                            const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
-                                ast.NodeInfixOp {
-                                    .base = undefined,
-                                    .lhs = dest_ptr.get(),
-                                    .op_token = token,
-                                    .op = switch (token.id) {
-                                        Token.Id.Keyword_catch => ast.NodeInfixOp.InfixOp { .Catch = null },
-                                        Token.Id.QuestionMarkQuestionMark => ast.NodeInfixOp.InfixOp { .UnwrapMaybe = void{} },
-                                        else => unreachable,
-                                    },
-                                    .rhs = undefined,
-                                }
-                            );
-
-                            stack.append(State { .UnwrapExpressionEnd = dest_ptr }) catch unreachable;
-                            try stack.append(State { .Expression = DestPtr { .Field = &node.rhs } });
-
-                            if (node.op == ast.NodeInfixOp.InfixOp.Catch) {
-                                try stack.append(State { .Payload = &node.op.Catch });
-                            }
+                        Token.Id.Bang => {
+                            fn_proto.return_type = ast.NodeFnProto.ReturnType { .InferErrorSet = undefined };
+                            stack.append(State {
+                                .TypeExprBegin = OptionalCtx { .Required = &fn_proto.return_type.InferErrorSet },
+                            }) catch unreachable;
                             continue;
                         },
                         else => {
+                            // 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
+                                    };
+                                    continue;
+                                }
+                            }
+
                             self.putBackToken(token);
+                            fn_proto.return_type = ast.NodeFnProto.ReturnType { .Explicit = undefined };
+                            stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &fn_proto.return_type.Explicit }, }) catch unreachable;
                             continue;
                         },
                     }
                 },
 
-                State.BoolOrExpressionBegin => |dest_ptr| {
-                    stack.append(State { .BoolOrExpressionEnd = dest_ptr }) catch unreachable;
-                    try stack.append(State { .BoolAndExpressionBegin = dest_ptr });
-                    continue;
-                },
 
-                State.BoolOrExpressionEnd => |dest_ptr| {
-                    const token = self.getNextToken();
-                    switch (token.id) {
-                        Token.Id.Keyword_or => {
-                            const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
-                                ast.NodeInfixOp {
-                                    .base = undefined,
-                                    .lhs = dest_ptr.get(),
-                                    .op_token = token,
-                                    .op = ast.NodeInfixOp.InfixOp.BoolOr,
-                                    .rhs = undefined,
-                                }
-                            );
-                            stack.append(State { .BoolOrExpressionEnd = dest_ptr }) catch unreachable;
-                            try stack.append(State { .BoolAndExpressionBegin = DestPtr { .Field = &node.rhs } });
-                            continue;
-                        },
-                        else => {
-                            self.putBackToken(token);
-                            continue;
-                        },
+                State.ParamDecl => |fn_proto| {
+                    if (self.eatToken(Token.Id.RParen)) |_| {
+                        continue;
                     }
-                },
+                    const param_decl = try self.createAttachNode(arena, &fn_proto.params, ast.NodeParamDecl,
+                        ast.NodeParamDecl {
+                            .base = undefined,
+                            .comptime_token = null,
+                            .noalias_token = null,
+                            .name_token = null,
+                            .type_node = undefined,
+                            .var_args_token = null,
+                        },
+                    );
 
-                State.BoolAndExpressionBegin => |dest_ptr| {
-                    stack.append(State { .BoolAndExpressionEnd = dest_ptr }) catch unreachable;
-                    try stack.append(State { .ComparisonExpressionBegin = dest_ptr });
+                    stack.append(State {
+                        .ParamDeclEnd = ParamDeclEndCtx {
+                            .param_decl = param_decl,
+                            .fn_proto = fn_proto,
+                        }
+                    }) catch unreachable;
+                    try stack.append(State { .ParamDeclName = param_decl });
+                    try stack.append(State { .ParamDeclAliasOrComptime = param_decl });
                     continue;
                 },
-
-                State.BoolAndExpressionEnd => |dest_ptr| {
-                    const token = self.getNextToken();
-                    switch (token.id) {
-                        Token.Id.Keyword_and => {
-                            const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
-                                ast.NodeInfixOp {
-                                    .base = undefined,
-                                    .lhs = dest_ptr.get(),
-                                    .op_token = token,
-                                    .op = ast.NodeInfixOp.InfixOp.BoolAnd,
-                                    .rhs = undefined,
-                                }
-                            );
-                            stack.append(State { .BoolAndExpressionEnd = dest_ptr }) catch unreachable;
-                            try stack.append(State { .ComparisonExpressionBegin = DestPtr { .Field = &node.rhs } });
-                            continue;
-                        },
-                        else => {
-                            self.putBackToken(token);
-                            continue;
-                        },
+                State.ParamDeclAliasOrComptime => |param_decl| {
+                    if (self.eatToken(Token.Id.Keyword_comptime)) |comptime_token| {
+                        param_decl.comptime_token = comptime_token;
+                    } else if (self.eatToken(Token.Id.Keyword_noalias)) |noalias_token| {
+                        param_decl.noalias_token = noalias_token;
                     }
                 },
-
-                State.ComparisonExpressionBegin => |dest_ptr| {
-                    stack.append(State { .ComparisonExpressionEnd = dest_ptr }) catch unreachable;
-                    try stack.append(State { .BinaryOrExpressionBegin = dest_ptr });
-                    continue;
+                State.ParamDeclName => |param_decl| {
+                    // TODO: Here, we eat two tokens in one state. This means that we can't have
+                    //       comments between these two tokens.
+                    if (self.eatToken(Token.Id.Identifier)) |ident_token| {
+                        if (self.eatToken(Token.Id.Colon)) |_| {
+                            param_decl.name_token = ident_token;
+                        } else {
+                            self.putBackToken(ident_token);
+                        }
+                    }
                 },
-
-                State.ComparisonExpressionEnd => |dest_ptr| {
-                    const token = self.getNextToken();
-                    if (tokenIdToComparison(token.id)) |comp_id| {
-                        const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
-                            ast.NodeInfixOp {
-                                .base = undefined,
-                                .lhs = dest_ptr.get(),
-                                .op_token = token,
-                                .op = comp_id,
-                                .rhs = undefined,
-                            }
-                        );
-                        stack.append(State { .ComparisonExpressionEnd = dest_ptr }) catch unreachable;
-                        try stack.append(State { .BinaryOrExpressionBegin = DestPtr { .Field = &node.rhs } });
-                        continue;
-                    } else {
-                        self.putBackToken(token);
+                State.ParamDeclEnd => |ctx| {
+                    if (self.eatToken(Token.Id.Ellipsis3)) |ellipsis3| {
+                        ctx.param_decl.var_args_token = ellipsis3;
+                        stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
                         continue;
                     }
-                },
 
-                State.BinaryOrExpressionBegin => |dest_ptr| {
-                    stack.append(State { .BinaryOrExpressionEnd = dest_ptr }) catch unreachable;
-                    try stack.append(State { .BinaryXorExpressionBegin = dest_ptr });
+                    try stack.append(State { .ParamDeclComma = ctx.fn_proto });
+                    try stack.append(State {
+                        .TypeExprBegin = OptionalCtx { .Required = &ctx.param_decl.type_node }
+                    });
+                },
+                State.ParamDeclComma => |fn_proto| {
+                    var discard_end: Token = undefined;
+                    try self.commaOrEnd(&stack, Token.Id.RParen, &discard_end, State { .ParamDecl = fn_proto });
                     continue;
                 },
 
-                State.BinaryOrExpressionEnd => |dest_ptr| {
+
+                State.LabeledExpression => |ctx| {
                     const token = self.getNextToken();
                     switch (token.id) {
-                        Token.Id.Pipe => {
-                            const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
-                                ast.NodeInfixOp {
+                        Token.Id.LBrace => {
+                            const block = try self.createToCtxNode(arena, ctx.opt_ctx, ast.NodeBlock,
+                                ast.NodeBlock {
                                     .base = undefined,
-                                    .lhs = dest_ptr.get(),
-                                    .op_token = token,
-                                    .op = ast.NodeInfixOp.InfixOp.BitOr,
-                                    .rhs = undefined,
+                                    .label = ctx.label,
+                                    .lbrace = token,
+                                    .statements = ArrayList(&ast.Node).init(arena),
+                                    .rbrace = undefined,
                                 }
                             );
-                            stack.append(State { .BinaryOrExpressionEnd = dest_ptr }) catch unreachable;
-                            try stack.append(State { .BinaryXorExpressionBegin = DestPtr { .Field = &node.rhs } });
+                            stack.append(State { .Block = block }) catch unreachable;
                             continue;
                         },
-                        else => {
-                            self.putBackToken(token);
+                        Token.Id.Keyword_while => {
+                            stack.append(State {
+                                .While = LoopCtx {
+                                    .label = ctx.label,
+                                    .inline_token = null,
+                                    .loop_token = token,
+                                    .opt_ctx = ctx.opt_ctx.toRequired(),
+                                }
+                            }) catch unreachable;
                             continue;
                         },
-                    }
-                },
-
-                State.BinaryXorExpressionBegin => |dest_ptr| {
-                    stack.append(State { .BinaryXorExpressionEnd = dest_ptr }) catch unreachable;
-                    try stack.append(State { .BinaryAndExpressionBegin = dest_ptr });
-                    continue;
-                },
-
-                State.BinaryXorExpressionEnd => |dest_ptr| {
-                    const token = self.getNextToken();
-                    switch (token.id) {
-                        Token.Id.Caret => {
-                            const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
-                                ast.NodeInfixOp {
-                                    .base = undefined,
-                                    .lhs = dest_ptr.get(),
-                                    .op_token = token,
-                                    .op = ast.NodeInfixOp.InfixOp.BitXor,
-                                    .rhs = undefined,
+                        Token.Id.Keyword_for => {
+                            stack.append(State {
+                                .For = LoopCtx {
+                                    .label = ctx.label,
+                                    .inline_token = null,
+                                    .loop_token = token,
+                                    .opt_ctx = ctx.opt_ctx.toRequired(),
                                 }
-                            );
-                            stack.append(State { .BinaryXorExpressionEnd = dest_ptr }) catch unreachable;
-                            try stack.append(State { .BinaryAndExpressionBegin = DestPtr { .Field = &node.rhs } });
+                            }) catch unreachable;
+                            continue;
+                        },
+                        Token.Id.Keyword_inline => {
+                            stack.append(State {
+                                .Inline = InlineCtx {
+                                    .label = ctx.label,
+                                    .inline_token = token,
+                                    .opt_ctx = ctx.opt_ctx.toRequired(),
+                                }
+                            }) catch unreachable;
                             continue;
                         },
                         else => {
+                            if (ctx.opt_ctx != OptionalCtx.Optional) {
+                                return self.parseError(token, "expected 'while', 'for', 'inline' or '{{', found {}", @tagName(token.id));
+                            }
+
                             self.putBackToken(token);
                             continue;
                         },
                     }
                 },
-
-                State.BinaryAndExpressionBegin => |dest_ptr| {
-                    stack.append(State { .BinaryAndExpressionEnd = dest_ptr }) catch unreachable;
-                    try stack.append(State { .BitShiftExpressionBegin = dest_ptr });
-                    continue;
-                },
-
-                State.BinaryAndExpressionEnd => |dest_ptr| {
+                State.Inline => |ctx| {
                     const token = self.getNextToken();
                     switch (token.id) {
-                        Token.Id.Ampersand => {
-                            const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
-                                ast.NodeInfixOp {
-                                    .base = undefined,
-                                    .lhs = dest_ptr.get(),
-                                    .op_token = token,
-                                    .op = ast.NodeInfixOp.InfixOp.BitAnd,
-                                    .rhs = undefined,
+                        Token.Id.Keyword_while => {
+                            stack.append(State {
+                                .While = LoopCtx {
+                                    .inline_token = ctx.inline_token,
+                                    .label = ctx.label,
+                                    .loop_token = token,
+                                    .opt_ctx = ctx.opt_ctx.toRequired(),
                                 }
-                            );
-                            stack.append(State { .BinaryAndExpressionEnd = dest_ptr }) catch unreachable;
-                            try stack.append(State { .BitShiftExpressionBegin = DestPtr { .Field = &node.rhs } });
+                            }) catch unreachable;
+                            continue;
+                        },
+                        Token.Id.Keyword_for => {
+                            stack.append(State {
+                                .For = LoopCtx {
+                                    .inline_token = ctx.inline_token,
+                                    .label = ctx.label,
+                                    .loop_token = token,
+                                    .opt_ctx = ctx.opt_ctx.toRequired(),
+                                }
+                            }) catch unreachable;
                             continue;
                         },
                         else => {
+                            if (ctx.opt_ctx != OptionalCtx.Optional) {
+                                return self.parseError(token, "expected 'while' or 'for', found {}", @tagName(token.id));
+                            }
+
                             self.putBackToken(token);
                             continue;
                         },
                     }
                 },
-
-                State.BitShiftExpressionBegin => |dest_ptr| {
-                    stack.append(State { .BitShiftExpressionEnd = dest_ptr }) catch unreachable;
-                    try stack.append(State { .AdditionExpressionBegin = dest_ptr });
-                    continue;
+                State.While => |ctx| {
+                    const node = try self.createToCtxNode(arena, ctx.opt_ctx, ast.NodeWhile,
+                        ast.NodeWhile {
+                            .base = undefined,
+                            .label = ctx.label,
+                            .inline_token = ctx.inline_token,
+                            .while_token = ctx.loop_token,
+                            .condition = undefined,
+                            .payload = null,
+                            .continue_expr = null,
+                            .body = undefined,
+                            .@"else" = null,
+                        }
+                    );
+                    stack.append(State { .Else = &node.@"else" }) catch unreachable;
+                    try stack.append(State { .Expression = OptionalCtx { .Required = &node.body } });
+                    try stack.append(State { .WhileContinueExpr = &node.continue_expr });
+                    try stack.append(State { .IfToken = Token.Id.Colon });
+                    try stack.append(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });
+                    try stack.append(State { .ExpectToken = Token.Id.RParen });
+                    try stack.append(State { .Expression = OptionalCtx { .Required = &node.condition } });
+                    try stack.append(State { .ExpectToken = Token.Id.LParen });
                 },
-
-                State.BitShiftExpressionEnd => |dest_ptr| {
-                    const token = self.getNextToken();
-                    if (tokenIdToBitShift(token.id)) |bitshift_id| {
-                        const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
-                            ast.NodeInfixOp {
-                                .base = undefined,
-                                .lhs = dest_ptr.get(),
-                                .op_token = token,
-                                .op = bitshift_id,
-                                .rhs = undefined,
-                            }
-                        );
-                        stack.append(State { .BitShiftExpressionEnd = dest_ptr }) catch unreachable;
-                        try stack.append(State { .AdditionExpressionBegin = DestPtr { .Field = &node.rhs } });
-                        continue;
-                    } else {
-                        self.putBackToken(token);
-                        continue;
-                    }
+                State.WhileContinueExpr => |dest| {
+                    stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
+                    try stack.append(State { .AssignmentExpressionBegin = OptionalCtx { .RequiredNull = dest } });
+                    try stack.append(State { .ExpectToken = Token.Id.LParen });
                 },
-
-                State.AdditionExpressionBegin => |dest_ptr| {
-                    stack.append(State { .AdditionExpressionEnd = dest_ptr }) catch unreachable;
-                    try stack.append(State { .MultiplyExpressionBegin = dest_ptr });
-                    continue;
+                State.For => |ctx| {
+                    const node = try self.createToCtxNode(arena, ctx.opt_ctx, ast.NodeFor,
+                        ast.NodeFor {
+                            .base = undefined,
+                            .label = ctx.label,
+                            .inline_token = ctx.inline_token,
+                            .for_token = ctx.loop_token,
+                            .array_expr = undefined,
+                            .payload = null,
+                            .body = undefined,
+                            .@"else" = null,
+                        }
+                    );
+                    stack.append(State { .Else = &node.@"else" }) catch unreachable;
+                    try stack.append(State { .Expression = OptionalCtx { .Required = &node.body } });
+                    try stack.append(State { .PointerIndexPayload = OptionalCtx { .Optional = &node.payload } });
+                    try stack.append(State { .ExpectToken = Token.Id.RParen });
+                    try stack.append(State { .Expression = OptionalCtx { .Required = &node.array_expr } });
+                    try stack.append(State { .ExpectToken = Token.Id.LParen });
                 },
-
-                State.AdditionExpressionEnd => |dest_ptr| {
-                    const token = self.getNextToken();
-                    if (tokenIdToAddition(token.id)) |add_id| {
-                        const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
-                            ast.NodeInfixOp {
-                                .base = undefined,
-                                .lhs = dest_ptr.get(),
-                                .op_token = token,
-                                .op = add_id,
-                                .rhs = undefined,
-                            }
-                        );
-                        stack.append(State { .AdditionExpressionEnd = dest_ptr }) catch unreachable;
-                        try stack.append(State { .MultiplyExpressionBegin = DestPtr { .Field = &node.rhs } });
-                        continue;
-                    } else {
-                        self.putBackToken(token);
+                State.Else => |dest| {
+                    const else_token = self.getNextToken();
+                    if (else_token.id != Token.Id.Keyword_else) {
+                        self.putBackToken(else_token);
                         continue;
                     }
-                },
-
-                State.MultiplyExpressionBegin => |dest_ptr| {
-                    stack.append(State { .MultiplyExpressionEnd = dest_ptr }) catch unreachable;
-                    try stack.append(State { .CurlySuffixExpressionBegin = dest_ptr });
-                    continue;
-                },
 
-                State.MultiplyExpressionEnd => |dest_ptr| {
-                    const token = self.getNextToken();
-                    if (tokenIdToMultiply(token.id)) |mult_id| {
-                        const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
-                            ast.NodeInfixOp {
-                                .base = undefined,
-                                .lhs = dest_ptr.get(),
-                                .op_token = token,
-                                .op = mult_id,
-                                .rhs = undefined,
-                            }
-                        );
-                        stack.append(State { .MultiplyExpressionEnd = dest_ptr }) catch unreachable;
-                        try stack.append(State { .CurlySuffixExpressionBegin = DestPtr { .Field = &node.rhs } });
-                        continue;
-                    } else {
-                        self.putBackToken(token);
-                        continue;
-                    }
-                },
+                    const node = try self.createNode(arena, ast.NodeElse,
+                        ast.NodeElse {
+                            .base = undefined,
+                            .else_token = else_token,
+                            .payload = null,
+                            .body = undefined,
+                        }
+                    );
+                    *dest = node;
 
-                State.CurlySuffixExpressionBegin => |dest_ptr| {
-                    stack.append(State { .CurlySuffixExpressionEnd = dest_ptr }) catch unreachable;
-                    try stack.append(State { .TypeExprBegin = dest_ptr });
-                    continue;
+                    stack.append(State { .Expression = OptionalCtx { .Required = &node.body } }) catch unreachable;
+                    try stack.append(State { .Payload = OptionalCtx { .Optional = &node.payload } });
                 },
 
-                State.CurlySuffixExpressionEnd => |dest_ptr| {
-                    if (self.eatToken(Token.Id.LBrace) == null) {
-                        continue;
-                    }
 
-                    if (self.isPeekToken(Token.Id.Period)) {
-                        const node = try self.createToDestNode(arena, dest_ptr, ast.NodeSuffixOp,
-                            ast.NodeSuffixOp {
-                                .base = undefined,
-                                .lhs = dest_ptr.get(),
-                                .op = ast.NodeSuffixOp.SuffixOp {
-                                    .StructInitializer = ArrayList(&ast.NodeFieldInitializer).init(arena),
-                                },
-                                .rtoken = undefined,
-                            }
-                        );
-                        stack.append(State { .CurlySuffixExpressionEnd = dest_ptr }) catch unreachable;
-                        try stack.append(State {
-                            .FieldInitListItemOrEnd = ListSave(&ast.NodeFieldInitializer) {
-                                .list = &node.op.StructInitializer,
-                                .ptr = &node.rtoken,
-                            }
-                        });
-                        continue;
-                    } else {
-                        const node = try self.createToDestNode(arena, dest_ptr, ast.NodeSuffixOp,
-                            ast.NodeSuffixOp {
-                                .base = undefined,
-                                .lhs = dest_ptr.get(),
-                                .op = ast.NodeSuffixOp.SuffixOp {
-                                    .ArrayInitializer = ArrayList(&ast.Node).init(arena),
-                                },
-                                .rtoken = undefined,
-                            }
-                        );
-                        stack.append(State { .CurlySuffixExpressionEnd = dest_ptr }) catch unreachable;
-                        try stack.append(State {
-                            .ExprListItemOrEnd = ExprListCtx {
-                                .list = &node.op.ArrayInitializer,
-                                .end = Token.Id.RBrace,
-                                .ptr = &node.rtoken,
-                            }
-                        });
-                        continue;
+                State.Block => |block| {
+                    const token = self.getNextToken();
+                    switch (token.id) {
+                        Token.Id.RBrace => {
+                            block.rbrace = token;
+                            continue;
+                        },
+                        else => {
+                            self.putBackToken(token);
+                            stack.append(State { .Block = block }) catch unreachable;
+                            try stack.append(State { .Statement = block });
+                            continue;
+                        },
                     }
                 },
-
-                State.TypeExprBegin => |dest_ptr| {
-                    stack.append(State { .TypeExprEnd = dest_ptr }) catch unreachable;
-                    try stack.append(State { .PrefixOpExpression = dest_ptr });
-                    continue;
-                },
-
-                State.TypeExprEnd => |dest_ptr| {
+                State.Statement => |block| {
                     const token = self.getNextToken();
                     switch (token.id) {
-                        Token.Id.Bang => {
-                            const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
-                                ast.NodeInfixOp {
+                        Token.Id.Keyword_comptime => {
+                            stack.append(State {
+                                .ComptimeStatement = ComptimeStatementCtx {
+                                    .comptime_token = token,
+                                    .block = block,
+                                }
+                            }) catch unreachable;
+                        },
+                        Token.Id.Keyword_var, Token.Id.Keyword_const => {
+                            const var_decl = try self.createAttachNode(arena, &block.statements, ast.NodeVarDecl,
+                                ast.NodeVarDecl {
                                     .base = undefined,
-                                    .lhs = dest_ptr.get(),
-                                    .op_token = token,
-                                    .op = ast.NodeInfixOp.InfixOp.ErrorUnion,
-                                    .rhs = undefined,
+                                    .visib_token = null,
+                                    .mut_token = token,
+                                    .comptime_token = null,
+                                    .extern_export_token = null,
+                                    .type_node = null,
+                                    .align_node = null,
+                                    .init_node = null,
+                                    .lib_name = null,
+                                    // initialized later
+                                    .name_token = undefined,
+                                    .eq_token = undefined,
+                                    .semicolon_token = undefined,
+                                }
+                            );
+                            stack.append(State { .VarDecl = var_decl }) catch unreachable;
+                            continue;
+                        },
+                        Token.Id.Keyword_defer, Token.Id.Keyword_errdefer => {
+                            const node = try self.createAttachNode(arena, &block.statements, ast.NodeDefer,
+                                ast.NodeDefer {
+                                    .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,
+                                        else => unreachable,
+                                    },
+                                    .expr = undefined,
+                                }
+                            );
+                            stack.append(State { .Semicolon = &node.base }) catch unreachable;
+                            try stack.append(State { .AssignmentExpressionBegin = OptionalCtx{ .Required = &node.expr } });
+                            continue;
+                        },
+                        Token.Id.LBrace => {
+                            const inner_block = try self.createAttachNode(arena, &block.statements, ast.NodeBlock,
+                                ast.NodeBlock {
+                                    .base = undefined,
+                                    .label = null,
+                                    .lbrace = token,
+                                    .statements = ArrayList(&ast.Node).init(arena),
+                                    .rbrace = undefined,
                                 }
                             );
-                            stack.append(State { .TypeExprEnd = dest_ptr }) catch unreachable;
-                            try stack.append(State { .PrefixOpExpression = DestPtr { .Field = &node.rhs } });
+                            stack.append(State { .Block = inner_block }) catch unreachable;
                             continue;
                         },
                         else => {
                             self.putBackToken(token);
+                            const statememt = try block.statements.addOne();
+                            stack.append(State { .Semicolon = statememt }) catch unreachable;
+                            try stack.append(State { .AssignmentExpressionBegin = OptionalCtx{ .Required = statememt } });
                             continue;
-                        },
+                        }
                     }
                 },
-
-                State.PrefixOpExpression => |dest_ptr| {
+                State.ComptimeStatement => |ctx| {
                     const token = self.getNextToken();
-                    if (tokenIdToPrefixOp(token.id)) |prefix_id| {
-                        var node = try self.createToDestNode(arena, dest_ptr, ast.NodePrefixOp,
-                            ast.NodePrefixOp {
+                    if (token.id == Token.Id.Keyword_var or token.id == Token.Id.Keyword_const) {
+                        const var_decl = try self.createAttachNode(arena, &ctx.block.statements, ast.NodeVarDecl,
+                            ast.NodeVarDecl {
                                 .base = undefined,
-                                .op_token = token,
-                                .op = prefix_id,
-                                .rhs = undefined,
+                                .visib_token = null,
+                                .mut_token = token,
+                                .comptime_token = ctx.comptime_token,
+                                .extern_export_token = null,
+                                .type_node = null,
+                                .align_node = null,
+                                .init_node = null,
+                                .lib_name = null,
+                                // initialized later
+                                .name_token = undefined,
+                                .eq_token = undefined,
+                                .semicolon_token = undefined,
                             }
                         );
-
-                        if (token.id == Token.Id.AsteriskAsterisk) {
-                            const child = try self.createNode(arena, ast.NodePrefixOp,
-                                ast.NodePrefixOp {
-                                    .base = undefined,
-                                    .op_token = token,
-                                    .op = prefix_id,
-                                    .rhs = undefined,
-                                }
-                            );
-                            node.rhs = &child.base;
-                            node = child;
+                        stack.append(State { .VarDecl = var_decl }) catch unreachable;
+                        continue;
+                    } else {
+                        self.putBackToken(token);
+                        self.putBackToken(ctx.comptime_token);
+                        const statememt = try ctx.block.statements.addOne();
+                        stack.append(State { .Semicolon = statememt }) catch unreachable;
+                        try stack.append(State { .Expression = OptionalCtx { .Required = statememt } });
+                        continue;
+                    }
+                },
+                State.Semicolon => |node_ptr| {
+                    const node = *node_ptr;
+                    if (requireSemiColon(node)) {
+                        stack.append(State { .ExpectToken = Token.Id.Semicolon }) catch unreachable;
+                    }
+                },
+
+
+                State.AsmOutputItems => |items| {
+                    const lbracket = self.getNextToken();
+                    if (lbracket.id != Token.Id.LBracket) {
+                        self.putBackToken(lbracket);
+                        continue;
+                    }
+
+                    const node = try self.createNode(arena, ast.NodeAsmOutput,
+                        ast.NodeAsmOutput {
+                            .base = undefined,
+                            .symbolic_name = undefined,
+                            .constraint = undefined,
+                            .kind = undefined,
                         }
+                    );
+                    try items.append(node);
 
-                        stack.append(State { .TypeExprBegin = DestPtr { .Field = &node.rhs } }) catch unreachable;
-                        if (node.op == ast.NodePrefixOp.PrefixOp.AddrOf) {
-                            try stack.append(State { .AddrOfModifiers = &node.op.AddrOf });
+                    stack.append(State { .AsmOutputItems = items }) catch unreachable;
+                    try stack.append(State { .IfToken = Token.Id.Comma });
+                    try stack.append(State { .ExpectToken = Token.Id.RParen });
+                    try stack.append(State { .AsmOutputReturnOrType = node });
+                    try stack.append(State { .ExpectToken = Token.Id.LParen });
+                    try stack.append(State { .StringLiteral = OptionalCtx { .Required = &node.constraint } });
+                    try stack.append(State { .ExpectToken = Token.Id.RBracket });
+                    try stack.append(State { .Identifier = OptionalCtx { .Required = &node.symbolic_name } });
+                },
+                State.AsmOutputReturnOrType => |node| {
+                    const token = self.getNextToken();
+                    switch (token.id) {
+                        Token.Id.Identifier => {
+                            node.kind = ast.NodeAsmOutput.Kind { .Variable = try self.createLiteral(arena, ast.NodeIdentifier, token) };
+                            continue;
+                        },
+                        Token.Id.Arrow => {
+                            node.kind = ast.NodeAsmOutput.Kind { .Return = undefined };
+                            try stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.kind.Return } });
+                            continue;
+                        },
+                        else => {
+                            return self.parseError(token, "expected '->' or {}, found {}",
+                                @tagName(Token.Id.Identifier),
+                                @tagName(token.id));
+                        },
+                    }
+                },
+                State.AsmInputItems => |items| {
+                    const lbracket = self.getNextToken();
+                    if (lbracket.id != Token.Id.LBracket) {
+                        self.putBackToken(lbracket);
+                        continue;
+                    }
+
+                    const node = try self.createNode(arena, ast.NodeAsmInput,
+                        ast.NodeAsmInput {
+                            .base = undefined,
+                            .symbolic_name = undefined,
+                            .constraint = undefined,
+                            .expr = undefined,
+                        }
+                    );
+                    try items.append(node);
+
+                    stack.append(State { .AsmInputItems = items }) catch unreachable;
+                    try stack.append(State { .IfToken = Token.Id.Comma });
+                    try stack.append(State { .ExpectToken = Token.Id.RParen });
+                    try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
+                    try stack.append(State { .ExpectToken = Token.Id.LParen });
+                    try stack.append(State { .StringLiteral = OptionalCtx { .Required = &node.constraint } });
+                    try stack.append(State { .ExpectToken = Token.Id.RBracket });
+                    try stack.append(State { .Identifier = OptionalCtx { .Required = &node.symbolic_name } });
+                },
+                State.AsmClopperItems => |items| {
+                    stack.append(State { .AsmClopperItems = items }) catch unreachable;
+                    try stack.append(State { .IfToken = Token.Id.Comma });
+                    try stack.append(State { .StringLiteral = OptionalCtx { .Required = try items.addOne() } });
+                },
+
+
+                State.ExprListItemOrEnd => |list_state| {
+                    if (self.eatToken(list_state.end)) |token| {
+                        *list_state.ptr = token;
+                        continue;
+                    }
+
+                    stack.append(State { .ExprListCommaOrEnd = list_state }) catch unreachable;
+                    try stack.append(State { .Expression = OptionalCtx { .Required = try list_state.list.addOne() } });
+                },
+                State.ExprListCommaOrEnd => |list_state| {
+                    try self.commaOrEnd(&stack, list_state.end, list_state.ptr, State { .ExprListItemOrEnd = list_state });
+                    continue;
+                },
+                State.FieldInitListItemOrEnd => |list_state| {
+                    if (self.eatToken(Token.Id.RBrace)) |rbrace| {
+                        *list_state.ptr = rbrace;
+                        continue;
+                    }
+
+                    const node = try self.createNode(arena, ast.NodeFieldInitializer,
+                        ast.NodeFieldInitializer {
+                            .base = undefined,
+                            .period_token = undefined,
+                            .name_token = undefined,
+                            .expr = undefined,
+                        }
+                    );
+                    try list_state.list.append(node);
+
+                    stack.append(State { .FieldInitListCommaOrEnd = list_state }) catch unreachable;
+                    try stack.append(State { .Expression = OptionalCtx{ .Required = &node.expr } });
+                    try stack.append(State { .ExpectToken = Token.Id.Equal });
+                    try stack.append(State {
+                        .ExpectTokenSave = ExpectTokenSave {
+                            .id = Token.Id.Identifier,
+                            .ptr = &node.name_token,
+                        }
+                    });
+                    try stack.append(State {
+                        .ExpectTokenSave = ExpectTokenSave {
+                            .id = Token.Id.Period,
+                            .ptr = &node.period_token,
+                        }
+                    });
+                },
+                State.FieldInitListCommaOrEnd => |list_state| {
+                    try self.commaOrEnd(&stack, Token.Id.RBrace, list_state.ptr, State { .FieldInitListItemOrEnd = list_state });
+                    continue;
+                },
+                State.FieldListCommaOrEnd => |container_decl| {
+                    try self.commaOrEnd(&stack, Token.Id.RBrace, &container_decl.rbrace_token,
+                        State { .ContainerDecl = container_decl });
+                    continue;
+                },
+                State.IdentifierListItemOrEnd => |list_state| {
+                    if (self.eatToken(Token.Id.RBrace)) |rbrace| {
+                        *list_state.ptr = rbrace;
+                        continue;
+                    }
+
+                    stack.append(State { .IdentifierListCommaOrEnd = list_state }) catch unreachable;
+                    try stack.append(State { .Identifier = OptionalCtx { .Required = try list_state.list.addOne() } });
+                },
+                State.IdentifierListCommaOrEnd => |list_state| {
+                    try self.commaOrEnd(&stack, Token.Id.RBrace, list_state.ptr, State { .IdentifierListItemOrEnd = list_state });
+                    continue;
+                },
+                State.SwitchCaseOrEnd => |list_state| {
+                    if (self.eatToken(Token.Id.RBrace)) |rbrace| {
+                        *list_state.ptr = rbrace;
+                        continue;
+                    }
+
+                    const node = try self.createNode(arena, ast.NodeSwitchCase,
+                        ast.NodeSwitchCase {
+                            .base = undefined,
+                            .items = ArrayList(&ast.Node).init(arena),
+                            .payload = null,
+                            .expr = undefined,
                         }
+                    );
+                    try list_state.list.append(node);
+                    stack.append(State { .SwitchCaseCommaOrEnd = list_state }) catch unreachable;
+                    try stack.append(State { .AssignmentExpressionBegin = OptionalCtx { .Required = &node.expr  } });
+                    try stack.append(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });
+                    try stack.append(State { .SwitchCaseFirstItem = &node.items });
+
+                },
+                State.SwitchCaseCommaOrEnd => |list_state| {
+                    try self.commaOrEnd(&stack, Token.Id.RBrace, list_state.ptr, State { .SwitchCaseOrEnd = list_state });
+                    continue;
+                },
+                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 {
+                                .base = undefined,
+                                .token = token,
+                            }
+                        );
+                        try stack.append(State { .ExpectToken = Token.Id.EqualAngleBracketRight });
                         continue;
                     } else {
                         self.putBackToken(token);
-                        stack.append(State { .SuffixOpExpressionBegin = dest_ptr }) catch unreachable;
+                        try stack.append(State { .SwitchCaseItem = case_items });
                         continue;
                     }
                 },
+                State.SwitchCaseItem => |case_items| {
+                    stack.append(State { .SwitchCaseItemCommaOrEnd = case_items }) catch unreachable;
+                    try stack.append(State { .RangeExpressionBegin = OptionalCtx { .Required = try case_items.addOne() } });
+                },
+                State.SwitchCaseItemCommaOrEnd => |case_items| {
+                    try self.commaOrEnd(&stack, Token.Id.EqualAngleBracketRight, null, State { .SwitchCaseItem = case_items });
+                    continue;
+                },
 
-                State.SuffixOpExpressionBegin => |dest_ptr| {
-                    const token = self.getNextToken();
-                    switch (token.id) {
-                        Token.Id.Keyword_async => {
-                            const async_node = try self.createNode(arena, ast.NodeAsyncAttribute,
-                                ast.NodeAsyncAttribute {
-                                    .base = undefined,
-                                    .async_token = token,
-                                    .allocator_type = null,
-                                    .rangle_bracket = null,
-                                }
-                            );
-                            stack.append(State {
-                                .AsyncEnd = AsyncEndCtx {
-                                    .dest_ptr = dest_ptr,
-                                    .attribute = async_node,
-                                }
-                            }) catch unreachable;
-                            try stack.append(State { .SuffixOpExpressionEnd = dest_ptr });
-                            try stack.append(State { .PrimaryExpression = dest_ptr });
 
-                            const langle_bracket = self.getNextToken();
-                            if (langle_bracket.id != Token.Id.AngleBracketLeft) {
-                                self.putBackToken(langle_bracket);
+                State.SuspendBody => |suspend_node| {
+                    if (suspend_node.payload != null) {
+                        try stack.append(State { .AssignmentExpressionBegin = OptionalCtx { .RequiredNull = &suspend_node.body } });
+                    }
+                    continue;
+                },
+                State.AsyncAllocator => |async_node| {
+                    if (self.eatToken(Token.Id.AngleBracketLeft) == null) {
+                        continue;
+                    }
+
+                    async_node.rangle_bracket = Token(undefined);
+                    try stack.append(State {
+                        .ExpectTokenSave = ExpectTokenSave {
+                            .id = Token.Id.AngleBracketRight,
+                            .ptr = &??async_node.rangle_bracket,
+                        }
+                    });
+                    try stack.append(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &async_node.allocator_type } });
+                },
+                State.AsyncEnd => |ctx| {
+                    const node = ctx.ctx.get() ?? continue;
+
+                    switch (node.id) {
+                        ast.Node.Id.FnProto => {
+                            const fn_proto = @fieldParentPtr(ast.NodeFnProto, "base", node);
+                            fn_proto.async_attr = ctx.attribute;
+                        },
+                        ast.Node.Id.SuffixOp => {
+                            const suffix_op = @fieldParentPtr(ast.NodeSuffixOp, "base", node);
+                            if (suffix_op.op == ast.NodeSuffixOp.SuffixOp.Call) {
+                                suffix_op.op.Call.async_attr = ctx.attribute;
                                 continue;
                             }
 
-                            async_node.rangle_bracket = Token(undefined);
-                            try stack.append(State {
-                                .ExpectTokenSave = ExpectTokenSave {
-                                    .id = Token.Id.AngleBracketRight,
-                                    .ptr = &??async_node.rangle_bracket,
-                                }
-                            });
-                            try stack.append(State { .TypeExprBegin = DestPtr { .NullableField = &async_node.allocator_type } });
-                            continue;
+                            return self.parseError(node.firstToken(), "expected {}, found {}.",
+                                @tagName(ast.NodeSuffixOp.SuffixOp.Call),
+                                @tagName(suffix_op.op));
                         },
                         else => {
-                            self.putBackToken(token);
-                            stack.append(State { .SuffixOpExpressionEnd = dest_ptr }) catch unreachable;
-                            try stack.append(State { .PrimaryExpression = dest_ptr });
-                            continue;
+                            return self.parseError(node.firstToken(), "expected {} or {}, found {}.",
+                                @tagName(ast.NodeSuffixOp.SuffixOp.Call),
+                                @tagName(ast.Node.Id.FnProto),
+                                @tagName(node.id));
                         }
                     }
                 },
 
-                State.SuffixOpExpressionEnd => |dest_ptr| {
-                    const token = self.getNextToken();
+
+                State.SliceOrArrayAccess => |node| {
+                    var token = self.getNextToken();
                     switch (token.id) {
-                        Token.Id.LParen => {
-                            const node = try self.createToDestNode(arena, dest_ptr, ast.NodeSuffixOp,
-                                ast.NodeSuffixOp {
-                                    .base = undefined,
-                                    .lhs = dest_ptr.get(),
-                                    .op = ast.NodeSuffixOp.SuffixOp {
-                                        .Call = ast.NodeSuffixOp.CallInfo {
-                                            .params = ArrayList(&ast.Node).init(arena),
-                                            .async_attr = null,
-                                        }
-                                    },
-                                    .rtoken = undefined,
+                        Token.Id.Ellipsis2 => {
+                            const start = node.op.ArrayAccess;
+                            node.op = ast.NodeSuffixOp.SuffixOp {
+                                .Slice = ast.NodeSuffixOp.SliceRange {
+                                    .start = start,
+                                    .end = null,
                                 }
-                            );
-                            stack.append(State { .SuffixOpExpressionEnd = dest_ptr }) catch unreachable;
-                            try stack.append(State {
-                                .ExprListItemOrEnd = ExprListCtx {
-                                    .list = &node.op.Call.params,
-                                    .end = Token.Id.RParen,
+                            };
+
+                            stack.append(State {
+                                .ExpectTokenSave = ExpectTokenSave {
+                                    .id = Token.Id.RBracket,
                                     .ptr = &node.rtoken,
                                 }
-                            });
-                            continue;
-                        },
-                        Token.Id.LBracket => {
-                            const node = try self.createToDestNode(arena, dest_ptr, ast.NodeSuffixOp,
-                                ast.NodeSuffixOp {
-                                    .base = undefined,
-                                    .lhs = dest_ptr.get(),
-                                    .op = ast.NodeSuffixOp.SuffixOp {
-                                        .ArrayAccess = undefined,
-                                    },
-                                    .rtoken = undefined
-                                }
-                            );
-                            stack.append(State { .SuffixOpExpressionEnd = dest_ptr }) catch unreachable;
-                            try stack.append(State { .SliceOrArrayAccess = node });
-                            try stack.append(State { .Expression = DestPtr { .Field = &node.op.ArrayAccess }});
+                            }) catch unreachable;
+                            try stack.append(State { .Expression = OptionalCtx { .Optional = &node.op.Slice.end } });
                             continue;
                         },
-                        Token.Id.Period => {
-                            const identifier = try self.createLiteral(arena, ast.NodeIdentifier, Token(undefined));
-                            const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
-                                ast.NodeInfixOp {
-                                    .base = undefined,
-                                    .lhs = dest_ptr.get(),
-                                    .op_token = token,
-                                    .op = ast.NodeInfixOp.InfixOp.Period,
-                                    .rhs = &identifier.base,
-                                }
-                            );
-                            stack.append(State { .SuffixOpExpressionEnd = dest_ptr }) catch unreachable;
-                            try stack.append(State {
-                                .ExpectTokenSave = ExpectTokenSave {
-                                    .id = Token.Id.Identifier,
-                                    .ptr = &identifier.token
-                                }
-                            });
+                        Token.Id.RBracket => {
+                            node.rtoken = token;
                             continue;
                         },
                         else => {
-                            self.putBackToken(token);
-                            continue;
-                        },
+                            return self.parseError(token, "expected ']' or '..', found {}", @tagName(token.id));
+                        }
                     }
                 },
+                State.SliceOrArrayType => |node| {
+                    if (self.eatToken(Token.Id.RBracket)) |_| {
+                        node.op = ast.NodePrefixOp.PrefixOp {
+                            .SliceType = ast.NodePrefixOp.AddrOfInfo {
+                                .align_expr = null,
+                                .bit_offset_start_token = null,
+                                .bit_offset_end_token = null,
+                                .const_token = null,
+                                .volatile_token = null,
+                            }
+                        };
+                        stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
+                        try stack.append(State { .AddrOfModifiers = &node.op.SliceType });
+                        continue;
+                    }
 
-                State.PrimaryExpression => |dest_ptr| {
-                    const token = self.getNextToken();
+                    node.op = ast.NodePrefixOp.PrefixOp { .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 } });
+                    continue;
+                },
+                State.AddrOfModifiers => |addr_of_info| {
+                    var token = self.getNextToken();
                     switch (token.id) {
-                        Token.Id.IntegerLiteral => {
-                            dest_ptr.store(&(try self.createLiteral(arena, ast.NodeStringLiteral, token)).base);
-                            continue;
-                        },
-                        Token.Id.FloatLiteral => {
-                            dest_ptr.store(&(try self.createLiteral(arena, ast.NodeFloatLiteral, token)).base);
-                            continue;
-                        },
-                        Token.Id.CharLiteral => {
-                            dest_ptr.store(&(try self.createLiteral(arena, ast.NodeCharLiteral, token)).base);
-                            continue;
-                        },
-                        Token.Id.Keyword_undefined => {
-                            dest_ptr.store(&(try self.createLiteral(arena, ast.NodeUndefinedLiteral, token)).base);
-                            continue;
-                        },
-                        Token.Id.Keyword_true, Token.Id.Keyword_false => {
-                            dest_ptr.store(&(try self.createLiteral(arena, ast.NodeBoolLiteral, token)).base);
-                            continue;
-                        },
-                        Token.Id.Keyword_null => {
-                            dest_ptr.store(&(try self.createLiteral(arena, ast.NodeNullLiteral, token)).base);
+                        Token.Id.Keyword_align => {
+                            stack.append(state) catch unreachable;
+                            if (addr_of_info.align_expr != null) {
+                                return self.parseError(token, "multiple align qualifiers");
+                            }
+                            try stack.append(State { .ExpectToken = Token.Id.RParen });
+                            try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &addr_of_info.align_expr} });
+                            try stack.append(State { .ExpectToken = Token.Id.LParen });
                             continue;
                         },
-                        Token.Id.Keyword_this => {
-                            dest_ptr.store(&(try self.createLiteral(arena, ast.NodeThisLiteral, token)).base);
+                        Token.Id.Keyword_const => {
+                            stack.append(state) catch unreachable;
+                            if (addr_of_info.const_token != null) {
+                                return self.parseError(token, "duplicate qualifier: const");
+                            }
+                            addr_of_info.const_token = token;
                             continue;
                         },
-                        Token.Id.Keyword_var => {
-                            dest_ptr.store(&(try self.createLiteral(arena, ast.NodeVarType, token)).base);
+                        Token.Id.Keyword_volatile => {
+                            stack.append(state) catch unreachable;
+                            if (addr_of_info.volatile_token != null) {
+                                return self.parseError(token, "duplicate qualifier: volatile");
+                            }
+                            addr_of_info.volatile_token = token;
                             continue;
                         },
-                        Token.Id.Keyword_unreachable => {
-                            dest_ptr.store(&(try self.createLiteral(arena, ast.NodeUnreachable, token)).base);
+                        else => {
+                            self.putBackToken(token);
                             continue;
                         },
-                        Token.Id.StringLiteral, Token.Id.MultilineStringLiteralLine => {
-                            dest_ptr.store((try self.parseStringLiteral(arena, token)) ?? unreachable);
-                        },
-                        Token.Id.LParen => {
-                            const node = try self.createToDestNode(arena, dest_ptr, ast.NodeGroupedExpression,
-                                ast.NodeGroupedExpression {
+                    }
+                },
+
+
+                State.Payload => |opt_ctx| {
+                    const token = self.getNextToken();
+                    if (token.id != Token.Id.Pipe) {
+                        if (opt_ctx != OptionalCtx.Optional) {
+                            return self.parseError(token, "expected {}, found {}.",
+                                @tagName(Token.Id.Pipe),
+                                @tagName(token.id));
+                        }
+
+                        self.putBackToken(token);
+                        continue;
+                    }
+
+                    const node = try self.createToCtxNode(arena, opt_ctx, ast.NodePayload,
+                        ast.NodePayload {
+                            .base = undefined,
+                            .lpipe = token,
+                            .error_symbol = undefined,
+                            .rpipe = undefined
+                        }
+                    );
+
+                    stack.append(State {
+                        .ExpectTokenSave = ExpectTokenSave {
+                            .id = Token.Id.Pipe,
+                            .ptr = &node.rpipe,
+                        }
+                    }) catch unreachable;
+                    try stack.append(State { .Identifier = OptionalCtx { .Required = &node.error_symbol } });
+                },
+                State.PointerPayload => |opt_ctx| {
+                    const token = self.getNextToken();
+                    if (token.id != Token.Id.Pipe) {
+                        if (opt_ctx != OptionalCtx.Optional) {
+                            return self.parseError(token, "expected {}, found {}.",
+                                @tagName(Token.Id.Pipe),
+                                @tagName(token.id));
+                        }
+
+                        self.putBackToken(token);
+                        continue;
+                    }
+
+                    const node = try self.createToCtxNode(arena, opt_ctx, ast.NodePointerPayload,
+                        ast.NodePointerPayload {
+                            .base = undefined,
+                            .lpipe = token,
+                            .ptr_token = null,
+                            .value_symbol = undefined,
+                            .rpipe = undefined
+                        }
+                    );
+
+                    stack.append(State {
+                        .ExpectTokenSave = ExpectTokenSave {
+                            .id = Token.Id.Pipe,
+                            .ptr = &node.rpipe,
+                        }
+                    }) catch unreachable;
+                    try stack.append(State { .Identifier = OptionalCtx { .Required = &node.value_symbol } });
+                    try stack.append(State {
+                        .OptionalTokenSave = OptionalTokenSave {
+                            .id = Token.Id.Asterisk,
+                            .ptr = &node.ptr_token,
+                        }
+                    });
+                },
+                State.PointerIndexPayload => |opt_ctx| {
+                    const token = self.getNextToken();
+                    if (token.id != Token.Id.Pipe) {
+                        if (opt_ctx != OptionalCtx.Optional) {
+                            return self.parseError(token, "expected {}, found {}.",
+                                @tagName(Token.Id.Pipe),
+                                @tagName(token.id));
+                        }
+
+                        self.putBackToken(token);
+                        continue;
+                    }
+
+                    const node = try self.createToCtxNode(arena, opt_ctx, ast.NodePointerIndexPayload,
+                        ast.NodePointerIndexPayload {
+                            .base = undefined,
+                            .lpipe = token,
+                            .ptr_token = null,
+                            .value_symbol = undefined,
+                            .index_symbol = null,
+                            .rpipe = undefined
+                        }
+                    );
+
+                    stack.append(State {
+                        .ExpectTokenSave = ExpectTokenSave {
+                            .id = Token.Id.Pipe,
+                            .ptr = &node.rpipe,
+                        }
+                    }) catch unreachable;
+                    try stack.append(State { .Identifier = OptionalCtx { .RequiredNull = &node.index_symbol } });
+                    try stack.append(State { .IfToken = Token.Id.Comma });
+                    try stack.append(State { .Identifier = OptionalCtx { .Required = &node.value_symbol } });
+                    try stack.append(State {
+                        .OptionalTokenSave = OptionalTokenSave {
+                            .id = Token.Id.Asterisk,
+                            .ptr = &node.ptr_token,
+                        }
+                    });
+                },
+
+
+                State.Expression => |opt_ctx| {
+                    const token = self.getNextToken();
+                    switch (token.id) {
+                        Token.Id.Keyword_return => {
+                            const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeControlFlowExpression,
+                                ast.NodeControlFlowExpression {
                                     .base = undefined,
-                                    .lparen = token,
-                                    .expr = undefined,
-                                    .rparen = undefined,
+                                    .ltoken = token,
+                                    .kind = ast.NodeControlFlowExpression.Kind.Return,
+                                    .rhs = null,
                                 }
                             );
-                            stack.append(State {
-                                .ExpectTokenSave = ExpectTokenSave {
-                                    .id = Token.Id.RParen,
-                                    .ptr = &node.rparen,
-                                }
-                            }) catch unreachable;
-                            try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
+
+                            stack.append(State { .Expression = OptionalCtx { .Optional = &node.rhs } }) catch unreachable;
                             continue;
                         },
-                        Token.Id.Builtin => {
-                            const node = try self.createToDestNode(arena, dest_ptr, ast.NodeBuiltinCall,
-                                ast.NodeBuiltinCall {
+                        Token.Id.Keyword_break, Token.Id.Keyword_continue => {
+                            const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeControlFlowExpression,
+                                ast.NodeControlFlowExpression {
                                     .base = undefined,
-                                    .builtin_token = token,
-                                    .params = ArrayList(&ast.Node).init(arena),
-                                    .rparen_token = undefined,
+                                    .ltoken = token,
+                                    .kind = undefined,
+                                    .rhs = null,
                                 }
                             );
-                            stack.append(State {
-                                .ExprListItemOrEnd = ExprListCtx {
-                                    .list = &node.params,
-                                    .end = Token.Id.RParen,
-                                    .ptr = &node.rparen_token,
-                                }
-                            }) catch unreachable;
-                            try stack.append(State { .ExpectToken = Token.Id.LParen, });
-                            continue;
-                        },
-                        Token.Id.LBracket => {
-                            const rbracket_token = self.getNextToken();
-                            if (rbracket_token.id == Token.Id.RBracket) {
-                                const node = try self.createToDestNode(arena, dest_ptr, ast.NodePrefixOp,
-                                    ast.NodePrefixOp {
-                                        .base = undefined,
-                                        .op_token = token,
-                                        .op = ast.NodePrefixOp.PrefixOp{
-                                            .SliceType = ast.NodePrefixOp.AddrOfInfo {
-                                                .align_expr = null,
-                                                .bit_offset_start_token = null,
-                                                .bit_offset_end_token = null,
-                                                .const_token = null,
-                                                .volatile_token = null,
-                                            }
-                                        },
-                                        .rhs = undefined,
-                                    }
-                                );
-                                dest_ptr.store(&node.base);
-                                stack.append(State { .TypeExprBegin = DestPtr { .Field = &node.rhs } }) catch unreachable;
-                                try stack.append(State { .AddrOfModifiers = &node.op.SliceType });
-                                continue;
-                            }
 
-                            self.putBackToken(rbracket_token);
+                            stack.append(State { .Expression = OptionalCtx { .Optional = &node.rhs } }) catch unreachable;
 
-                            const node = try self.createToDestNode(arena, dest_ptr, ast.NodePrefixOp,
+                            switch (token.id) {
+                                Token.Id.Keyword_break => {
+                                    node.kind = ast.NodeControlFlowExpression.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 };
+                                    try stack.append(State { .Identifier = OptionalCtx { .RequiredNull = &node.kind.Continue } });
+                                    try stack.append(State { .IfToken = Token.Id.Colon });
+                                },
+                                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 {
                                     .base = undefined,
                                     .op_token = token,
-                                    .op = ast.NodePrefixOp.PrefixOp{
-                                        .ArrayType = undefined,
+                                    .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{} },
+                                        else => unreachable,
                                     },
                                     .rhs = undefined,
                                 }
                             );
-                            stack.append(State { .TypeExprBegin = DestPtr { .Field = &node.rhs } }) catch unreachable;
-                            try stack.append(State { .ExpectToken = Token.Id.RBracket });
-                            try stack.append(State { .Expression = DestPtr { .Field = &node.op.ArrayType } });
 
+                            stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
+                            continue;
                         },
-                        Token.Id.Keyword_error => {
-                            if (self.eatToken(Token.Id.LBrace) == null) {
-                                dest_ptr.store(&(try self.createLiteral(arena, ast.NodeErrorType, token)).base);
-                                continue;
+                        else => {
+                            if (!try self.parseBlockExpr(&stack, arena, opt_ctx, token)) {
+                                self.putBackToken(token);
+                                stack.append(State { .UnwrapExpressionBegin = opt_ctx }) catch unreachable;
                             }
-
-                            const node = try self.createToDestNode(arena, dest_ptr, ast.NodeErrorSetDecl,
-                                ast.NodeErrorSetDecl {
-                                    .base = undefined,
-                                    .error_token = token,
-                                    .decls = ArrayList(&ast.NodeIdentifier).init(arena),
-                                    .rbrace_token = undefined,
-                                }
-                            );
-
-                            stack.append(State {
-                                .IdentifierListItemOrEnd = ListSave(&ast.NodeIdentifier) {
-                                    .list = &node.decls,
-                                    .ptr = &node.rbrace_token,
-                                }
-                            }) catch unreachable;
                             continue;
-                        },
-                        Token.Id.Keyword_packed => {
-                            stack.append(State {
-                                .ContainerExtern = ContainerExternCtx {
-                                    .dest_ptr = dest_ptr,
-                                    .ltoken = token,
-                                    .layout = ast.NodeContainerDecl.Layout.Packed,
-                                },
-                            }) catch unreachable;
-                        },
-                        Token.Id.Keyword_extern => {
-                            const next = self.getNextToken();
-                            if (next.id == Token.Id.Keyword_fn) {
-                                const fn_proto = try self.createToDestNode(arena, dest_ptr, ast.NodeFnProto,
-                                    ast.NodeFnProto {
-                                        .base = undefined,
-                                        .visib_token = null,
-                                        .name_token = null,
-                                        .fn_token = next,
-                                        .params = ArrayList(&ast.Node).init(arena),
-                                        .return_type = undefined,
-                                        .var_args_token = null,
-                                        .extern_export_inline_token = token,
-                                        .cc_token = null,
-                                        .async_attr = null,
-                                        .body_node = null,
-                                        .lib_name = null,
-                                        .align_expr = null,
-                                    }
-                                );
-                                stack.append(State { .FnProto = fn_proto }) catch unreachable;
-                                continue;
+                        }
+                    }
+                },
+                State.RangeExpressionBegin => |opt_ctx| {
+                    stack.append(State { .RangeExpressionEnd = opt_ctx }) catch unreachable;
+                    try stack.append(State { .Expression = opt_ctx });
+                    continue;
+                },
+                State.RangeExpressionEnd => |opt_ctx| {
+                    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 {
+                                .base = undefined,
+                                .lhs = lhs,
+                                .op_token = ellipsis3,
+                                .op = ast.NodeInfixOp.InfixOp.Range,
+                                .rhs = undefined,
                             }
+                        );
+                        stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
+                    }
 
-                            self.putBackToken(next);
-                            stack.append(State {
-                                .ContainerExtern = ContainerExternCtx {
-                                    .dest_ptr = dest_ptr,
-                                    .ltoken = token,
-                                    .layout = ast.NodeContainerDecl.Layout.Extern,
-                                },
-                            }) catch unreachable;
-                        },
-                        Token.Id.Keyword_struct, Token.Id.Keyword_union, Token.Id.Keyword_enum => {
-                            self.putBackToken(token);
-                            stack.append(State {
-                                .ContainerExtern = ContainerExternCtx {
-                                    .dest_ptr = dest_ptr,
-                                    .ltoken = token,
-                                    .layout = ast.NodeContainerDecl.Layout.Auto,
-                                },
-                            }) catch unreachable;
-                        },
-                        Token.Id.Identifier => {
-                            const next = self.getNextToken();
-                            if (next.id != Token.Id.Colon) {
-                                self.putBackToken(next);
-                                dest_ptr.store(&(try self.createLiteral(arena, ast.NodeIdentifier, token)).base);
-                                continue;
+                    continue;
+                },
+                State.AssignmentExpressionBegin => |opt_ctx| {
+                    stack.append(State { .AssignmentExpressionEnd = opt_ctx }) catch unreachable;
+                    try stack.append(State { .Expression = opt_ctx });
+                    continue;
+                },
+
+                State.AssignmentExpressionEnd => |opt_ctx| {
+                    const lhs = opt_ctx.get() ?? continue;
+
+                    const token = self.getNextToken();
+                    if (tokenIdToAssignment(token.id)) |ass_id| {
+                        const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
+                            ast.NodeInfixOp {
+                                .base = undefined,
+                                .lhs = lhs,
+                                .op_token = token,
+                                .op = ass_id,
+                                .rhs = undefined,
                             }
+                        );
+                        stack.append(State { .AssignmentExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
+                        try stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } });
+                        continue;
+                    } else {
+                        self.putBackToken(token);
+                        continue;
+                    }
+                },
 
-                            stack.append(State {
-                                .LabeledExpression = LabelCtx {
-                                    .label = token,
-                                    .dest_ptr = dest_ptr
-                                }
-                            }) catch unreachable;
-                            continue;
-                        },
-                        Token.Id.Keyword_fn => {
-                            const fn_proto = try self.createToDestNode(arena, dest_ptr, ast.NodeFnProto,
-                                ast.NodeFnProto {
+                State.UnwrapExpressionBegin => |opt_ctx| {
+                    stack.append(State { .UnwrapExpressionEnd = opt_ctx }) catch unreachable;
+                    try stack.append(State { .BoolOrExpressionBegin = opt_ctx });
+                    continue;
+                },
+
+                State.UnwrapExpressionEnd => |opt_ctx| {
+                    const lhs = opt_ctx.get() ?? continue;
+
+                    const token = self.getNextToken();
+                    switch (token.id) {
+                        Token.Id.Keyword_catch, Token.Id.QuestionMarkQuestionMark => {
+                            const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
+                                ast.NodeInfixOp {
                                     .base = undefined,
-                                    .visib_token = null,
-                                    .name_token = null,
-                                    .fn_token = token,
-                                    .params = ArrayList(&ast.Node).init(arena),
-                                    .return_type = undefined,
-                                    .var_args_token = null,
-                                    .extern_export_inline_token = null,
-                                    .cc_token = null,
-                                    .async_attr = null,
-                                    .body_node = null,
-                                    .lib_name = null,
-                                    .align_expr = null,
+                                    .lhs = lhs,
+                                    .op_token = token,
+                                    .op = switch (token.id) {
+                                        Token.Id.Keyword_catch => ast.NodeInfixOp.InfixOp { .Catch = null },
+                                        Token.Id.QuestionMarkQuestionMark => ast.NodeInfixOp.InfixOp { .UnwrapMaybe = void{} },
+                                        else => unreachable,
+                                    },
+                                    .rhs = undefined,
                                 }
                             );
-                            stack.append(State { .FnProto = fn_proto }) catch unreachable;
+
+                            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) {
+                                try stack.append(State { .Payload = OptionalCtx { .Optional = &node.op.Catch } });
+                            }
                             continue;
                         },
-                        Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
-                            const fn_token = (try self.expectToken(&stack, Token.Id.Keyword_fn)) ?? continue;
-                            const fn_proto = try self.createToDestNode(arena, dest_ptr, ast.NodeFnProto,
-                                ast.NodeFnProto {
-                                    .base = undefined,
-                                    .visib_token = null,
-                                    .name_token = null,
-                                    .fn_token = fn_token,
-                                    .params = ArrayList(&ast.Node).init(arena),
-                                    .return_type = undefined,
-                                    .var_args_token = null,
-                                    .extern_export_inline_token = null,
-                                    .cc_token = token,
-                                    .async_attr = null,
-                                    .body_node = null,
-                                    .lib_name = null,
-                                    .align_expr = null,
-                                }
-                            );
-                            stack.append(State { .FnProto = fn_proto }) catch unreachable;
+                        else => {
+                            self.putBackToken(token);
                             continue;
                         },
-                        Token.Id.Keyword_asm => {
-                            const is_volatile = blk: {
-                                const volatile_token = self.getNextToken();
-                                if (volatile_token.id != Token.Id.Keyword_volatile) {
-                                    self.putBackToken(volatile_token);
-                                    break :blk false;
-                                }
-                                break :blk true;
-                            };
-                            _ = (try self.expectToken(&stack, Token.Id.LParen)) ?? continue;
+                    }
+                },
 
-                            const template_token = self.getNextToken();
-                            const template = (try self.parseStringLiteral(arena, template_token)) ?? {
-                                try self.parseError(&stack, template_token, "expected string literal, found {}", @tagName(template_token.id));
-                                continue;
-                            };
-                            // TODO parse template
+                State.BoolOrExpressionBegin => |opt_ctx| {
+                    stack.append(State { .BoolOrExpressionEnd = opt_ctx }) catch unreachable;
+                    try stack.append(State { .BoolAndExpressionBegin = opt_ctx });
+                    continue;
+                },
 
-                            const node = try self.createToDestNode(arena, dest_ptr, ast.NodeAsm,
-                                ast.NodeAsm {
+                State.BoolOrExpressionEnd => |opt_ctx| {
+                    const lhs = opt_ctx.get() ?? continue;
+
+                    const token = self.getNextToken();
+                    switch (token.id) {
+                        Token.Id.Keyword_or => {
+                            const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
+                                ast.NodeInfixOp {
                                     .base = undefined,
-                                    .asm_token = token,
-                                    .is_volatile = is_volatile,
-                                    .template = template,
-                                    //.tokens = ArrayList(ast.NodeAsm.AsmToken).init(arena),
-                                    .outputs = ArrayList(&ast.NodeAsmOutput).init(arena),
-                                    .inputs = ArrayList(&ast.NodeAsmInput).init(arena),
-                                    .cloppers = ArrayList(&ast.Node).init(arena),
-                                    .rparen = undefined,
+                                    .lhs = lhs,
+                                    .op_token = token,
+                                    .op = ast.NodeInfixOp.InfixOp.BoolOr,
+                                    .rhs = undefined,
                                 }
                             );
-                            stack.append(State {
-                                .ExpectTokenSave = ExpectTokenSave {
-                                    .id = Token.Id.RParen,
-                                    .ptr = &node.rparen,
-                                }
-                            }) catch unreachable;
-                            try stack.append(State { .AsmClopperItems = &node.cloppers });
-                            try stack.append(State { .IfToken = Token.Id.Colon });
-                            try stack.append(State { .AsmInputItems = &node.inputs });
-                            try stack.append(State { .IfToken = Token.Id.Colon });
-                            try stack.append(State { .AsmOutputItems = &node.outputs });
-                            try stack.append(State { .IfToken = Token.Id.Colon });
-                        },
-                        Token.Id.Keyword_inline => {
-                            stack.append(State {
-                                .Inline = InlineCtx {
-                                    .label = null,
-                                    .inline_token = token,
-                                    .dest_ptr = dest_ptr,
-                                }
-                            }) catch unreachable;
+                            stack.append(State { .BoolOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
+                            try stack.append(State { .BoolAndExpressionBegin = OptionalCtx { .Required = &node.rhs } });
                             continue;
                         },
                         else => {
-                            if (!try self.parseBlockExpr(&stack, arena, dest_ptr, token)) {
-                                try self.parseError(&stack, token, "expected primary expression, found {}", @tagName(token.id));
-                            }
+                            self.putBackToken(token);
                             continue;
-                        }
+                        },
                     }
                 },
 
-                State.SliceOrArrayAccess => |node| {
-                    var token = self.getNextToken();
+                State.BoolAndExpressionBegin => |opt_ctx| {
+                    stack.append(State { .BoolAndExpressionEnd = opt_ctx }) catch unreachable;
+                    try stack.append(State { .ComparisonExpressionBegin = opt_ctx });
+                    continue;
+                },
+
+                State.BoolAndExpressionEnd => |opt_ctx| {
+                    const lhs = opt_ctx.get() ?? continue;
 
+                    const token = self.getNextToken();
                     switch (token.id) {
-                        Token.Id.Ellipsis2 => {
-                            const start = node.op.ArrayAccess;
-                            node.op = ast.NodeSuffixOp.SuffixOp {
-                                .Slice = ast.NodeSuffixOp.SliceRange {
-                                    .start = start,
-                                    .end = undefined,
+                        Token.Id.Keyword_and => {
+                            const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
+                                ast.NodeInfixOp {
+                                    .base = undefined,
+                                    .lhs = lhs,
+                                    .op_token = token,
+                                    .op = ast.NodeInfixOp.InfixOp.BoolAnd,
+                                    .rhs = undefined,
                                 }
-                            };
-
-                            const rbracket_token = self.getNextToken();
-                            if (rbracket_token.id != Token.Id.RBracket) {
-                                self.putBackToken(rbracket_token);
-                                stack.append(State {
-                                    .ExpectTokenSave = ExpectTokenSave {
-                                        .id = Token.Id.RBracket,
-                                        .ptr = &node.rtoken,
-                                    }
-                                }) catch unreachable;
-                                try stack.append(State { .Expression = DestPtr { .NullableField = &node.op.Slice.end } });
-                            } else {
-                                node.rtoken = rbracket_token;
-                            }
-                            continue;
-                        },
-                        Token.Id.RBracket => {
-                            node.rtoken = token;
+                            );
+                            stack.append(State { .BoolAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
+                            try stack.append(State { .ComparisonExpressionBegin = OptionalCtx { .Required = &node.rhs } });
                             continue;
                         },
                         else => {
-                            try self.parseError(&stack, token, "expected ']' or '..', found {}", @tagName(token.id));
+                            self.putBackToken(token);
                             continue;
-                        }
+                        },
                     }
                 },
 
+                State.ComparisonExpressionBegin => |opt_ctx| {
+                    stack.append(State { .ComparisonExpressionEnd = opt_ctx }) catch unreachable;
+                    try stack.append(State { .BinaryOrExpressionBegin = opt_ctx });
+                    continue;
+                },
 
-                State.AsmOutputItems => |items| {
-                    const lbracket = self.getNextToken();
-                    if (lbracket.id != Token.Id.LBracket) {
-                        self.putBackToken(lbracket);
-                        continue;
-                    }
-
-                    stack.append(State { .AsmOutputItems = items }) catch unreachable;
-                    try stack.append(State { .IfToken = Token.Id.Comma });
-
-                    const symbolic_name = (try self.expectToken(&stack, Token.Id.Identifier)) ?? continue;
-                    _ = (try self.expectToken(&stack, Token.Id.RBracket)) ?? continue;
+                State.ComparisonExpressionEnd => |opt_ctx| {
+                    const lhs = opt_ctx.get() ?? continue;
 
-                    const constraint_token = self.getNextToken();
-                    const constraint = (try self.parseStringLiteral(arena, constraint_token)) ?? {
-                        try self.parseError(&stack, constraint_token, "expected string literal, found {}", @tagName(constraint_token.id));
+                    const token = self.getNextToken();
+                    if (tokenIdToComparison(token.id)) |comp_id| {
+                        const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
+                            ast.NodeInfixOp {
+                                .base = undefined,
+                                .lhs = lhs,
+                                .op_token = token,
+                                .op = comp_id,
+                                .rhs = undefined,
+                            }
+                        );
+                        stack.append(State { .ComparisonExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
+                        try stack.append(State { .BinaryOrExpressionBegin = OptionalCtx { .Required = &node.rhs } });
                         continue;
-                    };
+                    } else {
+                        self.putBackToken(token);
+                        continue;
+                    }
+                },
 
-                    _ = (try self.expectToken(&stack, Token.Id.LParen)) ?? continue;
-                    try stack.append(State { .ExpectToken = Token.Id.RParen });
+                State.BinaryOrExpressionBegin => |opt_ctx| {
+                    stack.append(State { .BinaryOrExpressionEnd = opt_ctx }) catch unreachable;
+                    try stack.append(State { .BinaryXorExpressionBegin = opt_ctx });
+                    continue;
+                },
 
-                    const node = try self.createNode(arena, ast.NodeAsmOutput,
-                        ast.NodeAsmOutput {
-                            .base = undefined,
-                            .symbolic_name = try self.createLiteral(arena, ast.NodeIdentifier, symbolic_name),
-                            .constraint = constraint,
-                            .kind = undefined,
-                        }
-                    );
-                    try items.append(node);
+                State.BinaryOrExpressionEnd => |opt_ctx| {
+                    const lhs = opt_ctx.get() ?? continue;
 
-                    const symbol_or_arrow = self.getNextToken();
-                    switch (symbol_or_arrow.id) {
-                        Token.Id.Identifier => {
-                            node.kind = ast.NodeAsmOutput.Kind { .Variable = try self.createLiteral(arena, ast.NodeIdentifier, symbol_or_arrow) };
-                        },
-                        Token.Id.Arrow => {
-                            node.kind = ast.NodeAsmOutput.Kind { .Return = undefined };
-                            try stack.append(State { .TypeExprBegin = DestPtr { .Field = &node.kind.Return } });
+                    const token = self.getNextToken();
+                    switch (token.id) {
+                        Token.Id.Pipe => {
+                            const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
+                                ast.NodeInfixOp {
+                                    .base = undefined,
+                                    .lhs = lhs,
+                                    .op_token = token,
+                                    .op = ast.NodeInfixOp.InfixOp.BitOr,
+                                    .rhs = undefined,
+                                }
+                            );
+                            stack.append(State { .BinaryOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
+                            try stack.append(State { .BinaryXorExpressionBegin = OptionalCtx { .Required = &node.rhs } });
+                            continue;
                         },
                         else => {
-                            try self.parseError(&stack, symbol_or_arrow, "expected '->' or {}, found {}",
-                                @tagName(Token.Id.Identifier),
-                                @tagName(symbol_or_arrow.id));
+                            self.putBackToken(token);
                             continue;
                         },
                     }
                 },
 
-                State.AsmInputItems => |items| {
-                    const lbracket = self.getNextToken();
-                    if (lbracket.id != Token.Id.LBracket) {
-                        self.putBackToken(lbracket);
-                        continue;
-                    }
-
-                    stack.append(State { .AsmInputItems = items }) catch unreachable;
-                    try stack.append(State { .IfToken = Token.Id.Comma });
-
-                    const symbolic_name = (try self.expectToken(&stack, Token.Id.Identifier)) ?? continue;
-                    _ = (try self.expectToken(&stack, Token.Id.RBracket)) ?? continue;
-
-                    const constraint_token = self.getNextToken();
-                    const constraint = (try self.parseStringLiteral(arena, constraint_token)) ?? {
-                        try self.parseError(&stack, constraint_token, "expected string literal, found {}", @tagName(constraint_token.id));
-                        continue;
-                    };
-
-                    _ = (try self.expectToken(&stack, Token.Id.LParen)) ?? continue;
-                    try stack.append(State { .ExpectToken = Token.Id.RParen });
-
-                    const node = try self.createNode(arena, ast.NodeAsmInput,
-                        ast.NodeAsmInput {
-                            .base = undefined,
-                            .symbolic_name = try self.createLiteral(arena, ast.NodeIdentifier, symbolic_name),
-                            .constraint = constraint,
-                            .expr = undefined,
-                        }
-                    );
-                    try items.append(node);
-                    try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
-                },
-
-                State.AsmClopperItems => |items| {
-                    const string_token = self.getNextToken();
-                    const string = (try self.parseStringLiteral(arena, string_token)) ?? {
-                        self.putBackToken(string_token);
-                        continue;
-                    };
-                    try items.append(string);
-
-                    stack.append(State { .AsmClopperItems = items }) catch unreachable;
-                    try stack.append(State { .IfToken = Token.Id.Comma });
+                State.BinaryXorExpressionBegin => |opt_ctx| {
+                    stack.append(State { .BinaryXorExpressionEnd = opt_ctx }) catch unreachable;
+                    try stack.append(State { .BinaryAndExpressionBegin = opt_ctx });
+                    continue;
                 },
 
-                State.ExprListItemOrEnd => |list_state| {
-                    var token = self.getNextToken();
+                State.BinaryXorExpressionEnd => |opt_ctx| {
+                    const lhs = opt_ctx.get() ?? continue;
 
-                    const IdTag = @TagType(Token.Id);
-                    if (IdTag(list_state.end) == token.id) {
-                        *list_state.ptr = token;
-                        continue;
+                    const token = self.getNextToken();
+                    switch (token.id) {
+                        Token.Id.Caret => {
+                            const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
+                                ast.NodeInfixOp {
+                                    .base = undefined,
+                                    .lhs = lhs,
+                                    .op_token = token,
+                                    .op = ast.NodeInfixOp.InfixOp.BitXor,
+                                    .rhs = undefined,
+                                }
+                            );
+                            stack.append(State { .BinaryXorExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
+                            try stack.append(State { .BinaryAndExpressionBegin = OptionalCtx { .Required = &node.rhs } });
+                            continue;
+                        },
+                        else => {
+                            self.putBackToken(token);
+                            continue;
+                        },
                     }
-
-                    self.putBackToken(token);
-                    stack.append(State { .ExprListCommaOrEnd = list_state }) catch unreachable;
-                    try stack.append(State { .Expression = DestPtr{ .Field = try list_state.list.addOne() } });
                 },
 
-                State.FieldInitListItemOrEnd => |list_state| {
-                    if (self.eatToken(Token.Id.RBrace)) |rbrace| {
-                        *list_state.ptr = rbrace;
-                        continue;
-                    }
-
-                    const node = try self.createNode(arena, ast.NodeFieldInitializer,
-                        ast.NodeFieldInitializer {
-                            .base = undefined,
-                            .period_token = undefined,
-                            .name_token = undefined,
-                            .expr = undefined,
-                        }
-                    );
-                    try list_state.list.append(node);
-
-                    stack.append(State { .FieldInitListCommaOrEnd = list_state }) catch unreachable;
-                    try stack.append(State { .Expression = DestPtr{.Field = &node.expr} });
-                    try stack.append(State { .ExpectToken = Token.Id.Equal });
-                    try stack.append(State {
-                        .ExpectTokenSave = ExpectTokenSave {
-                            .id = Token.Id.Identifier,
-                            .ptr = &node.name_token,
-                        }
-                    });
-                    try stack.append(State {
-                        .ExpectTokenSave = ExpectTokenSave {
-                            .id = Token.Id.Period,
-                            .ptr = &node.period_token,
-                        }
-                    });
+                State.BinaryAndExpressionBegin => |opt_ctx| {
+                    stack.append(State { .BinaryAndExpressionEnd = opt_ctx }) catch unreachable;
+                    try stack.append(State { .BitShiftExpressionBegin = opt_ctx });
+                    continue;
                 },
 
-                State.IdentifierListItemOrEnd => |list_state| {
-                    if (self.eatToken(Token.Id.RBrace)) |rbrace| {
-                        *list_state.ptr = rbrace;
-                        continue;
-                    }
-
-                    const node = try self.createLiteral(arena, ast.NodeIdentifier, Token(undefined));
-                    try list_state.list.append(node);
+                State.BinaryAndExpressionEnd => |opt_ctx| {
+                    const lhs = opt_ctx.get() ?? continue;
 
-                    stack.append(State { .IdentifierListCommaOrEnd = list_state }) catch unreachable;
-                    try stack.append(State {
-                        .ExpectTokenSave = ExpectTokenSave {
-                            .id = Token.Id.Identifier,
-                            .ptr = &node.token,
-                        }
-                    });
+                    const token = self.getNextToken();
+                    switch (token.id) {
+                        Token.Id.Ampersand => {
+                            const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
+                                ast.NodeInfixOp {
+                                    .base = undefined,
+                                    .lhs = lhs,
+                                    .op_token = token,
+                                    .op = ast.NodeInfixOp.InfixOp.BitAnd,
+                                    .rhs = undefined,
+                                }
+                            );
+                            stack.append(State { .BinaryAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
+                            try stack.append(State { .BitShiftExpressionBegin = OptionalCtx { .Required = &node.rhs } });
+                            continue;
+                        },
+                        else => {
+                            self.putBackToken(token);
+                            continue;
+                        },
+                    }
                 },
 
-                State.SwitchCaseOrEnd => |list_state| {
-                    if (self.eatToken(Token.Id.RBrace)) |rbrace| {
-                        *list_state.ptr = rbrace;
-                        continue;
-                    }
+                State.BitShiftExpressionBegin => |opt_ctx| {
+                    stack.append(State { .BitShiftExpressionEnd = opt_ctx }) catch unreachable;
+                    try stack.append(State { .AdditionExpressionBegin = opt_ctx });
+                    continue;
+                },
 
-                    const node = try self.createNode(arena, ast.NodeSwitchCase,
-                        ast.NodeSwitchCase {
-                            .base = undefined,
-                            .items = ArrayList(&ast.Node).init(arena),
-                            .payload = null,
-                            .expr = undefined,
-                        }
-                    );
-                    try list_state.list.append(node);
-                    stack.append(State { .SwitchCaseCommaOrEnd = list_state }) catch unreachable;
-                    try stack.append(State { .AssignmentExpressionBegin = DestPtr{ .Field = &node.expr  } });
-                    try stack.append(State { .PointerPayload = &node.payload });
+                State.BitShiftExpressionEnd => |opt_ctx| {
+                    const lhs = opt_ctx.get() ?? continue;
 
-                    const maybe_else = self.getNextToken();
-                    if (maybe_else.id == Token.Id.Keyword_else) {
-                        const else_node = try self.createAttachNode(arena, &node.items, ast.NodeSwitchElse,
-                            ast.NodeSwitchElse {
+                    const token = self.getNextToken();
+                    if (tokenIdToBitShift(token.id)) |bitshift_id| {
+                        const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
+                            ast.NodeInfixOp {
                                 .base = undefined,
-                            .token = maybe_else,
+                                .lhs = lhs,
+                                .op_token = token,
+                                .op = bitshift_id,
+                                .rhs = undefined,
                             }
                         );
-                        try stack.append(State { .ExpectToken = Token.Id.EqualAngleBracketRight });
+                        stack.append(State { .BitShiftExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
+                        try stack.append(State { .AdditionExpressionBegin = OptionalCtx { .Required = &node.rhs } });
                         continue;
                     } else {
-                        self.putBackToken(maybe_else);
-                        try stack.append(State { .SwitchCaseItem = &node.items });
+                        self.putBackToken(token);
                         continue;
                     }
                 },
 
-                State.SwitchCaseItem => |case_items| {
-                    stack.append(State { .SwitchCaseItemCommaOrEnd = case_items }) catch unreachable;
-                    try stack.append(State { .RangeExpressionBegin = DestPtr{ .Field = try case_items.addOne() } });
-                },
-
-                State.ExprListCommaOrEnd => |list_state| {
-                    try self.commaOrEnd(&stack, list_state.end, list_state.ptr, State { .ExprListItemOrEnd = list_state });
-                    continue;
-                },
-
-                State.FieldInitListCommaOrEnd => |list_state| {
-                    try self.commaOrEnd(&stack, Token.Id.RBrace, list_state.ptr, State { .FieldInitListItemOrEnd = list_state });
+                State.AdditionExpressionBegin => |opt_ctx| {
+                    stack.append(State { .AdditionExpressionEnd = opt_ctx }) catch unreachable;
+                    try stack.append(State { .MultiplyExpressionBegin = opt_ctx });
                     continue;
                 },
 
-                State.FieldListCommaOrEnd => |container_decl| {
-                    try self.commaOrEnd(&stack, Token.Id.RBrace, &container_decl.rbrace_token,
-                        State { .ContainerDecl = container_decl });
-                    continue;
-                },
+                State.AdditionExpressionEnd => |opt_ctx| {
+                    const lhs = opt_ctx.get() ?? continue;
 
-                State.IdentifierListCommaOrEnd => |list_state| {
-                    try self.commaOrEnd(&stack, Token.Id.RBrace, list_state.ptr, State { .IdentifierListItemOrEnd = list_state });
-                    continue;
+                    const token = self.getNextToken();
+                    if (tokenIdToAddition(token.id)) |add_id| {
+                        const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
+                            ast.NodeInfixOp {
+                                .base = undefined,
+                                .lhs = lhs,
+                                .op_token = token,
+                                .op = add_id,
+                                .rhs = undefined,
+                            }
+                        );
+                        stack.append(State { .AdditionExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
+                        try stack.append(State { .MultiplyExpressionBegin = OptionalCtx { .Required = &node.rhs } });
+                        continue;
+                    } else {
+                        self.putBackToken(token);
+                        continue;
+                    }
                 },
 
-                State.SwitchCaseCommaOrEnd => |list_state| {
-                    try self.commaOrEnd(&stack, Token.Id.RBrace, list_state.ptr, State { .SwitchCaseOrEnd = list_state });
+                State.MultiplyExpressionBegin => |opt_ctx| {
+                    stack.append(State { .MultiplyExpressionEnd = opt_ctx }) catch unreachable;
+                    try stack.append(State { .CurlySuffixExpressionBegin = opt_ctx });
                     continue;
                 },
 
-                State.SwitchCaseItemCommaOrEnd => |case_items| {
-                    try self.commaOrEnd(&stack, Token.Id.EqualAngleBracketRight, null, State { .SwitchCaseItem = case_items });
-                    continue;
-                },
+                State.MultiplyExpressionEnd => |opt_ctx| {
+                    const lhs = opt_ctx.get() ?? continue;
 
-                State.Else => |dest| {
-                    const else_token = self.getNextToken();
-                    if (else_token.id != Token.Id.Keyword_else) {
-                        self.putBackToken(else_token);
+                    const token = self.getNextToken();
+                    if (tokenIdToMultiply(token.id)) |mult_id| {
+                        const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
+                            ast.NodeInfixOp {
+                                .base = undefined,
+                                .lhs = lhs,
+                                .op_token = token,
+                                .op = mult_id,
+                                .rhs = undefined,
+                            }
+                        );
+                        stack.append(State { .MultiplyExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
+                        try stack.append(State { .CurlySuffixExpressionBegin = OptionalCtx { .Required = &node.rhs } });
+                        continue;
+                    } else {
+                        self.putBackToken(token);
                         continue;
                     }
+                },
 
-                    const node = try self.createNode(arena, ast.NodeElse,
-                        ast.NodeElse {
-                            .base = undefined,
-                            .else_token = else_token,
-                            .payload = null,
-                            .body = undefined,
-                        }
-                    );
-                    *dest = node;
-
-                    stack.append(State { .Expression = DestPtr { .Field = &node.body } }) catch unreachable;
-                    try stack.append(State { .Payload = &node.payload });
+                State.CurlySuffixExpressionBegin => |opt_ctx| {
+                    stack.append(State { .CurlySuffixExpressionEnd = opt_ctx }) catch unreachable;
+                    try stack.append(State { .IfToken = Token.Id.LBrace });
+                    try stack.append(State { .TypeExprBegin = opt_ctx });
+                    continue;
                 },
 
-                State.WhileContinueExpr => |dest| {
-                    const colon = self.getNextToken();
-                    if (colon.id != Token.Id.Colon) {
-                        self.putBackToken(colon);
+                State.CurlySuffixExpressionEnd => |opt_ctx| {
+                    const lhs = opt_ctx.get() ?? continue;
+
+                    if (self.isPeekToken(Token.Id.Period)) {
+                        const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeSuffixOp,
+                            ast.NodeSuffixOp {
+                                .base = undefined,
+                                .lhs = lhs,
+                                .op = ast.NodeSuffixOp.SuffixOp {
+                                    .StructInitializer = ArrayList(&ast.NodeFieldInitializer).init(arena),
+                                },
+                                .rtoken = undefined,
+                            }
+                        );
+                        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) {
+                                .list = &node.op.StructInitializer,
+                                .ptr = &node.rtoken,
+                            }
+                        });
+                        continue;
+                    } else {
+                        const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeSuffixOp,
+                            ast.NodeSuffixOp {
+                                .base = undefined,
+                                .lhs = lhs,
+                                .op = ast.NodeSuffixOp.SuffixOp {
+                                    .ArrayInitializer = ArrayList(&ast.Node).init(arena),
+                                },
+                                .rtoken = undefined,
+                            }
+                        );
+                        stack.append(State { .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
+                        try stack.append(State { .IfToken = Token.Id.LBrace });
+                        try stack.append(State {
+                            .ExprListItemOrEnd = ExprListCtx {
+                                .list = &node.op.ArrayInitializer,
+                                .end = Token.Id.RBrace,
+                                .ptr = &node.rtoken,
+                            }
+                        });
                         continue;
                     }
-
-                    _ = (try self.expectToken(&stack, Token.Id.LParen)) ?? continue;
-                    stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
-                    try stack.append(State { .AssignmentExpressionBegin = DestPtr { .NullableField = dest } });
                 },
 
-                State.SuspendBody => |suspend_node| {
-                    if (suspend_node.payload != null) {
-                        try stack.append(State { .AssignmentExpressionBegin = DestPtr { .NullableField = &suspend_node.body } });
-                    }
+                State.TypeExprBegin => |opt_ctx| {
+                    stack.append(State { .TypeExprEnd = opt_ctx }) catch unreachable;
+                    try stack.append(State { .PrefixOpExpression = opt_ctx });
                     continue;
                 },
 
-                State.AsyncEnd => |ctx| {
-                    const node = ctx.dest_ptr.get();
-
-                    switch (node.id) {
-                        ast.Node.Id.FnProto => {
-                            const fn_proto = @fieldParentPtr(ast.NodeFnProto, "base", node);
-                            fn_proto.async_attr = ctx.attribute;
-                        },
-                        ast.Node.Id.SuffixOp => {
-                            const suffix_op = @fieldParentPtr(ast.NodeSuffixOp, "base", node);
-                            if (suffix_op.op == ast.NodeSuffixOp.SuffixOp.Call) {
-                                suffix_op.op.Call.async_attr = ctx.attribute;
-                                continue;
-                            }
+                State.TypeExprEnd => |opt_ctx| {
+                    const lhs = opt_ctx.get() ?? continue;
 
-                            try self.parseError(&stack, node.firstToken(), "expected call or fn proto, found {}.",
-                                @tagName(suffix_op.op));
+                    const token = self.getNextToken();
+                    switch (token.id) {
+                        Token.Id.Bang => {
+                            const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
+                                ast.NodeInfixOp {
+                                    .base = undefined,
+                                    .lhs = lhs,
+                                    .op_token = token,
+                                    .op = ast.NodeInfixOp.InfixOp.ErrorUnion,
+                                    .rhs = undefined,
+                                }
+                            );
+                            stack.append(State { .TypeExprEnd = opt_ctx.toRequired() }) catch unreachable;
+                            try stack.append(State { .PrefixOpExpression = OptionalCtx { .Required = &node.rhs } });
                             continue;
                         },
                         else => {
-                            try self.parseError(&stack, node.firstToken(), "expected call or fn proto, found {}.",
-                                @tagName(node.id));
+                            self.putBackToken(token);
                             continue;
-                        }
-                    }
-                },
-
-                State.Payload => |dest| {
-                    const lpipe = self.getNextToken();
-                    if (lpipe.id != Token.Id.Pipe) {
-                        self.putBackToken(lpipe);
-                        continue;
+                        },
                     }
-
-                    const error_symbol = (try self.expectToken(&stack, Token.Id.Identifier)) ?? continue;
-                    const rpipe = (try self.expectToken(&stack, Token.Id.Pipe)) ?? continue;
-                    *dest = try self.createNode(arena, ast.NodePayload,
-                        ast.NodePayload {
-                            .base = undefined,
-                            .lpipe = lpipe,
-                            .error_symbol = try self.createLiteral(arena, ast.NodeIdentifier, error_symbol),
-                            .rpipe = rpipe
-                        }
-                    );
                 },
 
-                State.PointerPayload => |dest| {
-                    const lpipe = self.getNextToken();
-                    if (lpipe.id != Token.Id.Pipe) {
-                        self.putBackToken(lpipe);
-                        continue;
-                    }
+                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 {
+                                .base = undefined,
+                                .op_token = token,
+                                .op = prefix_id,
+                                .rhs = undefined,
+                            }
+                        );
 
-                    const is_ptr = blk: {
-                        const asterik = self.getNextToken();
-                        if (asterik.id == Token.Id.Asterisk) {
-                            break :blk true;
-                        } else {
-                            self.putBackToken(asterik);
-                            break :blk false;
+                        if (token.id == Token.Id.AsteriskAsterisk) {
+                            const child = try self.createNode(arena, ast.NodePrefixOp,
+                                ast.NodePrefixOp {
+                                    .base = undefined,
+                                    .op_token = token,
+                                    .op = prefix_id,
+                                    .rhs = undefined,
+                                }
+                            );
+                            node.rhs = &child.base;
+                            node = child;
                         }
-                    };
 
-                    const value_symbol = (try self.expectToken(&stack, Token.Id.Identifier)) ?? continue;
-                    const rpipe = (try self.expectToken(&stack, Token.Id.Pipe)) ?? continue;
-                    *dest = try self.createNode(arena, ast.NodePointerPayload,
-                        ast.NodePointerPayload {
-                            .base = undefined,
-                            .lpipe = lpipe,
-                            .is_ptr = is_ptr,
-                            .value_symbol = try self.createLiteral(arena, ast.NodeIdentifier, value_symbol),
-                            .rpipe = rpipe
+                        stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
+                        if (node.op == ast.NodePrefixOp.PrefixOp.AddrOf) {
+                            try stack.append(State { .AddrOfModifiers = &node.op.AddrOf });
                         }
-                    );
-                },
-
-                State.PointerIndexPayload => |dest| {
-                    const lpipe = self.getNextToken();
-                    if (lpipe.id != Token.Id.Pipe) {
-                        self.putBackToken(lpipe);
+                        continue;
+                    } else {
+                        self.putBackToken(token);
+                        stack.append(State { .SuffixOpExpressionBegin = opt_ctx }) catch unreachable;
                         continue;
                     }
+                },
 
-                    const is_ptr = blk: {
-                        const asterik = self.getNextToken();
-                        if (asterik.id == Token.Id.Asterisk) {
-                            break :blk true;
-                        } else {
-                            self.putBackToken(asterik);
-                            break :blk false;
-                        }
-                    };
-
-                    const value_symbol = (try self.expectToken(&stack, Token.Id.Identifier)) ?? continue;
-                    const index_symbol = blk: {
-                        const comma = self.getNextToken();
-                        if (comma.id != Token.Id.Comma) {
-                            self.putBackToken(comma);
-                            break :blk null;
+                State.SuffixOpExpressionBegin => |opt_ctx| {
+                    const token = self.getNextToken();
+                    switch (token.id) {
+                        Token.Id.Keyword_async => {
+                            const async_node = try self.createNode(arena, ast.NodeAsyncAttribute,
+                                ast.NodeAsyncAttribute {
+                                    .base = undefined,
+                                    .async_token = token,
+                                    .allocator_type = null,
+                                    .rangle_bracket = null,
+                                }
+                            );
+                            stack.append(State {
+                                .AsyncEnd = AsyncEndCtx {
+                                    .ctx = opt_ctx,
+                                    .attribute = async_node,
+                                }
+                            }) catch unreachable;
+                            try stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() });
+                            try stack.append(State { .PrimaryExpression = opt_ctx.toRequired() });
+                            try stack.append(State { .AsyncAllocator = async_node });
+                            continue;
+                        },
+                        else => {
+                            self.putBackToken(token);
+                            stack.append(State { .SuffixOpExpressionEnd = opt_ctx }) catch unreachable;
+                            try stack.append(State { .PrimaryExpression = opt_ctx });
+                            continue;
                         }
+                    }
+                },
 
-                        const symbol = (try self.expectToken(&stack, Token.Id.Identifier)) ?? continue;
-                        break :blk try self.createLiteral(arena, ast.NodeIdentifier, symbol);
-                    };
+                State.SuffixOpExpressionEnd => |opt_ctx| {
+                    const lhs = opt_ctx.get() ?? continue;
 
-                    const rpipe = (try self.expectToken(&stack, Token.Id.Pipe)) ?? continue;
-                    *dest = try self.createNode(arena, ast.NodePointerIndexPayload,
-                        ast.NodePointerIndexPayload {
-                            .base = undefined,
-                            .lpipe = lpipe,
-                            .is_ptr = is_ptr,
-                            .value_symbol = try self.createLiteral(arena, ast.NodeIdentifier, value_symbol),
-                            .index_symbol = index_symbol,
-                            .rpipe = rpipe
-                        }
-                    );
+                    const token = self.getNextToken();
+                    switch (token.id) {
+                        Token.Id.LParen => {
+                            const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeSuffixOp,
+                                ast.NodeSuffixOp {
+                                    .base = undefined,
+                                    .lhs = lhs,
+                                    .op = ast.NodeSuffixOp.SuffixOp {
+                                        .Call = ast.NodeSuffixOp.CallInfo {
+                                            .params = ArrayList(&ast.Node).init(arena),
+                                            .async_attr = null,
+                                        }
+                                    },
+                                    .rtoken = undefined,
+                                }
+                            );
+                            stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
+                            try stack.append(State {
+                                .ExprListItemOrEnd = ExprListCtx {
+                                    .list = &node.op.Call.params,
+                                    .end = Token.Id.RParen,
+                                    .ptr = &node.rtoken,
+                                }
+                            });
+                            continue;
+                        },
+                        Token.Id.LBracket => {
+                            const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeSuffixOp,
+                                ast.NodeSuffixOp {
+                                    .base = undefined,
+                                    .lhs = lhs,
+                                    .op = ast.NodeSuffixOp.SuffixOp {
+                                        .ArrayAccess = undefined,
+                                    },
+                                    .rtoken = undefined
+                                }
+                            );
+                            stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
+                            try stack.append(State { .SliceOrArrayAccess = node });
+                            try stack.append(State { .Expression = OptionalCtx { .Required = &node.op.ArrayAccess }});
+                            continue;
+                        },
+                        Token.Id.Period => {
+                            const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
+                                ast.NodeInfixOp {
+                                    .base = undefined,
+                                    .lhs = lhs,
+                                    .op_token = token,
+                                    .op = ast.NodeInfixOp.InfixOp.Period,
+                                    .rhs = undefined,
+                                }
+                            );
+                            stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
+                            try stack.append(State { .Identifier = OptionalCtx { .Required = &node.rhs } });
+                            continue;
+                        },
+                        else => {
+                            self.putBackToken(token);
+                            continue;
+                        },
+                    }
                 },
 
-                State.AddrOfModifiers => |addr_of_info| {
-                    var token = self.getNextToken();
+                State.PrimaryExpression => |opt_ctx| {
+                    const token = self.getNextToken();
                     switch (token.id) {
-                        Token.Id.Keyword_align => {
-                            stack.append(state) catch unreachable;
-                            if (addr_of_info.align_expr != null) {
-                                try self.parseError(&stack, token, "multiple align qualifiers");
-                                continue;
-                            }
-                            try stack.append(State { .ExpectToken = Token.Id.RParen });
-                            try stack.append(State { .Expression = DestPtr{.NullableField = &addr_of_info.align_expr} });
-                            try stack.append(State { .ExpectToken = Token.Id.LParen });
+                        Token.Id.IntegerLiteral => {
+                            opt_ctx.store(&(try self.createLiteral(arena, ast.NodeStringLiteral, token)).base);
+                            continue;
+                        },
+                        Token.Id.FloatLiteral => {
+                            opt_ctx.store(&(try self.createLiteral(arena, ast.NodeFloatLiteral, token)).base);
+                            continue;
+                        },
+                        Token.Id.CharLiteral => {
+                            opt_ctx.store(&(try self.createLiteral(arena, ast.NodeCharLiteral, token)).base);
+                            continue;
+                        },
+                        Token.Id.Keyword_undefined => {
+                            opt_ctx.store(&(try self.createLiteral(arena, ast.NodeUndefinedLiteral, token)).base);
+                            continue;
+                        },
+                        Token.Id.Keyword_true, Token.Id.Keyword_false => {
+                            opt_ctx.store(&(try self.createLiteral(arena, ast.NodeBoolLiteral, token)).base);
                             continue;
                         },
-                        Token.Id.Keyword_const => {
-                            stack.append(state) catch unreachable;
-                            if (addr_of_info.const_token != null) {
-                                try self.parseError(&stack, token, "duplicate qualifier: const");
-                                continue;
-                            }
-                            addr_of_info.const_token = token;
+                        Token.Id.Keyword_null => {
+                            opt_ctx.store(&(try self.createLiteral(arena, ast.NodeNullLiteral, token)).base);
                             continue;
                         },
-                        Token.Id.Keyword_volatile => {
-                            stack.append(state) catch unreachable;
-                            if (addr_of_info.volatile_token != null) {
-                                try self.parseError(&stack, token, "duplicate qualifier: volatile");
-                                continue;
-                            }
-                            addr_of_info.volatile_token = token;
+                        Token.Id.Keyword_this => {
+                            opt_ctx.store(&(try self.createLiteral(arena, ast.NodeThisLiteral, token)).base);
                             continue;
                         },
-                        else => {
-                            self.putBackToken(token);
+                        Token.Id.Keyword_var => {
+                            opt_ctx.store(&(try self.createLiteral(arena, ast.NodeVarType, token)).base);
                             continue;
                         },
-                    }
-                },
-
-                State.FnProto => |fn_proto| {
-                    stack.append(State { .FnProtoAlign = fn_proto }) catch unreachable;
-                    try stack.append(State { .ParamDecl = fn_proto });
-                    try stack.append(State { .ExpectToken = Token.Id.LParen });
-
-                    const next_token = self.getNextToken();
-                    if (next_token.id == Token.Id.Identifier) {
-                        fn_proto.name_token = next_token;
-                        continue;
-                    }
-                    self.putBackToken(next_token);
-                    continue;
-                },
-
-                State.FnProtoAlign => |fn_proto| {
-                    stack.append(State { .FnProtoReturnType = fn_proto }) catch unreachable;
-
-                    if (self.eatToken(Token.Id.Keyword_align)) |align_token| {
-                        try stack.append(State { .ExpectToken = Token.Id.RParen });
-                        try stack.append(State { .Expression = DestPtr { .NullableField = &fn_proto.align_expr } });
-                        try stack.append(State { .ExpectToken = Token.Id.LParen });
-                    }
-
-                    continue;
-                },
-
-                State.FnProtoReturnType => |fn_proto| {
-                    const token = self.getNextToken();
-                    switch (token.id) {
-                        Token.Id.Bang => {
-                            fn_proto.return_type = ast.NodeFnProto.ReturnType { .InferErrorSet = undefined };
+                        Token.Id.Keyword_unreachable => {
+                            opt_ctx.store(&(try self.createLiteral(arena, ast.NodeUnreachable, token)).base);
+                            continue;
+                        },
+                        Token.Id.StringLiteral, Token.Id.MultilineStringLiteralLine => {
+                            opt_ctx.store((try self.parseStringLiteral(arena, token)) ?? unreachable);
+                        },
+                        Token.Id.LParen => {
+                            const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeGroupedExpression,
+                                ast.NodeGroupedExpression {
+                                    .base = undefined,
+                                    .lparen = token,
+                                    .expr = undefined,
+                                    .rparen = undefined,
+                                }
+                            );
                             stack.append(State {
-                                .TypeExprBegin = DestPtr {.Field = &fn_proto.return_type.InferErrorSet},
+                                .ExpectTokenSave = ExpectTokenSave {
+                                    .id = Token.Id.RParen,
+                                    .ptr = &node.rparen,
+                                }
                             }) catch unreachable;
+                            try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
                             continue;
                         },
-                        else => {
-                            // 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
-                                    };
-                                    continue;
+                        Token.Id.Builtin => {
+                            const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeBuiltinCall,
+                                ast.NodeBuiltinCall {
+                                    .base = undefined,
+                                    .builtin_token = token,
+                                    .params = ArrayList(&ast.Node).init(arena),
+                                    .rparen_token = undefined,
                                 }
-                            }
-
-                            self.putBackToken(token);
-                            fn_proto.return_type = ast.NodeFnProto.ReturnType { .Explicit = undefined };
+                            );
                             stack.append(State {
-                                .TypeExprBegin = DestPtr {.Field = &fn_proto.return_type.Explicit},
+                                .ExprListItemOrEnd = ExprListCtx {
+                                    .list = &node.params,
+                                    .end = Token.Id.RParen,
+                                    .ptr = &node.rparen_token,
+                                }
                             }) catch unreachable;
+                            try stack.append(State { .ExpectToken = Token.Id.LParen, });
                             continue;
                         },
-                    }
-                },
-
-                State.ParamDecl => |fn_proto| {
-                    if (self.eatToken(Token.Id.RParen)) |_| {
-                        continue;
-                    }
-                    const param_decl = try self.createAttachNode(arena, &fn_proto.params, ast.NodeParamDecl,
-                        ast.NodeParamDecl {
-                            .base = undefined,
-                            .comptime_token = null,
-                            .noalias_token = null,
-                            .name_token = null,
-                            .type_node = undefined,
-                            .var_args_token = null,
+                        Token.Id.LBracket => {
+                            const node = try self.createToCtxNode(arena, opt_ctx, ast.NodePrefixOp,
+                                ast.NodePrefixOp {
+                                    .base = undefined,
+                                    .op_token = token,
+                                    .op = undefined,
+                                    .rhs = undefined,
+                                }
+                            );
+                            stack.append(State { .SliceOrArrayType = node }) catch unreachable;
                         },
-                    );
-                    if (self.eatToken(Token.Id.Keyword_comptime)) |comptime_token| {
-                        param_decl.comptime_token = comptime_token;
-                    } else if (self.eatToken(Token.Id.Keyword_noalias)) |noalias_token| {
-                        param_decl.noalias_token = noalias_token;
-                    }
-                    if (self.eatToken(Token.Id.Identifier)) |identifier| {
-                        if (self.eatToken(Token.Id.Colon)) |_| {
-                            param_decl.name_token = identifier;
-                        } else {
-                            self.putBackToken(identifier);
-                        }
-                    }
-                    if (self.eatToken(Token.Id.Ellipsis3)) |ellipsis3| {
-                        param_decl.var_args_token = ellipsis3;
-                        stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
-                        continue;
-                    }
-
-                    stack.append(State { .ParamDecl = fn_proto }) catch unreachable;
-                    try stack.append(State.ParamDeclComma);
-                    try stack.append(State {
-                        .TypeExprBegin = DestPtr {.Field = &param_decl.type_node}
-                    });
-                    continue;
-                },
+                        Token.Id.Keyword_error => {
+                            stack.append(State {
+                                .ErrorTypeOrSetDecl = ErrorTypeOrSetDeclCtx {
+                                    .error_token = token,
+                                    .opt_ctx = opt_ctx
+                                }
+                            }) catch unreachable;
+                        },
+                        Token.Id.Keyword_packed => {
+                            stack.append(State {
+                                .ContainerExtern = ContainerExternCtx {
+                                    .opt_ctx = opt_ctx,
+                                    .ltoken = token,
+                                    .layout = ast.NodeContainerDecl.Layout.Packed,
+                                },
+                            }) catch unreachable;
+                        },
+                        Token.Id.Keyword_extern => {
+                            // TODO: Here, we eat two tokens in the same state. This prevents comments
+                            //       from being between these two tokens.
+                            const next = self.getNextToken();
+                            if (next.id == Token.Id.Keyword_fn) {
+                                const fn_proto = try self.createToCtxNode(arena, opt_ctx, ast.NodeFnProto,
+                                    ast.NodeFnProto {
+                                        .base = undefined,
+                                        .visib_token = null,
+                                        .name_token = null,
+                                        .fn_token = next,
+                                        .params = ArrayList(&ast.Node).init(arena),
+                                        .return_type = undefined,
+                                        .var_args_token = null,
+                                        .extern_export_inline_token = token,
+                                        .cc_token = null,
+                                        .async_attr = null,
+                                        .body_node = null,
+                                        .lib_name = null,
+                                        .align_expr = null,
+                                    }
+                                );
+                                stack.append(State { .FnProto = fn_proto }) catch unreachable;
+                                continue;
+                            }
 
-                State.ParamDeclComma => {
-                    const token = self.getNextToken();
-                    switch (token.id) {
-                        Token.Id.RParen => {
-                            _ = stack.pop(); // pop off the ParamDecl
-                            continue;
+                            self.putBackToken(next);
+                            stack.append(State {
+                                .ContainerExtern = ContainerExternCtx {
+                                    .opt_ctx = opt_ctx,
+                                    .ltoken = token,
+                                    .layout = ast.NodeContainerDecl.Layout.Extern,
+                                },
+                            }) catch unreachable;
                         },
-                        Token.Id.Comma => continue,
-                        else => {
-                            try self.parseError(&stack, token, "expected ',' or ')', found {}", @tagName(token.id));
-                            continue;
+                        Token.Id.Keyword_struct, Token.Id.Keyword_union, Token.Id.Keyword_enum => {
+                            self.putBackToken(token);
+                            stack.append(State {
+                                .ContainerExtern = ContainerExternCtx {
+                                    .opt_ctx = opt_ctx,
+                                    .ltoken = token,
+                                    .layout = ast.NodeContainerDecl.Layout.Auto,
+                                },
+                            }) catch unreachable;
                         },
-                    }
-                },
+                        Token.Id.Identifier => {
+                            // TODO: Here, we eat two tokens in the same state. This prevents comments
+                            //       from being between these two tokens.
+                            const next = self.getNextToken();
+                            if (next.id != Token.Id.Colon) {
+                                self.putBackToken(next);
+                                opt_ctx.store(&(try self.createLiteral(arena, ast.NodeIdentifier, token)).base);
+                                continue;
+                            }
 
-                State.FnDef => |fn_proto| {
-                    const token = self.getNextToken();
-                    switch(token.id) {
-                        Token.Id.LBrace => {
-                            const block = try self.createNode(arena, ast.NodeBlock,
-                                ast.NodeBlock {
+                            stack.append(State {
+                                .LabeledExpression = LabelCtx {
+                                    .label = token,
+                                    .opt_ctx = opt_ctx
+                                }
+                            }) catch unreachable;
+                            continue;
+                        },
+                        Token.Id.Keyword_fn => {
+                            const fn_proto = try self.createToCtxNode(arena, opt_ctx, ast.NodeFnProto,
+                                ast.NodeFnProto {
                                     .base = undefined,
-                                    .label = null,
-                                    .lbrace = token,
-                                    .statements = ArrayList(&ast.Node).init(arena),
-                                    .rbrace = undefined,
+                                    .visib_token = null,
+                                    .name_token = null,
+                                    .fn_token = token,
+                                    .params = ArrayList(&ast.Node).init(arena),
+                                    .return_type = undefined,
+                                    .var_args_token = null,
+                                    .extern_export_inline_token = null,
+                                    .cc_token = null,
+                                    .async_attr = null,
+                                    .body_node = null,
+                                    .lib_name = null,
+                                    .align_expr = null,
                                 }
                             );
-                            fn_proto.body_node = &block.base;
-                            stack.append(State { .Block = block }) catch unreachable;
+                            stack.append(State { .FnProto = fn_proto }) catch unreachable;
                             continue;
                         },
-                        Token.Id.Semicolon => continue,
-                        else => {
-                            try self.parseError(&stack, token, "expected ';' or '{{', found {}", @tagName(token.id));
+                        Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
+                            const fn_proto = try self.createToCtxNode(arena, opt_ctx, ast.NodeFnProto,
+                                ast.NodeFnProto {
+                                    .base = undefined,
+                                    .visib_token = null,
+                                    .name_token = null,
+                                    .fn_token = undefined,
+                                    .params = ArrayList(&ast.Node).init(arena),
+                                    .return_type = undefined,
+                                    .var_args_token = null,
+                                    .extern_export_inline_token = null,
+                                    .cc_token = token,
+                                    .async_attr = null,
+                                    .body_node = null,
+                                    .lib_name = null,
+                                    .align_expr = null,
+                                }
+                            );
+                            stack.append(State { .FnProto = fn_proto }) catch unreachable;
+                            try stack.append(State {
+                                .ExpectTokenSave = ExpectTokenSave {
+                                    .id = Token.Id.Keyword_fn,
+                                    .ptr = &fn_proto.fn_token
+                                }
+                            });
                             continue;
                         },
-                    }
-                },
-
-                State.LabeledExpression => |ctx| {
-                    const token = self.getNextToken();
-                    switch (token.id) {
-                        Token.Id.LBrace => {
-                            const block = try self.createToDestNode(arena, ctx.dest_ptr, ast.NodeBlock,
-                                ast.NodeBlock {
+                        Token.Id.Keyword_asm => {
+                            const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeAsm,
+                                ast.NodeAsm {
                                     .base = undefined,
-                                    .label = ctx.label,
-                                    .lbrace = token,
-                                    .statements = ArrayList(&ast.Node).init(arena),
-                                    .rbrace = 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),
+                                    .cloppers = ArrayList(&ast.Node).init(arena),
+                                    .rparen = undefined,
                                 }
                             );
-                            stack.append(State { .Block = block }) catch unreachable;
-                            continue;
-                        },
-                        Token.Id.Keyword_while => {
                             stack.append(State {
-                                .While = LoopCtx {
-                                    .label = ctx.label,
-                                    .inline_token = null,
-                                    .loop_token = token,
-                                    .dest_ptr = ctx.dest_ptr,
+                                .ExpectTokenSave = ExpectTokenSave {
+                                    .id = Token.Id.RParen,
+                                    .ptr = &node.rparen,
                                 }
                             }) catch unreachable;
-                            continue;
-                        },
-                        Token.Id.Keyword_for => {
-                            stack.append(State {
-                                .For = LoopCtx {
-                                    .label = ctx.label,
-                                    .inline_token = null,
-                                    .loop_token = token,
-                                    .dest_ptr = ctx.dest_ptr,
+                            try stack.append(State { .AsmClopperItems = &node.cloppers });
+                            try stack.append(State { .IfToken = Token.Id.Colon });
+                            try stack.append(State { .AsmInputItems = &node.inputs });
+                            try stack.append(State { .IfToken = Token.Id.Colon });
+                            try stack.append(State { .AsmOutputItems = &node.outputs });
+                            try stack.append(State { .IfToken = Token.Id.Colon });
+                            try stack.append(State { .StringLiteral = OptionalCtx { .Required = &node.template } });
+                            try stack.append(State { .ExpectToken = Token.Id.LParen });
+                            try stack.append(State {
+                                .OptionalTokenSave = OptionalTokenSave {
+                                    .id = Token.Id.Keyword_volatile,
+                                    .ptr = &node.volatile_token,
                                 }
-                            }) catch unreachable;
-                            continue;
+                            });
                         },
                         Token.Id.Keyword_inline => {
                             stack.append(State {
                                 .Inline = InlineCtx {
-                                    .label = ctx.label,
+                                    .label = null,
                                     .inline_token = token,
-                                    .dest_ptr = ctx.dest_ptr,
+                                    .opt_ctx = opt_ctx,
                                 }
                             }) catch unreachable;
                             continue;
                         },
                         else => {
-                            try self.parseError(&stack, token, "expected 'while', 'for', 'inline' or '{{', found {}", @tagName(token.id));
+                            if (!try self.parseBlockExpr(&stack, arena, opt_ctx, token)) {
+                                self.putBackToken(token);
+                                if (opt_ctx != OptionalCtx.Optional) {
+                                    return self.parseError(token, "expected primary expression, found {}", @tagName(token.id));
+                                }
+                            }
                             continue;
-                        },
+                        }
                     }
                 },
 
-                State.Inline => |ctx| {
-                    const token = self.getNextToken();
-                    switch (token.id) {
-                        Token.Id.Keyword_while => {
-                            stack.append(State {
-                                .While = LoopCtx {
-                                    .inline_token = ctx.inline_token,
-                                    .label = ctx.label,
-                                    .loop_token = token,
-                                    .dest_ptr = ctx.dest_ptr,
-                                }
-                            }) catch unreachable;
-                            continue;
-                        },
-                        Token.Id.Keyword_for => {
-                            stack.append(State {
-                                .For = LoopCtx {
-                                    .inline_token = ctx.inline_token,
-                                    .label = ctx.label,
-                                    .loop_token = token,
-                                    .dest_ptr = ctx.dest_ptr,
-                                }
-                            }) catch unreachable;
-                            continue;
-                        },
-                        else => {
-                            try self.parseError(&stack, token, "expected 'while' or 'for', found {}", @tagName(token.id));
-                            continue;
-                        },
+
+                State.ErrorTypeOrSetDecl => |ctx| {
+                    if (self.eatToken(Token.Id.LBrace) == null) {
+                        ctx.opt_ctx.store(&(try self.createLiteral(arena, ast.NodeErrorType, ctx.error_token)).base);
+                        continue;
                     }
-                },
 
-                State.While => |ctx| {
-                    const node = try self.createToDestNode(arena, ctx.dest_ptr, ast.NodeWhile,
-                        ast.NodeWhile {
+                    const node = try self.createToCtxNode(arena, ctx.opt_ctx, ast.NodeErrorSetDecl,
+                        ast.NodeErrorSetDecl {
                             .base = undefined,
-                            .label = ctx.label,
-                            .inline_token = ctx.inline_token,
-                            .while_token = ctx.loop_token,
-                            .condition = undefined,
-                            .payload = null,
-                            .continue_expr = null,
-                            .body = undefined,
-                            .@"else" = null,
+                            .error_token = ctx.error_token,
+                            .decls = ArrayList(&ast.Node).init(arena),
+                            .rbrace_token = undefined,
                         }
                     );
-                    stack.append(State { .Else = &node.@"else" }) catch unreachable;
-                    try stack.append(State { .Expression = DestPtr { .Field = &node.body } });
-                    try stack.append(State { .WhileContinueExpr = &node.continue_expr });
-                    try stack.append(State { .PointerPayload = &node.payload });
-                    try stack.append(State { .ExpectToken = Token.Id.RParen });
-                    try stack.append(State { .Expression = DestPtr { .Field = &node.condition } });
-                    try stack.append(State { .ExpectToken = Token.Id.LParen });
-                },
 
-                State.For => |ctx| {
-                    const node = try self.createToDestNode(arena, ctx.dest_ptr, ast.NodeFor,
-                        ast.NodeFor {
-                            .base = undefined,
-                            .label = ctx.label,
-                            .inline_token = ctx.inline_token,
-                            .for_token = ctx.loop_token,
-                            .array_expr = undefined,
-                            .payload = null,
-                            .body = undefined,
-                            .@"else" = null,
+                    stack.append(State {
+                        .IdentifierListItemOrEnd = ListSave(&ast.Node) {
+                            .list = &node.decls,
+                            .ptr = &node.rbrace_token,
                         }
-                    );
-                    stack.append(State { .Else = &node.@"else" }) catch unreachable;
-                    try stack.append(State { .Expression = DestPtr { .Field = &node.body } });
-                    try stack.append(State { .PointerIndexPayload = &node.payload });
-                    try stack.append(State { .ExpectToken = Token.Id.RParen });
-                    try stack.append(State { .Expression = DestPtr { .Field = &node.array_expr } });
-                    try stack.append(State { .ExpectToken = Token.Id.LParen });
+                    }) catch unreachable;
+                    continue;
                 },
-
-                State.Block => |block| {
+                State.StringLiteral => |opt_ctx| {
                     const token = self.getNextToken();
-                    switch (token.id) {
-                        Token.Id.RBrace => {
-                            block.rbrace = token;
-                            continue;
-                        },
-                        else => {
+                    opt_ctx.store(
+                        (try self.parseStringLiteral(arena, token)) ?? {
                             self.putBackToken(token);
-                            stack.append(State { .Block = block }) catch unreachable;
-                            try stack.append(State { .Statement = block });
+                            if (opt_ctx != OptionalCtx.Optional) {
+                                return self.parseError(token, "expected primary expression, found {}", @tagName(token.id));
+                            }
+
                             continue;
-                        },
+                        }
+                    );
+                },
+                State.Identifier => |opt_ctx| {
+                    if (self.eatToken(Token.Id.Identifier)) |ident_token| {
+                        opt_ctx.store(&(try self.createLiteral(arena, ast.NodeIdentifier, ident_token)).base);
+                        continue;
+                    }
+
+                    if (opt_ctx != OptionalCtx.Optional) {
+                        const token = self.getNextToken();
+                        return self.parseError(token, "expected identifier, found {}", @tagName(token.id));
                     }
                 },
 
-                State.Statement => |block| {
-                    const next = self.getNextToken();
-                    switch (next.id) {
-                        Token.Id.Keyword_comptime => {
-                            const mut_token = self.getNextToken();
-                            if (mut_token.id == Token.Id.Keyword_var or mut_token.id == Token.Id.Keyword_const) {
-                                const var_decl = try self.createAttachNode(arena, &block.statements, ast.NodeVarDecl,
-                                    ast.NodeVarDecl {
-                                        .base = undefined,
-                                        .visib_token = null,
-                                        .mut_token = mut_token,
-                                        .comptime_token = next,
-                                        .extern_export_token = null,
-                                        .type_node = null,
-                                        .align_node = null,
-                                        .init_node = null,
-                                        .lib_name = null,
-                                        // initialized later
-                                        .name_token = undefined,
-                                        .eq_token = undefined,
-                                        .semicolon_token = undefined,
-                                    }
-                                );
-                                stack.append(State { .VarDecl = var_decl }) catch unreachable;
-                                continue;
-                            } else {
-                                self.putBackToken(mut_token);
-                                self.putBackToken(next);
-                                const statememt = try block.statements.addOne();
-                                stack.append(State { .Semicolon = statememt }) catch unreachable;
-                                try stack.append(State { .Expression = DestPtr{.Field = statememt } });
-                            }
-                        },
-                        Token.Id.Keyword_var, Token.Id.Keyword_const => {
-                            const var_decl = try self.createAttachNode(arena, &block.statements, ast.NodeVarDecl,
-                                ast.NodeVarDecl {
-                                    .base = undefined,
-                                    .visib_token = null,
-                                    .mut_token = next,
-                                    .comptime_token = null,
-                                    .extern_export_token = null,
-                                    .type_node = null,
-                                    .align_node = null,
-                                    .init_node = null,
-                                    .lib_name = null,
-                                    // initialized later
-                                    .name_token = undefined,
-                                    .eq_token = undefined,
-                                    .semicolon_token = undefined,
-                                }
-                            );
-                            stack.append(State { .VarDecl = var_decl }) catch unreachable;
-                            continue;
-                        },
-                        Token.Id.Keyword_defer, Token.Id.Keyword_errdefer => {
-                            const node = try self.createAttachNode(arena, &block.statements, ast.NodeDefer,
-                                ast.NodeDefer {
-                                    .base = undefined,
-                                    .defer_token = next,
-                                    .kind = switch (next.id) {
-                                        Token.Id.Keyword_defer => ast.NodeDefer.Kind.Unconditional,
-                                        Token.Id.Keyword_errdefer => ast.NodeDefer.Kind.Error,
-                                        else => unreachable,
-                                    },
-                                    .expr = undefined,
-                                }
-                            );
-                            stack.append(State { .Semicolon = &node.base }) catch unreachable;
-                            try stack.append(State { .AssignmentExpressionBegin = DestPtr{.Field = &node.expr } });
-                            continue;
-                        },
-                        Token.Id.LBrace => {
-                            const inner_block = try self.createAttachNode(arena, &block.statements, ast.NodeBlock,
-                                ast.NodeBlock {
-                                    .base = undefined,
-                                    .label = null,
-                                    .lbrace = next,
-                                    .statements = ArrayList(&ast.Node).init(arena),
-                                    .rbrace = undefined,
-                                }
-                            );
-                            stack.append(State { .Block = inner_block }) catch unreachable;
-                            continue;
-                        },
-                        else => {
-                            self.putBackToken(next);
-                            const statememt = try block.statements.addOne();
-                            stack.append(State { .Semicolon = statememt }) catch unreachable;
-                            try stack.append(State { .AssignmentExpressionBegin = DestPtr{.Field = statememt } });
-                            continue;
-                        }
+
+                State.ExpectToken => |token_id| {
+                    _ = try self.expectToken(token_id);
+                    continue;
+                },
+                State.ExpectTokenSave => |expect_token_save| {
+                    *expect_token_save.ptr = try self.expectToken(expect_token_save.id);
+                    continue;
+                },
+                State.IfToken => |token_id| {
+                    if (self.eatToken(token_id)) |_| {
+                        continue;
                     }
 
+                    _ = stack.pop();
+                    continue;
                 },
+                State.IfTokenSave => |if_token_save| {
+                    if (self.eatToken(if_token_save.id)) |token| {
+                        *if_token_save.ptr = token;
+                        continue;
+                    }
 
-                State.Semicolon => |node_ptr| {
-                    const node = *node_ptr;
-                    if (requireSemiColon(node)) {
-                        _ = (try self.expectToken(&stack, Token.Id.Semicolon)) ?? continue;
+                    _ = stack.pop();
+                    continue;
+                },
+                State.OptionalTokenSave => |optional_token_save| {
+                    if (self.eatToken(optional_token_save.id)) |token| {
+                        *optional_token_save.ptr = token;
+                        continue;
                     }
-                }
+
+                    continue;
+                },
             }
         }
     }
@@ -2807,10 +2875,10 @@ pub const Parser = struct {
         }
     }
 
-    fn parseBlockExpr(self: &Parser, stack: &ArrayList(State), arena: &mem.Allocator, dest_ptr: &const DestPtr, token: &const Token) !bool {
+    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.createToDestNode(arena, dest_ptr, ast.NodeSuspend,
+                const node = try self.createToCtxNode(arena, ctx, ast.NodeSuspend,
                     ast.NodeSuspend {
                         .base = undefined,
                         .suspend_token = *token,
@@ -2820,11 +2888,11 @@ pub const Parser = struct {
                 );
 
                 stack.append(State { .SuspendBody = node }) catch unreachable;
-                try stack.append(State { .Payload = &node.payload });
+                try stack.append(State { .Payload = OptionalCtx { .Optional = &node.payload } });
                 return true;
             },
             Token.Id.Keyword_if => {
-                const node = try self.createToDestNode(arena, dest_ptr, ast.NodeIf,
+                const node = try self.createToCtxNode(arena, ctx, ast.NodeIf,
                     ast.NodeIf {
                         .base = undefined,
                         .if_token = *token,
@@ -2836,10 +2904,10 @@ pub const Parser = struct {
                 );
 
                 stack.append(State { .Else = &node.@"else" }) catch unreachable;
-                try stack.append(State { .Expression = DestPtr { .Field = &node.body } });
-                try stack.append(State { .PointerPayload = &node.payload });
+                try stack.append(State { .Expression = OptionalCtx { .Required = &node.body } });
+                try stack.append(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });
                 try stack.append(State { .ExpectToken = Token.Id.RParen });
-                try stack.append(State { .Expression = DestPtr { .Field = &node.condition } });
+                try stack.append(State { .Expression = OptionalCtx { .Required = &node.condition } });
                 try stack.append(State { .ExpectToken = Token.Id.LParen });
                 return true;
             },
@@ -2849,7 +2917,7 @@ pub const Parser = struct {
                         .label = null,
                         .inline_token = null,
                         .loop_token = *token,
-                        .dest_ptr = *dest_ptr,
+                        .opt_ctx = *ctx,
                     }
                 }) catch unreachable;
                 return true;
@@ -2860,13 +2928,13 @@ pub const Parser = struct {
                         .label = null,
                         .inline_token = null,
                         .loop_token = *token,
-                        .dest_ptr = *dest_ptr,
+                        .opt_ctx = *ctx,
                     }
                 }) catch unreachable;
                 return true;
             },
             Token.Id.Keyword_switch => {
-                const node = try self.createToDestNode(arena, dest_ptr, ast.NodeSwitch,
+                const node = try self.createToCtxNode(arena, ctx, ast.NodeSwitch,
                     ast.NodeSwitch {
                         .base = undefined,
                         .switch_token = *token,
@@ -2884,23 +2952,23 @@ pub const Parser = struct {
                 }) catch unreachable;
                 try stack.append(State { .ExpectToken = Token.Id.LBrace });
                 try stack.append(State { .ExpectToken = Token.Id.RParen });
-                try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
+                try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
                 try stack.append(State { .ExpectToken = Token.Id.LParen });
                 return true;
             },
             Token.Id.Keyword_comptime => {
-                const node = try self.createToDestNode(arena, dest_ptr, ast.NodeComptime,
+                const node = try self.createToCtxNode(arena, ctx, ast.NodeComptime,
                     ast.NodeComptime {
                         .base = undefined,
                         .comptime_token = *token,
                         .expr = undefined,
                     }
                 );
-                try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
+                try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
                 return true;
             },
             Token.Id.LBrace => {
-                const block = try self.createToDestNode(arena, dest_ptr, ast.NodeBlock,
+                const block = try self.createToCtxNode(arena, ctx, ast.NodeBlock,
                     ast.NodeBlock {
                         .base = undefined,
                         .label = null,
@@ -2933,7 +3001,7 @@ pub const Parser = struct {
                     return;
                 }
 
-                try self.parseError(stack, token, "expected ',' or {}, found {}", @tagName(*end), @tagName(token.id));
+                return self.parseError(token, "expected ',' or {}, found {}", @tagName(*end), @tagName(token.id));
             },
         }
     }
@@ -3049,9 +3117,9 @@ pub const Parser = struct {
         return node;
     }
 
-    fn createToDestNode(self: &Parser, arena: &mem.Allocator, dest_ptr: &const DestPtr, comptime T: type, init_to: &const T) !&T {
+    fn createToCtxNode(self: &Parser, arena: &mem.Allocator, opt_ctx: &const OptionalCtx, comptime T: type, init_to: &const T) !&T {
         const node = try self.createNode(arena, T, init_to);
-        dest_ptr.store(&node.base);
+        opt_ctx.store(&node.base);
 
         return node;
     }
@@ -3065,51 +3133,31 @@ pub const Parser = struct {
         );
     }
 
-    fn parseError(self: &Parser, stack: &ArrayList(State), token: &const Token, comptime fmt: []const u8, args: ...) !void {
-        // Before reporting an error. We pop the stack to see if our state was optional
-        self.revertIfOptional(stack) catch {
-            const loc = self.tokenizer.getTokenLocation(0, token);
-            warn("{}:{}:{}: error: " ++ fmt ++ "\n", self.source_file_name, loc.line + 1, loc.column + 1, args);
-            warn("{}\n", self.tokenizer.buffer[loc.line_start..loc.line_end]);
-            {
-                var i: usize = 0;
-                while (i < loc.column) : (i += 1) {
-                    warn(" ");
-                }
-            }
-            {
-                const caret_count = token.end - token.start;
-                var i: usize = 0;
-                while (i < caret_count) : (i += 1) {
-                    warn("~");
-                }
+    fn parseError(self: &Parser, token: &const Token, comptime fmt: []const u8, args: ...) (error{ParseError}) {
+        const loc = self.tokenizer.getTokenLocation(0, token);
+        warn("{}:{}:{}: error: " ++ fmt ++ "\n", self.source_file_name, loc.line + 1, loc.column + 1, args);
+        warn("{}\n", self.tokenizer.buffer[loc.line_start..loc.line_end]);
+        {
+            var i: usize = 0;
+            while (i < loc.column) : (i += 1) {
+                warn(" ");
             }
-            warn("\n");
-            return error.ParseError;
-        };
-    }
-
-    fn revertIfOptional(self: &Parser, stack: &ArrayList(State)) !void {
-        while (stack.popOrNull()) |state| {
-            switch (state) {
-                State.Optional => |revert| {
-                    *self = revert.parser;
-                    *self.tokenizer = revert.tokenizer;
-                    *revert.ptr = null;
-                    return;
-                },
-                else => { }
+        }
+        {
+            const caret_count = token.end - token.start;
+            var i: usize = 0;
+            while (i < caret_count) : (i += 1) {
+                warn("~");
             }
         }
-
-        return error.NoOptionalStateFound;
+        warn("\n");
+        return error.ParseError;
     }
 
-    fn expectToken(self: &Parser, stack: &ArrayList(State), id: @TagType(Token.Id)) !?Token {
+    fn expectToken(self: &Parser, id: @TagType(Token.Id)) !Token {
         const token = self.getNextToken();
         if (token.id != id) {
-            try self.parseError(stack, token, "expected {}, found {}", @tagName(id), @tagName(token.id));
-            return null;
+            return self.parseError(token, "expected {}, found {}", @tagName(id), @tagName(token.id));
         }
         return token;
     }
@@ -3424,7 +3472,7 @@ pub const Parser = struct {
                         }
 
                         if (suspend_node.payload) |payload| {
-                            try stack.append(RenderState { .Expression = &payload.base });
+                            try stack.append(RenderState { .Expression = payload });
                             try stack.append(RenderState { .Text = " " });
                         }
                     },
@@ -3435,7 +3483,7 @@ pub const Parser = struct {
                         if (prefix_op_node.op == ast.NodeInfixOp.InfixOp.Catch) {
                             if (prefix_op_node.op.Catch) |payload| {
                             try stack.append(RenderState { .Text = " " });
-                                try stack.append(RenderState { .Expression = &payload.base });
+                                try stack.append(RenderState { .Expression = payload });
                             }
                             try stack.append(RenderState { .Text = " catch " });
                         } else {
@@ -3612,17 +3660,25 @@ pub const Parser = struct {
                     },
                     ast.Node.Id.ControlFlowExpression => {
                         const flow_expr = @fieldParentPtr(ast.NodeControlFlowExpression, "base", base);
+
+                        if (flow_expr.rhs) |rhs| {
+                            try stack.append(RenderState { .Expression = rhs });
+                            try stack.append(RenderState { .Text = " " });
+                        }
+
                         switch (flow_expr.kind) {
-                            ast.NodeControlFlowExpression.Kind.Break => |maybe_blk_token| {
+                            ast.NodeControlFlowExpression.Kind.Break => |maybe_label| {
                                 try stream.print("break");
-                                if (maybe_blk_token) |blk_token| {
-                                    try stream.print(" :{}", self.tokenizer.getTokenSlice(blk_token));
+                                if (maybe_label) |label| {
+                                    try stream.print(" :");
+                                    try stack.append(RenderState { .Expression = label });
                                 }
                             },
-                            ast.NodeControlFlowExpression.Kind.Continue => |maybe_blk_token| {
+                            ast.NodeControlFlowExpression.Kind.Continue => |maybe_label| {
                                 try stream.print("continue");
-                                if (maybe_blk_token) |blk_token| {
-                                    try stream.print(" :{}", self.tokenizer.getTokenSlice(blk_token));
+                                if (maybe_label) |label| {
+                                    try stream.print(" :");
+                                    try stack.append(RenderState { .Expression = label });
                                 }
                             },
                             ast.NodeControlFlowExpression.Kind.Return => {
@@ -3630,25 +3686,20 @@ pub const Parser = struct {
                             },
 
                         }
-
-                        if (flow_expr.rhs) |rhs| {
-                            try stream.print(" ");
-                            try stack.append(RenderState { .Expression = rhs });
-                        }
                     },
                     ast.Node.Id.Payload => {
                         const payload = @fieldParentPtr(ast.NodePayload, "base", base);
                         try stack.append(RenderState { .Text = "|"});
-                        try stack.append(RenderState { .Expression = &payload.error_symbol.base });
+                        try stack.append(RenderState { .Expression = payload.error_symbol });
                         try stack.append(RenderState { .Text = "|"});
                     },
                     ast.Node.Id.PointerPayload => {
                         const payload = @fieldParentPtr(ast.NodePointerPayload, "base", base);
                         try stack.append(RenderState { .Text = "|"});
-                        try stack.append(RenderState { .Expression = &payload.value_symbol.base });
+                        try stack.append(RenderState { .Expression = payload.value_symbol });
 
-                        if (payload.is_ptr) {
-                            try stack.append(RenderState { .Text = "*"});
+                        if (payload.ptr_token) |ptr_token| {
+                            try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(ptr_token) });
                         }
 
                         try stack.append(RenderState { .Text = "|"});
@@ -3658,14 +3709,14 @@ pub const Parser = struct {
                         try stack.append(RenderState { .Text = "|"});
 
                         if (payload.index_symbol) |index_symbol| {
-                            try stack.append(RenderState { .Expression = &index_symbol.base });
+                            try stack.append(RenderState { .Expression = index_symbol });
                             try stack.append(RenderState { .Text = ", "});
                         }
 
-                        try stack.append(RenderState { .Expression = &payload.value_symbol.base });
+                        try stack.append(RenderState { .Expression = payload.value_symbol });
 
-                        if (payload.is_ptr) {
-                            try stack.append(RenderState { .Text = "*"});
+                        if (payload.ptr_token) |ptr_token| {
+                            try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(ptr_token) });
                         }
 
                         try stack.append(RenderState { .Text = "|"});
@@ -3800,7 +3851,7 @@ pub const Parser = struct {
                         while (i != 0) {
                             i -= 1;
                             const node = decls[i];
-                            try stack.append(RenderState { .Expression = &node.base});
+                            try stack.append(RenderState { .Expression = node });
                             try stack.append(RenderState.PrintIndent);
                             try stack.append(RenderState {
                                 .Text = blk: {
@@ -3959,7 +4010,7 @@ pub const Parser = struct {
                         try stack.append(RenderState { .Expression = switch_case.expr });
                         if (switch_case.payload) |payload| {
                             try stack.append(RenderState { .Text = " " });
-                            try stack.append(RenderState { .Expression = &payload.base });
+                            try stack.append(RenderState { .Expression = payload });
                         }
                         try stack.append(RenderState { .Text = " => "});
 
@@ -4000,7 +4051,7 @@ pub const Parser = struct {
 
                         if (else_node.payload) |payload| {
                             try stack.append(RenderState { .Text = " " });
-                            try stack.append(RenderState { .Expression = &payload.base });
+                            try stack.append(RenderState { .Expression = payload });
                         }
                     },
                     ast.Node.Id.While => {
@@ -4045,7 +4096,7 @@ pub const Parser = struct {
                         }
 
                         if (while_node.payload) |payload| {
-                            try stack.append(RenderState { .Expression = &payload.base });
+                            try stack.append(RenderState { .Expression = payload });
                             try stack.append(RenderState { .Text = " " });
                         }
 
@@ -4088,7 +4139,7 @@ pub const Parser = struct {
                         }
 
                         if (for_node.payload) |payload| {
-                            try stack.append(RenderState { .Expression = &payload.base });
+                            try stack.append(RenderState { .Expression = payload });
                             try stack.append(RenderState { .Text = " " });
                         }
 
@@ -4121,7 +4172,7 @@ pub const Parser = struct {
 
                                     if (@"else".payload) |payload| {
                                         try stack.append(RenderState { .Text = " " });
-                                        try stack.append(RenderState { .Expression = &payload.base });
+                                        try stack.append(RenderState { .Expression = payload });
                                     }
 
                                     try stack.append(RenderState { .Text = " " });
@@ -4135,7 +4186,7 @@ pub const Parser = struct {
                         try stack.append(RenderState { .Text = " " });
 
                         if (if_node.payload) |payload| {
-                            try stack.append(RenderState { .Expression = &payload.base });
+                            try stack.append(RenderState { .Expression = payload });
                             try stack.append(RenderState { .Text = " " });
                         }
 
@@ -4147,8 +4198,8 @@ pub const Parser = struct {
                         const asm_node = @fieldParentPtr(ast.NodeAsm, "base", base);
                         try stream.print("{} ", self.tokenizer.getTokenSlice(asm_node.asm_token));
 
-                        if (asm_node.is_volatile) {
-                            try stream.write("volatile ");
+                        if (asm_node.volatile_token) |volatile_token| {
+                            try stream.print("{} ", self.tokenizer.getTokenSlice(volatile_token));
                         }
 
                         try stack.append(RenderState { .Indent = indent });
@@ -4238,7 +4289,7 @@ pub const Parser = struct {
                         try stack.append(RenderState { .Text = " ("});
                         try stack.append(RenderState { .Expression = asm_input.constraint });
                         try stack.append(RenderState { .Text = "] "});
-                        try stack.append(RenderState { .Expression = &asm_input.symbolic_name.base});
+                        try stack.append(RenderState { .Expression = asm_input.symbolic_name });
                         try stack.append(RenderState { .Text = "["});
                     },
                     ast.Node.Id.AsmOutput => {
@@ -4257,7 +4308,7 @@ pub const Parser = struct {
                         try stack.append(RenderState { .Text = " ("});
                         try stack.append(RenderState { .Expression = asm_output.constraint });
                         try stack.append(RenderState { .Text = "] "});
-                        try stack.append(RenderState { .Expression = &asm_output.symbolic_name.base});
+                        try stack.append(RenderState { .Expression = asm_output.symbolic_name });
                         try stack.append(RenderState { .Text = "["});
                     },