#ifndef _ZIG0_AST_H__ #define _ZIG0_AST_H__ #include #include #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, /// `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; } 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