Skip to content
← Back

src/syntax/process/location_refresh.ghul

1
namespace Syntax.Process is
2
use Collections.LIST;
3
4
use Source;
5
use Trees;
6
7
// Reconciles the retained AST of an interface-preserving incremental
8
// EDIT against the freshly-parsed donor. An interface-preserving EDIT
9
// keeps the retained interface nodes (their symbols stay valid) but
10
// those nodes carry pre-edit locations — a body edit, or reformatting
11
// around it, moves them. This visitor copies the donor parse's correct
12
// locations onto the retained nodes, and records the pre-edit ->
13
// post-edit correspondence of every node it touches so the analyser's
14
// location side-tables can be reconciled the same way.
15
//
16
// It harvests from the donor in walk order, then applies to the
17
// retained tree in the same walk order. Body interiors are not
18
// descended (`pre` returns true for the body node types): after the
19
// splice the retained AST's bodies *are* the donor's body nodes,
20
// already current, and skipping them keeps the harvest and apply walks
21
// counting the same nodes. `is_consistent` is false if the two walks
22
// disagreed — on node count, or on a node's type — and the caller must
23
// then fall back to a full rebuild.
24
25
// One harvested node: its location, plus its runtime type (held as
26
// `object` — the result of `get_type()`, compared by identity). The
27
// type is checked against the retained node on apply, so a structural
28
// divergence between the two parses outside an edited body — meaning
29
// the interface classification was wrong — is caught at the first
30
// mismatching node, not just by an end-of-walk count.
31
struct TRANSFER_POINT is
32
location: LOCATION public;
33
kind: object public;
34
35
init(location: LOCATION, kind: object) is
36
self.location = location;
37
self.kind = kind;
38
si
39
si
40
41
class LOCATION_TRANSFER: Visitor is
42
_harvesting: bool;
43
_points: LIST[TRANSFER_POINT];
44
_index: int;
45
_structurally_consistent: bool;
46
_correspondence: LOCATION_CORRESPONDENCE;
47
48
init() is
49
super.init();
50
_points = LIST[TRANSFER_POINT]();
51
_correspondence = LOCATION_CORRESPONDENCE();
52
si
53
54
// The pre-edit -> post-edit location of every retained interface
55
// node, built during apply_to. Valid only when is_consistent.
56
correspondence: LOCATION_CORRESPONDENCE => _correspondence;
57
58
harvest(root: Node) is
59
_harvesting = true;
60
_points = LIST[TRANSFER_POINT]();
61
root.walk(self);
62
si
63
64
apply_to(root: Node) is
65
_harvesting = false;
66
_index = 0;
67
_structurally_consistent = true;
68
_correspondence = LOCATION_CORRESPONDENCE();
69
root.walk(self);
70
si
71
72
is_consistent: bool =>
73
!_harvesting /\ _index == _points.count /\ _structurally_consistent;
74
75
transfer(node: Node) is
76
if _harvesting then
77
_points.add(TRANSFER_POINT(node.location, node.get_type()));
78
return;
79
fi
80
81
if _index >= _points.count then
82
_structurally_consistent = false;
83
_index = _index + 1;
84
return;
85
fi
86
87
let point = _points[_index];
88
_index = _index + 1;
89
90
if node.get_type() != point.kind then
91
_structurally_consistent = false;
92
fi
93
94
// record old -> new before overwriting the location
95
_correspondence.add(node.location, point.location);
96
97
node.location = point.location;
98
si
99
100
// Body interiors are donor nodes already in current coordinates —
101
// skip them so harvest and apply walk the same node set.
102
pre(block: Bodies.BLOCK) -> bool => true;
103
pre(expression: Bodies.EXPRESSION) -> bool => true;
104
pre(innate_body: Bodies.INNATE) -> bool => true;
105
pre(null_body: Bodies.NULL) -> bool => true;
106
107
visit(identifier: Identifiers.Identifier) is transfer(identifier); si
108
visit(identifier: Identifiers.QUALIFIED) is transfer(identifier); si
109
110
visit(modifier: Modifiers.Modifier) is transfer(modifier); si
111
visit(modifiers: Modifiers.LIST) is transfer(modifiers); si
112
visit(pragma: Pragmas.PRAGMA) is transfer(pragma); si
113
114
visit(definition: Definitions.Definition) is transfer(definition); si
115
visit(definitions: Definitions.LIST) is transfer(definitions); si
116
visit(pragma: Definitions.PRAGMA) is transfer(pragma); si
117
visit(`namespace: Definitions.NAMESPACE) is transfer(`namespace); si
118
visit(`use: Definitions.USE) is transfer(`use); si
119
visit(`class: Definitions.CLASS) is transfer(`class); si
120
visit(`trait: Definitions.TRAIT) is transfer(`trait); si
121
visit(`struct: Definitions.STRUCT) is transfer(`struct); si
122
visit(`union: Definitions.UNION) is transfer(`union); si
123
visit(variant: Definitions.VARIANT) is transfer(variant); si
124
visit(`enum: Definitions.ENUM) is transfer(`enum); si
125
visit(enum_member: Definitions.ENUM_MEMBER) is transfer(enum_member); si
126
visit(function: Definitions.FUNCTION) is transfer(function); si
127
visit(functions: Definitions.FUNCTION_GROUP) is transfer(functions); si
128
visit(property: Definitions.PROPERTY) is transfer(property); si
129
visit(indexer: Definitions.INDEXER) is transfer(indexer); si
130
131
visit(variable: Variables.VARIABLE) is transfer(variable); si
132
visit(variables: Variables.LIST) is transfer(variables); si
133
visit(left: Trees.Variables.SIMPLE_VARIABLE_LEFT) is transfer(left); si
134
visit(destructure_left: Trees.Variables.DESTRUCTURING_VARIABLE_LEFT) is transfer(destructure_left); si
135
visit(literal_leaf: Trees.Variables.LITERAL_VARIABLE_LEFT) is transfer(literal_leaf); si
136
137
visit(type_expression: TypeExpressions.TypeExpression) is transfer(type_expression); si
138
visit(type_expression: TypeExpressions.INFER) is transfer(type_expression); si
139
visit(structured: TypeExpressions.Structured) is transfer(structured); si
140
visit(array: TypeExpressions.ARRAY_) is transfer(array); si
141
visit(pointer: TypeExpressions.POINTER) is transfer(pointer); si
142
visit(optional: TypeExpressions.OPTIONAL) is transfer(optional); si
143
visit(reference: TypeExpressions.REFERENCE) is transfer(reference); si
144
visit(member: TypeExpressions.MEMBER) is transfer(member); si
145
visit(named: TypeExpressions.NAMED) is transfer(named); si
146
visit(types: TypeExpressions.LIST) is transfer(types); si
147
visit(generic: TypeExpressions.GENERIC) is transfer(generic); si
148
visit(function: TypeExpressions.FUNCTION) is transfer(function); si
149
visit(functions: TypeExpressions.FUNCTION_GROUP) is transfer(functions); si
150
visit(tuple: TypeExpressions.TUPLE) is transfer(tuple); si
151
visit(element: TypeExpressions.NAMED_TUPLE_ELEMENT) is transfer(element); si
152
visit(constraint: TypeExpressions.TYPE_PARAMETER_CONSTRAINT) is transfer(constraint); si
153
visit(element: TypeExpressions.UNDEFINED) is transfer(element); si
154
155
visit(expression: Expressions.Expression) is transfer(expression); si
156
visit(identifier: Expressions.IDENTIFIER) is transfer(identifier); si
157
visit(literal: Expressions.Literals.Literal) is transfer(literal); si
158
visit(`string: Expressions.Literals.STRING) is transfer(`string); si
159
visit(interpolation: Expressions.STRING_INTERPOLATION) is transfer(interpolation); si
160
visit(integer: Expressions.Literals.INTEGER) is transfer(integer); si
161
visit(float: Expressions.Literals.FLOAT) is transfer(float); si
162
visit(character: Expressions.Literals.CHARACTER) is transfer(character); si
163
visit(boolean: Expressions.Literals.BOOLEAN) is transfer(boolean); si
164
visit(variable: Expressions.VARIABLE) is transfer(variable); si
165
visit(variable: Expressions.TUPLE_ELEMENT) is transfer(variable); si
166
visit(none: Expressions.Literals.NONE) is transfer(none); si
167
visit(`null: Expressions.NULL) is transfer(`null); si
168
visit(`self: Expressions.SELF) is transfer(`self); si
169
visit(`super: Expressions.SUPER) is transfer(`super); si
170
visit(`new: Expressions.NEW) is transfer(`new); si
171
visit(`cast: Expressions.CAST) is transfer(`cast); si
172
visit(`isa: Expressions.ISA) is transfer(`isa); si
173
visit(`isa: Expressions.TYPEOF) is transfer(`isa); si
174
visit(`default: Expressions.DEFAULT) is transfer(`default); si
175
visit(function: Expressions.FUNCTION) is transfer(function); si
176
visit(recurse: Expressions.RECURSE) is transfer(recurse); si
177
visit(tuple: Expressions.TUPLE) is transfer(tuple); si
178
visit(sequence: Expressions.SEQUENCE) is transfer(sequence); si
179
visit(list: Expressions.LIST) is transfer(list); si
180
visit(call: Expressions.CALL) is transfer(call); si
181
visit(member: Expressions.MEMBER) is transfer(member); si
182
visit(member: Expressions.EXPLICIT_SPECIALIZATION) is transfer(member); si
183
visit(ambiguous_expression: Expressions.AMBIGUOUS_EXPRESSION) is transfer(ambiguous_expression); si
184
visit(ambiguous_expression: Expressions.GENERIC_APPLICATION) is transfer(ambiguous_expression); si
185
visit(index: Expressions.INDEX) is transfer(index); si
186
visit(has_value: Expressions.HAS_VALUE) is transfer(has_value); si
187
visit(unwrap: Expressions.UNWRAP) is transfer(unwrap); si
188
visit(reference: Expressions.REFERENCE) is transfer(reference); si
189
visit(unary: Expressions.UNARY) is transfer(unary); si
190
visit(binary: Expressions.BINARY) is transfer(binary); si
191
visit(statement: Expressions.STATEMENT) is transfer(statement); si
192
visit(statement: Expressions.LET_IN) is transfer(statement); si
193
visit(block: Expressions.VAL_BLOCK) is transfer(block); si
194
visit(assert_in: Expressions.ASSERT_IN) is transfer(assert_in); si
195
196
visit(left: Trees.Expressions.SIMPLE_LEFT_EXPRESSION) is transfer(left); si
197
visit(destructure_left: Trees.Expressions.DESTRUCTURING_LEFT_EXPRESSION) is transfer(destructure_left); si
198
199
visit(statement: Statements.Statement) is transfer(statement); si
200
visit(statements: Statements.LIST) is transfer(statements); si
201
visit(l: Statements.LET) is transfer(l); si
202
visit(assign: Statements.ASSIGNMENT) is transfer(assign); si
203
visit(expression: Statements.EXPRESSION) is transfer(expression); si
204
visit(`return: Statements.RETURN) is transfer(`return); si
205
visit(`throw: Statements.THROW) is transfer(`throw); si
206
visit(assert__: Statements.ASSERT) is transfer(assert__); si
207
visit(`if: Statements.IF) is transfer(`if); si
208
visit(if_branch: Statements.IF_BRANCH) is transfer(if_branch); si
209
visit(`case: Statements.CASE) is transfer(`case); si
210
visit(case_match: Statements.CASE_MATCH) is transfer(case_match); si
211
visit(`try: Statements.TRY) is transfer(`try); si
212
visit(`catch: Statements.CATCH) is transfer(`catch); si
213
visit(`do: Statements.DO) is transfer(`do); si
214
visit(`for: Statements.FOR) is transfer(`for); si
215
visit(labelled: Statements.LABELLED) is transfer(labelled); si
216
visit(`break: Statements.BREAK) is transfer(`break); si
217
visit(`continue: Statements.CONTINUE) is transfer(`continue); si
218
visit(pragma: Statements.PRAGMA) is transfer(pragma); si
219
220
visit(expression: Bodies.EXPRESSION) is transfer(expression); si
221
visit(block: Bodies.BLOCK) is transfer(block); si
222
visit(block: Bodies.NULL) is transfer(block); si
223
visit(block: Bodies.INNATE) is transfer(block); si
224
si
225
226
// Copies the donor parse's locations onto the structurally-identical
227
// retained AST and returns the pre-edit -> post-edit correspondence of
228
// every retained interface node. Returns null if the two walks
229
// disagreed — on node count or node type — and the caller must then
230
// fall back to a full rebuild.
231
class LOCATION_REFRESH is
232
apply(retained_root: Trees.Node, donor_root: Trees.Node) -> Source.LOCATION_CORRESPONDENCE? static is
233
let transfer = LOCATION_TRANSFER();
234
235
transfer.harvest(donor_root);
236
transfer.apply_to(retained_root);
237
238
if !transfer.is_consistent then
239
return null;
240
fi
241
242
return transfer.correspondence;
243
si
244
si
245
si