Appearance
| 1 | namespace Syntax.Process is | |
| 2 | use Collections | |
| 3 | ||
| 4 | use LOCATION = Source.LOCATION | |
| 5 | use Type = Semantic.Types.Type | |
| 6 | use Value = IR.Values.Value | |
| 7 | use VariableLeft = Trees.Variables.VariableLeft | |
| 8 | ||
| 9 | // Compile-expressions output for one variable binding target (a | |
| 10 | // VariableLeft node). Owned by the compile-expressions pass and read | |
| 11 | // by IL generation; kept here, keyed by node, rather than in fields | |
| 12 | // on the node itself (see NodeStateStore). | |
| 13 | class VARIABLE_LEFT_STATE is | |
| 14 | // code to store into the bound variable, from the initializer | |
| 15 | value: Value? public | |
| 16 | explicit_type: Type? public | |
| 17 | ||
| 18 | // For an `if let` / `while let` clause pattern: the clause's | |
| 19 | // ascribed narrow type, specialized against the scrutinee's | |
| 20 | // type so a variant of a generic union carries its type | |
| 21 | // arguments. IL generation tests against this rather than the | |
| 22 | // written type expression, which for a generic union names the | |
| 23 | // open generic and is not a loadable `isinst` operand. | |
| 24 | narrow_type: Type? public | |
| 25 | ||
| 26 | // the compiled initializer, if any | |
| 27 | right_value: Value? public | |
| 28 | right_location: LOCATION? public | |
| 29 | variable_location: LOCATION? public | |
| 30 | ||
| 31 | // An untyped local initialized with an empty array literal and | |
| 32 | // no context to type it: the local waits on its later uses | |
| 33 | // rather than taking the literal's object fallback. | |
| 34 | awaits_later_use: bool public | |
| 35 | ||
| 36 | // Whether what the local waits on is an empty array literal, | |
| 37 | // which the fixing step can default to an object element type, | |
| 38 | // as against an initializer with no default at all. | |
| 39 | awaits_empty_literal: bool public | |
| 40 | ||
| 41 | // An untyped immutable local whose initializer has no type of its | |
| 42 | // own to give it - a `_()` construction, or a call leaving a type | |
| 43 | // parameter of its own unbound - once seen: from then on, every | |
| 44 | // walk types the initializer from the local's later uses. | |
| 45 | typed_by_later_use: bool public | |
| 46 | ||
| 47 | // For a literal leaf in a destructure pattern: the value-equality | |
| 48 | // test built the way `=~` (falling back to `<>`) would, and the | |
| 49 | // hole standing in for the source position's value. The source | |
| 50 | // value only exists once IL generation walks the pattern, so the | |
| 51 | // test is built against `match_operand` and generation fills it | |
| 52 | // in before emitting. Both null when no operator resolved, or for | |
| 53 | // a `null` leaf, which is a presence test rather than a compare. | |
| 54 | match_test: Value? public | |
| 55 | match_operand: IR.Values.WRAPPER? public | |
| 56 | ||
| 57 | init() is | |
| 58 | si | |
| 59 | si | |
| 60 | ||
| 61 | // Entries are keyed by (file name, node id), not node object | |
| 62 | // identity — see Node.node_id. Ids are never reused, so an entry | |
| 63 | // orphaned by tree replacement can go stale but can never be | |
| 64 | // served for a different node. | |
| 65 | class VARIABLE_LEFT_STATE_STORE: NodeStateStore is | |
| 66 | _state_by_file: MutableMap[string, MutableMap[int, VARIABLE_LEFT_STATE]] | |
| 67 | ||
| 68 | name: string => "variable-left" | |
| 69 | ||
| 70 | entry_count: int => _count_entries() | |
| 71 | ||
| 72 | init(registry: STATE_STORE_REGISTRY) is | |
| 73 | _state_by_file = MAP[string, MutableMap[int, VARIABLE_LEFT_STATE]]() | |
| 74 | ||
| 75 | registry.register(self) | |
| 76 | si | |
| 77 | ||
| 78 | // The state recorded for `left`, or null when none has been. | |
| 79 | get(left: VariableLeft) -> VARIABLE_LEFT_STATE? is | |
| 80 | let by_node: MutableMap[int, VARIABLE_LEFT_STATE] mut | |
| 81 | ||
| 82 | if !_state_by_file.try_get_value(left.location.file_name, by_node ref) then | |
| 83 | return null | |
| 84 | fi | |
| 85 | ||
| 86 | let result: VARIABLE_LEFT_STATE mut | |
| 87 | ||
| 88 | if by_node.try_get_value(left.node_id, result ref) then | |
| 89 | return result | |
| 90 | fi | |
| 91 | ||
| 92 | return null | |
| 93 | si | |
| 94 | ||
| 95 | get_or_add(left: VariableLeft) -> VARIABLE_LEFT_STATE is | |
| 96 | let file_name = left.location.file_name | |
| 97 | ||
| 98 | let by_node: MutableMap[int, VARIABLE_LEFT_STATE] mut | |
| 99 | ||
| 100 | if !_state_by_file.try_get_value(file_name, by_node ref) then | |
| 101 | by_node = MAP[int, VARIABLE_LEFT_STATE]() | |
| 102 | _state_by_file[file_name] = by_node | |
| 103 | fi | |
| 104 | ||
| 105 | let result: VARIABLE_LEFT_STATE mut | |
| 106 | ||
| 107 | if !by_node.try_get_value(left.node_id, result ref) then | |
| 108 | result = VARIABLE_LEFT_STATE() | |
| 109 | by_node[left.node_id] = result | |
| 110 | fi | |
| 111 | ||
| 112 | return result | |
| 113 | si | |
| 114 | ||
| 115 | remove(left: VariableLeft) is | |
| 116 | let by_node: MutableMap[int, VARIABLE_LEFT_STATE] mut | |
| 117 | ||
| 118 | if _state_by_file.try_get_value(left.location.file_name, by_node ref) then | |
| 119 | by_node.remove(left.node_id) | |
| 120 | fi | |
| 121 | si | |
| 122 | ||
| 123 | drop_file(file_name: string) is | |
| 124 | _state_by_file.remove(file_name) | |
| 125 | si | |
| 126 | ||
| 127 | clear_all() is | |
| 128 | _state_by_file = MAP[string, MutableMap[int, VARIABLE_LEFT_STATE]]() | |
| 129 | si | |
| 130 | ||
| 131 | _count_entries() -> int is | |
| 132 | let result mut = 0 | |
| 133 | ||
| 134 | for by_node in _state_by_file.values do | |
| 135 | result = result + by_node.count | |
| 136 | od | |
| 137 | ||
| 138 | return result | |
| 139 | si | |
| 140 | si | |
| 141 | si |