Changeset - f81833cf998f
[Not reviewed]
0 2 1
mh - 3 years ago 2022-02-15 12:23:01
contact@maxhenger.nl
Fix bug in search key for type table
3 files changed with 1512 insertions and 4 deletions:
0 comments (0 inline, 0 general)
ast_output.txt
Show inline comments
 
new file 100644
 
Root[0000]- Module:
 
             - Pragmas:
 
             - Imports:
 
             - Definitions:
 
DefS[0007]    - DefinitionStruct:
 
                 - Name: Holder
 
                   - PolyVar: T
 
                 - Fields:
 
                   - Field:
 
                     - Name: left
 
                     - Type: T[]
 
                   - Field:
 
                     - Name: right
 
                     - Type: T[]
 
DefF[0008]    - DefinitionFunction:
 
                 - Name: create_array
 
                   - PolyVar: T
 
                 - ReturnParserType: T[]
 
                 - Parameters:
 
Var [0008]        - Variable:
 
                     - Name: first_index
 
                     - Kind: Parameter
 
                     - ParserType: T
 
                     - RelativePos: -1
 
                     - UniqueScopeID: 0
 
Var [0009]        - Variable:
 
                     - Name: last_index
 
                     - Kind: Parameter
 
                     - ParserType: T
 
                     - RelativePos: -1
 
                     - UniqueScopeID: 1
 
                 - Body:
 
SBl [0008]        - Block:
 
                     - EndBlockID: 9
 
                     - ScopeID: 2
 
                     - Statements:
 
SMem[0000]            - LocalMemory:
 
                         - Variable:
 
Var [0010]                - Variable:
 
                             - Name: result
 
                             - Kind: Local
 
                             - ParserType: auto
 
                             - RelativePos: 0
 
                             - UniqueScopeID: 2
 
                         - InitialValue:
 
EAsi[0002]                - AssignmentExpr:
 
                             - UniqueId: 0
 
                             - Operation: Set
 
                             - Left:
 
EVar[0001]                    - VariableExpr:
 
                                 - UniqueId: 1
 
                                 - Name: result
 
                                 - Definition: Some(10)
 
                                 - Parent: Expr(2, 0)
 
                             - Right:
 
ELit[0000]                    - LiteralExpr:
 
                                 - UniqueId: 2
 
                                 - Value: Array
 
                                   - Elements:
 
                                 - Parent: Expr(2, 1)
 
                             - Parent: MemStmt(0)
 
                         - Next: 5
 
SWhi[0005]            - While:
 
                         - EndWhile: 6
 
                         - InSync: -1
 
                         - Condition:
 
EBin[0005]                - BinaryExpr:
 
                             - UniqueId: 3
 
                             - Operation: LessThan
 
                             - Left:
 
EVar[0003]                    - VariableExpr:
 
                                 - UniqueId: 4
 
                                 - Name: first_index
 
                                 - Definition: Some(8)
 
                                 - Parent: Expr(5, 0)
 
                             - Right:
 
EVar[0004]                    - VariableExpr:
 
                                 - UniqueId: 5
 
                                 - Name: last_index
 
                                 - Definition: Some(9)
 
                                 - Parent: Expr(5, 1)
 
                             - Parent: WhileStmt(5)
 
                         - Body:
 
SBl [0003]                - Block:
 
                             - EndBlockID: 4
 
                             - ScopeID: 0
 
                             - Statements:
 
SExp[0001]                    - ExpressionStatement:
 
EAsi[0011]                      - AssignmentExpr:
 
                                   - UniqueId: 6
 
                                   - Operation: Set
 
                                   - Left:
 
EVar[0006]                          - VariableExpr:
 
                                       - UniqueId: 7
 
                                       - Name: result
 
                                       - Definition: Some(10)
 
                                       - Parent: Expr(11, 0)
 
                                   - Right:
 
EBin[0010]                          - BinaryExpr:
 
                                       - UniqueId: 8
 
                                       - Operation: Concatenate
 
                                       - Left:
 
EVar[0007]                              - VariableExpr:
 
                                           - UniqueId: 9
 
                                           - Name: result
 
                                           - Definition: Some(10)
 
                                           - Parent: Expr(10, 0)
 
                                       - Right:
 
ELit[0009]                              - LiteralExpr:
 
                                           - UniqueId: 10
 
                                           - Value: Array
 
                                             - Elements:
 
EVar[0008]                                    - VariableExpr:
 
                                                 - UniqueId: 11
 
                                                 - Name: first_index
 
                                                 - Definition: Some(8)
 
                                                 - Parent: Expr(9, 0)
 
                                           - Parent: Expr(10, 1)
 
                                       - Parent: Expr(11, 1)
 
                                   - Parent: ExprStmt(1)
 
                                 - Next: 2
 
SExp[0002]                    - ExpressionStatement:
 
EAsi[0014]                      - AssignmentExpr:
 
                                   - UniqueId: 12
 
                                   - Operation: Added
 
                                   - Left:
 
EVar[0012]                          - VariableExpr:
 
                                       - UniqueId: 13
 
                                       - Name: first_index
 
                                       - Definition: Some(8)
 
                                       - Parent: Expr(14, 0)
 
                                   - Right:
 
ELit[0013]                          - LiteralExpr:
 
                                       - UniqueId: 14
 
                                       - Value: LiteralInteger { unsigned_value: 1, negated: false }
 
                                       - Parent: Expr(14, 1)
 
                                   - Parent: ExprStmt(2)
 
                                 - Next: 4
 
SRet[0007]            - Return:
 
                         - Expressions:
 
EVar[0015]                - VariableExpr:
 
                             - UniqueId: 15
 
                             - Name: result
 
                             - Definition: Some(10)
 
                             - Parent: ReturnStmt(7)
 
DefF[0009]    - DefinitionFunction:
 
                 - Name: create_holder
 
                   - PolyVar: T
 
                 - ReturnParserType: Holder<T>
 
                 - Parameters:
 
Var [0011]        - Variable:
 
                     - Name: left_first
 
                     - Kind: Parameter
 
                     - ParserType: T
 
                     - RelativePos: -1
 
                     - UniqueScopeID: 0
 
Var [0012]        - Variable:
 
                     - Name: left_last
 
                     - Kind: Parameter
 
                     - ParserType: T
 
                     - RelativePos: -1
 
                     - UniqueScopeID: 1
 
Var [0013]        - Variable:
 
                     - Name: right_first
 
                     - Kind: Parameter
 
                     - ParserType: T
 
                     - RelativePos: -1
 
                     - UniqueScopeID: 2
 
Var [0014]        - Variable:
 
                     - Name: right_last
 
                     - Kind: Parameter
 
                     - ParserType: T
 
                     - RelativePos: -1
 
                     - UniqueScopeID: 3
 
                 - Body:
 
SBl [0011]        - Block:
 
                     - EndBlockID: 12
 
                     - ScopeID: 4
 
                     - Statements:
 
SRet[0010]            - Return:
 
                         - Expressions:
 
ELit[0022]                - LiteralExpr:
 
                             - UniqueId: 0
 
                             - Value: Struct
 
                               - ParserType: Holder<auto>
 
                               - Definition: 7
 
                               - Field:
 
                                 - Name: left
 
                                 - Index: 0
 
                                 - ParserType:
 
ECll[0018]                        - CallExpr:
 
                                     - UniqueId: 1
 
                                     - BuiltIn: false
 
                                     - Variant: Function
 
                                     - MethodName: create_array
 
                                     - ParserType: create_array<auto>
 
                                     - Arguments:
 
EVar[0016]                            - VariableExpr:
 
                                         - UniqueId: 2
 
                                         - Name: left_first
 
                                         - Definition: Some(11)
 
                                         - Parent: Expr(18, 0)
 
EVar[0017]                            - VariableExpr:
 
                                         - UniqueId: 3
 
                                         - Name: left_last
 
                                         - Definition: Some(12)
 
                                         - Parent: Expr(18, 1)
 
                                     - Parent: Expr(22, 0)
 
                               - Field:
 
                                 - Name: right
 
                                 - Index: 1
 
                                 - ParserType:
 
ECll[0021]                        - CallExpr:
 
                                     - UniqueId: 4
 
                                     - BuiltIn: false
 
                                     - Variant: Function
 
                                     - MethodName: create_array
 
                                     - ParserType: create_array<auto>
 
                                     - Arguments:
 
EVar[0019]                            - VariableExpr:
 
                                         - UniqueId: 5
 
                                         - Name: right_first
 
                                         - Definition: Some(13)
 
                                         - Parent: Expr(21, 0)
 
EVar[0020]                            - VariableExpr:
 
                                         - UniqueId: 6
 
                                         - Name: right_last
 
                                         - Definition: Some(14)
 
                                         - Parent: Expr(21, 1)
 
                                     - Parent: Expr(22, 1)
 
                             - Parent: ReturnStmt(10)
 
DefF[0010]    - DefinitionFunction:
 
                 - Name: slicing_magic
 
                   - PolyVar: T
 
                 - ReturnParserType: T[]
 
                 - Parameters:
 
Var [0015]        - Variable:
 
                     - Name: holder
 
                     - Kind: Parameter
 
                     - ParserType: Holder<T>
 
                     - RelativePos: -1
 
                     - UniqueScopeID: 0
 
Var [0016]        - Variable:
 
                     - Name: left_base
 
                     - Kind: Parameter
 
                     - ParserType: u32
 
                     - RelativePos: -1
 
                     - UniqueScopeID: 1
 
Var [0017]        - Variable:
 
                     - Name: left_amount
 
                     - Kind: Parameter
 
                     - ParserType: u32
 
                     - RelativePos: -1
 
                     - UniqueScopeID: 2
 
Var [0018]        - Variable:
 
                     - Name: right_base
 
                     - Kind: Parameter
 
                     - ParserType: u32
 
                     - RelativePos: -1
 
                     - UniqueScopeID: 3
 
Var [0019]        - Variable:
 
                     - Name: right_amount
 
                     - Kind: Parameter
 
                     - ParserType: u32
 
                     - RelativePos: -1
 
                     - UniqueScopeID: 4
 
                 - Body:
 
SBl [0016]        - Block:
 
                     - EndBlockID: 17
 
                     - ScopeID: 6
 
                     - Statements:
 
SMem[0013]            - LocalMemory:
 
                         - Variable:
 
Var [0020]                - Variable:
 
                             - Name: left
 
                             - Kind: Local
 
                             - ParserType: auto
 
                             - RelativePos: 0
 
                             - UniqueScopeID: 5
 
                         - InitialValue:
 
EAsi[0031]                - AssignmentExpr:
 
                             - UniqueId: 0
 
                             - Operation: Set
 
                             - Left:
 
EVar[0030]                    - VariableExpr:
 
                                 - UniqueId: 1
 
                                 - Name: left
 
                                 - Definition: Some(20)
 
                                 - Parent: Expr(31, 0)
 
                             - Right:
 
ESli[0029]                    - SlicingExpr:
 
                                 - UniqueId: 2
 
                                 - Subject:
 
ESel[0024]                        - SelectExpr:
 
                                     - UniqueId: 3
 
                                     - Subject:
 
EVar[0023]                            - VariableExpr:
 
                                         - UniqueId: 4
 
                                         - Name: holder
 
                                         - Definition: Some(15)
 
                                         - Parent: Expr(24, 0)
 
                                     - StructField: left
 
                                     - Parent: Expr(29, 0)
 
                                 - FromIndex:
 
EVar[0025]                        - VariableExpr:
 
                                     - UniqueId: 5
 
                                     - Name: left_base
 
                                     - Definition: Some(16)
 
                                     - Parent: Expr(29, 1)
 
                                 - ToIndex:
 
EBin[0028]                        - BinaryExpr:
 
                                     - UniqueId: 6
 
                                     - Operation: Add
 
                                     - Left:
 
EVar[0026]                            - VariableExpr:
 
                                         - UniqueId: 7
 
                                         - Name: left_base
 
                                         - Definition: Some(16)
 
                                         - Parent: Expr(28, 0)
 
                                     - Right:
 
EVar[0027]                            - VariableExpr:
 
                                         - UniqueId: 8
 
                                         - Name: left_amount
 
                                         - Definition: Some(17)
 
                                         - Parent: Expr(28, 1)
 
                                     - Parent: Expr(29, 2)
 
                                 - Parent: Expr(31, 1)
 
                             - Parent: MemStmt(13)
 
                         - Next: 14
 
SMem[0014]            - LocalMemory:
 
                         - Variable:
 
Var [0021]                - Variable:
 
                             - Name: right
 
                             - Kind: Local
 
                             - ParserType: auto
 
                             - RelativePos: 1
 
                             - UniqueScopeID: 6
 
                         - InitialValue:
 
EAsi[0040]                - AssignmentExpr:
 
                             - UniqueId: 9
 
                             - Operation: Set
 
                             - Left:
 
EVar[0039]                    - VariableExpr:
 
                                 - UniqueId: 10
 
                                 - Name: right
 
                                 - Definition: Some(21)
 
                                 - Parent: Expr(40, 0)
 
                             - Right:
 
ESli[0038]                    - SlicingExpr:
 
                                 - UniqueId: 11
 
                                 - Subject:
 
ESel[0033]                        - SelectExpr:
 
                                     - UniqueId: 12
 
                                     - Subject:
 
EVar[0032]                            - VariableExpr:
 
                                         - UniqueId: 13
 
                                         - Name: holder
 
                                         - Definition: Some(15)
 
                                         - Parent: Expr(33, 0)
 
                                     - StructField: right
 
                                     - Parent: Expr(38, 0)
 
                                 - FromIndex:
 
EVar[0034]                        - VariableExpr:
 
                                     - UniqueId: 14
 
                                     - Name: right_base
 
                                     - Definition: Some(18)
 
                                     - Parent: Expr(38, 1)
 
                                 - ToIndex:
 
EBin[0037]                        - BinaryExpr:
 
                                     - UniqueId: 15
 
                                     - Operation: Add
 
                                     - Left:
 
EVar[0035]                            - VariableExpr:
 
                                         - UniqueId: 16
 
                                         - Name: right_base
 
                                         - Definition: Some(18)
 
                                         - Parent: Expr(37, 0)
 
                                     - Right:
 
EVar[0036]                            - VariableExpr:
 
                                         - UniqueId: 17
 
                                         - Name: right_amount
 
                                         - Definition: Some(19)
 
                                         - Parent: Expr(37, 1)
 
                                     - Parent: Expr(38, 2)
 
                                 - Parent: Expr(40, 1)
 
                             - Parent: MemStmt(14)
 
                         - Next: 15
 
SRet[0015]            - Return:
 
                         - Expressions:
 
EBin[0049]                - BinaryExpr:
 
                             - UniqueId: 18
 
                             - Operation: Concatenate
 
                             - Left:
 
ESli[0044]                    - SlicingExpr:
 
                                 - UniqueId: 19
 
                                 - Subject:
 
EVar[0041]                        - VariableExpr:
 
                                     - UniqueId: 20
 
                                     - Name: left
 
                                     - Definition: Some(20)
 
                                     - Parent: Expr(44, 0)
 
                                 - FromIndex:
 
ELit[0042]                        - LiteralExpr:
 
                                     - UniqueId: 21
 
                                     - Value: LiteralInteger { unsigned_value: 0, negated: false }
 
                                     - Parent: Expr(44, 1)
 
                                 - ToIndex:
 
ELit[0043]                        - LiteralExpr:
 
                                     - UniqueId: 22
 
                                     - Value: LiteralInteger { unsigned_value: 1, negated: false }
 
                                     - Parent: Expr(44, 2)
 
                                 - Parent: Expr(49, 0)
 
                             - Right:
 
ESli[0048]                    - SlicingExpr:
 
                                 - UniqueId: 23
 
                                 - Subject:
 
EVar[0045]                        - VariableExpr:
 
                                     - UniqueId: 24
 
                                     - Name: right
 
                                     - Definition: Some(21)
 
                                     - Parent: Expr(48, 0)
 
                                 - FromIndex:
 
ELit[0046]                        - LiteralExpr:
 
                                     - UniqueId: 25
 
                                     - Value: LiteralInteger { unsigned_value: 0, negated: false }
 
                                     - Parent: Expr(48, 1)
 
                                 - ToIndex:
 
ELit[0047]                        - LiteralExpr:
 
                                     - UniqueId: 26
 
                                     - Value: LiteralInteger { unsigned_value: 1, negated: false }
 
                                     - Parent: Expr(48, 2)
 
                                 - Parent: Expr(49, 1)
 
                             - Parent: ReturnStmt(15)
 
DefF[0011]    - DefinitionFunction:
 
                 - Name: foo
 
                 - ReturnParserType: bool
 
                 - Parameters:
 
                 - Body:
 
SBl [0031]        - Block:
 
                     - EndBlockID: 32
 
                     - ScopeID: 8
 
                     - Statements:
 
SMem[0018]            - LocalMemory:
 
                         - Variable:
 
Var [0022]                - Variable:
 
                             - Name: created_u08
 
                             - Kind: Local
 
                             - ParserType: auto
 
                             - RelativePos: 0
 
                             - UniqueScopeID: 0
 
                         - InitialValue:
 
EAsi[0056]                - AssignmentExpr:
 
                             - UniqueId: 0
 
                             - Operation: Set
 
                             - Left:
 
EVar[0055]                    - VariableExpr:
 
                                 - UniqueId: 1
 
                                 - Name: created_u08
 
                                 - Definition: Some(22)
 
                                 - Parent: Expr(56, 0)
 
                             - Right:
 
ECll[0054]                    - CallExpr:
 
                                 - UniqueId: 2
 
                                 - BuiltIn: false
 
                                 - Variant: Function
 
                                 - MethodName: create_holder
 
                                 - ParserType: create_holder<u8>
 
                                 - Arguments:
 
ELit[0050]                        - LiteralExpr:
 
                                     - UniqueId: 3
 
                                     - Value: LiteralInteger { unsigned_value: 0, negated: false }
 
                                     - Parent: Expr(54, 0)
 
ELit[0051]                        - LiteralExpr:
 
                                     - UniqueId: 4
 
                                     - Value: LiteralInteger { unsigned_value: 5, negated: false }
 
                                     - Parent: Expr(54, 1)
 
ELit[0052]                        - LiteralExpr:
 
                                     - UniqueId: 5
 
                                     - Value: LiteralInteger { unsigned_value: 2, negated: false }
 
                                     - Parent: Expr(54, 2)
 
ELit[0053]                        - LiteralExpr:
 
                                     - UniqueId: 6
 
                                     - Value: LiteralInteger { unsigned_value: 8, negated: false }
 
                                     - Parent: Expr(54, 3)
 
                                 - Parent: Expr(56, 1)
 
                             - Parent: MemStmt(18)
 
                         - Next: 19
 
SMem[0019]            - LocalMemory:
 
                         - Variable:
 
Var [0023]                - Variable:
 
                             - Name: created_u16
 
                             - Kind: Local
 
                             - ParserType: auto
 
                             - RelativePos: 1
 
                             - UniqueScopeID: 1
 
                         - InitialValue:
 
EAsi[0063]                - AssignmentExpr:
 
                             - UniqueId: 7
 
                             - Operation: Set
 
                             - Left:
 
EVar[0062]                    - VariableExpr:
 
                                 - UniqueId: 8
 
                                 - Name: created_u16
 
                                 - Definition: Some(23)
 
                                 - Parent: Expr(63, 0)
 
                             - Right:
 
ECll[0061]                    - CallExpr:
 
                                 - UniqueId: 9
 
                                 - BuiltIn: false
 
                                 - Variant: Function
 
                                 - MethodName: create_holder
 
                                 - ParserType: create_holder<u16>
 
                                 - Arguments:
 
ELit[0057]                        - LiteralExpr:
 
                                     - UniqueId: 10
 
                                     - Value: LiteralInteger { unsigned_value: 0, negated: false }
 
                                     - Parent: Expr(61, 0)
 
ELit[0058]                        - LiteralExpr:
 
                                     - UniqueId: 11
 
                                     - Value: LiteralInteger { unsigned_value: 5, negated: false }
 
                                     - Parent: Expr(61, 1)
 
ELit[0059]                        - LiteralExpr:
 
                                     - UniqueId: 12
 
                                     - Value: LiteralInteger { unsigned_value: 2, negated: false }
 
                                     - Parent: Expr(61, 2)
 
ELit[0060]                        - LiteralExpr:
 
                                     - UniqueId: 13
 
                                     - Value: LiteralInteger { unsigned_value: 8, negated: false }
 
                                     - Parent: Expr(61, 3)
 
                                 - Parent: Expr(63, 1)
 
                             - Parent: MemStmt(19)
 
                         - Next: 20
 
SMem[0020]            - LocalMemory:
 
                         - Variable:
 
Var [0024]                - Variable:
 
                             - Name: created_u32
 
                             - Kind: Local
 
                             - ParserType: auto
 
                             - RelativePos: 2
 
                             - UniqueScopeID: 2
 
                         - InitialValue:
 
EAsi[0070]                - AssignmentExpr:
 
                             - UniqueId: 14
 
                             - Operation: Set
 
                             - Left:
 
EVar[0069]                    - VariableExpr:
 
                                 - UniqueId: 15
 
                                 - Name: created_u32
 
                                 - Definition: Some(24)
 
                                 - Parent: Expr(70, 0)
 
                             - Right:
 
ECll[0068]                    - CallExpr:
 
                                 - UniqueId: 16
 
                                 - BuiltIn: false
 
                                 - Variant: Function
 
                                 - MethodName: create_holder
 
                                 - ParserType: create_holder<u32>
 
                                 - Arguments:
 
ELit[0064]                        - LiteralExpr:
 
                                     - UniqueId: 17
 
                                     - Value: LiteralInteger { unsigned_value: 0, negated: false }
 
                                     - Parent: Expr(68, 0)
 
ELit[0065]                        - LiteralExpr:
 
                                     - UniqueId: 18
 
                                     - Value: LiteralInteger { unsigned_value: 5, negated: false }
 
                                     - Parent: Expr(68, 1)
 
ELit[0066]                        - LiteralExpr:
 
                                     - UniqueId: 19
 
                                     - Value: LiteralInteger { unsigned_value: 2, negated: false }
 
                                     - Parent: Expr(68, 2)
 
ELit[0067]                        - LiteralExpr:
 
                                     - UniqueId: 20
 
                                     - Value: LiteralInteger { unsigned_value: 8, negated: false }
 
                                     - Parent: Expr(68, 3)
 
                                 - Parent: Expr(70, 1)
 
                             - Parent: MemStmt(20)
 
                         - Next: 21
 
SMem[0021]            - LocalMemory:
 
                         - Variable:
 
Var [0025]                - Variable:
 
                             - Name: created_u64
 
                             - Kind: Local
 
                             - ParserType: auto
 
                             - RelativePos: 3
 
                             - UniqueScopeID: 3
 
                         - InitialValue:
 
EAsi[0077]                - AssignmentExpr:
 
                             - UniqueId: 21
 
                             - Operation: Set
 
                             - Left:
 
EVar[0076]                    - VariableExpr:
 
                                 - UniqueId: 22
 
                                 - Name: created_u64
 
                                 - Definition: Some(25)
 
                                 - Parent: Expr(77, 0)
 
                             - Right:
 
ECll[0075]                    - CallExpr:
 
                                 - UniqueId: 23
 
                                 - BuiltIn: false
 
                                 - Variant: Function
 
                                 - MethodName: create_holder
 
                                 - ParserType: create_holder<u64>
 
                                 - Arguments:
 
ELit[0071]                        - LiteralExpr:
 
                                     - UniqueId: 24
 
                                     - Value: LiteralInteger { unsigned_value: 0, negated: false }
 
                                     - Parent: Expr(75, 0)
 
ELit[0072]                        - LiteralExpr:
 
                                     - UniqueId: 25
 
                                     - Value: LiteralInteger { unsigned_value: 5, negated: false }
 
                                     - Parent: Expr(75, 1)
 
ELit[0073]                        - LiteralExpr:
 
                                     - UniqueId: 26
 
                                     - Value: LiteralInteger { unsigned_value: 2, negated: false }
 
                                     - Parent: Expr(75, 2)
 
ELit[0074]                        - LiteralExpr:
 
                                     - UniqueId: 27
 
                                     - Value: LiteralInteger { unsigned_value: 8, negated: false }
 
                                     - Parent: Expr(75, 3)
 
                                 - Parent: Expr(77, 1)
 
                             - Parent: MemStmt(21)
 
                         - Next: 22
 
SMem[0022]            - LocalMemory:
 
                         - Variable:
 
Var [0026]                - Variable:
 
                             - Name: result_u08
 
                             - Kind: Local
 
                             - ParserType: auto
 
                             - RelativePos: 4
 
                             - UniqueScopeID: 4
 
                         - InitialValue:
 
EAsi[0085]                - AssignmentExpr:
 
                             - UniqueId: 28
 
                             - Operation: Set
 
                             - Left:
 
EVar[0084]                    - VariableExpr:
 
                                 - UniqueId: 29
 
                                 - Name: result_u08
 
                                 - Definition: Some(26)
 
                                 - Parent: Expr(85, 0)
 
                             - Right:
 
ECll[0083]                    - CallExpr:
 
                                 - UniqueId: 30
 
                                 - BuiltIn: false
 
                                 - Variant: Function
 
                                 - MethodName: slicing_magic
 
                                 - ParserType: slicing_magic<auto>
 
                                 - Arguments:
 
EVar[0078]                        - VariableExpr:
 
                                     - UniqueId: 31
 
                                     - Name: created_u08
 
                                     - Definition: Some(22)
 
                                     - Parent: Expr(83, 0)
 
ELit[0079]                        - LiteralExpr:
 
                                     - UniqueId: 32
 
                                     - Value: LiteralInteger { unsigned_value: 3, negated: false }
 
                                     - Parent: Expr(83, 1)
 
ELit[0080]                        - LiteralExpr:
 
                                     - UniqueId: 33
 
                                     - Value: LiteralInteger { unsigned_value: 2, negated: false }
 
                                     - Parent: Expr(83, 2)
 
ELit[0081]                        - LiteralExpr:
 
                                     - UniqueId: 34
 
                                     - Value: LiteralInteger { unsigned_value: 1, negated: false }
 
                                     - Parent: Expr(83, 3)
 
ELit[0082]                        - LiteralExpr:
 
                                     - UniqueId: 35
 
                                     - Value: LiteralInteger { unsigned_value: 2, negated: false }
 
                                     - Parent: Expr(83, 4)
 
                                 - Parent: Expr(85, 1)
 
                             - Parent: MemStmt(22)
 
                         - Next: 23
 
SMem[0023]            - LocalMemory:
 
                         - Variable:
 
Var [0027]                - Variable:
 
                             - Name: result_u16
 
                             - Kind: Local
 
                             - ParserType: auto
 
                             - RelativePos: 5
 
                             - UniqueScopeID: 5
 
                         - InitialValue:
 
EAsi[0093]                - AssignmentExpr:
 
                             - UniqueId: 36
 
                             - Operation: Set
 
                             - Left:
 
EVar[0092]                    - VariableExpr:
 
                                 - UniqueId: 37
 
                                 - Name: result_u16
 
                                 - Definition: Some(27)
 
                                 - Parent: Expr(93, 0)
 
                             - Right:
 
ECll[0091]                    - CallExpr:
 
                                 - UniqueId: 38
 
                                 - BuiltIn: false
 
                                 - Variant: Function
 
                                 - MethodName: slicing_magic
 
                                 - ParserType: slicing_magic<auto>
 
                                 - Arguments:
 
EVar[0086]                        - VariableExpr:
 
                                     - UniqueId: 39
 
                                     - Name: created_u16
 
                                     - Definition: Some(23)
 
                                     - Parent: Expr(91, 0)
 
ELit[0087]                        - LiteralExpr:
 
                                     - UniqueId: 40
 
                                     - Value: LiteralInteger { unsigned_value: 3, negated: false }
 
                                     - Parent: Expr(91, 1)
 
ELit[0088]                        - LiteralExpr:
 
                                     - UniqueId: 41
 
                                     - Value: LiteralInteger { unsigned_value: 2, negated: false }
 
                                     - Parent: Expr(91, 2)
 
ELit[0089]                        - LiteralExpr:
 
                                     - UniqueId: 42
 
                                     - Value: LiteralInteger { unsigned_value: 1, negated: false }
 
                                     - Parent: Expr(91, 3)
 
ELit[0090]                        - LiteralExpr:
 
                                     - UniqueId: 43
 
                                     - Value: LiteralInteger { unsigned_value: 2, negated: false }
 
                                     - Parent: Expr(91, 4)
 
                                 - Parent: Expr(93, 1)
 
                             - Parent: MemStmt(23)
 
                         - Next: 24
 
SMem[0024]            - LocalMemory:
 
                         - Variable:
 
Var [0028]                - Variable:
 
                             - Name: result_u32
 
                             - Kind: Local
 
                             - ParserType: auto
 
                             - RelativePos: 6
 
                             - UniqueScopeID: 6
 
                         - InitialValue:
 
EAsi[0101]                - AssignmentExpr:
 
                             - UniqueId: 44
 
                             - Operation: Set
 
                             - Left:
 
EVar[0100]                    - VariableExpr:
 
                                 - UniqueId: 45
 
                                 - Name: result_u32
 
                                 - Definition: Some(28)
 
                                 - Parent: Expr(101, 0)
 
                             - Right:
 
ECll[0099]                    - CallExpr:
 
                                 - UniqueId: 46
 
                                 - BuiltIn: false
 
                                 - Variant: Function
 
                                 - MethodName: slicing_magic
 
                                 - ParserType: slicing_magic<auto>
 
                                 - Arguments:
 
EVar[0094]                        - VariableExpr:
 
                                     - UniqueId: 47
 
                                     - Name: created_u32
 
                                     - Definition: Some(24)
 
                                     - Parent: Expr(99, 0)
 
ELit[0095]                        - LiteralExpr:
 
                                     - UniqueId: 48
 
                                     - Value: LiteralInteger { unsigned_value: 3, negated: false }
 
                                     - Parent: Expr(99, 1)
 
ELit[0096]                        - LiteralExpr:
 
                                     - UniqueId: 49
 
                                     - Value: LiteralInteger { unsigned_value: 2, negated: false }
 
                                     - Parent: Expr(99, 2)
 
ELit[0097]                        - LiteralExpr:
 
                                     - UniqueId: 50
 
                                     - Value: LiteralInteger { unsigned_value: 1, negated: false }
 
                                     - Parent: Expr(99, 3)
 
ELit[0098]                        - LiteralExpr:
 
                                     - UniqueId: 51
 
                                     - Value: LiteralInteger { unsigned_value: 2, negated: false }
 
                                     - Parent: Expr(99, 4)
 
                                 - Parent: Expr(101, 1)
 
                             - Parent: MemStmt(24)
 
                         - Next: 25
 
SMem[0025]            - LocalMemory:
 
                         - Variable:
 
Var [0029]                - Variable:
 
                             - Name: result_u64
 
                             - Kind: Local
 
                             - ParserType: auto
 
                             - RelativePos: 7
 
                             - UniqueScopeID: 7
 
                         - InitialValue:
 
EAsi[0109]                - AssignmentExpr:
 
                             - UniqueId: 52
 
                             - Operation: Set
 
                             - Left:
 
EVar[0108]                    - VariableExpr:
 
                                 - UniqueId: 53
 
                                 - Name: result_u64
 
                                 - Definition: Some(29)
 
                                 - Parent: Expr(109, 0)
 
                             - Right:
 
ECll[0107]                    - CallExpr:
 
                                 - UniqueId: 54
 
                                 - BuiltIn: false
 
                                 - Variant: Function
 
                                 - MethodName: slicing_magic
 
                                 - ParserType: slicing_magic<auto>
 
                                 - Arguments:
 
EVar[0102]                        - VariableExpr:
 
                                     - UniqueId: 55
 
                                     - Name: created_u64
 
                                     - Definition: Some(25)
 
                                     - Parent: Expr(107, 0)
 
ELit[0103]                        - LiteralExpr:
 
                                     - UniqueId: 56
 
                                     - Value: LiteralInteger { unsigned_value: 3, negated: false }
 
                                     - Parent: Expr(107, 1)
 
ELit[0104]                        - LiteralExpr:
 
                                     - UniqueId: 57
 
                                     - Value: LiteralInteger { unsigned_value: 2, negated: false }
 
                                     - Parent: Expr(107, 2)
 
ELit[0105]                        - LiteralExpr:
 
                                     - UniqueId: 58
 
                                     - Value: LiteralInteger { unsigned_value: 1, negated: false }
 
                                     - Parent: Expr(107, 3)
 
ELit[0106]                        - LiteralExpr:
 
                                     - UniqueId: 59
 
                                     - Value: LiteralInteger { unsigned_value: 2, negated: false }
 
                                     - Parent: Expr(107, 4)
 
                                 - Parent: Expr(109, 1)
 
                             - Parent: MemStmt(25)
 
                         - Next: 26
 
SMem[0026]            - LocalMemory:
 
                         - Variable:
 
Var [0030]                - Variable:
 
                             - Name: result_s08
 
                             - Kind: Local
 
                             - ParserType: auto
 
                             - RelativePos: 8
 
                             - UniqueScopeID: 8
 
                         - InitialValue:
 
EAsi[0121]                - AssignmentExpr:
 
                             - UniqueId: 60
 
                             - Operation: Set
 
                             - Left:
 
EVar[0120]                    - VariableExpr:
 
                                 - UniqueId: 61
 
                                 - Name: result_s08
 
                                 - Definition: Some(30)
 
                                 - Parent: Expr(121, 0)
 
                             - Right:
 
ECll[0119]                    - CallExpr:
 
                                 - UniqueId: 62
 
                                 - BuiltIn: false
 
                                 - Variant: Function
 
                                 - MethodName: slicing_magic
 
                                 - ParserType: slicing_magic<auto>
 
                                 - Arguments:
 
ECll[0114]                        - CallExpr:
 
                                     - UniqueId: 63
 
                                     - BuiltIn: false
 
                                     - Variant: Function
 
                                     - MethodName: create_holder
 
                                     - ParserType: create_holder<s8>
 
                                     - Arguments:
 
ELit[0110]                            - LiteralExpr:
 
                                         - UniqueId: 64
 
                                         - Value: LiteralInteger { unsigned_value: 0, negated: false }
 
                                         - Parent: Expr(114, 0)
 
ELit[0111]                            - LiteralExpr:
 
                                         - UniqueId: 65
 
                                         - Value: LiteralInteger { unsigned_value: 5, negated: false }
 
                                         - Parent: Expr(114, 1)
 
ELit[0112]                            - LiteralExpr:
 
                                         - UniqueId: 66
 
                                         - Value: LiteralInteger { unsigned_value: 2, negated: false }
 
                                         - Parent: Expr(114, 2)
 
ELit[0113]                            - LiteralExpr:
 
                                         - UniqueId: 67
 
                                         - Value: LiteralInteger { unsigned_value: 8, negated: false }
 
                                         - Parent: Expr(114, 3)
 
                                     - Parent: Expr(119, 0)
 
ELit[0115]                        - LiteralExpr:
 
                                     - UniqueId: 68
 
                                     - Value: LiteralInteger { unsigned_value: 3, negated: false }
 
                                     - Parent: Expr(119, 1)
 
ELit[0116]                        - LiteralExpr:
 
                                     - UniqueId: 69
 
                                     - Value: LiteralInteger { unsigned_value: 2, negated: false }
 
                                     - Parent: Expr(119, 2)
 
ELit[0117]                        - LiteralExpr:
 
                                     - UniqueId: 70
 
                                     - Value: LiteralInteger { unsigned_value: 1, negated: false }
 
                                     - Parent: Expr(119, 3)
 
ELit[0118]                        - LiteralExpr:
 
                                     - UniqueId: 71
 
                                     - Value: LiteralInteger { unsigned_value: 2, negated: false }
 
                                     - Parent: Expr(119, 4)
 
                                 - Parent: Expr(121, 1)
 
                             - Parent: MemStmt(26)
 
                         - Next: 27
 
SMem[0027]            - LocalMemory:
 
                         - Variable:
 
Var [0031]                - Variable:
 
                             - Name: result_s16
 
                             - Kind: Local
 
                             - ParserType: auto
 
                             - RelativePos: 9
 
                             - UniqueScopeID: 9
 
                         - InitialValue:
 
EAsi[0133]                - AssignmentExpr:
 
                             - UniqueId: 72
 
                             - Operation: Set
 
                             - Left:
 
EVar[0132]                    - VariableExpr:
 
                                 - UniqueId: 73
 
                                 - Name: result_s16
 
                                 - Definition: Some(31)
 
                                 - Parent: Expr(133, 0)
 
                             - Right:
 
ECll[0131]                    - CallExpr:
 
                                 - UniqueId: 74
 
                                 - BuiltIn: false
 
                                 - Variant: Function
 
                                 - MethodName: slicing_magic
 
                                 - ParserType: slicing_magic<auto>
 
                                 - Arguments:
 
ECll[0126]                        - CallExpr:
 
                                     - UniqueId: 75
 
                                     - BuiltIn: false
 
                                     - Variant: Function
 
                                     - MethodName: create_holder
 
                                     - ParserType: create_holder<s16>
 
                                     - Arguments:
 
ELit[0122]                            - LiteralExpr:
 
                                         - UniqueId: 76
 
                                         - Value: LiteralInteger { unsigned_value: 0, negated: false }
 
                                         - Parent: Expr(126, 0)
 
ELit[0123]                            - LiteralExpr:
 
                                         - UniqueId: 77
 
                                         - Value: LiteralInteger { unsigned_value: 5, negated: false }
 
                                         - Parent: Expr(126, 1)
 
ELit[0124]                            - LiteralExpr:
 
                                         - UniqueId: 78
 
                                         - Value: LiteralInteger { unsigned_value: 2, negated: false }
 
                                         - Parent: Expr(126, 2)
 
ELit[0125]                            - LiteralExpr:
 
                                         - UniqueId: 79
 
                                         - Value: LiteralInteger { unsigned_value: 8, negated: false }
 
                                         - Parent: Expr(126, 3)
 
                                     - Parent: Expr(131, 0)
 
ELit[0127]                        - LiteralExpr:
 
                                     - UniqueId: 80
 
                                     - Value: LiteralInteger { unsigned_value: 3, negated: false }
 
                                     - Parent: Expr(131, 1)
 
ELit[0128]                        - LiteralExpr:
 
                                     - UniqueId: 81
 
                                     - Value: LiteralInteger { unsigned_value: 2, negated: false }
 
                                     - Parent: Expr(131, 2)
 
ELit[0129]                        - LiteralExpr:
 
                                     - UniqueId: 82
 
                                     - Value: LiteralInteger { unsigned_value: 1, negated: false }
 
                                     - Parent: Expr(131, 3)
 
ELit[0130]                        - LiteralExpr:
 
                                     - UniqueId: 83
 
                                     - Value: LiteralInteger { unsigned_value: 2, negated: false }
 
                                     - Parent: Expr(131, 4)
 
                                 - Parent: Expr(133, 1)
 
                             - Parent: MemStmt(27)
 
                         - Next: 28
 
SMem[0028]            - LocalMemory:
 
                         - Variable:
 
Var [0032]                - Variable:
 
                             - Name: result_s32
 
                             - Kind: Local
 
                             - ParserType: auto
 
                             - RelativePos: 10
 
                             - UniqueScopeID: 10
 
                         - InitialValue:
 
EAsi[0145]                - AssignmentExpr:
 
                             - UniqueId: 84
 
                             - Operation: Set
 
                             - Left:
 
EVar[0144]                    - VariableExpr:
 
                                 - UniqueId: 85
 
                                 - Name: result_s32
 
                                 - Definition: Some(32)
 
                                 - Parent: Expr(145, 0)
 
                             - Right:
 
ECll[0143]                    - CallExpr:
 
                                 - UniqueId: 86
 
                                 - BuiltIn: false
 
                                 - Variant: Function
 
                                 - MethodName: slicing_magic
 
                                 - ParserType: slicing_magic<auto>
 
                                 - Arguments:
 
ECll[0138]                        - CallExpr:
 
                                     - UniqueId: 87
 
                                     - BuiltIn: false
 
                                     - Variant: Function
 
                                     - MethodName: create_holder
 
                                     - ParserType: create_holder<s32>
 
                                     - Arguments:
 
ELit[0134]                            - LiteralExpr:
 
                                         - UniqueId: 88
 
                                         - Value: LiteralInteger { unsigned_value: 0, negated: false }
 
                                         - Parent: Expr(138, 0)
 
ELit[0135]                            - LiteralExpr:
 
                                         - UniqueId: 89
 
                                         - Value: LiteralInteger { unsigned_value: 5, negated: false }
 
                                         - Parent: Expr(138, 1)
 
ELit[0136]                            - LiteralExpr:
 
                                         - UniqueId: 90
 
                                         - Value: LiteralInteger { unsigned_value: 2, negated: false }
 
                                         - Parent: Expr(138, 2)
 
ELit[0137]                            - LiteralExpr:
 
                                         - UniqueId: 91
 
                                         - Value: LiteralInteger { unsigned_value: 8, negated: false }
 
                                         - Parent: Expr(138, 3)
 
                                     - Parent: Expr(143, 0)
 
ELit[0139]                        - LiteralExpr:
 
                                     - UniqueId: 92
 
                                     - Value: LiteralInteger { unsigned_value: 3, negated: false }
 
                                     - Parent: Expr(143, 1)
 
ELit[0140]                        - LiteralExpr:
 
                                     - UniqueId: 93
 
                                     - Value: LiteralInteger { unsigned_value: 2, negated: false }
 
                                     - Parent: Expr(143, 2)
 
ELit[0141]                        - LiteralExpr:
 
                                     - UniqueId: 94
 
                                     - Value: LiteralInteger { unsigned_value: 1, negated: false }
 
                                     - Parent: Expr(143, 3)
 
ELit[0142]                        - LiteralExpr:
 
                                     - UniqueId: 95
 
                                     - Value: LiteralInteger { unsigned_value: 2, negated: false }
 
                                     - Parent: Expr(143, 4)
 
                                 - Parent: Expr(145, 1)
 
                             - Parent: MemStmt(28)
 
                         - Next: 29
 
SMem[0029]            - LocalMemory:
 
                         - Variable:
 
Var [0033]                - Variable:
 
                             - Name: result_s64
 
                             - Kind: Local
 
                             - ParserType: auto
 
                             - RelativePos: 11
 
                             - UniqueScopeID: 11
 
                         - InitialValue:
 
EAsi[0157]                - AssignmentExpr:
 
                             - UniqueId: 96
 
                             - Operation: Set
 
                             - Left:
 
EVar[0156]                    - VariableExpr:
 
                                 - UniqueId: 97
 
                                 - Name: result_s64
 
                                 - Definition: Some(33)
 
                                 - Parent: Expr(157, 0)
 
                             - Right:
 
ECll[0155]                    - CallExpr:
 
                                 - UniqueId: 98
 
                                 - BuiltIn: false
 
                                 - Variant: Function
 
                                 - MethodName: slicing_magic
 
                                 - ParserType: slicing_magic<auto>
 
                                 - Arguments:
 
ECll[0150]                        - CallExpr:
 
                                     - UniqueId: 99
 
                                     - BuiltIn: false
 
                                     - Variant: Function
 
                                     - MethodName: create_holder
 
                                     - ParserType: create_holder<s64>
 
                                     - Arguments:
 
ELit[0146]                            - LiteralExpr:
 
                                         - UniqueId: 100
 
                                         - Value: LiteralInteger { unsigned_value: 0, negated: false }
 
                                         - Parent: Expr(150, 0)
 
ELit[0147]                            - LiteralExpr:
 
                                         - UniqueId: 101
 
                                         - Value: LiteralInteger { unsigned_value: 5, negated: false }
 
                                         - Parent: Expr(150, 1)
 
ELit[0148]                            - LiteralExpr:
 
                                         - UniqueId: 102
 
                                         - Value: LiteralInteger { unsigned_value: 2, negated: false }
 
                                         - Parent: Expr(150, 2)
 
ELit[0149]                            - LiteralExpr:
 
                                         - UniqueId: 103
 
                                         - Value: LiteralInteger { unsigned_value: 8, negated: false }
 
                                         - Parent: Expr(150, 3)
 
                                     - Parent: Expr(155, 0)
 
ELit[0151]                        - LiteralExpr:
 
                                     - UniqueId: 104
 
                                     - Value: LiteralInteger { unsigned_value: 3, negated: false }
 
                                     - Parent: Expr(155, 1)
 
ELit[0152]                        - LiteralExpr:
 
                                     - UniqueId: 105
 
                                     - Value: LiteralInteger { unsigned_value: 2, negated: false }
 
                                     - Parent: Expr(155, 2)
 
ELit[0153]                        - LiteralExpr:
 
                                     - UniqueId: 106
 
                                     - Value: LiteralInteger { unsigned_value: 1, negated: false }
 
                                     - Parent: Expr(155, 3)
 
ELit[0154]                        - LiteralExpr:
 
                                     - UniqueId: 107
 
                                     - Value: LiteralInteger { unsigned_value: 2, negated: false }
 
                                     - Parent: Expr(155, 4)
 
                                 - Parent: Expr(157, 1)
 
                             - Parent: MemStmt(29)
 
                         - Next: 30
 
SRet[0030]            - Return:
 
                         - Expressions:
 
EBin[0236]                - BinaryExpr:
 
                             - UniqueId: 108
 
                             - Operation: LogicalAnd
 
                             - Left:
 
EBin[0226]                    - BinaryExpr:
 
                                 - UniqueId: 109
 
                                 - Operation: LogicalAnd
 
                                 - Left:
 
EBin[0216]                        - BinaryExpr:
 
                                     - UniqueId: 110
 
                                     - Operation: LogicalAnd
 
                                     - Left:
 
EBin[0206]                            - BinaryExpr:
 
                                         - UniqueId: 111
 
                                         - Operation: LogicalAnd
 
                                         - Left:
 
EBin[0196]                                - BinaryExpr:
 
                                             - UniqueId: 112
 
                                             - Operation: LogicalAnd
 
                                             - Left:
 
EBin[0186]                                    - BinaryExpr:
 
                                                 - UniqueId: 113
 
                                                 - Operation: LogicalAnd
 
                                                 - Left:
 
EBin[0176]                                        - BinaryExpr:
 
                                                     - UniqueId: 114
 
                                                     - Operation: LogicalAnd
 
                                                     - Left:
 
EBin[0166]                                            - BinaryExpr:
 
                                                         - UniqueId: 115
 
                                                         - Operation: Equality
 
                                                         - Left:
 
EBin[0164]                                                - BinaryExpr:
 
                                                             - UniqueId: 116
 
                                                             - Operation: Add
 
                                                             - Left:
 
EIdx[0160]                                                    - IndexingExpr:
 
                                                                 - UniqueId: 117
 
                                                                 - Subject:
 
EVar[0158]                                                        - VariableExpr:
 
                                                                     - UniqueId: 118
 
                                                                     - Name: result_u08
 
                                                                     - Definition: Some(26)
 
                                                                     - Parent: Expr(160, 0)
 
                                                                 - Index:
 
ELit[0159]                                                        - LiteralExpr:
 
                                                                     - UniqueId: 119
 
                                                                     - Value: LiteralInteger { unsigned_value: 0, negated: false }
 
                                                                     - Parent: Expr(160, 1)
 
                                                                 - Parent: Expr(164, 0)
 
                                                             - Right:
 
EIdx[0163]                                                    - IndexingExpr:
 
                                                                 - UniqueId: 120
 
                                                                 - Subject:
 
EVar[0161]                                                        - VariableExpr:
 
                                                                     - UniqueId: 121
 
                                                                     - Name: result_u08
 
                                                                     - Definition: Some(26)
 
                                                                     - Parent: Expr(163, 0)
 
                                                                 - Index:
 
ELit[0162]                                                        - LiteralExpr:
 
                                                                     - UniqueId: 122
 
                                                                     - Value: LiteralInteger { unsigned_value: 1, negated: false }
 
                                                                     - Parent: Expr(163, 1)
 
                                                                 - Parent: Expr(164, 1)
 
                                                             - Parent: Expr(166, 0)
 
                                                         - Right:
 
ELit[0165]                                                - LiteralExpr:
 
                                                             - UniqueId: 123
 
                                                             - Value: LiteralInteger { unsigned_value: 6, negated: false }
 
                                                             - Parent: Expr(166, 1)
 
                                                         - Parent: Expr(176, 0)
 
                                                     - Right:
 
EBin[0175]                                            - BinaryExpr:
 
                                                         - UniqueId: 124
 
                                                         - Operation: Equality
 
                                                         - Left:
 
EBin[0173]                                                - BinaryExpr:
 
                                                             - UniqueId: 125
 
                                                             - Operation: Add
 
                                                             - Left:
 
EIdx[0169]                                                    - IndexingExpr:
 
                                                                 - UniqueId: 126
 
                                                                 - Subject:
 
EVar[0167]                                                        - VariableExpr:
 
                                                                     - UniqueId: 127
 
                                                                     - Name: result_u16
 
                                                                     - Definition: Some(27)
 
                                                                     - Parent: Expr(169, 0)
 
                                                                 - Index:
 
ELit[0168]                                                        - LiteralExpr:
 
                                                                     - UniqueId: 128
 
                                                                     - Value: LiteralInteger { unsigned_value: 0, negated: false }
 
                                                                     - Parent: Expr(169, 1)
 
                                                                 - Parent: Expr(173, 0)
 
                                                             - Right:
 
EIdx[0172]                                                    - IndexingExpr:
 
                                                                 - UniqueId: 129
 
                                                                 - Subject:
 
EVar[0170]                                                        - VariableExpr:
 
                                                                     - UniqueId: 130
 
                                                                     - Name: result_u16
 
                                                                     - Definition: Some(27)
 
                                                                     - Parent: Expr(172, 0)
 
                                                                 - Index:
 
ELit[0171]                                                        - LiteralExpr:
 
                                                                     - UniqueId: 131
 
                                                                     - Value: LiteralInteger { unsigned_value: 1, negated: false }
 
                                                                     - Parent: Expr(172, 1)
 
                                                                 - Parent: Expr(173, 1)
 
                                                             - Parent: Expr(175, 0)
 
                                                         - Right:
 
ELit[0174]                                                - LiteralExpr:
 
                                                             - UniqueId: 132
 
                                                             - Value: LiteralInteger { unsigned_value: 6, negated: false }
 
                                                             - Parent: Expr(175, 1)
 
                                                         - Parent: Expr(176, 1)
 
                                                     - Parent: Expr(186, 0)
 
                                                 - Right:
 
EBin[0185]                                        - BinaryExpr:
 
                                                     - UniqueId: 133
 
                                                     - Operation: Equality
 
                                                     - Left:
 
EBin[0183]                                            - BinaryExpr:
 
                                                         - UniqueId: 134
 
                                                         - Operation: Add
 
                                                         - Left:
 
EIdx[0179]                                                - IndexingExpr:
 
                                                             - UniqueId: 135
 
                                                             - Subject:
 
EVar[0177]                                                    - VariableExpr:
 
                                                                 - UniqueId: 136
 
                                                                 - Name: result_u32
 
                                                                 - Definition: Some(28)
 
                                                                 - Parent: Expr(179, 0)
 
                                                             - Index:
 
ELit[0178]                                                    - LiteralExpr:
 
                                                                 - UniqueId: 137
 
                                                                 - Value: LiteralInteger { unsigned_value: 0, negated: false }
 
                                                                 - Parent: Expr(179, 1)
 
                                                             - Parent: Expr(183, 0)
 
                                                         - Right:
 
EIdx[0182]                                                - IndexingExpr:
 
                                                             - UniqueId: 138
 
                                                             - Subject:
 
EVar[0180]                                                    - VariableExpr:
 
                                                                 - UniqueId: 139
 
                                                                 - Name: result_u32
 
                                                                 - Definition: Some(28)
 
                                                                 - Parent: Expr(182, 0)
 
                                                             - Index:
 
ELit[0181]                                                    - LiteralExpr:
 
                                                                 - UniqueId: 140
 
                                                                 - Value: LiteralInteger { unsigned_value: 1, negated: false }
 
                                                                 - Parent: Expr(182, 1)
 
                                                             - Parent: Expr(183, 1)
 
                                                         - Parent: Expr(185, 0)
 
                                                     - Right:
 
ELit[0184]                                            - LiteralExpr:
 
                                                         - UniqueId: 141
 
                                                         - Value: LiteralInteger { unsigned_value: 6, negated: false }
 
                                                         - Parent: Expr(185, 1)
 
                                                     - Parent: Expr(186, 1)
 
                                                 - Parent: Expr(196, 0)
 
                                             - Right:
 
EBin[0195]                                    - BinaryExpr:
 
                                                 - UniqueId: 142
 
                                                 - Operation: Equality
 
                                                 - Left:
 
EBin[0193]                                        - BinaryExpr:
 
                                                     - UniqueId: 143
 
                                                     - Operation: Add
 
                                                     - Left:
 
EIdx[0189]                                            - IndexingExpr:
 
                                                         - UniqueId: 144
 
                                                         - Subject:
 
EVar[0187]                                                - VariableExpr:
 
                                                             - UniqueId: 145
 
                                                             - Name: result_u64
 
                                                             - Definition: Some(29)
 
                                                             - Parent: Expr(189, 0)
 
                                                         - Index:
 
ELit[0188]                                                - LiteralExpr:
 
                                                             - UniqueId: 146
 
                                                             - Value: LiteralInteger { unsigned_value: 0, negated: false }
 
                                                             - Parent: Expr(189, 1)
 
                                                         - Parent: Expr(193, 0)
 
                                                     - Right:
 
EIdx[0192]                                            - IndexingExpr:
 
                                                         - UniqueId: 147
 
                                                         - Subject:
 
EVar[0190]                                                - VariableExpr:
 
                                                             - UniqueId: 148
 
                                                             - Name: result_u64
 
                                                             - Definition: Some(29)
 
                                                             - Parent: Expr(192, 0)
 
                                                         - Index:
 
ELit[0191]                                                - LiteralExpr:
 
                                                             - UniqueId: 149
 
                                                             - Value: LiteralInteger { unsigned_value: 1, negated: false }
 
                                                             - Parent: Expr(192, 1)
 
                                                         - Parent: Expr(193, 1)
 
                                                     - Parent: Expr(195, 0)
 
                                                 - Right:
 
ELit[0194]                                        - LiteralExpr:
 
                                                     - UniqueId: 150
 
                                                     - Value: LiteralInteger { unsigned_value: 6, negated: false }
 
                                                     - Parent: Expr(195, 1)
 
                                                 - Parent: Expr(196, 1)
 
                                             - Parent: Expr(206, 0)
 
                                         - Right:
 
EBin[0205]                                - BinaryExpr:
 
                                             - UniqueId: 151
 
                                             - Operation: Equality
 
                                             - Left:
 
EBin[0203]                                    - BinaryExpr:
 
                                                 - UniqueId: 152
 
                                                 - Operation: Add
 
                                                 - Left:
 
EIdx[0199]                                        - IndexingExpr:
 
                                                     - UniqueId: 153
 
                                                     - Subject:
 
EVar[0197]                                            - VariableExpr:
 
                                                         - UniqueId: 154
 
                                                         - Name: result_s08
 
                                                         - Definition: Some(30)
 
                                                         - Parent: Expr(199, 0)
 
                                                     - Index:
 
ELit[0198]                                            - LiteralExpr:
 
                                                         - UniqueId: 155
 
                                                         - Value: LiteralInteger { unsigned_value: 0, negated: false }
 
                                                         - Parent: Expr(199, 1)
 
                                                     - Parent: Expr(203, 0)
 
                                                 - Right:
 
EIdx[0202]                                        - IndexingExpr:
 
                                                     - UniqueId: 156
 
                                                     - Subject:
 
EVar[0200]                                            - VariableExpr:
 
                                                         - UniqueId: 157
 
                                                         - Name: result_s08
 
                                                         - Definition: Some(30)
 
                                                         - Parent: Expr(202, 0)
 
                                                     - Index:
 
ELit[0201]                                            - LiteralExpr:
 
                                                         - UniqueId: 158
 
                                                         - Value: LiteralInteger { unsigned_value: 1, negated: false }
 
                                                         - Parent: Expr(202, 1)
 
                                                     - Parent: Expr(203, 1)
 
                                                 - Parent: Expr(205, 0)
 
                                             - Right:
 
ELit[0204]                                    - LiteralExpr:
 
                                                 - UniqueId: 159
 
                                                 - Value: LiteralInteger { unsigned_value: 6, negated: false }
 
                                                 - Parent: Expr(205, 1)
 
                                             - Parent: Expr(206, 1)
 
                                         - Parent: Expr(216, 0)
 
                                     - Right:
 
EBin[0215]                            - BinaryExpr:
 
                                         - UniqueId: 160
 
                                         - Operation: Equality
 
                                         - Left:
 
EBin[0213]                                - BinaryExpr:
 
                                             - UniqueId: 161
 
                                             - Operation: Add
 
                                             - Left:
 
EIdx[0209]                                    - IndexingExpr:
 
                                                 - UniqueId: 162
 
                                                 - Subject:
 
EVar[0207]                                        - VariableExpr:
 
                                                     - UniqueId: 163
 
                                                     - Name: result_s16
 
                                                     - Definition: Some(31)
 
                                                     - Parent: Expr(209, 0)
 
                                                 - Index:
 
ELit[0208]                                        - LiteralExpr:
 
                                                     - UniqueId: 164
 
                                                     - Value: LiteralInteger { unsigned_value: 0, negated: false }
 
                                                     - Parent: Expr(209, 1)
 
                                                 - Parent: Expr(213, 0)
 
                                             - Right:
 
EIdx[0212]                                    - IndexingExpr:
 
                                                 - UniqueId: 165
 
                                                 - Subject:
 
EVar[0210]                                        - VariableExpr:
 
                                                     - UniqueId: 166
 
                                                     - Name: result_s16
 
                                                     - Definition: Some(31)
 
                                                     - Parent: Expr(212, 0)
 
                                                 - Index:
 
ELit[0211]                                        - LiteralExpr:
 
                                                     - UniqueId: 167
 
                                                     - Value: LiteralInteger { unsigned_value: 1, negated: false }
 
                                                     - Parent: Expr(212, 1)
 
                                                 - Parent: Expr(213, 1)
 
                                             - Parent: Expr(215, 0)
 
                                         - Right:
 
ELit[0214]                                - LiteralExpr:
 
                                             - UniqueId: 168
 
                                             - Value: LiteralInteger { unsigned_value: 6, negated: false }
 
                                             - Parent: Expr(215, 1)
 
                                         - Parent: Expr(216, 1)
 
                                     - Parent: Expr(226, 0)
 
                                 - Right:
 
EBin[0225]                        - BinaryExpr:
 
                                     - UniqueId: 169
 
                                     - Operation: Equality
 
                                     - Left:
 
EBin[0223]                            - BinaryExpr:
 
                                         - UniqueId: 170
 
                                         - Operation: Add
 
                                         - Left:
 
EIdx[0219]                                - IndexingExpr:
 
                                             - UniqueId: 171
 
                                             - Subject:
 
EVar[0217]                                    - VariableExpr:
 
                                                 - UniqueId: 172
 
                                                 - Name: result_s32
 
                                                 - Definition: Some(32)
 
                                                 - Parent: Expr(219, 0)
 
                                             - Index:
 
ELit[0218]                                    - LiteralExpr:
 
                                                 - UniqueId: 173
 
                                                 - Value: LiteralInteger { unsigned_value: 0, negated: false }
 
                                                 - Parent: Expr(219, 1)
 
                                             - Parent: Expr(223, 0)
 
                                         - Right:
 
EIdx[0222]                                - IndexingExpr:
 
                                             - UniqueId: 174
 
                                             - Subject:
 
EVar[0220]                                    - VariableExpr:
 
                                                 - UniqueId: 175
 
                                                 - Name: result_s32
 
                                                 - Definition: Some(32)
 
                                                 - Parent: Expr(222, 0)
 
                                             - Index:
 
ELit[0221]                                    - LiteralExpr:
 
                                                 - UniqueId: 176
 
                                                 - Value: LiteralInteger { unsigned_value: 1, negated: false }
 
                                                 - Parent: Expr(222, 1)
 
                                             - Parent: Expr(223, 1)
 
                                         - Parent: Expr(225, 0)
 
                                     - Right:
 
ELit[0224]                            - LiteralExpr:
 
                                         - UniqueId: 177
 
                                         - Value: LiteralInteger { unsigned_value: 6, negated: false }
 
                                         - Parent: Expr(225, 1)
 
                                     - Parent: Expr(226, 1)
 
                                 - Parent: Expr(236, 0)
 
                             - Right:
 
EBin[0235]                    - BinaryExpr:
 
                                 - UniqueId: 178
 
                                 - Operation: Equality
 
                                 - Left:
 
EBin[0233]                        - BinaryExpr:
 
                                     - UniqueId: 179
 
                                     - Operation: Add
 
                                     - Left:
 
EIdx[0229]                            - IndexingExpr:
 
                                         - UniqueId: 180
 
                                         - Subject:
 
EVar[0227]                                - VariableExpr:
 
                                             - UniqueId: 181
 
                                             - Name: result_s64
 
                                             - Definition: Some(33)
 
                                             - Parent: Expr(229, 0)
 
                                         - Index:
 
ELit[0228]                                - LiteralExpr:
 
                                             - UniqueId: 182
 
                                             - Value: LiteralInteger { unsigned_value: 0, negated: false }
 
                                             - Parent: Expr(229, 1)
 
                                         - Parent: Expr(233, 0)
 
                                     - Right:
 
EIdx[0232]                            - IndexingExpr:
 
                                         - UniqueId: 183
 
                                         - Subject:
 
EVar[0230]                                - VariableExpr:
 
                                             - UniqueId: 184
 
                                             - Name: result_s64
 
                                             - Definition: Some(33)
 
                                             - Parent: Expr(232, 0)
 
                                         - Index:
 
ELit[0231]                                - LiteralExpr:
 
                                             - UniqueId: 185
 
                                             - Value: LiteralInteger { unsigned_value: 1, negated: false }
 
                                             - Parent: Expr(232, 1)
 
                                         - Parent: Expr(233, 1)
 
                                     - Parent: Expr(235, 0)
 
                                 - Right:
 
ELit[0234]                        - LiteralExpr:
 
                                     - UniqueId: 186
 
                                     - Value: LiteralInteger { unsigned_value: 6, negated: false }
 
                                     - Parent: Expr(235, 1)
 
                                 - Parent: Expr(236, 1)
 
                             - Parent: ReturnStmt(30)
src/protocol/ast_printer.rs
Show inline comments
 
#![allow(dead_code)]
 

	
 
use std::fmt::{Debug, Display};
 
use std::io::Write as IOWrite;
 

	
 
use super::ast::*;
 
use super::token_parsing::*;
 

	
 
const INDENT: usize = 2;
 

	
 
const PREFIX_EMPTY: &'static str = "    ";
 
const PREFIX_ROOT_ID: &'static str = "Root";
 
const PREFIX_PRAGMA_ID: &'static str = "Prag";
 
const PREFIX_IMPORT_ID: &'static str = "Imp ";
 
const PREFIX_TYPE_ANNOT_ID: &'static str = "TyAn";
 
const PREFIX_VARIABLE_ID: &'static str = "Var ";
 
const PREFIX_DEFINITION_ID: &'static str = "Def ";
 
const PREFIX_STRUCT_ID: &'static str = "DefS";
 
const PREFIX_ENUM_ID: &'static str = "DefE";
 
const PREFIX_UNION_ID: &'static str = "DefU";
 
const PREFIX_COMPONENT_ID: &'static str = "DefC";
 
const PREFIX_FUNCTION_ID: &'static str = "DefF";
 
const PREFIX_STMT_ID: &'static str = "Stmt";
 
const PREFIX_BLOCK_STMT_ID: &'static str = "SBl ";
 
const PREFIX_ENDBLOCK_STMT_ID: &'static str = "SEBl";
 
const PREFIX_LOCAL_STMT_ID: &'static str = "SLoc";
 
const PREFIX_MEM_STMT_ID: &'static str = "SMem";
 
const PREFIX_CHANNEL_STMT_ID: &'static str = "SCha";
 
const PREFIX_SKIP_STMT_ID: &'static str = "SSki";
 
const PREFIX_LABELED_STMT_ID: &'static str = "SLab";
 
const PREFIX_IF_STMT_ID: &'static str = "SIf ";
 
const PREFIX_ENDIF_STMT_ID: &'static str = "SEIf";
 
const PREFIX_WHILE_STMT_ID: &'static str = "SWhi";
 
const PREFIX_ENDWHILE_STMT_ID: &'static str = "SEWh";
 
const PREFIX_BREAK_STMT_ID: &'static str = "SBre";
 
const PREFIX_CONTINUE_STMT_ID: &'static str = "SCon";
 
const PREFIX_SYNC_STMT_ID: &'static str = "SSyn";
 
const PREFIX_ENDSYNC_STMT_ID: &'static str = "SESy";
 
const PREFIX_FORK_STMT_ID: &'static str = "SFrk";
 
const PREFIX_END_FORK_STMT_ID: &'static str = "SEFk";
 
const PREFIX_SELECT_STMT_ID: &'static str = "SSel";
 
const PREFIX_END_SELECT_STMT_ID: &'static str = "SESl";
 
const PREFIX_RETURN_STMT_ID: &'static str = "SRet";
 
const PREFIX_ASSERT_STMT_ID: &'static str = "SAsr";
 
const PREFIX_GOTO_STMT_ID: &'static str = "SGot";
 
const PREFIX_NEW_STMT_ID: &'static str = "SNew";
 
const PREFIX_PUT_STMT_ID: &'static str = "SPut";
 
const PREFIX_EXPR_STMT_ID: &'static str = "SExp";
 
const PREFIX_ASSIGNMENT_EXPR_ID: &'static str = "EAsi";
 
const PREFIX_BINDING_EXPR_ID: &'static str = "EBnd";
 
const PREFIX_CONDITIONAL_EXPR_ID: &'static str = "ECnd";
 
const PREFIX_BINARY_EXPR_ID: &'static str = "EBin";
 
const PREFIX_UNARY_EXPR_ID: &'static str = "EUna";
 
const PREFIX_INDEXING_EXPR_ID: &'static str = "EIdx";
 
const PREFIX_SLICING_EXPR_ID: &'static str = "ESli";
 
const PREFIX_SELECT_EXPR_ID: &'static str = "ESel";
 
const PREFIX_LITERAL_EXPR_ID: &'static str = "ELit";
 
const PREFIX_CAST_EXPR_ID: &'static str = "ECas";
 
const PREFIX_CALL_EXPR_ID: &'static str = "ECll";
 
const PREFIX_VARIABLE_EXPR_ID: &'static str = "EVar";
 

	
 
struct KV<'a> {
 
    buffer: &'a mut String,
 
    prefix: Option<(&'static str, i32)>,
 
    indent: usize,
 
    temp_key: &'a mut String,
 
    temp_val: &'a mut String,
 
}
 

	
 
impl<'a> KV<'a> {
 
    fn new(buffer: &'a mut String, temp_key: &'a mut String, temp_val: &'a mut String, indent: usize) -> Self {
 
        temp_key.clear();
 
        temp_val.clear();
 
        KV{
 
            buffer,
 
            prefix: None,
 
            indent,
 
            temp_key,
 
            temp_val
 
        }
 
    }
 

	
 
    fn with_id(mut self, prefix: &'static str, id: i32) -> Self {
 
        self.prefix = Some((prefix, id));
 
        self
 
    }
 

	
 
    fn with_s_key(self, key: &str) -> Self {
 
        self.temp_key.push_str(key);
 
        self
 
    }
 

	
 
    fn with_d_key<D: Display>(self, key: &D) -> Self {
 
        self.temp_key.push_str(&key.to_string());
 
        self
 
    }
 

	
 
    fn with_s_val(self, val: &str) -> Self {
 
        self.temp_val.push_str(val);
 
        self
 
    }
 

	
 
    fn with_disp_val<D: Display>(self, val: &D) -> Self {
 
        self.temp_val.push_str(&format!("{}", val));
 
        self
 
    }
 

	
 
    fn with_debug_val<D: Debug>(self, val: &D) -> Self {
 
        self.temp_val.push_str(&format!("{:?}", val));
 
        self
 
    }
 

	
 
    fn with_identifier_val(self, val: &Identifier) -> Self {
 
        self.temp_val.push_str(val.value.as_str());
 
        self
 
    }
 

	
 
    fn with_opt_disp_val<D: Display>(self, val: Option<&D>) -> Self {
 
        match val {
 
            Some(v) => { self.temp_val.push_str(&format!("Some({})", v)); },
 
            None => { self.temp_val.push_str("None"); }
 
        }
 
        self
 
    }
 

	
 
    fn with_opt_identifier_val(self, val: Option<&Identifier>) -> Self {
 
        match val {
 
            Some(v) => {
 
                self.temp_val.push_str("Some(");
 
                self.temp_val.push_str(v.value.as_str());
 
                self.temp_val.push(')');
 
            },
 
            None => {
 
                self.temp_val.push_str("None");
 
            }
 
        }
 
        self
 
    }
 

	
 
    fn with_custom_val<F: Fn(&mut String)>(mut self, val_fn: F) -> Self {
 
        val_fn(&mut self.temp_val);
 
        self
 
    }
 
}
 

	
 
impl<'a> Drop for KV<'a> {
 
    fn drop(&mut self) {
 
        // Prefix and indent
 
        if let Some((prefix, id)) = &self.prefix {
 
            self.buffer.push_str(&format!("{}[{:04}]", prefix, id));
 
        } else {
 
            self.buffer.push_str("           ");
 
        }
 

	
 
        for _ in 0..self.indent * INDENT {
 
            self.buffer.push(' ');
 
        }
 

	
 
        // Leading dash
 
        self.buffer.push_str("- ");
 

	
 
        // Key and value
 
        self.buffer.push_str(self.temp_key);
 
        if self.temp_val.is_empty() {
 
            self.buffer.push(':');
 
        } else {
 
            self.buffer.push_str(": ");
 
            self.buffer.push_str(&self.temp_val);
 
        }
 
        self.buffer.push('\n');
 
    }
 
}
 

	
 
pub(crate) struct ASTWriter {
 
    cur_definition: Option<DefinitionId>,
 
    buffer: String,
 
    temp1: String,
 
    temp2: String,
 
}
 

	
 
impl ASTWriter {
 
    pub(crate) fn new() -> Self {
 
        Self{
 
            cur_definition: None,
 
            buffer: String::with_capacity(4096),
 
            temp1: String::with_capacity(256),
 
            temp2: String::with_capacity(256),
 
        }
 
    }
 
    pub(crate) fn write_ast<W: IOWrite>(&mut self, w: &mut W, heap: &Heap) {
 
        for root_id in heap.protocol_descriptions.iter().map(|v| v.this) {
 
            self.write_module(heap, root_id);
 
            w.write_all(self.buffer.as_bytes()).expect("flush buffer");
 
            self.buffer.clear();
 
        }
 
    }
 

	
 
    //--------------------------------------------------------------------------
 
    // Top-level module writing
 
    //--------------------------------------------------------------------------
 

	
 
    fn write_module(&mut self, heap: &Heap, root_id: RootId) {
 
        self.kv(0).with_id(PREFIX_ROOT_ID, root_id.index)
 
            .with_s_key("Module");
 

	
 
        let root = &heap[root_id];
 
        self.kv(1).with_s_key("Pragmas");
 
        for pragma_id in &root.pragmas {
 
            self.write_pragma(heap, *pragma_id, 2);
 
        }
 

	
 
        self.kv(1).with_s_key("Imports");
 
        for import_id in &root.imports {
 
            self.write_import(heap, *import_id, 2);
 
        }
 

	
 
        self.kv(1).with_s_key("Definitions");
 
        for def_id in &root.definitions {
 
            self.write_definition(heap, *def_id, 2);
 
        }
 
    }
 

	
 
    fn write_pragma(&mut self, heap: &Heap, pragma_id: PragmaId, indent: usize) {
 
        match &heap[pragma_id] {
 
            Pragma::Version(pragma) => {
 
                self.kv(indent).with_id(PREFIX_PRAGMA_ID, pragma.this.index)
 
                    .with_s_key("PragmaVersion")
 
                    .with_disp_val(&pragma.version);
 
            },
 
            Pragma::Module(pragma) => {
 
                self.kv(indent).with_id(PREFIX_PRAGMA_ID, pragma.this.index)
 
                    .with_s_key("PragmaModule")
 
                    .with_identifier_val(&pragma.value);
 
            }
 
        }
 
    }
 

	
 
    fn write_import(&mut self, heap: &Heap, import_id: ImportId, indent: usize) {
 
        let import = &heap[import_id];
 
        let indent2 = indent + 1;
 

	
 
        match import {
 
            Import::Module(import) => {
 
                self.kv(indent).with_id(PREFIX_IMPORT_ID, import.this.index)
 
                    .with_s_key("ImportModule");
 

	
 
                self.kv(indent2).with_s_key("Name").with_identifier_val(&import.module);
 
                self.kv(indent2).with_s_key("Alias").with_identifier_val(&import.alias);
 
                self.kv(indent2).with_s_key("Target").with_disp_val(&import.module_id.index);
 
            },
 
            Import::Symbols(import) => {
 
                self.kv(indent).with_id(PREFIX_IMPORT_ID, import.this.index)
 
                    .with_s_key("ImportSymbol");
 

	
 
                self.kv(indent2).with_s_key("Name").with_identifier_val(&import.module);
 
                self.kv(indent2).with_s_key("Target").with_disp_val(&import.module_id.index);
 

	
 
                self.kv(indent2).with_s_key("Symbols");
 

	
 
                let indent3 = indent2 + 1;
 
                let indent4 = indent3 + 1;
 
                for symbol in &import.symbols {
 
                    self.kv(indent3).with_s_key("AliasedSymbol");
 
                    self.kv(indent4).with_s_key("Name").with_identifier_val(&symbol.name);
 
                    self.kv(indent4).with_s_key("Alias").with_opt_identifier_val(symbol.alias.as_ref());
 
                    self.kv(indent4).with_s_key("Definition").with_disp_val(&symbol.definition_id.index);
 
                }
 
            }
 
        }
 
    }
 

	
 
    //--------------------------------------------------------------------------
 
    // Top-level definition writing
 
    //--------------------------------------------------------------------------
 

	
 
    fn write_definition(&mut self, heap: &Heap, def_id: DefinitionId, indent: usize) {
 
        self.cur_definition = Some(def_id);
 
        let indent2 = indent + 1;
 
        let indent3 = indent2 + 1;
 
        let indent4 = indent3 + 1;
 

	
 
        match &heap[def_id] {
 
            Definition::Struct(def) => {
 
                self.kv(indent).with_id(PREFIX_STRUCT_ID, def.this.0.index)
 
                    .with_s_key("DefinitionStruct");
 

	
 
                self.kv(indent2).with_s_key("Name").with_identifier_val(&def.identifier);
 
                for poly_var_id in &def.poly_vars {
 
                    self.kv(indent3).with_s_key("PolyVar").with_identifier_val(&poly_var_id);
 
                }
 

	
 
                self.kv(indent2).with_s_key("Fields");
 
                for field in &def.fields {
 
                    self.kv(indent3).with_s_key("Field");
 
                    self.kv(indent4).with_s_key("Name")
 
                        .with_identifier_val(&field.field);
 
                    self.kv(indent4).with_s_key("Type")
 
                        .with_custom_val(|s| write_parser_type(s, heap, &field.parser_type));
 
                }
 
            },
 
            Definition::Enum(def) => {
 
                self.kv(indent).with_id(PREFIX_ENUM_ID, def.this.0.index)
 
                    .with_s_key("DefinitionEnum");
 

	
 
                self.kv(indent2).with_s_key("Name").with_identifier_val(&def.identifier);
 
                for poly_var_id in &def.poly_vars {
 
                    self.kv(indent3).with_s_key("PolyVar").with_identifier_val(&poly_var_id);
 
                }
 

	
 
                self.kv(indent2).with_s_key("Variants");
 
                for variant in &def.variants {
 
                    self.kv(indent3).with_s_key("Variant");
 
                    self.kv(indent4).with_s_key("Name")
 
                        .with_identifier_val(&variant.identifier);
 
                    let variant_value = self.kv(indent4).with_s_key("Value");
 
                    match &variant.value {
 
                        EnumVariantValue::None => variant_value.with_s_val("None"),
 
                        EnumVariantValue::Integer(value) => variant_value.with_disp_val(value),
 
                    };
 
                }
 
            },
 
            Definition::Union(def) => {
 
                self.kv(indent).with_id(PREFIX_UNION_ID, def.this.0.index)
 
                    .with_s_key("DefinitionUnion");
 

	
 
                self.kv(indent2).with_s_key("Name").with_identifier_val(&def.identifier);
 
                for poly_var_id in &def.poly_vars {
 
                    self.kv(indent3).with_s_key("PolyVar").with_identifier_val(&poly_var_id);
 
                }
 

	
 
                self.kv(indent2).with_s_key("Variants");
 
                for variant in &def.variants {
 
                    self.kv(indent3).with_s_key("Variant");
 
                    self.kv(indent4).with_s_key("Name")
 
                        .with_identifier_val(&variant.identifier);
 
                        
 
                    if variant.value.is_empty() {
 
                        self.kv(indent4).with_s_key("Value").with_s_val("None");
 
                    } else {
 
                        self.kv(indent4).with_s_key("Values");
 
                        for embedded in &variant.value {
 
                            self.kv(indent4+1).with_s_key("Value")
 
                                .with_custom_val(|v| write_parser_type(v, heap, embedded));
 
                        }
 
                    }
 
                }
 
            }
 
            Definition::Function(def) => {
 
                self.kv(indent).with_id(PREFIX_FUNCTION_ID, def.this.0.index)
 
                    .with_s_key("DefinitionFunction");
 

	
 
                self.kv(indent2).with_s_key("Name").with_identifier_val(&def.identifier);
 
                for poly_var_id in &def.poly_vars {
 
                    self.kv(indent3).with_s_key("PolyVar").with_identifier_val(&poly_var_id);
 
                }
 

	
 
                self.kv(indent2).with_s_key("ReturnParserType")
 
                    .with_custom_val(|s| write_parser_type(s, heap, &def.return_type));
 

	
 
                self.kv(indent2).with_s_key("Parameters");
 
                for variable_id in &def.parameters {
 
                    self.write_variable(heap, *variable_id, indent3);
 
                }
 

	
 
                self.kv(indent2).with_s_key("Body");
 
                self.write_stmt(heap, def.body.upcast(), indent3);
 
            },
 
            Definition::Component(def) => {
 
                self.kv(indent).with_id(PREFIX_COMPONENT_ID,def.this.0.index)
 
                    .with_s_key("DefinitionComponent");
 

	
 
                self.kv(indent2).with_s_key("Name").with_identifier_val(&def.identifier);
 
                self.kv(indent2).with_s_key("Variant").with_debug_val(&def.variant);
 

	
 
                self.kv(indent2).with_s_key("PolymorphicVariables");
 
                for poly_var_id in &def.poly_vars {
 
                    self.kv(indent3).with_s_key("PolyVar").with_identifier_val(&poly_var_id);
 
                }
 

	
 
                self.kv(indent2).with_s_key("Parameters");
 
                for variable_id in &def.parameters {
 
                    self.write_variable(heap, *variable_id, indent3)
 
                }
 

	
 
                self.kv(indent2).with_s_key("Body");
 
                self.write_stmt(heap, def.body.upcast(), indent3);
 
            }
 
        }
 
    }
 

	
 
    fn write_stmt(&mut self, heap: &Heap, stmt_id: StatementId, indent: usize) {
 
        let stmt = &heap[stmt_id];
 
        let indent2 = indent + 1;
 
        let indent3 = indent2 + 1;
 

	
 
        match stmt {
 
            Statement::Block(stmt) => {
 
                self.kv(indent).with_id(PREFIX_BLOCK_STMT_ID, stmt.this.0.index)
 
                    .with_s_key("Block");
 
                self.kv(indent2).with_s_key("EndBlockID").with_disp_val(&stmt.end_block.0.index);
 
                self.kv(indent2).with_s_key("ScopeID").with_disp_val(&stmt.scope.index);
 

	
 
                self.kv(indent2).with_s_key("Statements");
 
                for stmt_id in &stmt.statements {
 
                    self.write_stmt(heap, *stmt_id, indent3);
 
                }
 
            },
 
            Statement::EndBlock(stmt) => {
 
                self.kv(indent).with_id(PREFIX_ENDBLOCK_STMT_ID, stmt.this.0.index)
 
                    .with_s_key("EndBlock");
 
                self.kv(indent2).with_s_key("StartBlockID").with_disp_val(&stmt.start_block.0.index);
 
            }
 
            Statement::Local(stmt) => {
 
                match stmt {
 
                    LocalStatement::Channel(stmt) => {
 
                        self.kv(indent).with_id(PREFIX_CHANNEL_STMT_ID, stmt.this.0.0.index)
 
                            .with_s_key("LocalChannel");
 

	
 
                        self.kv(indent2).with_s_key("From");
 
                        self.write_variable(heap, stmt.from, indent3);
 
                        self.kv(indent2).with_s_key("To");
 
                        self.write_variable(heap, stmt.to, indent3);
 
                        self.kv(indent2).with_s_key("Next").with_disp_val(&stmt.next.index);
 
                    },
 
                    LocalStatement::Memory(stmt) => {
 
                        self.kv(indent).with_id(PREFIX_MEM_STMT_ID, stmt.this.0.0.index)
 
                            .with_s_key("LocalMemory");
 

	
 
                        self.kv(indent2).with_s_key("Variable");
 
                        self.write_variable(heap, stmt.variable, indent3);
 
                        self.kv(indent2).with_s_key("InitialValue");
 
                        self.write_expr(heap, stmt.initial_expr.upcast(), indent3);
 
                        self.kv(indent2).with_s_key("Next").with_disp_val(&stmt.next.index);
 
                    }
 
                }
 
            },
 
            Statement::Labeled(stmt) => {
 
                self.kv(indent).with_id(PREFIX_LABELED_STMT_ID, stmt.this.0.index)
 
                    .with_s_key("Labeled");
 

	
 
                self.kv(indent2).with_s_key("Label").with_identifier_val(&stmt.label);
 
                self.kv(indent2).with_s_key("Statement");
 
                self.write_stmt(heap, stmt.body, indent3);
 
            },
 
            Statement::If(stmt) => {
 
                self.kv(indent).with_id(PREFIX_IF_STMT_ID, stmt.this.0.index)
 
                    .with_s_key("If");
 

	
 
                self.kv(indent2).with_s_key("EndIf").with_disp_val(&stmt.end_if.0.index);
 

	
 
                self.kv(indent2).with_s_key("Condition");
 
                self.write_expr(heap, stmt.test, indent3);
 

	
 
                self.kv(indent2).with_s_key("TrueBody");
 
                self.write_stmt(heap, stmt.true_case.body, indent3);
 

	
 
                if let Some(false_body) = stmt.false_case {
 
                    self.kv(indent2).with_s_key("FalseBody");
 
                    self.write_stmt(heap, false_body.body, indent3);
 
                }
 
            },
 
            Statement::EndIf(stmt) => {
 
                self.kv(indent).with_id(PREFIX_ENDIF_STMT_ID, stmt.this.0.index)
 
                    .with_s_key("EndIf");
 
                self.kv(indent2).with_s_key("StartIf").with_disp_val(&stmt.start_if.0.index);
 
                self.kv(indent2).with_s_key("Next").with_disp_val(&stmt.next.index);
 
            },
 
            Statement::While(stmt) => {
 
                self.kv(indent).with_id(PREFIX_WHILE_STMT_ID, stmt.this.0.index)
 
                    .with_s_key("While");
 

	
 
                self.kv(indent2).with_s_key("EndWhile").with_disp_val(&stmt.end_while.0.index);
 
                self.kv(indent2).with_s_key("InSync")
 
                    .with_disp_val(&stmt.in_sync.0.index);
 
                self.kv(indent2).with_s_key("Condition");
 
                self.write_expr(heap, stmt.test, indent3);
 
                self.kv(indent2).with_s_key("Body");
 
                self.write_stmt(heap, stmt.body, indent3);
 
            },
 
            Statement::EndWhile(stmt) => {
 
                self.kv(indent).with_id(PREFIX_ENDWHILE_STMT_ID, stmt.this.0.index)
 
                    .with_s_key("EndWhile");
 
                self.kv(indent2).with_s_key("StartWhile").with_disp_val(&stmt.start_while.0.index);
 
                self.kv(indent2).with_s_key("Next").with_disp_val(&stmt.next.index);
 
            },
 
            Statement::Break(stmt) => {
 
                self.kv(indent).with_id(PREFIX_BREAK_STMT_ID, stmt.this.0.index)
 
                    .with_s_key("Break");
 
                self.kv(indent2).with_s_key("Label")
 
                    .with_opt_identifier_val(stmt.label.as_ref());
 
                self.kv(indent2).with_s_key("Target")
 
                    .with_disp_val(&stmt.target.0.index);
 
            },
 
            Statement::Continue(stmt) => {
 
                self.kv(indent).with_id(PREFIX_CONTINUE_STMT_ID, stmt.this.0.index)
 
                    .with_s_key("Continue");
 
                self.kv(indent2).with_s_key("Label")
 
                    .with_opt_identifier_val(stmt.label.as_ref());
 
                self.kv(indent2).with_s_key("Target")
 
                    .with_disp_val(&stmt.target.0.index);
 
            },
 
            Statement::Synchronous(stmt) => {
 
                self.kv(indent).with_id(PREFIX_SYNC_STMT_ID, stmt.this.0.index)
 
                    .with_s_key("Synchronous");
 
                self.kv(indent2).with_s_key("EndSync").with_disp_val(&stmt.end_sync.0.index);
 
                self.kv(indent2).with_s_key("Body");
 
                self.write_stmt(heap, stmt.body, indent3);
 
            },
 
            Statement::EndSynchronous(stmt) => {
 
                self.kv(indent).with_id(PREFIX_ENDSYNC_STMT_ID, stmt.this.0.index)
 
                    .with_s_key("EndSynchronous");
 
                self.kv(indent2).with_s_key("StartSync").with_disp_val(&stmt.start_sync.0.index);
 
                self.kv(indent2).with_s_key("Next").with_disp_val(&stmt.next.index);
 
            },
 
            Statement::Fork(stmt) => {
 
                self.kv(indent).with_id(PREFIX_FORK_STMT_ID, stmt.this.0.index)
 
                    .with_s_key("Fork");
 
                self.kv(indent2).with_s_key("EndFork").with_disp_val(&stmt.end_fork.0.index);
 
                self.kv(indent2).with_s_key("LeftBody");
 
                self.write_stmt(heap, stmt.left_body, indent3);
 

	
 
                if let Some(right_body_id) = stmt.right_body {
 
                    self.kv(indent2).with_s_key("RightBody");
 
                    self.write_stmt(heap, right_body_id, indent3);
 
                }
 
            },
 
            Statement::EndFork(stmt) => {
 
                self.kv(indent).with_id(PREFIX_END_FORK_STMT_ID, stmt.this.0.index)
 
                    .with_s_key("EndFork");
 
                self.kv(indent2).with_s_key("StartFork").with_disp_val(&stmt.start_fork.0.index);
 
                self.kv(indent2).with_s_key("Next").with_disp_val(&stmt.next.index);
 
            },
 
            Statement::Select(stmt) => {
 
                self.kv(indent).with_id(PREFIX_SELECT_STMT_ID, stmt.this.0.index)
 
                    .with_s_key("Select");
 
                self.kv(indent2).with_s_key("EndSelect").with_disp_val(&stmt.end_select.0.index);
 
                self.kv(indent2).with_s_key("Cases");
 
                let indent3 = indent2 + 1;
 
                let indent4 = indent3 + 1;
 
                for case in &stmt.cases {
 
                    self.kv(indent3).with_s_key("Guard");
 
                    self.write_stmt(heap, case.guard, indent4);
 

	
 
                    self.kv(indent3).with_s_key("Block");
 
                    self.write_stmt(heap, case.body, indent4);
 
                }
 
            },
 
            Statement::EndSelect(stmt) => {
 
                self.kv(indent).with_id(PREFIX_END_SELECT_STMT_ID, stmt.this.0.index)
 
                    .with_s_key("EndSelect");
 
                self.kv(indent2).with_s_key("StartSelect").with_disp_val(&stmt.start_select.0.index);
 
                self.kv(indent2).with_s_key("Next").with_disp_val(&stmt.next.index);
 
            }
 
            Statement::Return(stmt) => {
 
                self.kv(indent).with_id(PREFIX_RETURN_STMT_ID, stmt.this.0.index)
 
                    .with_s_key("Return");
 
                self.kv(indent2).with_s_key("Expressions");
 
                for expr_id in &stmt.expressions {
 
                    self.write_expr(heap, *expr_id, indent3);
 
                }
 
            },
 
            Statement::Goto(stmt) => {
 
                self.kv(indent).with_id(PREFIX_GOTO_STMT_ID, stmt.this.0.index)
 
                    .with_s_key("Goto");
 
                self.kv(indent2).with_s_key("Label").with_identifier_val(&stmt.label);
 
                self.kv(indent2).with_s_key("Target")
 
                    .with_disp_val(&stmt.target.0.index);
 
            },
 
            Statement::New(stmt) => {
 
                self.kv(indent).with_id(PREFIX_NEW_STMT_ID, stmt.this.0.index)
 
                    .with_s_key("New");
 
                self.kv(indent2).with_s_key("Expression");
 
                self.write_expr(heap, stmt.expression.upcast(), indent3);
 
                self.kv(indent2).with_s_key("Next").with_disp_val(&stmt.next.index);
 
            },
 
            Statement::Expression(stmt) => {
 
                self.kv(indent).with_id(PREFIX_EXPR_STMT_ID, stmt.this.0.index)
 
                    .with_s_key("ExpressionStatement");
 
                self.write_expr(heap, stmt.expression, indent2);
 
                self.kv(indent2).with_s_key("Next").with_disp_val(&stmt.next.index);
 
            }
 
        }
 
    }
 

	
 
    fn write_expr(&mut self, heap: &Heap, expr_id: ExpressionId, indent: usize) {
 
        let expr = &heap[expr_id];
 
        let indent2 = indent + 1;
 
        let indent3 = indent2 + 1;
 

	
 
        match expr {
 
            Expression::Assignment(expr) => {
 
                self.kv(indent).with_id(PREFIX_ASSIGNMENT_EXPR_ID, expr.this.0.index)
 
                    .with_s_key("AssignmentExpr");
 
                self.kv(indent2).with_s_key("UniqueId").with_disp_val(&expr.unique_id_in_definition);
 
                self.kv(indent2).with_s_key("Operation").with_debug_val(&expr.operation);
 
                self.kv(indent2).with_s_key("Left");
 
                self.write_expr(heap, expr.left, indent3);
 
                self.kv(indent2).with_s_key("Right");
 
                self.write_expr(heap, expr.right, indent3);
 
                self.kv(indent2).with_s_key("Parent")
 
                    .with_custom_val(|v| write_expression_parent(v, &expr.parent));
 
            },
 
            Expression::Binding(expr) => {
 
                self.kv(indent).with_id(PREFIX_BINARY_EXPR_ID, expr.this.0.index)
 
                    .with_s_key("BindingExpr");
 
                self.kv(indent2).with_s_key("UniqueId").with_disp_val(&expr.unique_id_in_definition);
 
                self.kv(indent2).with_s_key("BindToExpression");
 
                self.write_expr(heap, expr.bound_to, indent3);
 
                self.kv(indent2).with_s_key("BindFromExpression");
 
                self.write_expr(heap, expr.bound_from, indent3);
 
                self.kv(indent2).with_s_key("Parent")
 
                    .with_custom_val(|v| write_expression_parent(v, &expr.parent));
 
            },
 
            Expression::Conditional(expr) => {
 
                self.kv(indent).with_id(PREFIX_CONDITIONAL_EXPR_ID, expr.this.0.index)
 
                    .with_s_key("ConditionalExpr");
 
                self.kv(indent2).with_s_key("UniqueId").with_disp_val(&expr.unique_id_in_definition);
 
                self.kv(indent2).with_s_key("Condition");
 
                self.write_expr(heap, expr.test, indent3);
 
                self.kv(indent2).with_s_key("TrueExpression");
 
                self.write_expr(heap, expr.true_expression, indent3);
 
                self.kv(indent2).with_s_key("FalseExpression");
 
                self.write_expr(heap, expr.false_expression, indent3);
 
                self.kv(indent2).with_s_key("Parent")
 
                    .with_custom_val(|v| write_expression_parent(v, &expr.parent));
 
            },
 
            Expression::Binary(expr) => {
 
                self.kv(indent).with_id(PREFIX_BINARY_EXPR_ID, expr.this.0.index)
 
                    .with_s_key("BinaryExpr");
 
                self.kv(indent2).with_s_key("UniqueId").with_disp_val(&expr.unique_id_in_definition);
 
                self.kv(indent2).with_s_key("Operation").with_debug_val(&expr.operation);
 
                self.kv(indent2).with_s_key("Left");
 
                self.write_expr(heap, expr.left, indent3);
 
                self.kv(indent2).with_s_key("Right");
 
                self.write_expr(heap, expr.right, indent3);
 
                self.kv(indent2).with_s_key("Parent")
 
                    .with_custom_val(|v| write_expression_parent(v, &expr.parent));
 
            },
 
            Expression::Unary(expr) => {
 
                self.kv(indent).with_id(PREFIX_UNARY_EXPR_ID, expr.this.0.index)
 
                    .with_s_key("UnaryExpr");
 
                self.kv(indent2).with_s_key("UniqueId").with_disp_val(&expr.unique_id_in_definition);
 
                self.kv(indent2).with_s_key("Operation").with_debug_val(&expr.operation);
 
                self.kv(indent2).with_s_key("Argument");
 
                self.write_expr(heap, expr.expression, indent3);
 
                self.kv(indent2).with_s_key("Parent")
 
                    .with_custom_val(|v| write_expression_parent(v, &expr.parent));
 
            },
 
            Expression::Indexing(expr) => {
 
                self.kv(indent).with_id(PREFIX_INDEXING_EXPR_ID, expr.this.0.index)
 
                    .with_s_key("IndexingExpr");
 
                self.kv(indent2).with_s_key("UniqueId").with_disp_val(&expr.unique_id_in_definition);
 
                self.kv(indent2).with_s_key("Subject");
 
                self.write_expr(heap, expr.subject, indent3);
 
                self.kv(indent2).with_s_key("Index");
 
                self.write_expr(heap, expr.index, indent3);
 
                self.kv(indent2).with_s_key("Parent")
 
                    .with_custom_val(|v| write_expression_parent(v, &expr.parent));
 
            },
 
            Expression::Slicing(expr) => {
 
                self.kv(indent).with_id(PREFIX_SLICING_EXPR_ID, expr.this.0.index)
 
                    .with_s_key("SlicingExpr");
 
                self.kv(indent2).with_s_key("UniqueId").with_disp_val(&expr.unique_id_in_definition);
 
                self.kv(indent2).with_s_key("Subject");
 
                self.write_expr(heap, expr.subject, indent3);
 
                self.kv(indent2).with_s_key("FromIndex");
 
                self.write_expr(heap, expr.from_index, indent3);
 
                self.kv(indent2).with_s_key("ToIndex");
 
                self.write_expr(heap, expr.to_index, indent3);
 
                self.kv(indent2).with_s_key("Parent")
 
                    .with_custom_val(|v| write_expression_parent(v, &expr.parent));
 
            },
 
            Expression::Select(expr) => {
 
                self.kv(indent).with_id(PREFIX_SELECT_EXPR_ID, expr.this.0.index)
 
                    .with_s_key("SelectExpr");
 
                self.kv(indent2).with_s_key("UniqueId").with_disp_val(&expr.unique_id_in_definition);
 
                self.kv(indent2).with_s_key("Subject");
 
                self.write_expr(heap, expr.subject, indent3);
 

	
 
                match &expr.kind {
 
                    SelectKind::StructField(field_name) => {
 
                        self.kv(indent2).with_s_key("StructField").with_identifier_val(field_name);
 
                    },
 
                    SelectKind::TupleMember(member_index) => {
 
                        self.kv(indent2).with_s_key("TupleMember").with_disp_val(member_index);
 
                    },
 
                }
 

	
 
                self.kv(indent2).with_s_key("Parent")
 
                    .with_custom_val(|v| write_expression_parent(v, &expr.parent));
 
            },
 
            Expression::Literal(expr) => {
 
                self.kv(indent).with_id(PREFIX_LITERAL_EXPR_ID, expr.this.0.index)
 
                    .with_s_key("LiteralExpr");
 

	
 
                self.kv(indent2).with_s_key("UniqueId").with_disp_val(&expr.unique_id_in_definition);
 
                let val = self.kv(indent2).with_s_key("Value");
 
                match &expr.value {
 
                    Literal::Null => { val.with_s_val("null"); },
 
                    Literal::True => { val.with_s_val("true"); },
 
                    Literal::False => { val.with_s_val("false"); },
 
                    Literal::Character(data) => { val.with_disp_val(data); },
 
                    Literal::String(data) => {
 
                        // Stupid hack
 
                        let string = String::from(data.as_str());
 
                        val.with_disp_val(&string);
 
                    },
 
                    Literal::Integer(data) => { val.with_debug_val(data); },
 
                    Literal::Struct(data) => {
 
                        val.with_s_val("Struct");
 
                        let indent4 = indent3 + 1;
 

	
 
                        self.kv(indent3).with_s_key("ParserType")
 
                            .with_custom_val(|t| write_parser_type(t, heap, &data.parser_type));
 
                        self.kv(indent3).with_s_key("Definition").with_disp_val(&data.definition.index);
 

	
 
                        for field in &data.fields {
 
                            self.kv(indent3).with_s_key("Field");
 
                            self.kv(indent4).with_s_key("Name").with_identifier_val(&field.identifier);
 
                            self.kv(indent4).with_s_key("Index").with_disp_val(&field.field_idx);
 
                            self.kv(indent4).with_s_key("ParserType");
 
                            self.write_expr(heap, field.value, indent4 + 1);
 
                        }
 
                    },
 
                    Literal::Enum(data) => {
 
                        val.with_s_val("Enum");
 

	
 
                        self.kv(indent3).with_s_key("ParserType")
 
                            .with_custom_val(|t| write_parser_type(t, heap, &data.parser_type));
 
                        self.kv(indent3).with_s_key("Definition").with_disp_val(&data.definition.index);
 
                        self.kv(indent3).with_s_key("VariantIdx").with_disp_val(&data.variant_idx);
 
                    },
 
                    Literal::Union(data) => {
 
                        val.with_s_val("Union");
 
                        let indent4 = indent3 + 1;
 

	
 
                        self.kv(indent3).with_s_key("ParserType")
 
                            .with_custom_val(|t| write_parser_type(t, heap, &data.parser_type));
 
                        self.kv(indent3).with_s_key("Definition").with_disp_val(&data.definition.index);
 
                        self.kv(indent3).with_s_key("VariantIdx").with_disp_val(&data.variant_idx);
 

	
 
                        for value in &data.values {
 
                            self.kv(indent3).with_s_key("Value");
 
                            self.write_expr(heap, *value, indent4);
 
                        }
 
                    },
 
                    Literal::Array(data) => {
 
                        val.with_s_val("Array");
 
                        let indent4 = indent3 + 1;
 

	
 
                        self.kv(indent3).with_s_key("Elements");
 
                        for expr_id in data {
 
                            self.write_expr(heap, *expr_id, indent4);
 
                        }
 
                    },
 
                    Literal::Tuple(data) => {
 
                        val.with_s_val("Tuple");
 
                        let indent4 = indent3 + 1;
 
                        self.kv(indent3).with_s_key("Elements");
 
                        for expr_id in data {
 
                            self.write_expr(heap, *expr_id, indent4);
 
                        }
 
                    }
 
                }
 

	
 
                self.kv(indent2).with_s_key("Parent")
 
                    .with_custom_val(|v| write_expression_parent(v, &expr.parent));
 
            },
 
            Expression::Cast(expr) => {
 
                self.kv(indent).with_id(PREFIX_CAST_EXPR_ID, expr.this.0.index)
 
                    .with_s_key("CallExpr");
 
                self.kv(indent2).with_s_key("UniqueId").with_disp_val(&expr.unique_id_in_definition);
 
                self.kv(indent2).with_s_key("ToType")
 
                    .with_custom_val(|t| write_parser_type(t, heap, &expr.to_type));
 
                self.kv(indent2).with_s_key("Subject");
 
                self.write_expr(heap, expr.subject, indent3);
 
                self.kv(indent2).with_s_key("Parent")
 
                    .with_custom_val(|v| write_expression_parent(v, &expr.parent));
 
            }
 
            Expression::Call(expr) => {
 
                self.kv(indent).with_id(PREFIX_CALL_EXPR_ID, expr.this.0.index)
 
                    .with_s_key("CallExpr");
 

	
 
                self.kv(indent2).with_s_key("UniqueId").with_disp_val(&expr.unique_id_in_definition);
 
                let definition = &heap[expr.definition];
 
                match definition {
 
                    Definition::Component(definition) => {
 
                        self.kv(indent2).with_s_key("BuiltIn").with_disp_val(&false);
 
                        self.kv(indent2).with_s_key("Variant").with_debug_val(&definition.variant);
 
                    },
 
                    Definition::Function(definition) => {
 
                        self.kv(indent2).with_s_key("BuiltIn").with_disp_val(&definition.builtin);
 
                        self.kv(indent2).with_s_key("Variant").with_s_val("Function");
 
                    },
 
                    _ => unreachable!()
 
                }
 
                self.kv(indent2).with_s_key("MethodName").with_identifier_val(definition.identifier());
 
                self.kv(indent2).with_s_key("ParserType")
 
                    .with_custom_val(|t| write_parser_type(t, heap, &expr.parser_type));
 

	
 
                // Arguments
 
                self.kv(indent2).with_s_key("Arguments");
 
                for arg_id in &expr.arguments {
 
                    self.write_expr(heap, *arg_id, indent3);
 
                }
 

	
 
                // Parent
 
                self.kv(indent2).with_s_key("Parent")
 
                    .with_custom_val(|v| write_expression_parent(v, &expr.parent));
 
            },
 
            Expression::Variable(expr) => {
 
                self.kv(indent).with_id(PREFIX_VARIABLE_EXPR_ID, expr.this.0.index)
 
                    .with_s_key("VariableExpr");
 
                self.kv(indent2).with_s_key("UniqueId").with_disp_val(&expr.unique_id_in_definition);
 
                self.kv(indent2).with_s_key("Name").with_identifier_val(&expr.identifier);
 
                self.kv(indent2).with_s_key("Definition")
 
                    .with_opt_disp_val(expr.declaration.as_ref().map(|v| &v.index));
 
                self.kv(indent2).with_s_key("Parent")
 
                    .with_custom_val(|v| write_expression_parent(v, &expr.parent));
 
            }
 
        }
 
    }
 

	
 
    fn write_variable(&mut self, heap: &Heap, variable_id: VariableId, indent: usize) {
 
        let var = &heap[variable_id];
 
        let indent2 = indent + 1;
 

	
 
        self.kv(indent).with_id(PREFIX_VARIABLE_ID, variable_id.index)
 
            .with_s_key("Variable");
 

	
 
        self.kv(indent2).with_s_key("Name").with_identifier_val(&var.identifier);
 
        self.kv(indent2).with_s_key("Kind").with_debug_val(&var.kind);
 
        self.kv(indent2).with_s_key("ParserType")
 
            .with_custom_val(|w| write_parser_type(w, heap, &var.parser_type));
 
        self.kv(indent2).with_s_key("RelativePos").with_disp_val(&var.relative_pos_in_parent);
 
        self.kv(indent2).with_s_key("UniqueScopeID").with_disp_val(&var.unique_id_in_scope);
 
    }
 

	
 
    //--------------------------------------------------------------------------
 
    // Printing Utilities
 
    //--------------------------------------------------------------------------
 

	
 
    fn kv(&mut self, indent: usize) -> KV {
 
        KV::new(&mut self.buffer, &mut self.temp1, &mut self.temp2, indent)
 
    }
 

	
 
    fn flush<W: IOWrite>(&mut self, w: &mut W) {
 
        w.write(self.buffer.as_bytes()).unwrap();
 
        self.buffer.clear()
 
    }
 
}
 

	
 
fn write_option<V: Display>(target: &mut String, value: Option<V>) {
 
    target.clear();
 
    match &value {
 
        Some(v) => target.push_str(&format!("Some({})", v)),
 
        None => target.push_str("None")
 
    };
 
}
 

	
 
fn write_parser_type(target: &mut String, heap: &Heap, t: &ParserType) {
 
    use ParserTypeVariant as PTV;
 

	
 
    fn write_element(target: &mut String, heap: &Heap, t: &ParserType, mut element_idx: usize) -> usize {
 
        let element = &t.elements[element_idx];
 
        match &element.variant {
 
            PTV::Void => target.push_str("void"),
 
            PTV::InputOrOutput => {
 
                target.push_str("portlike<");
 
                element_idx = write_element(target, heap, t, element_idx + 1);
 
                target.push('>');
 
            },
 
            PTV::ArrayLike => {
 
                element_idx = write_element(target, heap, t, element_idx + 1);
 
                target.push_str("[???]");
 
            },
 
            PTV::IntegerLike => target.push_str("integerlike"),
 
            PTV::Message => { target.push_str(KW_TYPE_MESSAGE_STR); },
 
            PTV::Bool => { target.push_str(KW_TYPE_BOOL_STR); },
 
            PTV::UInt8 => { target.push_str(KW_TYPE_UINT8_STR); },
 
            PTV::UInt16 => { target.push_str(KW_TYPE_UINT16_STR); },
 
            PTV::UInt32 => { target.push_str(KW_TYPE_UINT32_STR); },
 
            PTV::UInt64 => { target.push_str(KW_TYPE_UINT64_STR); },
 
            PTV::SInt8 => { target.push_str(KW_TYPE_SINT8_STR); },
 
            PTV::SInt16 => { target.push_str(KW_TYPE_SINT16_STR); },
 
            PTV::SInt32 => { target.push_str(KW_TYPE_SINT32_STR); },
 
            PTV::SInt64 => { target.push_str(KW_TYPE_SINT64_STR); },
 
            PTV::Character => { target.push_str(KW_TYPE_CHAR_STR); },
 
            PTV::String => { target.push_str(KW_TYPE_STRING_STR); },
 
            PTV::IntegerLiteral => { target.push_str("int_literal"); },
 
            PTV::Inferred => { target.push_str(KW_TYPE_INFERRED_STR); },
 
            PTV::Array => {
 
                element_idx = write_element(target, heap, t, element_idx + 1);
 
                target.push_str("[]");
 
            },
 
            PTV::Input => {
 
                target.push_str(KW_TYPE_IN_PORT_STR);
 
                target.push('<');
 
                element_idx = write_element(target, heap, t, element_idx + 1);
 
                target.push('>');
 
            },
 
            PTV::Output => {
 
                target.push_str(KW_TYPE_OUT_PORT_STR);
 
                target.push('<');
 
                element_idx = write_element(target, heap, t, element_idx + 1);
 
                target.push('>');
 
            },
 
            PTV::Tuple(num_embedded) => {
 
                target.push('(');
 
                let num_embedded = *num_embedded;
 
                for embedded_idx in 0..num_embedded {
 
                    if embedded_idx != 0 {
 
                        target.push(',');
 
                    }
 
                    element_idx = write_element(target, heap, t, element_idx + 1);
 
                }
 
                target.push(')');
 
            }
 
            PTV::PolymorphicArgument(definition_id, arg_idx) => {
 
                let definition = &heap[*definition_id];
 
                let poly_var = &definition.poly_vars()[*arg_idx as usize].value;
 
                target.push_str(poly_var.as_str());
 
            },
 
            PTV::Definition(definition_id, num_embedded) => {
 
                let definition = &heap[*definition_id];
 
                let definition_ident = definition.identifier().value.as_str();
 
                target.push_str(definition_ident);
 

	
 
                let num_embedded = *num_embedded;
 
                if num_embedded != 0 {
 
                    target.push('<');
 
                    for embedded_idx in 0..num_embedded {
 
                        if embedded_idx != 0 {
 
                            target.push(',');
 
                        }
 
                        element_idx = write_element(target, heap, t, element_idx + 1);
 
                    }
 
                    target.push('>');
 
                }
 
            }
 
        }
 

	
 
        element_idx
 
    }
 

	
 
    write_element(target, heap, t, 0);
 
}
 

	
 
fn write_concrete_type(target: &mut String, heap: &Heap, def_id: DefinitionId, t: &ConcreteType) {
 
    use ConcreteTypePart as CTP;
 

	
 
    fn write_concrete_part(target: &mut String, heap: &Heap, def_id: DefinitionId, t: &ConcreteType, mut idx: usize) -> usize {
 
        if idx >= t.parts.len() {
 
            return idx;
 
        }
 

	
 
        match &t.parts[idx] {
 
            CTP::Void => target.push_str("void"),
 
            CTP::Message => target.push_str("msg"),
 
            CTP::Bool => target.push_str("bool"),
 
            CTP::UInt8 => target.push_str(KW_TYPE_UINT8_STR),
 
            CTP::UInt16 => target.push_str(KW_TYPE_UINT16_STR),
 
            CTP::UInt32 => target.push_str(KW_TYPE_UINT32_STR),
 
            CTP::UInt64 => target.push_str(KW_TYPE_UINT64_STR),
 
            CTP::SInt8 => target.push_str(KW_TYPE_SINT8_STR),
 
            CTP::SInt16 => target.push_str(KW_TYPE_SINT16_STR),
 
            CTP::SInt32 => target.push_str(KW_TYPE_SINT32_STR),
 
            CTP::SInt64 => target.push_str(KW_TYPE_SINT64_STR),
 
            CTP::Character => target.push_str(KW_TYPE_CHAR_STR),
 
            CTP::String => target.push_str(KW_TYPE_STRING_STR),
 
            CTP::Array => {
 
                idx = write_concrete_part(target, heap, def_id, t, idx + 1);
 
                target.push_str("[]");
 
            },
 
            CTP::Slice => {
 
                idx = write_concrete_part(target, heap, def_id, t, idx + 1);
 
                target.push_str("[..]");
 
            }
 
            CTP::Input => {
 
                target.push_str("in<");
 
                idx = write_concrete_part(target, heap, def_id, t, idx + 1);
 
                target.push('>');
 
            },
 
            CTP::Output => {
 
                target.push_str("out<");
 
                idx = write_concrete_part(target, heap, def_id, t, idx + 1);
 
                target.push('>')
 
            },
 
            CTP::Tuple(num_embedded) => {
 
                target.push('(');
 
                for idx_embedded in 0..*num_embedded {
 
                    if idx_embedded != 0 {
 
                        target.push_str(", ");
 
                    }
 
                    idx = write_concrete_part(target, heap, def_id, t, idx + 1);
 
                }
 
                target.push(')');
 
            },
 
            CTP::Instance(definition_id, num_embedded) => {
 
                let identifier = heap[*definition_id].identifier();
 
                target.push_str(identifier.value.as_str());
 
                target.push('<');
 
                for idx_embedded in 0..*num_embedded {
 
                    if idx_embedded != 0 {
 
                        target.push_str(", ");
 
                    }
 
                    idx = write_concrete_part(target, heap, def_id, t, idx + 1);
 
                }
 
                target.push('>');
 
            },
 
            CTP::Function(_, _) => todo!("AST printer for ConcreteTypePart::Function"),
 
            CTP::Component(_, _) => todo!("AST printer for ConcreteTypePart::Component"),
 
        }
 

	
 
        idx + 1
 
    }
 

	
 
    write_concrete_part(target, heap, def_id, t, 0);
 
}
 

	
 
fn write_expression_parent(target: &mut String, parent: &ExpressionParent) {
 
    use ExpressionParent as EP;
 

	
 
    *target = match parent {
 
        EP::None => String::from("None"),
 
        EP::Memory(id) => format!("MemStmt({})", id.0.0.index),
 
        EP::If(id) => format!("IfStmt({})", id.0.index),
 
        EP::While(id) => format!("WhileStmt({})", id.0.index),
 
        EP::Return(id) => format!("ReturnStmt({})", id.0.index),
 
        EP::New(id) => format!("NewStmt({})", id.0.index),
 
        EP::ExpressionStmt(id) => format!("ExprStmt({})", id.0.index),
 
        EP::Expression(id, idx) => format!("Expr({}, {})", id.index, idx)
 
    };
 
}
 
\ No newline at end of file
src/protocol/parser/type_table.rs
Show inline comments
 
/**
 
 * type_table.rs
 
 *
 
 * The type table is a lookup from AST definition (which contains just what the
 
 * programmer typed) to a type with additional information computed (e.g. the
 
 * byte size and offsets of struct members). The type table should be considered
 
 * the authoritative source of information on types by the compiler (not the
 
 * AST itself!).
 
 *
 
 * The type table operates in two modes: one is where we just look up the type,
 
 * check its fields for correctness and mark whether it is polymorphic or not.
 
 * The second one is where we compute byte sizes, alignment and offsets.
 
 *
 
 * The basic algorithm for type resolving and computing byte sizes is to
 
 * recursively try to lay out each member type of a particular type. This is
 
 * done in a stack-like fashion, where each embedded type pushes a breadcrumb
 
 * unto the stack. We may discover a cycle in embedded types (we call this a
 
 * "type loop"). After which the type table attempts to break the type loop by
 
 * making specific types heap-allocated. Upon doing so we know their size
 
 * because their stack-size is now based on pointers. Hence breaking the type
 
 * loop required for computing the byte size of types.
 
 *
 
 * The reason for these type shenanigans is because PDL is a value-based
 
 * language, but we would still like to be able to express recursively defined
 
 * types like trees or linked lists. Hence we need to insert pointers somewhere
 
 * to break these cycles.
 
 *
 
 * We will insert these pointers into the variants of unions. However note that
 
 * we can only compute the stack size of a union until we've looked at *all*
 
 * variants. Hence we perform an initial pass where we detect type loops, a
 
 * second pass where we compute the stack sizes of everything, and a third pass
 
 * where we actually compute the size of the heap allocations for unions.
 
 *
 
 * As a final bit of global documentation: non-polymorphic types will always
 
 * have one "monomorph" entry. This contains the non-polymorphic type's memory
 
 * layout.
 
 */
 

	
 
use std::fmt::{Formatter, Result as FmtResult};
 
use std::collections::HashMap;
 
use std::hash::{Hash, Hasher};
 

	
 
use crate::protocol::ast::*;
 
use crate::protocol::parser::symbol_table::SymbolScope;
 
use crate::protocol::input_source::ParseError;
 
use crate::protocol::parser::*;
 

	
 
//------------------------------------------------------------------------------
 
// Defined Types
 
//------------------------------------------------------------------------------
 

	
 
#[derive(Copy, Clone, PartialEq, Eq)]
 
pub enum TypeClass {
 
    Enum,
 
    Union,
 
    Struct,
 
    Function,
 
    Component
 
}
 

	
 
impl TypeClass {
 
    pub(crate) fn display_name(&self) -> &'static str {
 
        match self {
 
            TypeClass::Enum => "enum",
 
            TypeClass::Union => "union",
 
            TypeClass::Struct => "struct",
 
            TypeClass::Function => "function",
 
            TypeClass::Component => "component",
 
        }
 
    }
 

	
 
    pub(crate) fn is_data_type(&self) -> bool {
 
        match self {
 
            TypeClass::Enum | TypeClass::Union | TypeClass::Struct => true,
 
            TypeClass::Function | TypeClass::Component => false,
 
        }
 
    }
 
}
 

	
 
impl std::fmt::Display for TypeClass {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
 
        write!(f, "{}", self.display_name())
 
    }
 
}
 

	
 
/// Struct wrapping around a potentially polymorphic type. If the type does not
 
/// have any polymorphic arguments then it will not have any monomorphs and
 
/// `is_polymorph` will be set to `false`. A type with polymorphic arguments
 
/// only has `is_polymorph` set to `true` if the polymorphic arguments actually
 
/// appear in the types associated types (function return argument, struct
 
/// field, enum variant, etc.). Otherwise the polymorphic argument is just a
 
/// marker and does not influence the bytesize of the type.
 
pub struct DefinedType {
 
    pub(crate) ast_root: RootId,
 
    pub(crate) ast_definition: DefinitionId,
 
    pub(crate) definition: DefinedTypeVariant,
 
    pub(crate) poly_vars: Vec<PolymorphicVariable>,
 
    pub(crate) is_polymorph: bool,
 
}
 

	
 
pub enum DefinedTypeVariant {
 
    Enum(EnumType),
 
    Union(UnionType),
 
    Struct(StructType),
 
    Function(FunctionType),
 
    Component(ComponentType)
 
}
 

	
 
impl DefinedTypeVariant {
 
    pub(crate) fn type_class(&self) -> TypeClass {
 
        match self {
 
            DefinedTypeVariant::Enum(_) => TypeClass::Enum,
 
            DefinedTypeVariant::Union(_) => TypeClass::Union,
 
            DefinedTypeVariant::Struct(_) => TypeClass::Struct,
 
            DefinedTypeVariant::Function(_) => TypeClass::Function,
 
            DefinedTypeVariant::Component(_) => TypeClass::Component
 
        }
 
    }
 

	
 
    pub(crate) fn as_struct(&self) -> &StructType {
 
        match self {
 
            DefinedTypeVariant::Struct(v) => v,
 
            _ => unreachable!("Cannot convert {} to struct variant", self.type_class())
 
        }
 
    }
 

	
 
    pub(crate) fn as_enum(&self) -> &EnumType {
 
        match self {
 
            DefinedTypeVariant::Enum(v) => v,
 
            _ => unreachable!("Cannot convert {} to enum variant", self.type_class())
 
        }
 
    }
 

	
 
    pub(crate) fn as_union(&self) -> &UnionType {
 
        match self {
 
            DefinedTypeVariant::Union(v) => v,
 
            _ => unreachable!("Cannot convert {} to union variant", self.type_class())
 
        }
 
    }
 
}
 

	
 
pub struct PolymorphicVariable {
 
    identifier: Identifier,
 
    is_in_use: bool, // a polymorphic argument may be defined, but not used by the type definition
 
}
 

	
 
/// `EnumType` is the classical C/C++ enum type. It has various variants with
 
/// an assigned integer value. The integer values may be user-defined,
 
/// compiler-defined, or a mix of the two. If a user assigns the same enum
 
/// value multiple times, we assume the user is an expert and we consider both
 
/// variants to be equal to one another.
 
pub struct EnumType {
 
    pub variants: Vec<EnumVariant>,
 
    pub minimum_tag_value: i64,
 
    pub maximum_tag_value: i64,
 
    pub tag_type: ConcreteType,
 
    pub size: usize,
 
    pub alignment: usize,
 
}
 

	
 
// TODO: Also support maximum u64 value
 
pub struct EnumVariant {
 
    pub identifier: Identifier,
 
    pub value: i64,
 
}
 

	
 
/// `UnionType` is the algebraic datatype (or sum type, or discriminated union).
 
/// A value is an element of the union, identified by its tag, and may contain
 
/// a single subtype.
 
/// For potentially infinite types (i.e. a tree, or a linked list) only unions
 
/// can break the infinite cycle. So when we lay out these unions in memory we
 
/// will reserve enough space on the stack for all union variants that do not
 
/// cause "type loops" (i.e. a union `A` with a variant containing a struct
 
/// `B`). And we will reserve enough space on the heap (and store a pointer in
 
/// the union) for all variants which do cause type loops (i.e. a union `A`
 
/// with a variant to a struct `B` that contains the union `A` again).
 
pub struct UnionType {
 
    pub variants: Vec<UnionVariant>,
 
    pub tag_type: ConcreteType,
 
    pub tag_size: usize,
 
}
 

	
 
pub struct UnionVariant {
 
    pub identifier: Identifier,
 
    pub embedded: Vec<ParserType>, // zero-length does not have embedded values
 
    pub tag_value: i64,
 
}
 

	
 
/// `StructType` is a generic C-like struct type (or record type, or product
 
/// type) type.
 
pub struct StructType {
 
    pub fields: Vec<StructField>,
 
}
 

	
 
pub struct StructField {
 
    pub identifier: Identifier,
 
    pub parser_type: ParserType,
 
}
 

	
 
/// `FunctionType` is what you expect it to be: a particular function's
 
/// signature.
 
pub struct FunctionType {
 
    pub return_type: ParserType,
 
    pub arguments: Vec<FunctionArgument>,
 
}
 

	
 
pub struct ComponentType {
 
    pub variant: ComponentVariant,
 
    pub arguments: Vec<FunctionArgument>,
 
}
 

	
 
pub struct FunctionArgument {
 
    identifier: Identifier,
 
    parser_type: ParserType,
 
}
 

	
 
/// Represents the data associated with a single expression after type inference
 
/// for a monomorph (or just the normal expression types, if dealing with a
 
/// non-polymorphic function/component).
 
pub struct MonomorphExpression {
 
    // The output type of the expression. Note that for a function it is not the
 
    // function's signature but its return type
 
    pub(crate) expr_type: ConcreteType,
 
    // Has multiple meanings: the field index for select expressions, the
 
    // monomorph index for polymorphic function calls or literals. Negative
 
    // values are never used, but used to catch programming errors.
 
    pub(crate) field_or_monomorph_idx: i32,
 
    pub(crate) type_id: TypeId,
 
}
 

	
 
//------------------------------------------------------------------------------
 
// Type monomorph storage
 
//------------------------------------------------------------------------------
 

	
 
pub(crate) enum MonoTypeVariant {
 
    Builtin, // no extra data, added manually in compiler initialization code
 
    Enum, // no extra data
 
    Struct(StructMonomorph),
 
    Union(UnionMonomorph),
 
    Procedure(ProcedureMonomorph), // functions, components
 
    Tuple(TupleMonomorph),
 
}
 

	
 
impl MonoTypeVariant {
 
    fn as_struct_mut(&mut self) -> &mut StructMonomorph {
 
        match self {
 
            MonoTypeVariant::Struct(v) => v,
 
            _ => unreachable!(),
 
        }
 
    }
 

	
 
    pub(crate) fn as_union(&self) -> &UnionMonomorph {
 
        match self {
 
            MonoTypeVariant::Union(v) => v,
 
            _ => unreachable!(),
 
        }
 
    }
 

	
 
    fn as_union_mut(&mut self) -> &mut UnionMonomorph {
 
        match self {
 
            MonoTypeVariant::Union(v) => v,
 
            _ => unreachable!(),
 
        }
 
    }
 

	
 
    fn as_tuple_mut(&mut self) -> &mut TupleMonomorph {
 
        match self {
 
            MonoTypeVariant::Tuple(v) => v,
 
            _ => unreachable!(),
 
        }
 
    }
 

	
 
    fn as_procedure(&self) -> &ProcedureMonomorph {
 
        match self {
 
            MonoTypeVariant::Procedure(v) => v,
 
            _ => unreachable!(),
 
        }
 
    }
 

	
 
    fn as_procedure_mut(&mut self) -> &mut ProcedureMonomorph {
 
        match self {
 
            MonoTypeVariant::Procedure(v) => v,
 
            _ => unreachable!(),
 
        }
 
    }
 
}
 

	
 
/// Struct monomorph
 
pub struct StructMonomorph {
 
    pub fields: Vec<StructMonomorphField>,
 
}
 

	
 
pub struct StructMonomorphField {
 
    pub type_id: TypeId,
 
    concrete_type: ConcreteType,
 
    pub size: usize,
 
    pub alignment: usize,
 
    pub offset: usize,
 
}
 

	
 
/// Union monomorph
 
pub struct UnionMonomorph {
 
    pub variants: Vec<UnionMonomorphVariant>,
 
    pub tag_size: usize, // copied from `UnionType` upon monomorph construction.
 
    // note that the stack size is in the `TypeMonomorph` struct. This size and
 
    // alignment will include the size of the union tag.
 
    //
 
    // heap_size contains the allocated size of the union in the case it
 
    // is used to break a type loop. If it is 0, then it doesn't require
 
    // allocation and lives entirely on the stack.
 
    pub heap_size: usize,
 
    pub heap_alignment: usize,
 
}
 

	
 
pub struct UnionMonomorphVariant {
 
    pub lives_on_heap: bool,
 
    pub embedded: Vec<UnionMonomorphEmbedded>,
 
}
 

	
 
pub struct UnionMonomorphEmbedded {
 
    pub type_id: TypeId,
 
    concrete_type: ConcreteType,
 
    // Note that the meaning of the offset (and alignment) depend on whether or
 
    // not the variant lives on the stack/heap. If it lives on the stack then
 
    // they refer to the offset from the start of the union value (so the first
 
    // embedded type lives at a non-zero offset, because the union tag sits in
 
    // the front). If it lives on the heap then it refers to the offset from the
 
    // allocated memory region (so the first embedded type lives at a 0 offset).
 
    pub size: usize,
 
    pub alignment: usize,
 
    pub offset: usize,
 
}
 

	
 
/// Procedure (functions and components of all possible types) monomorph. Also
 
/// stores the expression type data from the typechecking/inferencing pass.
 
pub struct ProcedureMonomorph {
 
    // Expression data for one particular monomorph
 
    pub arg_types: Vec<ConcreteType>,
 
    pub expr_data: Vec<MonomorphExpression>,
 
}
 

	
 
/// Tuple monomorph. Again a kind of exception because one cannot define a named
 
/// tuple type containing explicit polymorphic variables. But again: we need to
 
/// store size/offset/alignment information, so we do it here.
 
pub struct TupleMonomorph {
 
    pub members: Vec<TupleMonomorphMember>
 
}
 

	
 
pub struct TupleMonomorphMember {
 
    pub type_id: TypeId,
 
    concrete_type: ConcreteType,
 
    pub size: usize,
 
    pub alignment: usize,
 
    pub offset: usize,
 
}
 

	
 
/// Generic unique type ID. Every monomorphed type and every non-polymorphic
 
/// type will have one of these associated with it.
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct TypeId(i64);
 

	
 
impl TypeId {
 
    pub(crate) fn new_invalid() -> Self {
 
        return Self(-1);
 
    }
 
}
 

	
 
/// A monomorphed type (or non-polymorphic type's) memory layout and information
 
/// regarding associated types (like a struct's field type).
 
pub struct MonoType {
 
    pub type_id: TypeId,
 
    pub concrete_type: ConcreteType,
 
    pub size: usize,
 
    pub alignment: usize,
 
    pub(crate) variant: MonoTypeVariant
 
}
 

	
 
impl MonoType {
 
    #[inline]
 
    fn new_empty(type_id: TypeId, concrete_type: ConcreteType, variant: MonoTypeVariant) -> Self {
 
        return Self {
 
            type_id, concrete_type,
 
            size: 0,
 
            alignment: 0,
 
            variant,
 
        }
 
    }
 

	
 
    /// Little internal helper function as a reminder: if alignment is 0, then
 
    /// the size/alignment are not actually computed yet!
 
    #[inline]
 
    fn get_size_alignment(&self) -> Option<(usize, usize)> {
 
        if self.alignment == 0 {
 
            return None
 
        } else {
 
            return Some((self.size, self.alignment));
 
        }
 
    }
 
}
 

	
 
/// Special structure that acts like the lookup key for `ConcreteType` instances
 
/// that have already been added to the type table before.
 
#[derive(Clone)]
 
struct MonoSearchKey {
 
    // Uses bitflags to denote when parts between search keys should match and
 
    // whether they should be checked. Needs to have a system like this to
 
    // accommodate tuples.
 
    parts: Vec<(u8, ConcreteTypePart)>,
 
    change_bit: u8,
 
}
 

	
 
impl MonoSearchKey {
 
    const KEY_IN_USE: u8 = 0x01;
 
    const KEY_CHANGE_BIT: u8 = 0x02;
 

	
 
    fn with_capacity(capacity: usize) -> Self {
 
        return MonoSearchKey{
 
            parts: Vec::with_capacity(capacity),
 
            change_bit: 0,
 
        };
 
    }
 

	
 
    /// Sets the search key based on a single concrete type and its polymorphic
 
    /// variables.
 
    fn set(&mut self, concrete_type_parts: &[ConcreteTypePart], poly_var_in_use: &[PolymorphicVariable]) {
 
        self.set_top_type(concrete_type_parts[0]);
 

	
 
        let mut poly_var_index = 0;
 
        for subtype in ConcreteTypeIter::new(concrete_type_parts, 0) {
 
            let in_use = poly_var_in_use[poly_var_index].is_in_use;
 
            poly_var_index += 1;
 
            self.push_subtype(subtype, in_use);
 
        }
 

	
 
        debug_assert_eq!(poly_var_index, poly_var_in_use.len());
 
    }
 

	
 
    /// Starts setting the search key based on an initial top-level type,
 
    /// programmer must call `push_subtype` the appropriate number of times
 
    /// after calling this function
 
    fn set_top_type(&mut self, type_part: ConcreteTypePart) {
 
        self.parts.clear();
 
        self.parts.push((self.change_bit | Self::KEY_IN_USE, type_part));
 
        self.change_bit ^= Self::KEY_CHANGE_BIT;
 
        self.parts.push((Self::KEY_IN_USE, type_part));
 
        self.change_bit = Self::KEY_CHANGE_BIT;
 
    }
 

	
 
    fn push_subtype(&mut self, concrete_type: &[ConcreteTypePart], in_use: bool) {
 
        let flag = self.change_bit | (if in_use { Self::KEY_IN_USE } else { 0 });
 

	
 
        for part in concrete_type {
 
            self.parts.push((flag, *part));
 
        }
 
        self.change_bit ^= Self::KEY_CHANGE_BIT;
 
    }
 

	
 
    fn push_subtree(&mut self, concrete_type: &[ConcreteTypePart], poly_var_in_use: &[PolymorphicVariable]) {
 
        self.parts.push((self.change_bit | Self::KEY_IN_USE, concrete_type[0]));
 
        self.change_bit ^= Self::KEY_CHANGE_BIT;
 

	
 
        let mut poly_var_index = 0;
 
        for subtype in ConcreteTypeIter::new(concrete_type, 0) {
 
            let in_use = poly_var_in_use[poly_var_index].is_in_use;
 
            poly_var_index += 1;
 
            self.push_subtype(subtype, in_use);
 
        }
 

	
 
        debug_assert_eq!(poly_var_index, poly_var_in_use.len());
 
    }
 

	
 
    // Utilities for hashing and comparison
 
    fn find_end_index(&self, start_index: usize) -> usize {
 
        // Check if we're already at the end
 
        let mut index = start_index;
 
        if index >= self.parts.len() {
 
            return index;
 
        }
 

	
 
        // Iterate until bit flips, or until at end
 
        let expected_bit = self.parts[index].0 & Self::KEY_CHANGE_BIT;
 

	
 
        index += 1;
 
        while index < self.parts.len() {
 
            let current_bit = self.parts[index].0 & Self::KEY_CHANGE_BIT;
 
            if current_bit != expected_bit {
 
                return index;
 
            }
 

	
 
            index += 1;
 
        }
 

	
 
        return self.parts.len();
 
        return index;
 
    }
 
}
 

	
 
impl Hash for MonoSearchKey {
 
    fn hash<H: Hasher>(&self, state: &mut H) {
 
        for index in 0..self.parts.len() {
 
            let (flags, part) = self.parts[index];
 
            if flags & Self::KEY_IN_USE != 0 {
 
                part.hash(state);
 
            }
 
        }
 
    }
 
}
 

	
 
impl PartialEq for MonoSearchKey {
 
    fn eq(&self, other: &Self) -> bool {
 
        let mut self_index = 0;
 
        let mut other_index = 0;
 

	
 
        while self_index < self.parts.len() && other_index < other.parts.len() {
 
            // Retrieve part and flags
 
            let (self_bits, _) = self.parts[self_index];
 
            let (other_bits, _) = other.parts[other_index];
 
            let self_in_use = (self_bits & Self::KEY_IN_USE) != 0;
 
            let other_in_use = (other_bits & Self::KEY_IN_USE) != 0;
 

	
 
            // Determine ending indices
 
            let self_end_index = self.find_end_index(self_index);
 
            let other_end_index = other.find_end_index(other_index);
 

	
 

	
 
            if self_in_use == other_in_use {
 
                if self_in_use {
 
                    // Both are in use, so both parts should be equal
 
                    let delta_self = self_end_index - self_index;
 
                    let delta_other = other_end_index - other_index;
 
                    if delta_self != delta_other {
 
                        // Both in use, but not of equal length, so the types
 
                        // cannot match
 
                        return false;
 
                    }
 

	
 
                    for _ in 0..delta_self {
 
                        let (_, self_part) = self.parts[self_index];
 
                        let (_, other_part) = self.parts[other_index];
 
                        let (_, other_part) = other.parts[other_index];
 

	
 
                        if self_part != other_part {
 
                            return false;
 
                        }
 

	
 
                        self_index += 1;
 
                        other_index += 1;
 
                    }
 
                } else {
 
                    // Both not in use, so skip associated parts
 
                    self_index = self_end_index;
 
                    other_index = other_end_index;
 
                }
 
            } else {
 
                // No agreement on importance of parts. This is practically
 
                // impossible
 
                unreachable!();
 
            }
 
        }
 

	
 
        // Everything matched, so if we're at the end of both arrays then we're
 
        // certain that the two keys are equal.
 
        return self_index == self.parts.len() && other_index == other.parts.len();
 
    }
 
}
 

	
 
impl Eq for MonoSearchKey{}
 

	
 
//------------------------------------------------------------------------------
 
// Type table
 
//------------------------------------------------------------------------------
 

	
 
// Programmer note: keep this struct free of dynamically allocated memory
 
#[derive(Clone)]
 
struct TypeLoopBreadcrumb {
 
    type_id: TypeId,
 
    next_member: u32,
 
    next_embedded: u32, // for unions, the index into the variant's embedded types
 
}
 

	
 
// Programmer note: keep this struct free of dynamically allocated memory
 
#[derive(Clone)]
 
struct MemoryBreadcrumb {
 
    type_id: TypeId,
 
    next_member: u32,
 
    next_embedded: u32,
 
    first_size_alignment_idx: u32,
 
}
 

	
 
#[derive(Debug, PartialEq, Eq)]
 
enum TypeLoopResult {
 
    TypeExists,
 
    PushBreadcrumb(DefinitionId, ConcreteType),
 
    TypeLoop(usize), // index into vec of breadcrumbs at which the type matched
 
}
 

	
 
enum MemoryLayoutResult {
 
    TypeExists(usize, usize), // (size, alignment)
 
    PushBreadcrumb(MemoryBreadcrumb),
 
}
 

	
 
// TODO: @Optimize, initial memory-unoptimized implementation
 
struct TypeLoopEntry {
 
    type_id: TypeId,
 
    is_union: bool,
 
}
 

	
 
struct TypeLoop {
 
    members: Vec<TypeLoopEntry>,
 
}
 

	
 
type DefinitionMap = HashMap<DefinitionId, DefinedType>;
 
type MonoTypeMap = HashMap<MonoSearchKey, TypeId>;
 
type MonoTypeArray = Vec<MonoType>;
 

	
 
pub struct TypeTable {
 
    // Lookup from AST DefinitionId to a defined type. Also lookups for
 
    // concrete type to monomorphs
 
    pub(crate) definition_lookup: DefinitionMap,
 
    mono_type_lookup: MonoTypeMap,
 
    pub(crate) mono_types: MonoTypeArray,
 
    mono_search_key: MonoSearchKey,
 
    // Breadcrumbs left behind while trying to find type loops. Also used to
 
    // determine sizes of types when all type loops are detected.
 
    type_loop_breadcrumbs: Vec<TypeLoopBreadcrumb>,
 
    type_loops: Vec<TypeLoop>,
 
    // Stores all encountered types during type loop detection. Used afterwards
 
    // to iterate over all types in order to compute size/alignment.
 
    encountered_types: Vec<TypeLoopEntry>,
 
    // Breadcrumbs and temporary storage during memory layout computation.
 
    memory_layout_breadcrumbs: Vec<MemoryBreadcrumb>,
 
    size_alignment_stack: Vec<(usize, usize)>,
 
}
 

	
 
impl TypeTable {
 
    /// Construct a new type table without any resolved types.
 
    pub(crate) fn new() -> Self {
 
        Self{ 
 
            definition_lookup: HashMap::with_capacity(128),
 
            mono_type_lookup: HashMap::with_capacity(128),
 
            mono_types: Vec::with_capacity(128),
 
            mono_search_key: MonoSearchKey::with_capacity(32),
 
            type_loop_breadcrumbs: Vec::with_capacity(32),
 
            type_loops: Vec::with_capacity(8),
 
            encountered_types: Vec::with_capacity(32),
 
            memory_layout_breadcrumbs: Vec::with_capacity(32),
 
            size_alignment_stack: Vec::with_capacity(64),
 
        }
 
    }
 

	
 
    /// Iterates over all defined types (polymorphic and non-polymorphic) and
 
    /// add their types in two passes. In the first pass we will just add the
 
    /// base types (we will not consider monomorphs, and we will not compute
 
    /// byte sizes). In the second pass we will compute byte sizes of
 
    /// non-polymorphic types, and potentially the monomorphs that are embedded
 
    /// in those types.
 
    pub(crate) fn build_base_types(&mut self, modules: &mut [Module], ctx: &mut PassCtx) -> Result<(), ParseError> {
 
        // Make sure we're allowed to cast root_id to index into ctx.modules
 
        debug_assert!(modules.iter().all(|m| m.phase >= ModuleCompilationPhase::DefinitionsParsed));
 
        debug_assert!(self.definition_lookup.is_empty());
 

	
 
        dbg_code!({
 
            for (index, module) in modules.iter().enumerate() {
 
                debug_assert_eq!(index, module.root_id.index as usize);
 
            }
 
        });
 

	
 
        // Use context to guess hashmap size of the base types
 
        let reserve_size = ctx.heap.definitions.len();
 
        self.definition_lookup.reserve(reserve_size);
 

	
 
        // Resolve all base types
 
        for definition_idx in 0..ctx.heap.definitions.len() {
 
            let definition_id = ctx.heap.definitions.get_id(definition_idx);
 
            let definition = &ctx.heap[definition_id];
 

	
 
            match definition {
 
                Definition::Enum(_) => self.build_base_enum_definition(modules, ctx, definition_id)?,
 
                Definition::Union(_) => self.build_base_union_definition(modules, ctx, definition_id)?,
 
                Definition::Struct(_) => self.build_base_struct_definition(modules, ctx, definition_id)?,
 
                Definition::Function(_) => self.build_base_function_definition(modules, ctx, definition_id)?,
 
                Definition::Component(_) => self.build_base_component_definition(modules, ctx, definition_id)?,
 
            }
 
        }
 

	
 
        debug_assert_eq!(self.definition_lookup.len(), reserve_size, "mismatch in reserved size of type table");
 
        for module in modules.iter_mut() {
 
            module.phase = ModuleCompilationPhase::TypesAddedToTable;
 
        }
 

	
 
        // Go through all types again, lay out all types that are not
 
        // polymorphic. This might cause us to lay out monomorphized polymorphs
 
        // if these were member types of non-polymorphic types.
 
        for definition_idx in 0..ctx.heap.definitions.len() {
 
            let definition_id = ctx.heap.definitions.get_id(definition_idx);
 
            let poly_type = self.definition_lookup.get(&definition_id).unwrap();
 

	
 
            if !poly_type.definition.type_class().is_data_type() || !poly_type.poly_vars.is_empty() {
 
                continue;
 
            }
 

	
 
            // If here then the type is a data type without polymorphic
 
            // variables, but we might have instantiated it already, so:
 
            let concrete_parts = [ConcreteTypePart::Instance(definition_id, 0)];
 
            self.mono_search_key.set(&concrete_parts, &[]);
 
            let type_id = self.mono_type_lookup.get(&self.mono_search_key);
 
            if type_id.is_none() {
 
                self.detect_and_resolve_type_loops_for(
 
                    modules, ctx.heap,
 
                    ConcreteType{
 
                        parts: vec![ConcreteTypePart::Instance(definition_id, 0)]
 
                    },
 
                )?;
 
                self.lay_out_memory_for_encountered_types(ctx.arch);
 
            }
 
        }
 

	
 
        Ok(())
 
    }
 

	
 
    /// Retrieves base definition from type table. We must be able to retrieve
 
    /// it as we resolve all base types upon type table construction (for now).
 
    /// However, in the future we might do on-demand type resolving, so return
 
    /// an option anyway
 
    #[inline]
 
    pub(crate) fn get_base_definition(&self, definition_id: &DefinitionId) -> Option<&DefinedType> {
 
        self.definition_lookup.get(&definition_id)
 
    }
 

	
 
    /// Returns the index into the monomorph type array if the procedure type
 
    /// already has a (reserved) monomorph.
 
    #[inline]
 
    pub(crate) fn get_procedure_monomorph_type_id(&self, definition_id: &DefinitionId, type_parts: &[ConcreteTypePart]) -> Option<TypeId> {
 
        // Cannot use internal search key due to mutability issues. But this
 
        // method should end up being deprecated at some point anyway.
 
        debug_assert_eq!(get_concrete_type_definition(type_parts).unwrap(), *definition_id);
 
        let base_type = self.definition_lookup.get(definition_id).unwrap();
 
        let mut search_key = MonoSearchKey::with_capacity(type_parts.len());
 
        search_key.set(type_parts, &base_type.poly_vars);
 

	
 
        return self.mono_type_lookup.get(&search_key).copied();
 
    }
 

	
 
    #[inline]
 
    pub(crate) fn get_monomorph(&self, type_id: TypeId) -> &MonoType {
 
        return &self.mono_types[type_id.0 as usize];
 
    }
 

	
 
    /// Returns a mutable reference to a procedure's monomorph expression data.
 
    /// Used by typechecker to fill in previously reserved type information
 
    #[inline]
 
    pub(crate) fn get_procedure_monomorph_mut(&mut self, type_id: TypeId) -> &mut ProcedureMonomorph {
 
        let mono_type = &mut self.mono_types[type_id.0 as usize];
 
        return mono_type.variant.as_procedure_mut();
 
    }
 

	
 
    #[inline]
 
    pub(crate) fn get_procedure_monomorph(&self, type_id: TypeId) -> &ProcedureMonomorph {
 
        let mono_type = &self.mono_types[type_id.0 as usize];
 
        return mono_type.variant.as_procedure();
 
    }
 

	
 
    /// Reserves space for a monomorph of a polymorphic procedure. The index
 
    /// will point into a (reserved) slot of the array of expression types. The
 
    /// monomorph may NOT exist yet (because the reservation implies that we're
 
    /// going to be performing typechecking on it, and we don't want to
 
    /// check the same monomorph twice)
 
    pub(crate) fn reserve_procedure_monomorph_type_id(&mut self, definition_id: &DefinitionId, concrete_type: ConcreteType) -> TypeId {
 
        debug_assert_eq!(get_concrete_type_definition(&concrete_type.parts).unwrap(), *definition_id);
 
        let type_id = TypeId(self.mono_types.len() as i64);
 
        let base_type = self.definition_lookup.get_mut(definition_id).unwrap();
 
        self.mono_search_key.set(&concrete_type.parts, &base_type.poly_vars);
 

	
 
        debug_assert!(!self.mono_type_lookup.contains_key(&self.mono_search_key));
 
        self.mono_type_lookup.insert(self.mono_search_key.clone(), type_id);
 
        self.mono_types.push(MonoType::new_empty(type_id, concrete_type, MonoTypeVariant::Procedure(ProcedureMonomorph{
 
            arg_types: Vec::new(),
 
            expr_data: Vec::new(),
 
        })));
 

	
 
        return type_id;
 
    }
 

	
 
    /// Adds a builtin type to the type table. As this is only called by the
 
    /// compiler during setup we assume it cannot fail.
 
    // TODO: Finish this train of thought, requires a little bit of design work
 
    pub(crate) fn add_builtin_type(&mut self, concrete_type: ConcreteType, poly_vars: &[PolymorphicVariable], size: usize, alignment: usize) -> TypeId {
 
        self.mono_search_key.set(&concrete_type.parts, poly_vars);
 
        debug_assert!(!self.mono_type_lookup.contains_key(&self.mono_search_key));
 
        let type_id = TypeId(self.mono_types.len() as i64);
 
        self.mono_type_lookup.insert(self.mono_search_key.clone(), type_id);
 
        self.mono_types.push(MonoType{
 
            type_id,
 
            concrete_type,
 
            size,
 
            alignment,
 
            variant: MonoTypeVariant::Builtin,
 
        });
 

	
 
        return type_id;
 
    }
 

	
 
    /// Adds a monomorphed type to the type table. If it already exists then the
 
    /// previous entry will be used.
 
    pub(crate) fn add_monomorphed_type(
 
        &mut self, modules: &[Module], heap: &Heap, arch: &TargetArch,
 
        definition_id: DefinitionId, concrete_type: ConcreteType
 
    ) -> Result<TypeId, ParseError> {
 
        debug_assert_eq!(definition_id, get_concrete_type_definition(&concrete_type.parts).unwrap());
 

	
 
        // Check if the concrete type was already added
 
        let definition = self.definition_lookup.get(&definition_id).unwrap();
 
        let poly_var_in_use = &definition.poly_vars;
 
        self.mono_search_key.set(&concrete_type.parts, poly_var_in_use.as_slice());
 
        if let Some(type_id) = self.mono_type_lookup.get(&self.mono_search_key) {
 
            return Ok(*type_id);
 
        }
 

	
 
        // Concrete type needs to be added
 
        self.detect_and_resolve_type_loops_for(modules, heap, concrete_type)?;
 
        let type_id = self.encountered_types[0].type_id;
 
        self.lay_out_memory_for_encountered_types(arch);
 

	
 
        return Ok(type_id);
 
    }
 

	
 
    //--------------------------------------------------------------------------
 
    // Building base types
 
    //--------------------------------------------------------------------------
 

	
 
    /// Builds the base type for an enum. Will not compute byte sizes
 
    fn build_base_enum_definition(&mut self, modules: &[Module], ctx: &mut PassCtx, definition_id: DefinitionId) -> Result<(), ParseError> {
 
        debug_assert!(!self.definition_lookup.contains_key(&definition_id), "base enum already built");
 
        let definition = ctx.heap[definition_id].as_enum();
 
        let root_id = definition.defined_in;
 

	
 
        // Determine enum variants
 
        let mut enum_value = -1;
 
        let mut variants = Vec::with_capacity(definition.variants.len());
 

	
 
        for variant in &definition.variants {
 
            if enum_value == i64::MAX {
 
                let source = &modules[definition.defined_in.index as usize].source;
 
                return Err(ParseError::new_error_str_at_span(
 
                    source, variant.identifier.span,
 
                    "this enum variant has an integer value that is too large"
 
                ));
 
            }
 

	
 
            enum_value += 1;
 
            if let EnumVariantValue::Integer(explicit_value) = variant.value {
 
                enum_value = explicit_value;
 
            }
 

	
 
            variants.push(EnumVariant{
 
                identifier: variant.identifier.clone(),
 
                value: enum_value,
 
            });
 
        }
 

	
 
        // Determine tag size
 
        let mut min_enum_value = 0;
 
        let mut max_enum_value = 0;
 
        if !variants.is_empty() {
 
            min_enum_value = variants[0].value;
 
            max_enum_value = variants[0].value;
 
            for variant in variants.iter().skip(1) {
 
                min_enum_value = min_enum_value.min(variant.value);
 
                max_enum_value = max_enum_value.max(variant.value);
 
            }
 
        }
 

	
 
        let (tag_type, size_and_alignment) = Self::variant_tag_type_from_values(min_enum_value, max_enum_value);
 

	
 
        // Enum names and polymorphic args do not conflict
 
        Self::check_identifier_collision(
 
            modules, root_id, &variants, |variant| &variant.identifier, "enum variant"
 
        )?;
 

	
 
        // Polymorphic arguments cannot appear as embedded types, because
 
        // they can only consist of integer variants.
 
        Self::check_poly_args_collision(modules, ctx, root_id, &definition.poly_vars)?;
 
        let poly_vars = Self::create_polymorphic_variables(&definition.poly_vars);
 

	
 
        self.definition_lookup.insert(definition_id, DefinedType {
 
            ast_root: root_id,
 
            ast_definition: definition_id,
 
            definition: DefinedTypeVariant::Enum(EnumType{
 
                variants,
 
                minimum_tag_value: min_enum_value,
 
                maximum_tag_value: max_enum_value,
 
                tag_type,
 
                size: size_and_alignment,
 
                alignment: size_and_alignment
 
            }),
 
            poly_vars,
 
            is_polymorph: false,
 
        });
 

	
 
        return Ok(());
 
    }
 

	
 
    /// Builds the base type for a union. Will compute byte sizes.
 
    fn build_base_union_definition(&mut self, modules: &[Module], ctx: &mut PassCtx, definition_id: DefinitionId) -> Result<(), ParseError> {
 
        debug_assert!(!self.definition_lookup.contains_key(&definition_id), "base union already built");
 
        let definition = ctx.heap[definition_id].as_union();
 
        let root_id = definition.defined_in;
 

	
 
        // Check all variants and their embedded types
 
        let mut variants = Vec::with_capacity(definition.variants.len());
 
        let mut tag_counter = 0;
 
        for variant in &definition.variants {
 
            for embedded in &variant.value {
 
                Self::check_member_parser_type(
 
                    modules, ctx, root_id, embedded, false
 
                )?;
 
            }
 

	
 
            variants.push(UnionVariant{
 
                identifier: variant.identifier.clone(),
 
                embedded: variant.value.clone(),
 
                tag_value: tag_counter,
 
            });
 
            tag_counter += 1;
 
        }
 

	
 
        let mut max_tag_value = 0;
 
        if tag_counter != 0 {
 
            max_tag_value = tag_counter - 1
 
        }
 

	
 
        let (tag_type, tag_size) = Self::variant_tag_type_from_values(0, max_tag_value);
 

	
 
        // Make sure there are no conflicts in identifiers
 
        Self::check_identifier_collision(
 
            modules, root_id, &variants, |variant| &variant.identifier, "union variant"
 
        )?;
 
        Self::check_poly_args_collision(modules, ctx, root_id, &definition.poly_vars)?;
 

	
 
        // Construct internal representation of union
 
        let mut poly_vars = Self::create_polymorphic_variables(&definition.poly_vars);
 
        for variant in &definition.variants {
 
            for embedded in &variant.value {
 
                Self::mark_used_polymorphic_variables(&mut poly_vars, embedded);
 
            }
 
        }
 

	
 
        let is_polymorph = poly_vars.iter().any(|arg| arg.is_in_use);
 

	
 
        self.definition_lookup.insert(definition_id, DefinedType{
 
            ast_root: root_id,
 
            ast_definition: definition_id,
 
            definition: DefinedTypeVariant::Union(UnionType{ variants, tag_type, tag_size }),
 
            poly_vars,
 
            is_polymorph
 
        });
 

	
 
        return Ok(());
 
    }
 

	
 
    /// Builds base struct type. Will not compute byte sizes.
 
    fn build_base_struct_definition(&mut self, modules: &[Module], ctx: &mut PassCtx, definition_id: DefinitionId) -> Result<(), ParseError> {
 
        debug_assert!(!self.definition_lookup.contains_key(&definition_id), "base struct already built");
 
        let definition = ctx.heap[definition_id].as_struct();
 
        let root_id = definition.defined_in;
 

	
 
        // Check all struct fields and construct internal representation
 
        let mut fields = Vec::with_capacity(definition.fields.len());
 

	
 
        for field in &definition.fields {
 
            Self::check_member_parser_type(
 
                modules, ctx, root_id, &field.parser_type, false
 
            )?;
 

	
 
            fields.push(StructField{
 
                identifier: field.field.clone(),
 
                parser_type: field.parser_type.clone(),
 
            });
 
        }
 

	
 
        // Make sure there are no conflicting variables
 
        Self::check_identifier_collision(
 
            modules, root_id, &fields, |field| &field.identifier, "struct field"
 
        )?;
 
        Self::check_poly_args_collision(modules, ctx, root_id, &definition.poly_vars)?;
 

	
 
        // Construct base type in table
 
        let mut poly_vars = Self::create_polymorphic_variables(&definition.poly_vars);
 
        for field in &fields {
 
            Self::mark_used_polymorphic_variables(&mut poly_vars, &field.parser_type);
 
        }
 

	
 
        let is_polymorph = poly_vars.iter().any(|arg| arg.is_in_use);
 

	
 
        self.definition_lookup.insert(definition_id, DefinedType{
 
            ast_root: root_id,
 
            ast_definition: definition_id,
 
            definition: DefinedTypeVariant::Struct(StructType{ fields }),
 
            poly_vars,
 
            is_polymorph
 
        });
 

	
 
        return Ok(())
 
    }
 

	
 
    /// Builds base function type.
 
    fn build_base_function_definition(&mut self, modules: &[Module], ctx: &mut PassCtx, definition_id: DefinitionId) -> Result<(), ParseError> {
 
        debug_assert!(!self.definition_lookup.contains_key(&definition_id), "base function already built");
 
        let definition = ctx.heap[definition_id].as_function();
 
        let root_id = definition.defined_in;
 

	
 
        // Check and construct return types and argument types.
 
        Self::check_member_parser_type(
 
            modules, ctx, root_id, &definition.return_type, definition.builtin
 
        )?;
 

	
 
        let mut arguments = Vec::with_capacity(definition.parameters.len());
 
        for parameter_id in &definition.parameters {
 
            let parameter = &ctx.heap[*parameter_id];
 
            Self::check_member_parser_type(
 
                modules, ctx, root_id, &parameter.parser_type, definition.builtin
 
            )?;
 

	
 
            arguments.push(FunctionArgument{
 
                identifier: parameter.identifier.clone(),
 
                parser_type: parameter.parser_type.clone(),
 
            });
 
        }
 

	
 
        // Check conflict of identifiers
 
        Self::check_identifier_collision(
 
            modules, root_id, &arguments, |arg| &arg.identifier, "function argument"
 
        )?;
 
        Self::check_poly_args_collision(modules, ctx, root_id, &definition.poly_vars)?;
 

	
 
        // Construct internal representation of function type
 
        let mut poly_vars = Self::create_polymorphic_variables(&definition.poly_vars);
 

	
 
        Self::mark_used_polymorphic_variables(&mut poly_vars, &definition.return_type);
 
        for argument in &arguments {
 
            Self::mark_used_polymorphic_variables(&mut poly_vars, &argument.parser_type);
 
        }
 

	
 
        let is_polymorph = poly_vars.iter().any(|arg| arg.is_in_use);
 

	
 
        self.definition_lookup.insert(definition_id, DefinedType{
 
            ast_root: root_id,
 
            ast_definition: definition_id,
 
            definition: DefinedTypeVariant::Function(FunctionType{ return_type: definition.return_type.clone(), arguments }),
 
            poly_vars,
 
            is_polymorph
 
        });
 

	
 
        return Ok(());
 
    }
 

	
 
    /// Builds base component type.
 
    fn build_base_component_definition(&mut self, modules: &[Module], ctx: &mut PassCtx, definition_id: DefinitionId) -> Result<(), ParseError> {
 
        debug_assert!(!self.definition_lookup.contains_key(&definition_id), "base component already built");
 

	
 
        let definition = &ctx.heap[definition_id].as_component();
 
        let root_id = definition.defined_in;
 

	
 
        // Check the argument types
 
        let mut arguments = Vec::with_capacity(definition.parameters.len());
 
        for parameter_id in &definition.parameters {
 
            let parameter = &ctx.heap[*parameter_id];
 
            Self::check_member_parser_type(
 
                modules, ctx, root_id, &parameter.parser_type, false
 
            )?;
 

	
 
            arguments.push(FunctionArgument{
 
                identifier: parameter.identifier.clone(),
 
                parser_type: parameter.parser_type.clone(),
 
            });
 
        }
 

	
 
        // Check conflict of identifiers
 
        Self::check_identifier_collision(
 
            modules, root_id, &arguments, |arg| &arg.identifier, "connector argument"
 
        )?;
 
        Self::check_poly_args_collision(modules, ctx, root_id, &definition.poly_vars)?;
 

	
 
        // Construct internal representation of component
 
        // TODO: Marking used polymorphic variables on procedures requires
 
        //  making sure that each is used in the body. For now, mark them all
 
        //  as required.
 
        let mut poly_vars = Self::create_polymorphic_variables(&definition.poly_vars);
 
        // for argument in &arguments {
 
        //     Self::mark_used_polymorphic_variables(&mut poly_vars, &argument.parser_type);
 
        // }
 
        for poly_var in &mut poly_vars {
 
            poly_var.is_in_use = true;
 
        }
 

	
 
        let is_polymorph = poly_vars.iter().any(|arg| arg.is_in_use);
 

	
 
        self.definition_lookup.insert(definition_id, DefinedType{
 
            ast_root: root_id,
 
            ast_definition: definition_id,
 
            definition: DefinedTypeVariant::Component(ComponentType{ variant: definition.variant, arguments }),
 
            poly_vars,
 
            is_polymorph
 
        });
 

	
 
        Ok(())
 
    }
 

	
 
    /// Will check if the member type (field of a struct, embedded type in a
 
    /// union variant) is valid.
 
    fn check_member_parser_type(
 
        modules: &[Module], ctx: &PassCtx, base_definition_root_id: RootId,
 
        member_parser_type: &ParserType, allow_special_compiler_types: bool
 
    ) -> Result<(), ParseError> {
 
        use ParserTypeVariant as PTV;
 

	
 
        for element in &member_parser_type.elements {
 
            match element.variant {
 
                // Special cases
 
                PTV::Void | PTV::InputOrOutput | PTV::ArrayLike | PTV::IntegerLike => {
 
                    if !allow_special_compiler_types {
 
                        unreachable!("compiler-only ParserTypeVariant in member type");
 
                    }
 
                },
 
                // Builtin types, always valid
 
                PTV::Message | PTV::Bool |
 
                PTV::UInt8 | PTV::UInt16 | PTV::UInt32 | PTV::UInt64 |
 
                PTV::SInt8 | PTV::SInt16 | PTV::SInt32 | PTV::SInt64 |
 
                PTV::Character | PTV::String |
 
                PTV::Array | PTV::Input | PTV::Output | PTV::Tuple(_) |
 
                // Likewise, polymorphic variables are always valid
 
                PTV::PolymorphicArgument(_, _) => {},
 
                // Types that are not constructable, or types that are not
 
                // allowed (and checked earlier)
 
                PTV::IntegerLiteral | PTV::Inferred => {
 
                    unreachable!("illegal ParserTypeVariant within type definition");
 
                },
 
                // Finally, user-defined types
 
                PTV::Definition(definition_id, _) => {
 
                    let definition = &ctx.heap[definition_id];
 
                    if !(definition.is_struct() || definition.is_enum() || definition.is_union()) {
 
                        let source = &modules[base_definition_root_id.index as usize].source;
 
                        return Err(ParseError::new_error_str_at_span(
 
                            source, element.element_span, "expected a datatype (a struct, enum or union)"
 
                        ));
 
                    }
 

	
 
                    // Otherwise, we're fine
 
                }
 
            }
 
        }
 

	
 
        // If here, then all elements check out
 
        return Ok(());
 
    }
 

	
 
    /// Go through a list of identifiers and ensure that all identifiers have
 
    /// unique names
 
    fn check_identifier_collision<T: Sized, F: Fn(&T) -> &Identifier>(
 
        modules: &[Module], root_id: RootId, items: &[T], getter: F, item_name: &'static str
 
    ) -> Result<(), ParseError> {
 
        for (item_idx, item) in items.iter().enumerate() {
 
            let item_ident = getter(item);
 
            for other_item in &items[0..item_idx] {
 
                let other_item_ident = getter(other_item);
 
                if item_ident == other_item_ident {
 
                    let module_source = &modules[root_id.index as usize].source;
 
                    return Err(ParseError::new_error_at_span(
 
                        module_source, item_ident.span, format!("This {} is defined more than once", item_name)
 
                    ).with_info_at_span(
 
                        module_source, other_item_ident.span, format!("The other {} is defined here", item_name)
 
                    ));
 
                }
 
            }
 
        }
 

	
 
        Ok(())
 
    }
 

	
 
    /// Go through a list of polymorphic arguments and make sure that the
 
    /// arguments all have unique names, and the arguments do not conflict with
 
    /// any symbols defined at the module scope.
 
    fn check_poly_args_collision(
 
        modules: &[Module], ctx: &PassCtx, root_id: RootId, poly_args: &[Identifier]
 
    ) -> Result<(), ParseError> {
 
        // Make sure polymorphic arguments are unique and none of the
 
        // identifiers conflict with any imported scopes
 
        for (arg_idx, poly_arg) in poly_args.iter().enumerate() {
 
            for other_poly_arg in &poly_args[..arg_idx] {
 
                if poly_arg == other_poly_arg {
 
                    let module_source = &modules[root_id.index as usize].source;
 
                    return Err(ParseError::new_error_str_at_span(
 
                        module_source, poly_arg.span,
 
                        "This polymorphic argument is defined more than once"
 
                    ).with_info_str_at_span(
 
                        module_source, other_poly_arg.span,
 
                        "It conflicts with this polymorphic argument"
 
                    ));
 
                }
 
            }
 

	
 
            // Check if identifier conflicts with a symbol defined or imported
 
            // in the current module
 
            if let Some(symbol) = ctx.symbols.get_symbol_by_name(SymbolScope::Module(root_id), poly_arg.value.as_bytes()) {
 
                // We have a conflict
 
                let module_source = &modules[root_id.index as usize].source;
 
                let introduction_span = symbol.variant.span_of_introduction(ctx.heap);
 
                return Err(ParseError::new_error_str_at_span(
 
                    module_source, poly_arg.span,
 
                    "This polymorphic argument conflicts with another symbol"
 
                ).with_info_str_at_span(
 
                    module_source, introduction_span,
 
                    "It conflicts due to this symbol"
 
                ));
 
            }
 
        }
 

	
 
        // All arguments are fine
 
        Ok(())
 
    }
 

	
 
    //--------------------------------------------------------------------------
 
    // Detecting type loops
 
    //--------------------------------------------------------------------------
 

	
 
    /// Internal function that will detect type loops and check if they're
 
    /// resolvable. If so then the appropriate union variants will be marked as
 
    /// "living on heap". If not then a `ParseError` will be returned
 
    fn detect_and_resolve_type_loops_for(&mut self, modules: &[Module], heap: &Heap, concrete_type: ConcreteType) -> Result<(), ParseError> {
 
        // Programmer notes: what happens here is the we call
 
        // `check_member_for_type_loops` for a particular type's member, and
 
        // then take action using the return value:
 
        // 1. It might already be resolved: in this case it implies we don't
 
        //  have type loops, or they have been resolved.
 
        // 2. A new type is encountered. If so then it is added to the type loop
 
        //  breadcrumbs.
 
        // 3. A type loop is detected (implying the type is already resolved, or
 
        //  already exists in the type loop breadcrumbs).
 
        //
 
        // Using the breadcrumbs we incrementally check every member type of a
 
        // particular considered type (e.g. a struct field, tuple member), and
 
        // do the same as above. Note that when a breadcrumb is added we reserve
 
        // space in the monomorph storage, initialized to zero-values (i.e.
 
        // wrong values). The breadcrumbs keep track of how far and along we are
 
        // with resolving the member types.
 
        //
 
        // At the end we may have some type loops. If they're unresolvable then
 
        // we throw an error). If there are no type loops or they are all
 
        // resolvable then we end up with a list of `encountered_types`. These
 
        // are then used by `lay_out_memory_for_encountered_types`.
 
        debug_assert!(self.type_loop_breadcrumbs.is_empty());
 
        debug_assert!(self.type_loops.is_empty());
 
        debug_assert!(self.encountered_types.is_empty());
 

	
 
        // Push the initial breadcrumb
 
        let initial_breadcrumb = Self::check_member_for_type_loops(
 
            &self.type_loop_breadcrumbs, &self.definition_lookup, &self.mono_type_lookup,
 
            &mut self.mono_search_key, &concrete_type
 
        );
 
        if let TypeLoopResult::PushBreadcrumb(definition_id, concrete_type) = initial_breadcrumb {
 
            self.handle_new_breadcrumb_for_type_loops(definition_id, concrete_type);
 
        } else {
 
            unreachable!();
 
        }
 

	
 
        // Enter into the main resolving loop
 
        while !self.type_loop_breadcrumbs.is_empty() {
 
            // Because we might be modifying the breadcrumb array we need to
 
            let breadcrumb_idx = self.type_loop_breadcrumbs.len() - 1;
 
            let mut breadcrumb = self.type_loop_breadcrumbs[breadcrumb_idx].clone();
 

	
 
            let mono_type = &self.mono_types[breadcrumb.type_id.0 as usize];
 
            let resolve_result = match &mono_type.variant {
 
                MonoTypeVariant::Builtin => {
 
                    TypeLoopResult::TypeExists
 
                }
 
                MonoTypeVariant::Enum => {
 
                    TypeLoopResult::TypeExists
 
                },
 
                MonoTypeVariant::Union(monomorph) => {
 
                    let num_variants = monomorph.variants.len() as u32;
 
                    let mut union_result = TypeLoopResult::TypeExists;
 

	
 
                    'member_loop: while breadcrumb.next_member < num_variants {
 
                        let mono_variant = &monomorph.variants[breadcrumb.next_member as usize];
 
                        let num_embedded = mono_variant.embedded.len() as u32;
 

	
 
                        while breadcrumb.next_embedded < num_embedded {
 
                            let mono_embedded = &mono_variant.embedded[breadcrumb.next_embedded as usize];
 
                            union_result = Self::check_member_for_type_loops(
 
                                &self.type_loop_breadcrumbs, &self.definition_lookup, &self.mono_type_lookup,
 
                                &mut self.mono_search_key, &mono_embedded.concrete_type
 
                            );
 

	
 
                            if union_result != TypeLoopResult::TypeExists {
 
                                // In type loop or new breadcrumb pushed, so
 
                                // break out of the resolving loop
 
                                break 'member_loop;
 
                            }
 

	
 
                            breadcrumb.next_embedded += 1;
 
                        }
 

	
 
                        breadcrumb.next_embedded = 0;
 
                        breadcrumb.next_member += 1
 
                    }
 

	
 
                    union_result
 
                },
 
                MonoTypeVariant::Struct(monomorph) => {
 
                    let num_fields = monomorph.fields.len() as u32;
 

	
 
                    let mut struct_result = TypeLoopResult::TypeExists;
 
                    while breadcrumb.next_member < num_fields {
 
                        let mono_field = &monomorph.fields[breadcrumb.next_member as usize];
 
                        struct_result = Self::check_member_for_type_loops(
 
                            &self.type_loop_breadcrumbs, &self.definition_lookup, &self.mono_type_lookup,
 
                            &mut self.mono_search_key, &mono_field.concrete_type
 
                        );
 

	
 
                        if struct_result != TypeLoopResult::TypeExists {
 
                            // Type loop or breadcrumb pushed, so break out of
 
                            // the resolving loop
 
                            break;
 
                        }
 

	
 
                        breadcrumb.next_member += 1;
 
                    }
 

	
 
                    struct_result
 
                },
 
                MonoTypeVariant::Procedure(_) => unreachable!(),
 
                MonoTypeVariant::Tuple(monomorph) => {
 
                    let num_members = monomorph.members.len() as u32;
 
                    let mut tuple_result = TypeLoopResult::TypeExists;
 

	
 
                    while breadcrumb.next_member < num_members {
 
                        let tuple_member = &monomorph.members[breadcrumb.next_member as usize];
 
                        tuple_result = Self::check_member_for_type_loops(
 
                            &self.type_loop_breadcrumbs, &self.definition_lookup, &self.mono_type_lookup,
 
                            &mut self.mono_search_key, &tuple_member.concrete_type
 
                        );
 

	
 
                        if tuple_result != TypeLoopResult::TypeExists {
 
                            break;
 
                        }
 

	
 
                        breadcrumb.next_member += 1;
 
                    }
 

	
 
                    tuple_result
 
                }
 
            };
 

	
 
            // Handle the result of attempting to resolve the current breadcrumb
 
            match resolve_result {
 
                TypeLoopResult::TypeExists => {
 
                    // We finished parsing the type
 
                    self.type_loop_breadcrumbs.pop();
 
                },
 
                TypeLoopResult::PushBreadcrumb(definition_id, concrete_type) => {
 
                    // We recurse into the member type.
 
                    self.type_loop_breadcrumbs[breadcrumb_idx] = breadcrumb;
 
                    self.handle_new_breadcrumb_for_type_loops(definition_id, concrete_type);
 
                },
 
                TypeLoopResult::TypeLoop(first_idx) => {
 
                    // Because we will be modifying breadcrumbs within the
 
                    // type-loop handling code, put back the modified breadcrumb
 
                    self.type_loop_breadcrumbs[breadcrumb_idx] = breadcrumb;
 

	
 
                    // We're in a type loop. Add the type loop
 
                    let mut loop_members = Vec::with_capacity(self.type_loop_breadcrumbs.len() - first_idx);
 
                    let mut contains_union = false;
 

	
 
                    for breadcrumb_idx in first_idx..self.type_loop_breadcrumbs.len() {
 
                        let breadcrumb = &mut self.type_loop_breadcrumbs[breadcrumb_idx];
 
                        let mut is_union = false;
 

	
 
                        // Check if type loop member is a union that may be
 
                        // broken up by moving some of its members to the heap.
 
                        let mono_type = &mut self.mono_types[breadcrumb.type_id.0 as usize];
 
                        if let MonoTypeVariant::Union(union_type) = &mut mono_type.variant {
 
                            // Mark the variant that caused the loop as heap
 
                            // allocated to break the type loop.
 
                            let variant = &mut union_type.variants[breadcrumb.next_member as usize];
 
                            variant.lives_on_heap = true;
 
                            breadcrumb.next_embedded += 1;
 

	
 
                            is_union = true;
 
                            contains_union = true;
 
                        } // else: we don't care about the type for now
 

	
 
                        loop_members.push(TypeLoopEntry{
 
                            type_id: breadcrumb.type_id,
 
                            is_union
 
                        });
 
                    }
 

	
 
                    let new_type_loop = TypeLoop{ members: loop_members };
 
                    if !contains_union {
 
                        // No way to (potentially) break the union. So return a
 
                        // type loop error. This is because otherwise our
 
                        // breadcrumb resolver ends up in an infinite loop.
 
                        return Err(construct_type_loop_error(
 
                            &self.mono_types, &new_type_loop, modules, heap
 
                        ));
 
                    }
 

	
 
                    self.type_loops.push(new_type_loop);
 
                }
 
            }
 
        }
 

	
 
        // All breadcrumbs have been cleared. So now `type_loops` contains all
 
        // of the encountered type loops, and `encountered_types` contains a
 
        // list of all unique monomorphs we encountered.
 

	
 
        // The next step is to figure out if all of the type loops can be
 
        // broken. A type loop can be broken if at least one union exists in the
 
        // loop and that union ended up having variants that are not part of
 
        // a type loop.
 
        fn type_loop_source_span_and_message<'a>(
 
            modules: &'a [Module], heap: &Heap, mono_types: &MonoTypeArray,
 
            definition_id: DefinitionId, mono_type_id: TypeId, index_in_loop: usize
 
        ) -> (&'a InputSource, InputSpan, String) {
 
            // Note: because we will discover the type loop the *first* time we
 
            // instantiate a monomorph with the provided polymorphic arguments
 
            // (not all arguments are actually used in the type). We don't have
 
            // to care about a second instantiation where certain unused
 
            // polymorphic arguments are different.
 
            let mono_type = &mono_types[mono_type_id.0 as usize];
 
            let type_name = mono_type.concrete_type.display_name(heap);
 

	
 
            let message = if index_in_loop == 0 {
 
                format!(
 
                    "encountered an infinitely large type for '{}' (which can be fixed by \
 
                    introducing a union type that has a variant whose embedded types are \
 
                    not part of a type loop, or do not have embedded types)",
 
                    type_name
 
                )
 
            } else if index_in_loop == 1 {
 
                format!("because it depends on the type '{}'", type_name)
 
            } else {
 
                format!("which depends on the type '{}'", type_name)
 
            };
 

	
 
            let ast_definition = &heap[definition_id];
 
            let ast_root_id = ast_definition.defined_in();
 

	
 
            return (
 
                &modules[ast_root_id.index as usize].source,
 
                ast_definition.identifier().span,
 
                message
 
            );
 
        }
 

	
 
        fn construct_type_loop_error(mono_types: &MonoTypeArray, type_loop: &TypeLoop, modules: &[Module], heap: &Heap) -> ParseError {
 
            // Seek first entry to produce parse error. Then continue builder
 
            // pattern. This is the error case so efficiency can go home.
 
            let mut parse_error = None;
 
            let mut next_member_index = 0;
 
            while next_member_index < type_loop.members.len() {
 
                let first_entry = &type_loop.members[next_member_index];
 
                next_member_index += 1;
 

	
 
                // Retrieve definition of first type in loop
 
                let first_mono_type = &mono_types[first_entry.type_id.0 as usize];
 
                let first_definition_id = get_concrete_type_definition(&first_mono_type.concrete_type.parts);
 
                if first_definition_id.is_none() {
 
                    continue;
 
                }
 
                let first_definition_id = first_definition_id.unwrap();
 

	
 
                // Produce error message for first type in loop
 
                let (first_module, first_span, first_message) = type_loop_source_span_and_message(
 
                    modules, heap, mono_types, first_definition_id, first_entry.type_id, 0
 
                );
 
                parse_error = Some(ParseError::new_error_at_span(first_module, first_span, first_message));
 
                break;
 
            }
 

	
 
            let mut parse_error = parse_error.unwrap(); // Loop above cannot have failed, because we must have a type loop, type loops cannot contain only unnamed types
 

	
 
            let mut error_counter = 1;
 
            for member_idx in next_member_index..type_loop.members.len() {
 
                let entry = &type_loop.members[member_idx];
 
                let mono_type = &mono_types[entry.type_id.0 as usize];
 
                let definition_id = get_concrete_type_definition(&mono_type.concrete_type.parts);
 
                if definition_id.is_none() {
 
                    continue;
 
                }
 
                let definition_id = definition_id.unwrap();
 

	
 
                let (module, span, message) = type_loop_source_span_and_message(
 
                    modules, heap, mono_types, definition_id, entry.type_id, error_counter
 
                );
 
                parse_error = parse_error.with_info_at_span(module, span, message);
 
                error_counter += 1;
 
            }
 

	
 
            parse_error
 
        }
 

	
 
        for type_loop in &self.type_loops {
 
            let mut can_be_broken = false;
 
            debug_assert!(!type_loop.members.is_empty());
 

	
 
            for entry in &type_loop.members {
 
                if entry.is_union {
 
                    let mono_type = self.mono_types[entry.type_id.0 as usize].variant.as_union();
 
                    debug_assert!(!mono_type.variants.is_empty()); // otherwise it couldn't be part of the type loop
 
                    let has_stack_variant = mono_type.variants.iter().any(|variant| !variant.lives_on_heap);
 
                    if has_stack_variant {
 
                        can_be_broken = true;
 
                        break;
 
                    }
 
                }
 
            }
 

	
 
            if !can_be_broken {
 
                // Construct a type loop error
 
                return Err(construct_type_loop_error(&self.mono_types, type_loop, modules, heap));
 
            }
 
        }
 

	
 
        // If here, then all type loops have been resolved and we can lay out
 
        // all of the members
 
        self.type_loops.clear();
 

	
 
        return Ok(());
 
    }
 

	
 
    /// Checks if the specified type needs to be resolved (i.e. we need to push
 
    /// a breadcrumb), is already resolved (i.e. we can continue with the next
 
    /// member of the currently considered type) or is in the process of being
 
    /// resolved (i.e. we're in a type loop). Because of borrowing rules we
 
    /// don't do any modifications of internal types here. Hence: if we
0 comments (0 inline, 0 general)