#ifndef _ZIG0_AST_H__
#define _ZIG0_AST_H__

#include <stdbool.h>
#include <stdint.h>

#include "common.h"
#include "tokenizer.h"

typedef enum {
    /// sub_list[lhs...rhs]
    AST_NODE_ROOT,
    /// `usingnamespace lhs;`. rhs unused. main_token is `usingnamespace`.
    AST_NODE_USINGNAMESPACE,
    /// lhs is test name token (must be string literal or identifier), if any.
    /// rhs is the body node.
    AST_NODE_TEST_DECL,
    /// lhs is the index into extra_data.
    /// rhs is the initialization expression, if any.
    /// main_token is `var` or `const`.
    AST_NODE_GLOBAL_VAR_DECL,
    /// `var a: x align(y) = rhs`
    /// lhs is the index into extra_data.
    /// main_token is `var` or `const`.
    AST_NODE_LOCAL_VAR_DECL,
    /// `var a: lhs = rhs`. lhs and rhs may be unused.
    /// Can be local or global.
    /// main_token is `var` or `const`.
    AST_NODE_SIMPLE_VAR_DECL,
    /// `var a align(lhs) = rhs`. lhs and rhs may be unused.
    /// Can be local or global.
    /// main_token is `var` or `const`.
    AST_NODE_ALIGNED_VAR_DECL,
    /// lhs is the identifier token payload if any,
    /// rhs is the deferred expression.
    AST_NODE_ERRDEFER,
    /// lhs is unused.
    /// rhs is the deferred expression.
    AST_NODE_DEFER,
    /// lhs catch rhs
    /// lhs catch |err| rhs
    /// main_token is the `catch` keyword.
    /// payload is determined by looking at the next token after the `catch`
    /// keyword.
    AST_NODE_CATCH,
    /// `lhs.a`. main_token is the dot. rhs is the identifier token index.
    AST_NODE_FIELD_ACCESS,
    /// `lhs.?`. main_token is the dot. rhs is the `?` token index.
    AST_NODE_UNWRAP_OPTIONAL,
    /// `lhs == rhs`. main_token is op.
    AST_NODE_EQUAL_EQUAL,
    /// `lhs != rhs`. main_token is op.
    AST_NODE_BANG_EQUAL,
    /// `lhs < rhs`. main_token is op.
    AST_NODE_LESS_THAN,
    /// `lhs > rhs`. main_token is op.
    AST_NODE_GREATER_THAN,
    /// `lhs <= rhs`. main_token is op.
    AST_NODE_LESS_OR_EQUAL,
    /// `lhs >= rhs`. main_token is op.
    AST_NODE_GREATER_OR_EQUAL,
    /// `lhs *= rhs`. main_token is op.
    AST_NODE_ASSIGN_MUL,
    /// `lhs /= rhs`. main_token is op.
    AST_NODE_ASSIGN_DIV,
    /// `lhs %= rhs`. main_token is op.
    AST_NODE_ASSIGN_MOD,
    /// `lhs += rhs`. main_token is op.
    AST_NODE_ASSIGN_ADD,
    /// `lhs -= rhs`. main_token is op.
    AST_NODE_ASSIGN_SUB,
    /// `lhs <<= rhs`. main_token is op.
    AST_NODE_ASSIGN_SHL,
    /// `lhs <<|= rhs`. main_token is op.
    AST_NODE_ASSIGN_SHL_SAT,
    /// `lhs >>= rhs`. main_token is op.
    AST_NODE_ASSIGN_SHR,
    /// `lhs &= rhs`. main_token is op.
    AST_NODE_ASSIGN_BIT_AND,
    /// `lhs ^= rhs`. main_token is op.
    AST_NODE_ASSIGN_BIT_XOR,
    /// `lhs |= rhs`. main_token is op.
    AST_NODE_ASSIGN_BIT_OR,
    /// `lhs *%= rhs`. main_token is op.
    AST_NODE_ASSIGN_MUL_WRAP,
    /// `lhs +%= rhs`. main_token is op.
    AST_NODE_ASSIGN_ADD_WRAP,
    /// `lhs -%= rhs`. main_token is op.
    AST_NODE_ASSIGN_SUB_WRAP,
    /// `lhs *|= rhs`. main_token is op.
    AST_NODE_ASSIGN_MUL_SAT,
    /// `lhs +|= rhs`. main_token is op.
    AST_NODE_ASSIGN_ADD_SAT,
    /// `lhs -|= rhs`. main_token is op.
    AST_NODE_ASSIGN_SUB_SAT,
    /// `lhs = rhs`. main_token is op.
    AST_NODE_ASSIGN,
    /// `a, b, ... = rhs`. main_token is op. lhs is index into `extra_data`
    /// of an lhs elem count followed by an array of that many `Node.Index`,
    /// with each node having one of the following types:
    /// * `global_var_decl`
    /// * `local_var_decl`
    /// * `simple_var_decl`
    /// * `aligned_var_decl`
    /// * Any expression node
    /// The first 3 types correspond to a `var` or `const` lhs node (note
    /// that their `rhs` is always 0). An expression node corresponds to a
    /// standard assignment LHS (which must be evaluated as an lvalue).
    /// There may be a preceding `comptime` token, which does not create a
    /// corresponding `comptime` node so must be manually detected.
    AST_NODE_ASSIGN_DESTRUCTURE,
    /// `lhs || rhs`. main_token is the `||`.
    AST_NODE_MERGE_ERROR_SETS,
    /// `lhs * rhs`. main_token is the `*`.
    AST_NODE_MUL,
    /// `lhs / rhs`. main_token is the `/`.
    AST_NODE_DIV,
    /// `lhs % rhs`. main_token is the `%`.
    AST_NODE_MOD,
    /// `lhs ** rhs`. main_token is the `**`.
    AST_NODE_ARRAY_MULT,
    /// `lhs *% rhs`. main_token is the `*%`.
    AST_NODE_MUL_WRAP,
    /// `lhs *| rhs`. main_token is the `*|`.
    AST_NODE_MUL_SAT,
    /// `lhs + rhs`. main_token is the `+`.
    AST_NODE_ADD,
    /// `lhs - rhs`. main_token is the `-`.
    AST_NODE_SUB,
    /// `lhs ++ rhs`. main_token is the `++`.
    AST_NODE_ARRAY_CAT,
    /// `lhs +% rhs`. main_token is the `+%`.
    AST_NODE_ADD_WRAP,
    /// `lhs -% rhs`. main_token is the `-%`.
    AST_NODE_SUB_WRAP,
    /// `lhs +| rhs`. main_token is the `+|`.
    AST_NODE_ADD_SAT,
    /// `lhs -| rhs`. main_token is the `-|`.
    AST_NODE_SUB_SAT,
    /// `lhs << rhs`. main_token is the `<<`.
    AST_NODE_SHL,
    /// `lhs <<| rhs`. main_token is the `<<|`.
    AST_NODE_SHL_SAT,
    /// `lhs >> rhs`. main_token is the `>>`.
    AST_NODE_SHR,
    /// `lhs & rhs`. main_token is the `&`.
    AST_NODE_BIT_AND,
    /// `lhs ^ rhs`. main_token is the `^`.
    AST_NODE_BIT_XOR,
    /// `lhs | rhs`. main_token is the `|`.
    AST_NODE_BIT_OR,
    /// `lhs orelse rhs`. main_token is the `orelse`.
    AST_NODE_ORELSE,
    /// `lhs and rhs`. main_token is the `and`.
    AST_NODE_BOOL_AND,
    /// `lhs or rhs`. main_token is the `or`.
    AST_NODE_BOOL_OR,
    /// `op lhs`. rhs unused. main_token is op.
    AST_NODE_BOOL_NOT,
    /// `op lhs`. rhs unused. main_token is op.
    AST_NODE_NEGATION,
    /// `op lhs`. rhs unused. main_token is op.
    AST_NODE_BIT_NOT,
    /// `op lhs`. rhs unused. main_token is op.
    AST_NODE_NEGATION_WRAP,
    /// `op lhs`. rhs unused. main_token is op.
    AST_NODE_ADDRESS_OF,
    /// `op lhs`. rhs unused. main_token is op.
    AST_NODE_TRY,
    /// `op lhs`. rhs unused. main_token is op.
    AST_NODE_AWAIT,
    /// `?lhs`. rhs unused. main_token is the `?`.
    AST_NODE_OPTIONAL_TYPE,
    /// `[lhs]rhs`.
    AST_NODE_ARRAY_TYPE,
    /// `[lhs:a]b`. `ArrayTypeSentinel[rhs]`.
    AST_NODE_ARRAY_TYPE_SENTINEL,
    /// `[*]align(lhs) rhs`. lhs can be omitted.
    /// `*align(lhs) rhs`. lhs can be omitted.
    /// `[]rhs`.
    /// main_token is the asterisk if a single item pointer or the lbracket
    /// if a slice, many-item pointer, or C-pointer
    /// main_token might be a ** token, which is shared with a parent/child
    /// pointer type and may require special handling.
    AST_NODE_PTR_TYPE_ALIGNED,
    /// `[*:lhs]rhs`. lhs can be omitted.
    /// `*rhs`.
    /// `[:lhs]rhs`.
    /// main_token is the asterisk if a single item pointer or the lbracket
    /// if a slice, many-item pointer, or C-pointer
    /// main_token might be a ** token, which is shared with a parent/child
    /// pointer type and may require special handling.
    AST_NODE_PTR_TYPE_SENTINEL,
    /// lhs is index into ptr_type. rhs is the element type expression.
    /// main_token is the asterisk if a single item pointer or the lbracket
    /// if a slice, many-item pointer, or C-pointer
    /// main_token might be a ** token, which is shared with a parent/child
    /// pointer type and may require special handling.
    AST_NODE_PTR_TYPE,
    /// lhs is index into ptr_type_bit_range. rhs is the element type
    /// expression.
    /// main_token is the asterisk if a single item pointer or the lbracket
    /// if a slice, many-item pointer, or C-pointer
    /// main_token might be a ** token, which is shared with a parent/child
    /// pointer type and may require special handling.
    AST_NODE_PTR_TYPE_BIT_RANGE,
    /// `lhs[rhs..]`
    /// main_token is the lbracket.
    AST_NODE_SLICE_OPEN,
    /// `lhs[b..c]`. rhs is index into Slice
    /// main_token is the lbracket.
    AST_NODE_SLICE,
    /// `lhs[b..c :d]`. rhs is index into SliceSentinel. Slice end c can be
    /// omitted.
    /// main_token is the lbracket.
    AST_NODE_SLICE_SENTINEL,
    /// `lhs.*`. rhs is unused.
    AST_NODE_DEREF,
    /// `lhs[rhs]`.
    AST_NODE_ARRAY_ACCESS,
    /// `lhs{rhs}`. rhs can be omitted.
    AST_NODE_ARRAY_INIT_ONE,
    /// `lhs{rhs,}`. rhs can *not* be omitted
    AST_NODE_ARRAY_INIT_ONE_COMMA,
    /// `.{lhs, rhs}`. lhs and rhs can be omitted.
    AST_NODE_ARRAY_INIT_DOT_TWO,
    /// Same as `array_init_dot_two` except there is known to be a trailing
    /// comma
    /// before the final rbrace.
    AST_NODE_ARRAY_INIT_DOT_TWO_COMMA,
    /// `.{a, b}`. `sub_list[lhs..rhs]`.
    AST_NODE_ARRAY_INIT_DOT,
    /// Same as `array_init_dot` except there is known to be a trailing comma
    /// before the final rbrace.
    AST_NODE_ARRAY_INIT_DOT_COMMA,
    /// `lhs{a, b}`. `sub_range_list[rhs]`. lhs can be omitted which means
    /// `.{a, b}`.
    AST_NODE_ARRAY_INIT,
    /// Same as `array_init` except there is known to be a trailing comma
    /// before the final rbrace.
    AST_NODE_ARRAY_INIT_COMMA,
    /// `lhs{.a = rhs}`. rhs can be omitted making it empty.
    /// main_token is the lbrace.
    AST_NODE_STRUCT_INIT_ONE,
    /// `lhs{.a = rhs,}`. rhs can *not* be omitted.
    /// main_token is the lbrace.
    AST_NODE_STRUCT_INIT_ONE_COMMA,
    /// `.{.a = lhs, .b = rhs}`. lhs and rhs can be omitted.
    /// main_token is the lbrace.
    /// No trailing comma before the rbrace.
    AST_NODE_STRUCT_INIT_DOT_TWO,
    /// Same as `struct_init_dot_two` except there is known to be a trailing
    /// comma
    /// before the final rbrace.
    AST_NODE_STRUCT_INIT_DOT_TWO_COMMA,
    /// `.{.a = b, .c = d}`. `sub_list[lhs..rhs]`.
    /// main_token is the lbrace.
    AST_NODE_STRUCT_INIT_DOT,
    /// Same as `struct_init_dot` except there is known to be a trailing comma
    /// before the final rbrace.
    AST_NODE_STRUCT_INIT_DOT_COMMA,
    /// `lhs{.a = b, .c = d}`. `sub_range_list[rhs]`.
    /// lhs can be omitted which means `.{.a = b, .c = d}`.
    /// main_token is the lbrace.
    AST_NODE_STRUCT_INIT,
    /// Same as `struct_init` except there is known to be a trailing comma
    /// before the final rbrace.
    AST_NODE_STRUCT_INIT_COMMA,
    /// `lhs(rhs)`. rhs can be omitted.
    /// main_token is the lparen.
    AST_NODE_CALL_ONE,
    /// `lhs(rhs,)`. rhs can be omitted.
    /// main_token is the lparen.
    AST_NODE_CALL_ONE_COMMA,
    /// `async lhs(rhs)`. rhs can be omitted.
    AST_NODE_ASYNC_CALL_ONE,
    /// `async lhs(rhs,)`.
    AST_NODE_ASYNC_CALL_ONE_COMMA,
    /// `lhs(a, b, c)`. `SubRange[rhs]`.
    /// main_token is the `(`.
    AST_NODE_CALL,
    /// `lhs(a, b, c,)`. `SubRange[rhs]`.
    /// main_token is the `(`.
    AST_NODE_CALL_COMMA,
    /// `async lhs(a, b, c)`. `SubRange[rhs]`.
    /// main_token is the `(`.
    AST_NODE_ASYNC_CALL,
    /// `async lhs(a, b, c,)`. `SubRange[rhs]`.
    /// main_token is the `(`.
    AST_NODE_ASYNC_CALL_COMMA,
    /// `switch(lhs) {}`. `SubRange[rhs]`.
    /// `main_token` is the identifier of a preceding label, if any; otherwise
    /// `switch`.
    AST_NODE_SWITCH,
    /// Same as switch except there is known to be a trailing comma
    /// before the final rbrace
    AST_NODE_SWITCH_COMMA,
    /// `lhs => rhs`. If lhs is omitted it means `else`.
    /// main_token is the `=>`
    AST_NODE_SWITCH_CASE_ONE,
    /// Same ast `switch_case_one` but the case is inline
    AST_NODE_SWITCH_CASE_INLINE_ONE,
    /// `a, b, c => rhs`. `SubRange[lhs]`.
    /// main_token is the `=>`
    AST_NODE_SWITCH_CASE,
    /// Same ast `switch_case` but the case is inline
    AST_NODE_SWITCH_CASE_INLINE,
    /// `lhs...rhs`.
    AST_NODE_SWITCH_RANGE,
    /// `while (lhs) rhs`.
    /// `while (lhs) |x| rhs`.
    AST_NODE_WHILE_SIMPLE,
    /// `while (lhs) : (a) b`. `WhileCont[rhs]`.
    /// `while (lhs) : (a) b`. `WhileCont[rhs]`.
    AST_NODE_WHILE_CONT,
    /// `while (lhs) : (a) b else c`. `While[rhs]`.
    /// `while (lhs) |x| : (a) b else c`. `While[rhs]`.
    /// `while (lhs) |x| : (a) b else |y| c`. `While[rhs]`.
    /// The cont expression part `: (a)` may be omitted.
    AST_NODE_WHILE,
    /// `for (lhs) rhs`.
    AST_NODE_FOR_SIMPLE,
    /// `for (lhs[0..inputs]) lhs[inputs + 1] else lhs[inputs + 2]`.
    /// `For[rhs]`.
    AST_NODE_FOR,
    /// `lhs..rhs`. rhs can be omitted.
    AST_NODE_FOR_RANGE,
    /// `if (lhs) rhs`.
    /// `if (lhs) |a| rhs`.
    AST_NODE_IF_SIMPLE,
    /// `if (lhs) a else b`. `If[rhs]`.
    /// `if (lhs) |x| a else b`. `If[rhs]`.
    /// `if (lhs) |x| a else |y| b`. `If[rhs]`.
    AST_NODE_IF,
    /// `suspend lhs`. lhs can be omitted. rhs is unused.
    AST_NODE_SUSPEND,
    /// `resume lhs`. rhs is unused.
    AST_NODE_RESUME,
    /// `continue :lhs rhs`
    /// both lhs and rhs may be omitted.
    AST_NODE_CONTINUE,
    /// `break :lhs rhs`
    /// both lhs and rhs may be omitted.
    AST_NODE_BREAK,
    /// `return lhs`. lhs can be omitted. rhs is unused.
    AST_NODE_RETURN,
    /// `fn (a: lhs) rhs`. lhs can be omitted.
    /// anytype and ... parameters are omitted from the AST tree.
    /// main_token is the `fn` keyword.
    /// extern function declarations use this tag.
    AST_NODE_FN_PROTO_SIMPLE,
    /// `fn (a: b, c: d) rhs`. `sub_range_list[lhs]`.
    /// anytype and ... parameters are omitted from the AST tree.
    /// main_token is the `fn` keyword.
    /// extern function declarations use this tag.
    AST_NODE_FN_PROTO_MULTI,
    /// `fn (a: b) addrspace(e) linksection(f) callconv(g) rhs`.
    /// `FnProtoOne[lhs]`.
    /// zero or one parameters.
    /// anytype and ... parameters are omitted from the AST tree.
    /// main_token is the `fn` keyword.
    /// extern function declarations use this tag.
    AST_NODE_FN_PROTO_ONE,
    /// `fn (a: b, c: d) addrspace(e) linksection(f) callconv(g) rhs`.
    /// `FnProto[lhs]`.
    /// anytype and ... parameters are omitted from the AST tree.
    /// main_token is the `fn` keyword.
    /// extern function declarations use this tag.
    AST_NODE_FN_PROTO,
    /// lhs is the fn_proto.
    /// rhs is the function body block.
    /// Note that extern function declarations use the fn_proto tags rather
    /// than this one.
    AST_NODE_FN_DECL,
    /// `anyframe->rhs`. main_token is `anyframe`. `lhs` is arrow token index.
    AST_NODE_ANYFRAME_TYPE,
    /// Both lhs and rhs unused.
    AST_NODE_ANYFRAME_LITERAL,
    /// Both lhs and rhs unused.
    AST_NODE_CHAR_LITERAL,
    /// Both lhs and rhs unused.
    AST_NODE_NUMBER_LITERAL,
    /// Both lhs and rhs unused.
    AST_NODE_UNREACHABLE_LITERAL,
    /// Both lhs and rhs unused.
    /// Most identifiers will not have explicit AST nodes, however for
    /// expressions
    /// which could be one of many different kinds of AST nodes, there will be
    /// an
    /// identifier AST node for it.
    AST_NODE_IDENTIFIER,
    /// lhs is the dot token index, rhs unused, main_token is the identifier.
    AST_NODE_ENUM_LITERAL,
    /// main_token is the string literal token
    /// Both lhs and rhs unused.
    AST_NODE_STRING_LITERAL,
    /// main_token is the first token index (redundant with lhs)
    /// lhs is the first token index; rhs is the last token index.
    /// Could be a series of multiline_string_literal_line tokens, or a single
    /// string_literal token.
    AST_NODE_MULTILINE_STRING_LITERAL,
    /// `(lhs)`. main_token is the `(`; rhs is the token index of the `)`.
    AST_NODE_GROUPED_EXPRESSION,
    /// `@a(lhs, rhs)`. lhs and rhs may be omitted.
    /// main_token is the builtin token.
    AST_NODE_BUILTIN_CALL_TWO,
    /// Same as builtin_call_two but there is known to be a trailing comma
    /// before the rparen.
    AST_NODE_BUILTIN_CALL_TWO_COMMA,
    /// `@a(b, c)`. `sub_list[lhs..rhs]`.
    /// main_token is the builtin token.
    AST_NODE_BUILTIN_CALL,
    /// Same as builtin_call but there is known to be a trailing comma before
    /// the rparen.
    AST_NODE_BUILTIN_CALL_COMMA,
    /// `error{a, b}`.
    /// rhs is the rbrace, lhs is unused.
    AST_NODE_ERROR_SET_DECL,
    /// `struct {}`, `union {}`, `opaque {}`, `enum {}`.
    /// `extra_data[lhs..rhs]`.
    /// main_token is `struct`, `union`, `opaque`, `enum` keyword.
    AST_NODE_CONTAINER_DECL,
    /// Same as ContainerDecl but there is known to be a trailing comma
    /// or semicolon before the rbrace.
    AST_NODE_CONTAINER_DECL_TRAILING,
    /// `struct {lhs, rhs}`, `union {lhs, rhs}`, `opaque {lhs, rhs}`, `enum
    /// {lhs, rhs}`.
    /// lhs or rhs can be omitted.
    /// main_token is `struct`, `union`, `opaque`, `enum` keyword.
    AST_NODE_CONTAINER_DECL_TWO,
    /// Same as ContainerDeclTwo except there is known to be a trailing comma
    /// or semicolon before the rbrace.
    AST_NODE_CONTAINER_DECL_TWO_TRAILING,
    /// `struct(lhs)` / `union(lhs)` / `enum(lhs)`. `SubRange[rhs]`.
    AST_NODE_CONTAINER_DECL_ARG,
    /// Same as container_decl_arg but there is known to be a trailing
    /// comma or semicolon before the rbrace.
    AST_NODE_CONTAINER_DECL_ARG_TRAILING,
    /// `union(enum) {}`. `sub_list[lhs..rhs]`.
    /// Note that tagged unions with explicitly provided enums are represented
    /// by `container_decl_arg`.
    AST_NODE_TAGGED_UNION,
    /// Same as tagged_union but there is known to be a trailing comma
    /// or semicolon before the rbrace.
    AST_NODE_TAGGED_UNION_TRAILING,
    /// `union(enum) {lhs, rhs}`. lhs or rhs may be omitted.
    /// Note that tagged unions with explicitly provided enums are represented
    /// by `container_decl_arg`.
    AST_NODE_TAGGED_UNION_TWO,
    /// Same as tagged_union_two but there is known to be a trailing comma
    /// or semicolon before the rbrace.
    AST_NODE_TAGGED_UNION_TWO_TRAILING,
    /// `union(enum(lhs)) {}`. `SubRange[rhs]`.
    AST_NODE_TAGGED_UNION_ENUM_TAG,
    /// Same as tagged_union_enum_tag but there is known to be a trailing comma
    /// or semicolon before the rbrace.
    AST_NODE_TAGGED_UNION_ENUM_TAG_TRAILING,
    /// `a: lhs = rhs,`. lhs and rhs can be omitted.
    /// main_token is the field name identifier.
    /// lastToken() does not include the possible trailing comma.
    AST_NODE_CONTAINER_FIELD_INIT,
    /// `a: lhs align(rhs),`. rhs can be omitted.
    /// main_token is the field name identifier.
    /// lastToken() does not include the possible trailing comma.
    AST_NODE_CONTAINER_FIELD_ALIGN,
    /// `a: lhs align(c) = d,`. `container_field_list[rhs]`.
    /// main_token is the field name identifier.
    /// lastToken() does not include the possible trailing comma.
    AST_NODE_CONTAINER_FIELD,
    /// `comptime lhs`. rhs unused.
    AST_NODE_COMPTIME,
    /// `nosuspend lhs`. rhs unused.
    AST_NODE_NOSUSPEND,
    /// `{lhs rhs}`. rhs or lhs can be omitted.
    /// main_token points at the lbrace.
    AST_NODE_BLOCK_TWO,
    /// Same as block_two but there is known to be a semicolon before the
    /// rbrace.
    AST_NODE_BLOCK_TWO_SEMICOLON,
    /// `{}`. `sub_list[lhs..rhs]`.
    /// main_token points at the lbrace.
    AST_NODE_BLOCK,
    /// Same as block but there is known to be a semicolon before the rbrace.
    AST_NODE_BLOCK_SEMICOLON,
    /// `asm(lhs)`. rhs is the token index of the rparen.
    AST_NODE_ASM_SIMPLE,
    /// Legacy asm with string clobbers. `asm(lhs, a)`.
    /// `AsmLegacy[rhs]`.
    AST_NODE_ASM_LEGACY,
    /// `asm(lhs, a)`. `Asm[rhs]`.
    AST_NODE_ASM,
    /// `[a] "b" (c)`. lhs is 0, rhs is token index of the rparen.
    /// `[a] "b" (-> lhs)`. rhs is token index of the rparen.
    /// main_token is `a`.
    AST_NODE_ASM_OUTPUT,
    /// `[a] "b" (lhs)`. rhs is token index of the rparen.
    /// main_token is `a`.
    AST_NODE_ASM_INPUT,
    /// `error.a`. lhs is token index of `.`. rhs is token index of `a`.
    AST_NODE_ERROR_VALUE,
    /// `lhs!rhs`. main_token is the `!`.
    AST_NODE_ERROR_UNION,
} AstNodeTag;

typedef uint32_t AstTokenIndex;
typedef uint32_t AstNodeIndex;
typedef uint32_t AstIndex;

typedef struct {
    AstIndex lhs;
    AstIndex rhs;
} AstData;

typedef struct {
    uint32_t len;
    uint32_t cap;
    AstNodeTag* tags;
    AstTokenIndex* main_tokens;
    AstData* datas;
} AstNodeList;

typedef struct {
    AstNodeTag tag;
    AstTokenIndex main_token;
    AstData data;
} AstNodeItem;

typedef struct {
    uint32_t len;
    uint32_t cap;
    TokenizerTag* tags;
    AstIndex* starts;
} AstTokenList;

typedef SLICE(AstNodeIndex) AstNodeIndexSlice;

typedef struct {
    const char* source;
    uint32_t source_len;
    AstTokenList tokens;
    AstNodeList nodes;
    AstNodeIndexSlice extra_data;
    bool has_error;
    char* err_msg;
} Ast;

typedef struct AstPtrType {
    AstNodeIndex sentinel;
    AstNodeIndex align_node;
    AstNodeIndex addrspace_node;
} AstPtrType;

typedef struct AstPtrTypeBitRange {
    AstNodeIndex sentinel;
    AstNodeIndex align_node;
    AstNodeIndex addrspace_node;
    AstNodeIndex bit_range_start;
    AstNodeIndex bit_range_end;
} AstPtrTypeBitRange;

typedef struct AstFnProtoOne {
    AstNodeIndex param;
    AstNodeIndex align_expr;
    AstNodeIndex addrspace_expr;
    AstNodeIndex section_expr;
    AstNodeIndex callconv_expr;
} AstFnProtoOne;

typedef struct AstFnProto {
    AstNodeIndex params_start;
    AstNodeIndex params_end;
    AstNodeIndex align_expr;
    AstNodeIndex addrspace_expr;
    AstNodeIndex section_expr;
    AstNodeIndex callconv_expr;
} AstFnProto;

typedef struct AstSubRange {
    AstNodeIndex start;
    AstNodeIndex end;
} AstSubRange;

typedef struct AstSliceSentinel {
    AstNodeIndex start;
    AstNodeIndex end;
    AstNodeIndex sentinel;
} AstSliceSentinel;

typedef struct AstWhileCont {
    AstNodeIndex cont_expr;
    AstNodeIndex then_expr;
} AstWhileCont;

typedef struct AstWhile {
    AstNodeIndex cont_expr;
    AstNodeIndex then_expr;
    AstNodeIndex else_expr;
} AstWhile;

typedef struct AstFor {
    unsigned int inputs : 31;
    unsigned int has_else : 1;
} AstFor;

typedef struct AstIf {
    AstNodeIndex then_expr;
    AstNodeIndex else_expr;
} AstIf;

typedef struct AstError {
    bool is_note;
    AstTokenIndex token;
    union {
        struct {
            TokenizerTag expected_tag;
        } expected;
        struct {
        } none;
    } extra;
} AstError;

Ast astParse(const char* source, uint32_t len);
void astDeinit(Ast*);

#endif
