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 | init() is | |
| 37 | super.init(); | |
| 38 | _preserve_resolved_types = false; | |
| 39 | si | |
| 40 | ||
| 41 | init(preserve_resolved_types: bool) is | |
| 42 | super.init(); | |
| 43 | _preserve_resolved_types = preserve_resolved_types; | |
| 44 | si | |
| 45 | ||
| 46 | apply(root: Trees.Node) is | |
| 47 | root.walk(self); | |
| 48 | si | |
| 49 | ||
| 50 | _clear_type(type_expression: TypeExpressions.TypeExpression) is | |
| 51 | if !_preserve_resolved_types then | |
| 52 | type_expression.clear(); | |
| 53 | fi | |
| 54 | si | |
| 55 | ||
| 56 | // StrictVisitor.pre(STATEMENT) and pre(VAL_BLOCK) throw. Override | |
| 57 | // here to allow normal recursion into the child body. | |
| 58 | pre(statement: Trees.Expressions.STATEMENT) -> bool => false; | |
| 59 | pre(block: Trees.Expressions.VAL_BLOCK) -> bool => false; | |
| 60 | // Identifiers | |
| 61 | visit(identifier: Identifiers.Identifier) is identifier.clear(); si | |
| 62 | visit(identifier: Identifiers.QUALIFIED) is identifier.clear(); si | |
| 63 | ||
| 64 | // Modifiers / pragmas | |
| 65 | visit(modifier: Modifiers.Modifier) is modifier.clear(); si | |
| 66 | visit(modifiers: Modifiers.LIST) is modifiers.clear(); si | |
| 67 | visit(pragma: Pragmas.PRAGMA) is pragma.clear(); si | |
| 68 | ||
| 69 | // Definitions | |
| 70 | visit(definition: Definitions.Definition) is definition.clear(); si | |
| 71 | // LIST has no per-build state of its own; the walk has already | |
| 72 | // visited each child in `definitions` and called clear() on it. | |
| 73 | visit(definitions: Definitions.LIST) is si | |
| 74 | visit(pragma: Definitions.PRAGMA) is pragma.clear(); si | |
| 75 | visit(`namespace: Definitions.NAMESPACE) is `namespace.clear(); si | |
| 76 | visit(`use: Definitions.USE) is `use.clear(); si | |
| 77 | visit(`class: Definitions.CLASS) is `class.clear(); si | |
| 78 | visit(`partial: Definitions.PARTIAL) is `partial.clear(); si | |
| 79 | visit(`impl: Definitions.IMPL) is `impl.clear(); si | |
| 80 | visit(`trait: Definitions.TRAIT) is `trait.clear(); si | |
| 81 | visit(`struct: Definitions.STRUCT) is `struct.clear(); si | |
| 82 | visit(`union: Definitions.UNION) is `union.clear(); si | |
| 83 | visit(variant: Definitions.VARIANT) is variant.clear(); si | |
| 84 | visit(`enum: Definitions.ENUM) is `enum.clear(); si | |
| 85 | visit(enum_member: Definitions.ENUM_MEMBER) is enum_member.clear(); si | |
| 86 | visit(function: Definitions.FUNCTION) is function.clear(); si | |
| 87 | visit(functions: Definitions.FUNCTION_GROUP) is functions.clear(); si | |
| 88 | visit(property: Definitions.PROPERTY) is property.clear(); si | |
| 89 | visit(indexer: Definitions.INDEXER) is indexer.clear(); si | |
| 90 | ||
| 91 | // Variables (definition-side) | |
| 92 | visit(variable: Variables.VARIABLE) is variable.clear(); si | |
| 93 | visit(variables: Variables.LIST) is variables.clear(); si | |
| 94 | visit(left: Trees.Variables.SIMPLE_VARIABLE_LEFT) is left.clear(); si | |
| 95 | visit(destructure_left: Trees.Variables.DESTRUCTURING_VARIABLE_LEFT) is destructure_left.clear(); si | |
| 96 | visit(literal_leaf: Trees.Variables.LITERAL_VARIABLE_LEFT) is literal_leaf.clear(); si | |
| 97 | ||
| 98 | // Type expressions — clearing `type` here is skipped when | |
| 99 | // preserving resolved types (see `_clear_type`). | |
| 100 | visit(type_expression: TypeExpressions.TypeExpression) is _clear_type(type_expression); si | |
| 101 | visit(type_expression: TypeExpressions.INFER) is _clear_type(type_expression); si | |
| 102 | visit(structured: TypeExpressions.Structured) is _clear_type(structured); si | |
| 103 | visit(array: TypeExpressions.ARRAY_) is _clear_type(array); si | |
| 104 | visit(pointer: TypeExpressions.POINTER) is _clear_type(pointer); si | |
| 105 | visit(optional: TypeExpressions.OPTIONAL) is _clear_type(optional); si | |
| 106 | visit(reference: TypeExpressions.REFERENCE) is _clear_type(reference); si | |
| 107 | visit(member: TypeExpressions.MEMBER) is _clear_type(member); si | |
| 108 | visit(named: TypeExpressions.NAMED) is _clear_type(named); si | |
| 109 | visit(types: TypeExpressions.LIST) is types.clear(); si | |
| 110 | visit(generic: TypeExpressions.GENERIC) is _clear_type(generic); si | |
| 111 | visit(function: TypeExpressions.FUNCTION) is _clear_type(function); si | |
| 112 | visit(functions: TypeExpressions.FUNCTION_GROUP) is _clear_type(functions); si | |
| 113 | visit(tuple: TypeExpressions.TUPLE) is _clear_type(tuple); si | |
| 114 | visit(element: TypeExpressions.NAMED_TUPLE_ELEMENT) is _clear_type(element); si | |
| 115 | visit(constraint: TypeExpressions.TYPE_PARAMETER_CONSTRAINT) is _clear_type(constraint); si | |
| 116 | visit(element: TypeExpressions.UNDEFINED) is _clear_type(element); si | |
| 117 | ||
| 118 | // Expressions | |
| 119 | visit(expression: Expressions.Expression) is expression.clear(); si | |
| 120 | visit(identifier: Expressions.IDENTIFIER) is identifier.clear(); si | |
| 121 | visit(literal: Expressions.Literals.Literal) is literal.clear(); si | |
| 122 | visit(`string: Expressions.Literals.STRING) is `string.clear(); si | |
| 123 | visit(interpolation: Expressions.STRING_INTERPOLATION) is interpolation.clear(); si | |
| 124 | visit(integer: Expressions.Literals.INTEGER) is integer.clear(); si | |
| 125 | visit(float: Expressions.Literals.FLOAT) is float.clear(); si | |
| 126 | visit(character: Expressions.Literals.CHARACTER) is character.clear(); si | |
| 127 | visit(boolean: Expressions.Literals.BOOLEAN) is boolean.clear(); si | |
| 128 | visit(variable: Expressions.VARIABLE) is variable.clear(); si | |
| 129 | visit(variable: Expressions.TUPLE_ELEMENT) is variable.clear(); si | |
| 130 | visit(none: Expressions.Literals.NONE) is none.clear(); si | |
| 131 | visit(`null: Expressions.NULL) is `null.clear(); si | |
| 132 | visit(`self: Expressions.SELF) is `self.clear(); si | |
| 133 | visit(`super: Expressions.SUPER) is `super.clear(); si | |
| 134 | visit(`new: Expressions.NEW) is `new.clear(); si | |
| 135 | visit(`cast: Expressions.CAST) is `cast.clear(); si | |
| 136 | visit(`await: Expressions.AWAIT) is `await.clear(); si | |
| 137 | visit(spill: Expressions.SPILL) is spill.clear(); si | |
| 138 | visit(`isa: Expressions.ISA) is `isa.clear(); si | |
| 139 | visit(`isa: Expressions.TYPEOF) is `isa.clear(); si | |
| 140 | visit(`default: Expressions.DEFAULT) is `default.clear(); si | |
| 141 | visit(function: Expressions.FUNCTION) is function.clear(); si | |
| 142 | visit(recurse: Expressions.RECURSE) is recurse.clear(); si | |
| 143 | visit(tuple: Expressions.TUPLE) is tuple.clear(); si | |
| 144 | visit(sequence: Expressions.SEQUENCE) is sequence.clear(); si | |
| 145 | visit(list: Expressions.LIST) is list.clear(); si | |
| 146 | visit(call: Expressions.CALL) is call.clear(); si | |
| 147 | visit(member: Expressions.MEMBER) is member.clear(); si | |
| 148 | visit(member: Expressions.EXPLICIT_SPECIALIZATION) is member.clear(); si | |
| 149 | visit(ambiguous_expression: Expressions.AMBIGUOUS_EXPRESSION) is ambiguous_expression.clear(); si | |
| 150 | visit(ambiguous_expression: Expressions.GENERIC_APPLICATION) is ambiguous_expression.clear(); si | |
| 151 | visit(index: Expressions.INDEX) is index.clear(); si | |
| 152 | visit(has_value: Expressions.HAS_VALUE) is has_value.clear(); si | |
| 153 | visit(unwrap: Expressions.UNWRAP) is unwrap.clear(); si | |
| 154 | visit(reference: Expressions.REFERENCE) is reference.clear(); si | |
| 155 | visit(unary: Expressions.UNARY) is unary.clear(); si | |
| 156 | visit(binary: Expressions.BINARY) is binary.clear(); si | |
| 157 | visit(statement: Expressions.STATEMENT) is statement.clear(); si | |
| 158 | visit(statement: Expressions.LET_IN) is statement.clear(); si | |
| 159 | visit(block: Expressions.VAL_BLOCK) is block.clear(); si | |
| 160 | visit(assert_in: Expressions.ASSERT_IN) is assert_in.clear(); si | |
| 161 | ||
| 162 | // Left-side expressions | |
| 163 | visit(left: Trees.Expressions.SIMPLE_LEFT_EXPRESSION) is left.clear(); si | |
| 164 | visit(destructure_left: Trees.Expressions.DESTRUCTURING_LEFT_EXPRESSION) is destructure_left.clear(); si | |
| 165 | ||
| 166 | // Statements | |
| 167 | visit(statement: Statements.Statement) is statement.clear(); si | |
| 168 | visit(statements: Statements.LIST) is statements.clear(); si | |
| 169 | visit(l: Statements.LET) is l.clear(); si | |
| 170 | visit(assign: Statements.ASSIGNMENT) is assign.clear(); si | |
| 171 | visit(expression: Statements.EXPRESSION) is expression.clear(); si | |
| 172 | visit(`return: Statements.RETURN) is `return.clear(); si | |
| 173 | visit(`throw: Statements.THROW) is `throw.clear(); si | |
| 174 | visit(`yield: Statements.YIELD) is `yield.clear(); si | |
| 175 | visit(assert__: Statements.ASSERT) is assert__.clear(); si | |
| 176 | visit(`if: Statements.IF) is `if.clear(); si | |
| 177 | visit(if_branch: Statements.IF_BRANCH) is if_branch.clear(); si | |
| 178 | visit(rb: Statements.REFUTABLE_BINDING) is rb.clear(); si | |
| 179 | visit(`case: Statements.CASE) is `case.clear(); si | |
| 180 | visit(case_match: Statements.CASE_MATCH) is case_match.clear(); si | |
| 181 | visit(`try: Statements.TRY) is `try.clear(); si | |
| 182 | visit(`catch: Statements.CATCH) is `catch.clear(); si | |
| 183 | visit(`do: Statements.DO) is `do.clear(); si | |
| 184 | visit(`for: Statements.FOR) is `for.clear(); si | |
| 185 | visit(labelled: Statements.LABELLED) is labelled.clear(); si | |
| 186 | visit(`break: Statements.BREAK) is `break.clear(); si | |
| 187 | visit(`continue: Statements.CONTINUE) is `continue.clear(); si | |
| 188 | visit(pragma: Statements.PRAGMA) is pragma.clear(); si | |
| 189 | ||
| 190 | // Bodies | |
| 191 | visit(expression: Bodies.EXPRESSION) is expression.clear(); si | |
| 192 | visit(block: Bodies.BLOCK) is block.clear(); si | |
| 193 | visit(block: Bodies.NULL) is block.clear(); si | |
| 194 | visit(block: Bodies.INNATE) is block.clear(); si | |
| 195 | si | |
| 196 | si |