Appearance
| 1 | namespace Syntax.Process is | |
| 2 | use Trees | |
| 3 | ||
| 4 | // Walk an AST resetting per-build mutable state on each node. | |
| 5 | // | |
| 6 | // Each visit override calls `node.clear()` (non-recursive — Node.clear | |
| 7 | // resets only its own state). Traversal is handled by the existing walk | |
| 8 | // methods on each tree class, which already know how to recurse. | |
| 9 | // | |
| 10 | // Run between compile-expressions invocations on the same AST (analyser | |
| 11 | // COMPILE-after-EDIT, multi-file rebuilds). See project_analysis_mode_workflow | |
| 12 | // memory for why this is needed: ad-hoc resets in individual visit | |
| 13 | // methods cover most state, but the constraint mechanism's narrowing-only | |
| 14 | // upgrade can leave stale entries across `apply` calls. This visitor | |
| 15 | // makes clearing structural rather than ad-hoc. | |
| 16 | // Inherits from StrictVisitor (rather than Visitor) so that any AST | |
| 17 | // node type added to the codebase later will throw NotImplementedException | |
| 18 | // here until someone adds an override — forces us to consider whether | |
| 19 | // the new node has clearable state. The default override per node type | |
| 20 | // calls node.clear() which is itself a no-op unless the subclass adds | |
| 21 | // state to clear, so the cost of adding a new node type is one trivial | |
| 22 | // override here. | |
| 23 | class CLEAR_STATE_VISITOR: StrictVisitor is | |
| 24 | // When true, TypeExpression.type (resolve-type-expressions output) | |
| 25 | // is left intact and only compile-expressions output is cleared. | |
| 26 | // The recompile-dependents path uses this: a referencing file's | |
| 27 | // bodies must re-compile to rebind to a reconciled symbol, but its | |
| 28 | // interface type expressions are unchanged and re-resolving them | |
| 29 | // against the retained interface symbols would set their types | |
| 30 | // twice. Compile-expressions output lives in Expression/Statement | |
| 31 | // compile state and the VariableLeft store, separate from | |
| 32 | // TypeExpression.type, so clearing it without touching the resolved | |
| 33 | // types is a clean split. | |
| 34 | _preserve_resolved_types: bool | |
| 35 | ||
| 36 | // When true, each node keeps what its context pushed down and | |
| 37 | // drops only what the walk produced (see Node.clear_outputs): | |
| 38 | // the reset the compile-expressions retry loop makes between | |
| 39 | // walks of one body. Implies preserving resolved types. | |
| 40 | _outputs_only: bool | |
| 41 | ||
| 42 | init() is | |
| 43 | super.init() | |
| 44 | _preserve_resolved_types = false | |
| 45 | _outputs_only = false | |
| 46 | si | |
| 47 | ||
| 48 | init(preserve_resolved_types: bool) is | |
| 49 | super.init() | |
| 50 | _preserve_resolved_types = preserve_resolved_types | |
| 51 | _outputs_only = false | |
| 52 | si | |
| 53 | ||
| 54 | init(preserve_resolved_types: bool, outputs_only: bool) is | |
| 55 | super.init() | |
| 56 | _preserve_resolved_types = preserve_resolved_types \/ outputs_only | |
| 57 | _outputs_only = outputs_only | |
| 58 | si | |
| 59 | ||
| 60 | _clear(node: Trees.Node) is | |
| 61 | if _outputs_only then | |
| 62 | node.clear_outputs() | |
| 63 | else | |
| 64 | node.clear() | |
| 65 | fi | |
| 66 | si | |
| 67 | ||
| 68 | apply(root: Trees.Node) is | |
| 69 | root.walk(self) | |
| 70 | si | |
| 71 | ||
| 72 | _clear_type(type_expression: TypeExpressions.TypeExpression) is | |
| 73 | if !_preserve_resolved_types then | |
| 74 | type_expression.clear() | |
| 75 | fi | |
| 76 | si | |
| 77 | ||
| 78 | // StrictVisitor.pre(STATEMENT) and pre(VAL_BLOCK) throw. Override | |
| 79 | // here to allow normal recursion into the child body. | |
| 80 | pre(statement: Trees.Expressions.STATEMENT) -> bool => false | |
| 81 | pre(block: Trees.Expressions.VAL_BLOCK) -> bool => false | |
| 82 | // Identifiers | |
| 83 | visit(identifier: Identifiers.Identifier) is _clear(identifier); si | |
| 84 | visit(identifier: Identifiers.QUALIFIED) is _clear(identifier); si | |
| 85 | ||
| 86 | // Modifiers / pragmas | |
| 87 | visit(modifier: Modifiers.Modifier) is _clear(modifier); si | |
| 88 | visit(modifiers: Modifiers.LIST) is _clear(modifiers); si | |
| 89 | visit(pragma: Pragmas.PRAGMA) is _clear(pragma); si | |
| 90 | ||
| 91 | // Definitions | |
| 92 | visit(definition: Definitions.Definition) is _clear(definition); si | |
| 93 | // LIST has no per-build state of its own; the walk has already | |
| 94 | // visited each child in `definitions` and called clear() on it. | |
| 95 | visit(definitions: Definitions.LIST) is si | |
| 96 | visit(pragma: Definitions.PRAGMA) is _clear(pragma); si | |
| 97 | visit(`namespace: Definitions.NAMESPACE) is _clear(`namespace); si | |
| 98 | visit(`use: Definitions.USE) is _clear(`use); si | |
| 99 | visit(`class: Definitions.CLASS) is _clear(`class); si | |
| 100 | visit(`partial: Definitions.PARTIAL) is _clear(`partial); si | |
| 101 | visit(`impl: Definitions.IMPL) is _clear(`impl); si | |
| 102 | visit(`trait: Definitions.TRAIT) is _clear(`trait); si | |
| 103 | visit(`struct: Definitions.STRUCT) is _clear(`struct); si | |
| 104 | visit(`union: Definitions.UNION) is _clear(`union); si | |
| 105 | visit(variant: Definitions.VARIANT) is _clear(variant); si | |
| 106 | visit(`enum: Definitions.ENUM) is _clear(`enum); si | |
| 107 | visit(enum_member: Definitions.ENUM_MEMBER) is _clear(enum_member); si | |
| 108 | visit(function: Definitions.FUNCTION) is _clear(function); si | |
| 109 | visit(functions: Definitions.FUNCTION_GROUP) is _clear(functions); si | |
| 110 | visit(property: Definitions.PROPERTY) is _clear(property); si | |
| 111 | visit(indexer: Definitions.INDEXER) is _clear(indexer); si | |
| 112 | ||
| 113 | // Variables (definition-side) | |
| 114 | visit(variable: Variables.VARIABLE) is _clear(variable); si | |
| 115 | visit(variables: Variables.LIST) is _clear(variables); si | |
| 116 | visit(left: Trees.Variables.SIMPLE_VARIABLE_LEFT) is _clear(left); si | |
| 117 | visit(destructure_left: Trees.Variables.DESTRUCTURING_VARIABLE_LEFT) is _clear(destructure_left); si | |
| 118 | visit(literal_leaf: Trees.Variables.LITERAL_VARIABLE_LEFT) is _clear(literal_leaf); si | |
| 119 | ||
| 120 | // Type expressions — clearing `type` here is skipped when | |
| 121 | // preserving resolved types (see `_clear_type`). | |
| 122 | visit(type_expression: TypeExpressions.TypeExpression) is _clear_type(type_expression); si | |
| 123 | visit(type_expression: TypeExpressions.INFER) is _clear_type(type_expression); si | |
| 124 | visit(structured: TypeExpressions.Structured) is _clear_type(structured); si | |
| 125 | visit(array: TypeExpressions.ARRAY_) is _clear_type(array); si | |
| 126 | visit(pointer: TypeExpressions.POINTER) is _clear_type(pointer); si | |
| 127 | visit(optional: TypeExpressions.OPTIONAL) is _clear_type(optional); si | |
| 128 | visit(reference: TypeExpressions.REFERENCE) is _clear_type(reference); si | |
| 129 | visit(member: TypeExpressions.MEMBER) is _clear_type(member); si | |
| 130 | visit(named: TypeExpressions.NAMED) is _clear_type(named); si | |
| 131 | visit(types: TypeExpressions.LIST) is _clear(types); si | |
| 132 | visit(generic: TypeExpressions.GENERIC) is _clear_type(generic); si | |
| 133 | visit(function: TypeExpressions.FUNCTION) is _clear_type(function); si | |
| 134 | visit(functions: TypeExpressions.FUNCTION_GROUP) is _clear_type(functions); si | |
| 135 | visit(tuple: TypeExpressions.TUPLE) is _clear_type(tuple); si | |
| 136 | visit(element: TypeExpressions.NAMED_TUPLE_ELEMENT) is _clear_type(element); si | |
| 137 | visit(constraint: TypeExpressions.TYPE_PARAMETER_CONSTRAINT) is _clear_type(constraint); si | |
| 138 | visit(element: TypeExpressions.UNDEFINED) is _clear_type(element); si | |
| 139 | ||
| 140 | // Expressions | |
| 141 | visit(expression: Expressions.Expression) is _clear(expression); si | |
| 142 | visit(identifier: Expressions.IDENTIFIER) is _clear(identifier); si | |
| 143 | visit(literal: Expressions.Literals.Literal) is _clear(literal); si | |
| 144 | visit(`string: Expressions.Literals.STRING) is _clear(`string); si | |
| 145 | visit(interpolation: Expressions.STRING_INTERPOLATION) is _clear(interpolation); si | |
| 146 | visit(integer: Expressions.Literals.INTEGER) is _clear(integer); si | |
| 147 | visit(float: Expressions.Literals.FLOAT) is _clear(float); si | |
| 148 | visit(character: Expressions.Literals.CHARACTER) is _clear(character); si | |
| 149 | visit(boolean: Expressions.Literals.BOOLEAN) is _clear(boolean); si | |
| 150 | visit(variable: Expressions.VARIABLE) is _clear(variable); si | |
| 151 | visit(variable: Expressions.TUPLE_ELEMENT) is _clear(variable); si | |
| 152 | visit(none: Expressions.Literals.NONE) is _clear(none); si | |
| 153 | visit(`null: Expressions.NULL) is _clear(`null); si | |
| 154 | visit(`self: Expressions.SELF) is _clear(`self); si | |
| 155 | visit(`super: Expressions.SUPER) is _clear(`super); si | |
| 156 | visit(construct: Expressions.CONSTRUCT) is _clear(construct); si | |
| 157 | // The reading of an ambiguous cast is a resolve-type-expressions | |
| 158 | // result like any other, so it is cleared with them: a later | |
| 159 | // walk decides again against whatever the scope says then. | |
| 160 | visit(`cast: Expressions.CAST) is | |
| 161 | `cast.set_reading(Expressions.CastReading.UNDECIDED) | |
| 162 | _clear(`cast) | |
| 163 | si | |
| 164 | visit(`await: Expressions.AWAIT) is _clear(`await); si | |
| 165 | visit(spill: Expressions.SPILL) is _clear(spill); si | |
| 166 | visit(`isa: Expressions.ISA) is _clear(`isa); si | |
| 167 | ||
| 168 | visit(field_equals: Expressions.FIELD_EQUALS) is _clear(field_equals); si | |
| 169 | visit(hash_operand: Expressions.HASH_OPERAND) is _clear(hash_operand); si | |
| 170 | visit(memberwise_equals: Expressions.MEMBERWISE_EQUALS) is _clear(memberwise_equals); si | |
| 171 | visit(memberwise_hash: Expressions.MEMBERWISE_HASH) is _clear(memberwise_hash); si | |
| 172 | visit(`isa: Expressions.TYPEOF) is _clear(`isa); si | |
| 173 | visit(`default: Expressions.DEFAULT) is _clear(`default); si | |
| 174 | visit(function: Expressions.FUNCTION) is _clear(function); si | |
| 175 | visit(recurse: Expressions.RECURSE) is _clear(recurse); si | |
| 176 | visit(tuple: Expressions.TUPLE) is _clear(tuple); si | |
| 177 | visit(sequence: Expressions.SEQUENCE) is _clear(sequence); si | |
| 178 | visit(list: Expressions.LIST) is _clear(list); si | |
| 179 | visit(call: Expressions.CALL) is _clear(call); si | |
| 180 | visit(member: Expressions.MEMBER) is _clear(member); si | |
| 181 | visit(ambiguous_expression: Expressions.AMBIGUOUS_EXPRESSION) is _clear(ambiguous_expression); si | |
| 182 | visit(ambiguous_expression: Expressions.GENERIC_APPLICATION) is _clear(ambiguous_expression); si | |
| 183 | visit(index: Expressions.INDEX) is _clear(index); si | |
| 184 | visit(has_value: Expressions.HAS_VALUE) is _clear(has_value); si | |
| 185 | visit(unwrap: Expressions.UNWRAP) is _clear(unwrap); si | |
| 186 | visit(reference: Expressions.REFERENCE) is _clear(reference); si | |
| 187 | visit(unary: Expressions.UNARY) is _clear(unary); si | |
| 188 | visit(binary: Expressions.BINARY) is _clear(binary); si | |
| 189 | visit(statement: Expressions.STATEMENT) is _clear(statement); si | |
| 190 | visit(statement: Expressions.LET_IN) is _clear(statement); si | |
| 191 | visit(block: Expressions.VAL_BLOCK) is _clear(block); si | |
| 192 | visit(assert_in: Expressions.ASSERT_IN) is _clear(assert_in); si | |
| 193 | ||
| 194 | // Left-side expressions | |
| 195 | visit(left: Trees.Expressions.SIMPLE_LEFT_EXPRESSION) is _clear(left); si | |
| 196 | visit(destructure_left: Trees.Expressions.DESTRUCTURING_LEFT_EXPRESSION) is _clear(destructure_left); si | |
| 197 | ||
| 198 | // Statements | |
| 199 | visit(statement: Statements.Statement) is _clear(statement); si | |
| 200 | visit(statements: Statements.LIST) is _clear(statements); si | |
| 201 | visit(f: Statements.FUNCTION) is _clear(f); si | |
| 202 | visit(l: Statements.LET) is _clear(l); si | |
| 203 | visit(assign: Statements.ASSIGNMENT) is _clear(assign); si | |
| 204 | visit(expression: Statements.EXPRESSION) is _clear(expression); si | |
| 205 | visit(`return: Statements.RETURN) is _clear(`return); si | |
| 206 | visit(`throw: Statements.THROW) is _clear(`throw); si | |
| 207 | visit(`yield: Statements.YIELD) is _clear(`yield); si | |
| 208 | visit(`yield: Statements.YIELD_ALL) is _clear(`yield); si | |
| 209 | visit(assert__: Statements.ASSERT) is _clear(assert__); si | |
| 210 | visit(`if: Statements.IF) is _clear(`if); si | |
| 211 | visit(if_branch: Statements.IF_BRANCH) is _clear(if_branch); si | |
| 212 | visit(rb: Statements.REFUTABLE_BINDING) is _clear(rb); si | |
| 213 | visit(`case: Statements.CASE) is _clear(`case); si | |
| 214 | visit(case_match: Statements.CASE_MATCH) is _clear(case_match); si | |
| 215 | visit(`try: Statements.TRY) is _clear(`try); si | |
| 216 | visit(`catch: Statements.CATCH) is _clear(`catch); si | |
| 217 | visit(`do: Statements.DO) is _clear(`do); si | |
| 218 | visit(`for: Statements.FOR) is _clear(`for); si | |
| 219 | visit(labelled: Statements.LABELLED) is _clear(labelled); si | |
| 220 | visit(`break: Statements.BREAK) is _clear(`break); si | |
| 221 | visit(`continue: Statements.CONTINUE) is _clear(`continue); si | |
| 222 | visit(pragma: Statements.PRAGMA) is _clear(pragma); si | |
| 223 | ||
| 224 | // Bodies | |
| 225 | visit(expression: Bodies.EXPRESSION) is _clear(expression); si | |
| 226 | visit(block: Bodies.BLOCK) is _clear(block); si | |
| 227 | visit(block: Bodies.NULL) is _clear(block); si | |
| 228 | visit(block: Bodies.INNATE) is _clear(block); si | |
| 229 | si | |
| 230 | si |