@bablr/agast-helpers 0.6.1 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/builders.js +15 -63
- package/lib/path.js +285 -227
- package/lib/print.js +14 -43
- package/lib/shorthand.js +2 -2
- package/lib/stream.js +6 -220
- package/lib/sumtree.js +62 -0
- package/lib/symbols.js +3 -10
- package/lib/template.js +4 -4
- package/lib/tree.js +33 -242
- package/package.json +3 -2
package/lib/path.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { WeakStackFrame } from '@bablr/weak-stack';
|
|
2
2
|
import * as btree from '@bablr/agast-helpers/btree';
|
|
3
|
+
import * as sumtree from '@bablr/agast-helpers/sumtree';
|
|
3
4
|
import {
|
|
4
5
|
ReferenceTag,
|
|
5
|
-
|
|
6
|
+
InitializerTag,
|
|
6
7
|
EmbeddedNode,
|
|
7
8
|
DoctypeTag,
|
|
8
9
|
OpenNodeTag,
|
|
@@ -12,7 +13,7 @@ import {
|
|
|
12
13
|
ShiftTag,
|
|
13
14
|
} from './symbols.js';
|
|
14
15
|
import {
|
|
15
|
-
|
|
16
|
+
buildInitializerTag,
|
|
16
17
|
buildEmbeddedNode,
|
|
17
18
|
buildGapTag,
|
|
18
19
|
buildReferenceTag,
|
|
@@ -20,10 +21,11 @@ import {
|
|
|
20
21
|
} from './builders.js';
|
|
21
22
|
|
|
22
23
|
export const getOpenTag = (node) => {
|
|
23
|
-
|
|
24
|
+
if (!node.children.length) return null;
|
|
25
|
+
let tag = sumtree.getAt(0, node.children);
|
|
24
26
|
if (tag.type === NullTag || tag.type === GapTag) return null;
|
|
25
27
|
if (tag.type === DoctypeTag) {
|
|
26
|
-
tag =
|
|
28
|
+
tag = sumtree.getAt(1, node.children);
|
|
27
29
|
}
|
|
28
30
|
if (tag && tag.type !== OpenNodeTag) throw new Error();
|
|
29
31
|
return tag;
|
|
@@ -31,13 +33,13 @@ export const getOpenTag = (node) => {
|
|
|
31
33
|
|
|
32
34
|
export const getCloseTag = (node) => {
|
|
33
35
|
const { children } = node;
|
|
34
|
-
const tag =
|
|
36
|
+
const tag = sumtree.getAt(-1, children);
|
|
35
37
|
if (tag.type !== CloseNodeTag) return null;
|
|
36
38
|
return tag;
|
|
37
39
|
};
|
|
38
40
|
|
|
39
41
|
export const isNullNode = (node) => {
|
|
40
|
-
return node && node.type === null &&
|
|
42
|
+
return node && node.type === null && sumtree.getAt(0, node.children).type === NullTag;
|
|
41
43
|
};
|
|
42
44
|
|
|
43
45
|
export const isFragmentNode = (node) => {
|
|
@@ -45,7 +47,117 @@ export const isFragmentNode = (node) => {
|
|
|
45
47
|
};
|
|
46
48
|
|
|
47
49
|
export const isGapNode = (node) => {
|
|
48
|
-
return node && node.type === null &&
|
|
50
|
+
return node && node.type === null && sumtree.getAt(0, node.children).type === GapTag;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export const getChildPropertyIndex = (agAstNode, childrenIndex) => {
|
|
54
|
+
let stack = sumtree.findPath(childrenIndex, agAstNode.children);
|
|
55
|
+
let { node, index: leafIdx } = stack.value;
|
|
56
|
+
let leaf = sumtree.getAt(leafIdx, node);
|
|
57
|
+
|
|
58
|
+
if (leaf.type !== ReferenceTag) return null;
|
|
59
|
+
|
|
60
|
+
let { name, isArray } = leaf.value;
|
|
61
|
+
let count = -1;
|
|
62
|
+
|
|
63
|
+
if (!isArray) return null;
|
|
64
|
+
|
|
65
|
+
for (let i = leafIdx; i >= 0; i--) {
|
|
66
|
+
let value = sumtree.getAt(i, node);
|
|
67
|
+
|
|
68
|
+
if (value.type === ReferenceTag && value.value.name === name) {
|
|
69
|
+
count++;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
stack = stack.pop();
|
|
73
|
+
|
|
74
|
+
if (!stack.size) return count - 1;
|
|
75
|
+
|
|
76
|
+
({ node, index: leafIdx } = stack.value);
|
|
77
|
+
|
|
78
|
+
do {
|
|
79
|
+
for (let i = leafIdx - 1; i >= 0; i--) {
|
|
80
|
+
let childNode = sumtree.getValues(node)[i];
|
|
81
|
+
let { references } = sumtree.getSums(childNode);
|
|
82
|
+
|
|
83
|
+
if (hasOwn(references, name)) {
|
|
84
|
+
count += references[name];
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
stack = stack.pop();
|
|
88
|
+
if (stack.size) {
|
|
89
|
+
({ node, index: leafIdx } = stack.value);
|
|
90
|
+
}
|
|
91
|
+
} while (stack.size);
|
|
92
|
+
|
|
93
|
+
// the initializer doesn't matter to us
|
|
94
|
+
// also we're going from fenceposts to gaps
|
|
95
|
+
return count - 1;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export const getPropertyChildrenIndex = (agAstNode, reference) => {
|
|
99
|
+
let { index, name } = reference.value;
|
|
100
|
+
if (isArray) {
|
|
101
|
+
if (index == null) {
|
|
102
|
+
index = btree.getSize(agAstNode.properties[name]) - 1;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
let firstRefIndex = __getPropertyChildrenIndex(agAstNode, name, 0);
|
|
107
|
+
let nextTag = sumtree.getAt(firstRefIndex + 1, agAstNode.children);
|
|
108
|
+
|
|
109
|
+
return __getPropertyChildrenIndex(
|
|
110
|
+
agAstNode,
|
|
111
|
+
name,
|
|
112
|
+
index + (nextTag.type === InitializerTag ? 1 : 0),
|
|
113
|
+
);
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
export const getInitializerChildrenIndex = (agAstNode, reference) => {
|
|
117
|
+
return __getPropertyChildrenIndex(agAstNode, reference.value.name, 0);
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const __getPropertyChildrenIndex = (agAstNode, name, index) => {
|
|
121
|
+
let nameCount = 0;
|
|
122
|
+
let node = agAstNode.children;
|
|
123
|
+
let idx = -1;
|
|
124
|
+
|
|
125
|
+
// drill into subtrees, passing over subtrees with too few references of the desired name
|
|
126
|
+
outer: while (node) {
|
|
127
|
+
let isLeaf = sumtree.isLeafNode(node);
|
|
128
|
+
let sums = sumtree.getSums(node);
|
|
129
|
+
let valueNameCount = sums.references[name];
|
|
130
|
+
|
|
131
|
+
if (nameCount + valueNameCount < index) {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
for (const value of sumtree.getValues(node)) {
|
|
136
|
+
if (isLeaf) {
|
|
137
|
+
idx++;
|
|
138
|
+
let tag = value;
|
|
139
|
+
if (tag.type === ReferenceTag && tag.value.name === name) {
|
|
140
|
+
nameCount += 1;
|
|
141
|
+
if (nameCount > index) {
|
|
142
|
+
return idx;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
} else {
|
|
146
|
+
let valueSums = sumtree.getSums(value);
|
|
147
|
+
if (nameCount + valueSums.references[name] > index) {
|
|
148
|
+
node = value;
|
|
149
|
+
continue outer;
|
|
150
|
+
} else {
|
|
151
|
+
nameCount += valueSums.references[name] ?? 0;
|
|
152
|
+
idx += sumtree.getSize(value);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return null;
|
|
49
161
|
};
|
|
50
162
|
|
|
51
163
|
const { hasOwn } = Object;
|
|
@@ -70,7 +182,7 @@ export const getProperties = (ref, properties) => {
|
|
|
70
182
|
}
|
|
71
183
|
}
|
|
72
184
|
|
|
73
|
-
if (isArray) {
|
|
185
|
+
if (isArray || Array.isArray(properties[name])) {
|
|
74
186
|
return btree.getAt(index ?? -1, properties[name]);
|
|
75
187
|
} else {
|
|
76
188
|
return properties[name];
|
|
@@ -91,9 +203,12 @@ export const getPropertiesSimple = (ref, properties) => {
|
|
|
91
203
|
}
|
|
92
204
|
};
|
|
93
205
|
|
|
206
|
+
export const isDefined = (obj, key) => hasOwn(obj, key) && obj[key] !== undefined;
|
|
207
|
+
export const isUndefined = (obj, key) => !hasOwn(obj, key) || obj[key] === undefined;
|
|
208
|
+
|
|
94
209
|
export const get = (ref, node) => {
|
|
95
|
-
const { flags } = ref.value;
|
|
96
210
|
const result = getProperties(ref, node.properties);
|
|
211
|
+
const { flags } = result.reference.value;
|
|
97
212
|
|
|
98
213
|
return flags.expression ? btree.getAt(-1, result.node) : result?.node;
|
|
99
214
|
};
|
|
@@ -106,7 +221,10 @@ export const getShifted = (shiftIndex, ref, node) => {
|
|
|
106
221
|
};
|
|
107
222
|
|
|
108
223
|
export const add = (node, reference, value, shift = null) => {
|
|
109
|
-
if (node == null || reference == null
|
|
224
|
+
if (node == null || reference == null) throw new Error('invalid arguments to add');
|
|
225
|
+
if (value === node) {
|
|
226
|
+
throw new Error('cannot add a node to itself');
|
|
227
|
+
}
|
|
110
228
|
|
|
111
229
|
const { properties } = node;
|
|
112
230
|
const { name, isArray, flags } = reference.value;
|
|
@@ -115,22 +233,26 @@ export const add = (node, reference, value, shift = null) => {
|
|
|
115
233
|
throw new Error('Only fragments can have . properties');
|
|
116
234
|
}
|
|
117
235
|
|
|
236
|
+
if (Array.isArray(value) && !isArray) throw new Error();
|
|
237
|
+
if (Array.isArray(value) && value.length) throw new Error();
|
|
238
|
+
|
|
118
239
|
if (name == null) throw new Error();
|
|
119
240
|
|
|
120
|
-
const lastChild =
|
|
241
|
+
const lastChild = sumtree.getAt(-1, node.children);
|
|
121
242
|
|
|
122
243
|
if (lastChild.type === ReferenceTag) {
|
|
123
244
|
if (!referencesAreEqual(lastChild, reference)) throw new Error();
|
|
124
245
|
} else if (lastChild.type !== ShiftTag) {
|
|
125
|
-
|
|
246
|
+
if ([ShiftTag, ReferenceTag].includes(sumtree.getAt(-1, node.children).type)) throw new Error();
|
|
247
|
+
node.children = sumtree.push(node.children, shift > 0 ? buildShiftTag(shift) : reference);
|
|
126
248
|
}
|
|
127
249
|
|
|
128
250
|
if (name === '#' || name === '@') {
|
|
129
|
-
node.children =
|
|
251
|
+
node.children = sumtree.push(node.children, buildEmbeddedNode(value));
|
|
130
252
|
} else {
|
|
131
253
|
if (isArray) {
|
|
132
254
|
let isInitializer = Array.isArray(value);
|
|
133
|
-
let exists = !isInitializer &&
|
|
255
|
+
let exists = !isInitializer && isDefined(properties, name);
|
|
134
256
|
|
|
135
257
|
let existed = exists;
|
|
136
258
|
if (!existed) {
|
|
@@ -138,19 +260,19 @@ export const add = (node, reference, value, shift = null) => {
|
|
|
138
260
|
throw new Error('Array value only allowed for initialization');
|
|
139
261
|
|
|
140
262
|
properties[name] = [];
|
|
141
|
-
node.children =
|
|
263
|
+
node.children = sumtree.push(node.children, buildInitializerTag(true));
|
|
142
264
|
exists = !isInitializer;
|
|
143
265
|
}
|
|
144
266
|
|
|
145
267
|
if (exists) {
|
|
146
268
|
if (!existed) {
|
|
147
|
-
if (
|
|
148
|
-
node.children =
|
|
269
|
+
if (sumtree.getAt(-1, node.children).type === ReferenceTag) throw new Error();
|
|
270
|
+
node.children = sumtree.push(node.children, reference);
|
|
149
271
|
}
|
|
150
272
|
|
|
151
273
|
let newBinding;
|
|
152
274
|
if (flags.expression) {
|
|
153
|
-
let shiftedNodes = shift
|
|
275
|
+
let shiftedNodes = shift > 0 ? btree.getAt(-1, properties[name])?.node : [];
|
|
154
276
|
|
|
155
277
|
newBinding = {
|
|
156
278
|
reference,
|
|
@@ -161,40 +283,67 @@ export const add = (node, reference, value, shift = null) => {
|
|
|
161
283
|
}
|
|
162
284
|
|
|
163
285
|
properties[name] =
|
|
164
|
-
shift
|
|
286
|
+
shift > 0
|
|
165
287
|
? btree.replaceAt(-1, properties[name], newBinding)
|
|
166
288
|
: btree.push(properties[name], newBinding);
|
|
167
289
|
|
|
168
|
-
node.children =
|
|
290
|
+
node.children = sumtree.push(node.children, buildGapTag(value));
|
|
169
291
|
}
|
|
170
292
|
} else {
|
|
171
|
-
if (
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
293
|
+
if (value === undefined) {
|
|
294
|
+
if (isUndefined(properties, name)) {
|
|
295
|
+
let newBinding;
|
|
296
|
+
if (flags.expression) {
|
|
297
|
+
let shiftedNodes = shift > 0 ? btree.getAt(-1, properties[name])?.node : [];
|
|
298
|
+
|
|
299
|
+
newBinding = {
|
|
300
|
+
reference,
|
|
301
|
+
node: btree.push(shiftedNodes, undefined),
|
|
302
|
+
};
|
|
303
|
+
} else {
|
|
304
|
+
newBinding = { reference, node: undefined };
|
|
305
|
+
}
|
|
306
|
+
properties[name] = newBinding;
|
|
307
|
+
node.children = sumtree.push(node.children, buildInitializerTag());
|
|
308
|
+
}
|
|
178
309
|
} else {
|
|
179
|
-
|
|
310
|
+
if (flags.expression) {
|
|
311
|
+
if (shift == null) {
|
|
312
|
+
throw new Error();
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
let shiftedNodes = shift ? properties[name]?.node : [];
|
|
316
|
+
properties[name] = { reference, node: btree.push(shiftedNodes, value) };
|
|
317
|
+
} else {
|
|
318
|
+
if (shift != null) throw new Error();
|
|
319
|
+
if (hasOwn(properties, name) && properties[name].node !== undefined) {
|
|
320
|
+
throw new Error();
|
|
321
|
+
}
|
|
322
|
+
properties[name] = { reference, node: value };
|
|
323
|
+
}
|
|
324
|
+
node.children = sumtree.push(node.children, buildGapTag(value));
|
|
180
325
|
}
|
|
181
|
-
node.children = btree.push(node.children, buildGapTag(value));
|
|
182
326
|
}
|
|
183
327
|
}
|
|
184
328
|
};
|
|
185
329
|
|
|
186
|
-
export function* allTagPathsFor(range) {
|
|
330
|
+
export function* allTagPathsFor(range, options = {}) {
|
|
187
331
|
if (range == null) return;
|
|
188
332
|
|
|
333
|
+
const { unshift = false } = options;
|
|
189
334
|
let startPath = range[0];
|
|
190
335
|
let endPath = range[1];
|
|
191
336
|
let path = startPath;
|
|
192
337
|
|
|
193
338
|
while (path) {
|
|
194
|
-
if (path.inner) {
|
|
339
|
+
if (path.inner && path.previousSibling.tag.type === ReferenceTag) {
|
|
195
340
|
path = new TagPath(path.innerPath, 0);
|
|
196
341
|
}
|
|
197
342
|
|
|
343
|
+
if (path.path.depth < startPath.path.depth) {
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
|
|
198
347
|
yield path;
|
|
199
348
|
|
|
200
349
|
if (
|
|
@@ -205,24 +354,38 @@ export function* allTagPathsFor(range) {
|
|
|
205
354
|
return;
|
|
206
355
|
}
|
|
207
356
|
|
|
208
|
-
|
|
357
|
+
let gapPath = path.path.parent && TagPath.from(path.path.parent, path.path.referenceIndex + 1);
|
|
358
|
+
|
|
359
|
+
if (
|
|
360
|
+
endPath &&
|
|
361
|
+
path.tag.type === CloseNodeTag &&
|
|
362
|
+
gapPath &&
|
|
363
|
+
gapPath.childrenIndex === endPath.childrenIndex &&
|
|
364
|
+
gapPath.path.node === endPath.path.node
|
|
365
|
+
) {
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
path = unshift ? path.nextUnshifted : path.next;
|
|
209
369
|
}
|
|
210
370
|
}
|
|
211
371
|
|
|
212
|
-
export function* allTagsFor(range) {
|
|
213
|
-
for (const path of allTagPathsFor(range)) {
|
|
372
|
+
export function* allTagsFor(range, options = {}) {
|
|
373
|
+
for (const path of allTagPathsFor(range, options)) {
|
|
214
374
|
yield path.tag;
|
|
215
375
|
}
|
|
216
376
|
}
|
|
217
377
|
|
|
378
|
+
export const buildFullRange = (node) => {
|
|
379
|
+
const sum = sumtree.getSize(node.children);
|
|
380
|
+
return sum ? [0, sum - 1] : null;
|
|
381
|
+
};
|
|
382
|
+
|
|
218
383
|
export function* ownTagPathsFor(range) {
|
|
219
384
|
if (!isArray(range)) throw new Error();
|
|
220
385
|
|
|
221
386
|
const startPath = range[0];
|
|
222
387
|
const endPath = range[1];
|
|
223
388
|
|
|
224
|
-
let path = startPath;
|
|
225
|
-
|
|
226
389
|
if (startPath.outer !== endPath.outer) throw new Error();
|
|
227
390
|
|
|
228
391
|
const { children } = startPath.outer;
|
|
@@ -232,46 +395,6 @@ export function* ownTagPathsFor(range) {
|
|
|
232
395
|
}
|
|
233
396
|
}
|
|
234
397
|
|
|
235
|
-
export class PathResolver {
|
|
236
|
-
constructor() {
|
|
237
|
-
this.childrenIndex = -1;
|
|
238
|
-
this.counters = {};
|
|
239
|
-
this.reference = null;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
advance(tag) {
|
|
243
|
-
this.childrenIndex++;
|
|
244
|
-
|
|
245
|
-
const { counters } = this;
|
|
246
|
-
if (tag.type === ReferenceTag) {
|
|
247
|
-
const { isArray, name, flags } = tag.value;
|
|
248
|
-
|
|
249
|
-
let resolvedReference = tag;
|
|
250
|
-
|
|
251
|
-
this.reference = tag;
|
|
252
|
-
|
|
253
|
-
if (isArray) {
|
|
254
|
-
if (hasOwn(counters, name)) {
|
|
255
|
-
const counter = ++counters[name];
|
|
256
|
-
|
|
257
|
-
resolvedReference = buildReferenceTag(name, isArray, flags, counter);
|
|
258
|
-
}
|
|
259
|
-
} else if (name !== '@' && name !== '#') {
|
|
260
|
-
if (hasOwn(counters, name)) throw new Error();
|
|
261
|
-
|
|
262
|
-
counters[name] = true;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
return resolvedReference;
|
|
266
|
-
} else if (tag.type === ArrayInitializerTag) {
|
|
267
|
-
counters[this.reference.value.name] = -1;
|
|
268
|
-
return this.reference.value.name;
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
Object.freeze(PathResolver.prototype);
|
|
274
|
-
|
|
275
398
|
const findRight = (arr, predicate) => {
|
|
276
399
|
for (let i = arr.length - 1; i >= 0; i--) {
|
|
277
400
|
const value = arr[i];
|
|
@@ -318,94 +441,6 @@ const skipToDepth = (depth, frame) => {
|
|
|
318
441
|
return parent;
|
|
319
442
|
};
|
|
320
443
|
|
|
321
|
-
const buildBindings = (node) => {
|
|
322
|
-
const { children, properties } = node;
|
|
323
|
-
const referenceIndexes = new Array(children.length);
|
|
324
|
-
const childrenIndexes = Object.fromEntries(Object.keys(properties).map((key) => [key, null]));
|
|
325
|
-
|
|
326
|
-
const resolver = new PathResolver();
|
|
327
|
-
|
|
328
|
-
for (const tag of btree.traverse(children)) {
|
|
329
|
-
resolver.advance(tag);
|
|
330
|
-
const i = resolver.childrenIndex;
|
|
331
|
-
|
|
332
|
-
if (tag.type === ReferenceTag) {
|
|
333
|
-
const { name, isArray, index } = tag.value;
|
|
334
|
-
|
|
335
|
-
if (!name) throw new Error();
|
|
336
|
-
// if (name === '.') throw new Error();
|
|
337
|
-
|
|
338
|
-
const counter = isArray
|
|
339
|
-
? hasOwn(resolver.counters, name)
|
|
340
|
-
? resolver.counters[name]
|
|
341
|
-
: null
|
|
342
|
-
: null;
|
|
343
|
-
|
|
344
|
-
if (index != null && index !== counter) throw new Error();
|
|
345
|
-
|
|
346
|
-
referenceIndexes[i] = counter;
|
|
347
|
-
|
|
348
|
-
if (isArray) {
|
|
349
|
-
if (childrenIndexes[name] === null || !hasOwn(childrenIndexes, name)) {
|
|
350
|
-
childrenIndexes[name] = [];
|
|
351
|
-
} else if (counter >= 0) {
|
|
352
|
-
childrenIndexes[name][counter] = i;
|
|
353
|
-
} else {
|
|
354
|
-
throw new Error();
|
|
355
|
-
}
|
|
356
|
-
} else {
|
|
357
|
-
if (name !== '#' && name !== '@') {
|
|
358
|
-
childrenIndexes[name] = i;
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
} else {
|
|
362
|
-
referenceIndexes[i] = null;
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
return { referenceIndexes, childrenIndexes };
|
|
367
|
-
};
|
|
368
|
-
|
|
369
|
-
const nodeStates = new WeakMap();
|
|
370
|
-
|
|
371
|
-
// TODO remove this; it is a very bad API to have to support!!
|
|
372
|
-
export const updatePath = (path, tag) => {
|
|
373
|
-
const { node, childrenIndexes, referenceIndexes } = path;
|
|
374
|
-
const i = btree.getSum(node.children) - 1;
|
|
375
|
-
|
|
376
|
-
if (tag.type === ReferenceTag) {
|
|
377
|
-
const { name, isArray, index: literalArrayIndex } = tag.value;
|
|
378
|
-
|
|
379
|
-
const arrayIndex = isArray
|
|
380
|
-
? hasOwn(node.properties, name)
|
|
381
|
-
? btree.getSum(node.properties[name])
|
|
382
|
-
: -1
|
|
383
|
-
: null;
|
|
384
|
-
|
|
385
|
-
if (literalArrayIndex != null && literalArrayIndex !== arrayIndex) throw new Error();
|
|
386
|
-
|
|
387
|
-
referenceIndexes[i] = arrayIndex;
|
|
388
|
-
|
|
389
|
-
if (isArray) {
|
|
390
|
-
if (!hasOwn(childrenIndexes, name) || childrenIndexes[name] === null) {
|
|
391
|
-
childrenIndexes[name] = [];
|
|
392
|
-
} else {
|
|
393
|
-
if (arrayIndex >= 0) {
|
|
394
|
-
childrenIndexes[name][arrayIndex] = i;
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
} else {
|
|
398
|
-
if (name !== '#' && name !== '@') {
|
|
399
|
-
childrenIndexes[name] = i;
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
} else if (tag.type === ArrayInitializerTag) {
|
|
403
|
-
referenceIndexes[i] = -1;
|
|
404
|
-
} else {
|
|
405
|
-
referenceIndexes[i] = null;
|
|
406
|
-
}
|
|
407
|
-
};
|
|
408
|
-
|
|
409
444
|
export const Path = class AgastPath extends WeakStackFrame {
|
|
410
445
|
static from(node) {
|
|
411
446
|
return this.create(node);
|
|
@@ -425,11 +460,10 @@ export const Path = class AgastPath extends WeakStackFrame {
|
|
|
425
460
|
|
|
426
461
|
if (
|
|
427
462
|
referenceIndex != null &&
|
|
428
|
-
![ReferenceTag, ShiftTag].includes(
|
|
429
|
-
)
|
|
463
|
+
![ReferenceTag, ShiftTag].includes(sumtree.getAt(referenceIndex, parent.node.children).type)
|
|
464
|
+
) {
|
|
430
465
|
throw new Error();
|
|
431
|
-
|
|
432
|
-
nodeStates.set(node, buildBindings(node));
|
|
466
|
+
}
|
|
433
467
|
|
|
434
468
|
if (parent && (!this.reference || ![ReferenceTag, ShiftTag].includes(this.reference.type))) {
|
|
435
469
|
throw new Error();
|
|
@@ -440,16 +474,24 @@ export const Path = class AgastPath extends WeakStackFrame {
|
|
|
440
474
|
buildSkips(this);
|
|
441
475
|
}
|
|
442
476
|
|
|
443
|
-
get
|
|
444
|
-
return
|
|
477
|
+
get openTagPath() {
|
|
478
|
+
return TagPath.from(this, 0);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
get openTag() {
|
|
482
|
+
return this.openTagPath.tag;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
get closeTagPath() {
|
|
486
|
+
return TagPath.from(this, -1);
|
|
445
487
|
}
|
|
446
488
|
|
|
447
|
-
get
|
|
448
|
-
return
|
|
489
|
+
get closeTag() {
|
|
490
|
+
return this.closeTagPath.tag;
|
|
449
491
|
}
|
|
450
492
|
|
|
451
493
|
get reference() {
|
|
452
|
-
return this.outer &&
|
|
494
|
+
return this.outer && sumtree.getAt(this.referenceIndex, this.outer.children);
|
|
453
495
|
}
|
|
454
496
|
|
|
455
497
|
get referencePath() {
|
|
@@ -457,7 +499,7 @@ export const Path = class AgastPath extends WeakStackFrame {
|
|
|
457
499
|
}
|
|
458
500
|
|
|
459
501
|
get gap() {
|
|
460
|
-
return this.outer &&
|
|
502
|
+
return this.outer && sumtree.getAt(this.referenceIndex + 1, this.outer.children);
|
|
461
503
|
}
|
|
462
504
|
|
|
463
505
|
get gapPath() {
|
|
@@ -473,9 +515,7 @@ export const Path = class AgastPath extends WeakStackFrame {
|
|
|
473
515
|
|
|
474
516
|
let shiftOffset = (shiftIndex ?? 0) * 2;
|
|
475
517
|
|
|
476
|
-
return (
|
|
477
|
-
node && this.push(node, getPropertiesSimple(reference, this.childrenIndexes) + shiftOffset)
|
|
478
|
-
);
|
|
518
|
+
return node && this.push(node, getPropertyChildrenIndex(this.node, reference) + shiftOffset);
|
|
479
519
|
}
|
|
480
520
|
|
|
481
521
|
at(depth) {
|
|
@@ -499,12 +539,16 @@ export class TagPath {
|
|
|
499
539
|
}
|
|
500
540
|
|
|
501
541
|
static from(path, childrenIndex) {
|
|
502
|
-
let size =
|
|
542
|
+
let size = sumtree.getSize(path.node.children);
|
|
503
543
|
let index = childrenIndex < 0 ? size + childrenIndex : childrenIndex;
|
|
504
544
|
|
|
505
545
|
return index >= 0 && index < size ? new TagPath(path, index) : null;
|
|
506
546
|
}
|
|
507
547
|
|
|
548
|
+
static fromNode(node, childrenIndex) {
|
|
549
|
+
return TagPath.from(Path.from(node), childrenIndex);
|
|
550
|
+
}
|
|
551
|
+
|
|
508
552
|
get tag() {
|
|
509
553
|
return this.child;
|
|
510
554
|
}
|
|
@@ -514,16 +558,24 @@ export class TagPath {
|
|
|
514
558
|
}
|
|
515
559
|
|
|
516
560
|
get child() {
|
|
517
|
-
return
|
|
561
|
+
return sumtree.getAt(this.childrenIndex, this.path.node.children);
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
siblingPathAt(index) {
|
|
565
|
+
return TagPath.from(this.path, index);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
siblingAt(index) {
|
|
569
|
+
return this.siblingPathAt(index)?.tag;
|
|
518
570
|
}
|
|
519
571
|
|
|
520
572
|
get nextSibling() {
|
|
521
573
|
const { path, childrenIndex } = this;
|
|
522
574
|
|
|
523
575
|
const child =
|
|
524
|
-
childrenIndex + 1 >=
|
|
576
|
+
childrenIndex + 1 >= sumtree.getSize(path.node.children)
|
|
525
577
|
? null
|
|
526
|
-
:
|
|
578
|
+
: sumtree.getAt(childrenIndex + 1, path.node.children);
|
|
527
579
|
|
|
528
580
|
return child && new TagPath(path, childrenIndex + 1);
|
|
529
581
|
}
|
|
@@ -534,8 +586,8 @@ export class TagPath {
|
|
|
534
586
|
let leaving = false;
|
|
535
587
|
|
|
536
588
|
for (;;) {
|
|
537
|
-
let prevTag =
|
|
538
|
-
let tag =
|
|
589
|
+
let prevTag = sumtree.getAt(childrenIndex - 1, path.node.children);
|
|
590
|
+
let tag = sumtree.getAt(childrenIndex, path.node.children);
|
|
539
591
|
let isInitialTag = path.node === this.path.node && childrenIndex === this.childrenIndex;
|
|
540
592
|
let wasLeaving = leaving;
|
|
541
593
|
leaving = false;
|
|
@@ -562,18 +614,20 @@ export class TagPath {
|
|
|
562
614
|
if (tag.type === GapTag && !wasLeaving && !isGapNode(path.node)) {
|
|
563
615
|
let refIndex = childrenIndex - 1;
|
|
564
616
|
let refTag;
|
|
565
|
-
let prevTag =
|
|
566
|
-
let nextTag =
|
|
617
|
+
let prevTag = sumtree.getAt(childrenIndex - 1, path.node.children);
|
|
618
|
+
let nextTag = sumtree.getAt(childrenIndex + 1, path.node.children);
|
|
567
619
|
|
|
568
620
|
if (
|
|
569
621
|
path.parent &&
|
|
570
|
-
|
|
571
|
-
childrenIndex === 2
|
|
622
|
+
sumtree.getAt(path.referenceIndex, path.outer.children)?.type === ShiftTag
|
|
572
623
|
) {
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
624
|
+
let third = sumtree.getAt(2, path.node.children);
|
|
625
|
+
if (childrenIndex === 2 || (childrenIndex === 4 && third.type === InitializerTag)) {
|
|
626
|
+
childrenIndex = path.referenceIndex + 1;
|
|
627
|
+
path = path.parent;
|
|
628
|
+
leaving = true;
|
|
629
|
+
continue;
|
|
630
|
+
}
|
|
577
631
|
}
|
|
578
632
|
|
|
579
633
|
if (prevTag.type === ReferenceTag) {
|
|
@@ -587,7 +641,7 @@ export class TagPath {
|
|
|
587
641
|
const { name, isArray, flags } = refTag.value;
|
|
588
642
|
let resolvedReference = refTag;
|
|
589
643
|
if (isArray) {
|
|
590
|
-
let index = path.
|
|
644
|
+
let index = getChildPropertyIndex(path.node, refIndex);
|
|
591
645
|
resolvedReference =
|
|
592
646
|
index === -1 ? null : buildReferenceTag(name, index != null, flags, index);
|
|
593
647
|
}
|
|
@@ -602,12 +656,12 @@ export class TagPath {
|
|
|
602
656
|
} else {
|
|
603
657
|
if (
|
|
604
658
|
!['#', '@'].includes(refTag.value.name) &&
|
|
605
|
-
(!refTag.value.isArray || path.
|
|
659
|
+
(!refTag.value.isArray || getChildPropertyIndex(path.node, refIndex) != null)
|
|
606
660
|
) {
|
|
607
661
|
const { name, isArray, flags } = refTag.value;
|
|
608
662
|
let resolvedReference = refTag;
|
|
609
663
|
if (isArray) {
|
|
610
|
-
let index = path.
|
|
664
|
+
let index = getChildPropertyIndex(path.node, refIndex);
|
|
611
665
|
resolvedReference =
|
|
612
666
|
index === -1 ? null : buildReferenceTag(name, index != null, flags, index);
|
|
613
667
|
}
|
|
@@ -625,22 +679,22 @@ export class TagPath {
|
|
|
625
679
|
}
|
|
626
680
|
} else if (prevTag.type === ShiftTag) {
|
|
627
681
|
let refIndex = childrenIndex - prevTag.value.index * 2 - 1;
|
|
628
|
-
let refTag =
|
|
682
|
+
let refTag = sumtree.getAt(refIndex, path.node.children);
|
|
629
683
|
|
|
630
684
|
const { name, isArray, flags } = refTag.value;
|
|
631
685
|
let resolvedReference = refTag;
|
|
632
686
|
if (isArray) {
|
|
633
|
-
let index = path.
|
|
687
|
+
let index = getChildPropertyIndex(path.node, refIndex);
|
|
634
688
|
resolvedReference =
|
|
635
689
|
index === -1 ? null : buildReferenceTag(name, index != null, flags, index);
|
|
636
690
|
}
|
|
637
691
|
|
|
638
692
|
if (resolvedReference) {
|
|
639
|
-
path = path.get(resolvedReference);
|
|
693
|
+
path = path.get(resolvedReference, prevTag.value.index);
|
|
640
694
|
// this was introducing errors
|
|
641
695
|
// caused us to return to a point before we left
|
|
642
696
|
path.referenceIndex = childrenIndex;
|
|
643
|
-
childrenIndex = 3;
|
|
697
|
+
childrenIndex = sumtree.getAt(2, path.node.children).type === InitializerTag ? 5 : 3;
|
|
644
698
|
continue;
|
|
645
699
|
}
|
|
646
700
|
} else {
|
|
@@ -651,12 +705,12 @@ export class TagPath {
|
|
|
651
705
|
// shift
|
|
652
706
|
if (tag.type === ShiftTag) {
|
|
653
707
|
let refIndex = childrenIndex - tag.value.index * 2;
|
|
654
|
-
let refTag =
|
|
708
|
+
let refTag = sumtree.getAt(refIndex, path.node.children);
|
|
655
709
|
|
|
656
710
|
const { name, isArray, flags } = refTag.value;
|
|
657
711
|
let resolvedReference = null;
|
|
658
712
|
if (isArray) {
|
|
659
|
-
let index = path.
|
|
713
|
+
let index = getChildPropertyIndex(path.node, refIndex);
|
|
660
714
|
resolvedReference =
|
|
661
715
|
index === -1 ? null : buildReferenceTag(name, index != null, flags, index);
|
|
662
716
|
} else {
|
|
@@ -665,18 +719,16 @@ export class TagPath {
|
|
|
665
719
|
|
|
666
720
|
if (resolvedReference) {
|
|
667
721
|
path = path.get(resolvedReference, tag.value.index);
|
|
722
|
+
|
|
723
|
+
if (!path) return null;
|
|
724
|
+
|
|
668
725
|
childrenIndex = 0;
|
|
669
726
|
continue;
|
|
670
727
|
}
|
|
671
|
-
|
|
672
|
-
// go backwards through any other shifts until we're done
|
|
673
|
-
// path = path.parent;
|
|
674
|
-
// childrenIndex = 0;
|
|
675
|
-
// continue;
|
|
676
728
|
}
|
|
677
729
|
|
|
678
730
|
// over
|
|
679
|
-
if (path.node && childrenIndex + 1 <
|
|
731
|
+
if (path.node && childrenIndex + 1 < sumtree.getSize(path.node.children)) {
|
|
680
732
|
childrenIndex++;
|
|
681
733
|
continue;
|
|
682
734
|
}
|
|
@@ -684,9 +736,9 @@ export class TagPath {
|
|
|
684
736
|
// out
|
|
685
737
|
if (path.referenceIndex != null) {
|
|
686
738
|
do {
|
|
687
|
-
if (
|
|
739
|
+
if (sumtree.getAt(path.referenceIndex + 2, path.outer.children)?.type === ShiftTag) {
|
|
688
740
|
childrenIndex =
|
|
689
|
-
|
|
741
|
+
sumtree.getSize(path.outer.children) > path.referenceIndex + 2
|
|
690
742
|
? path.referenceIndex + 2
|
|
691
743
|
: null;
|
|
692
744
|
} else {
|
|
@@ -711,7 +763,7 @@ export class TagPath {
|
|
|
711
763
|
let leaving = false;
|
|
712
764
|
|
|
713
765
|
for (;;) {
|
|
714
|
-
let tag =
|
|
766
|
+
let tag = sumtree.getAt(childrenIndex, path.node.children);
|
|
715
767
|
let isInitialTag = path.node === this.path.node && childrenIndex === this.childrenIndex;
|
|
716
768
|
let wasLeaving = leaving;
|
|
717
769
|
leaving = false;
|
|
@@ -739,7 +791,7 @@ export class TagPath {
|
|
|
739
791
|
if (tag.type === GapTag && !wasLeaving && !isGapNode(path.node)) {
|
|
740
792
|
let refIndex = childrenIndex - 1;
|
|
741
793
|
let refTag;
|
|
742
|
-
let prevTag =
|
|
794
|
+
let prevTag = sumtree.getAt(childrenIndex - 1, path.node.children);
|
|
743
795
|
|
|
744
796
|
if (prevTag.type === ShiftTag) {
|
|
745
797
|
// continue
|
|
@@ -748,12 +800,12 @@ export class TagPath {
|
|
|
748
800
|
|
|
749
801
|
if (
|
|
750
802
|
!['#', '@'].includes(refTag.value.name) &&
|
|
751
|
-
(!refTag.value.isArray || path.
|
|
803
|
+
(!refTag.value.isArray || getChildPropertyIndex(path.node, refIndex) != null)
|
|
752
804
|
) {
|
|
753
805
|
const { name, isArray, flags } = refTag.value;
|
|
754
806
|
let resolvedReference = refTag;
|
|
755
807
|
if (isArray) {
|
|
756
|
-
let index = path.
|
|
808
|
+
let index = getChildPropertyIndex(path.node, refIndex);
|
|
757
809
|
resolvedReference =
|
|
758
810
|
index === -1 ? null : buildReferenceTag(name, index != null, flags, index);
|
|
759
811
|
}
|
|
@@ -774,7 +826,7 @@ export class TagPath {
|
|
|
774
826
|
}
|
|
775
827
|
|
|
776
828
|
// over
|
|
777
|
-
if (path.node && childrenIndex + 1 <
|
|
829
|
+
if (path.node && childrenIndex + 1 < sumtree.getSize(path.node.children)) {
|
|
778
830
|
childrenIndex++;
|
|
779
831
|
continue;
|
|
780
832
|
}
|
|
@@ -814,7 +866,7 @@ export class TagPath {
|
|
|
814
866
|
let leaving = false;
|
|
815
867
|
|
|
816
868
|
for (;;) {
|
|
817
|
-
let tag =
|
|
869
|
+
let tag = sumtree.getAt(childrenIndex, path.node.children);
|
|
818
870
|
let isInitialTag = path.node === this.path.node && childrenIndex === this.childrenIndex;
|
|
819
871
|
let wasLeaving = leaving;
|
|
820
872
|
leaving = false;
|
|
@@ -834,7 +886,7 @@ export class TagPath {
|
|
|
834
886
|
// in
|
|
835
887
|
if (tag.type === EmbeddedNode && !wasLeaving) {
|
|
836
888
|
path = path.push(tag.value, childrenIndex - 1);
|
|
837
|
-
childrenIndex =
|
|
889
|
+
childrenIndex = sumtree.getSize(tag.value.children) - 1;
|
|
838
890
|
continue;
|
|
839
891
|
}
|
|
840
892
|
|
|
@@ -842,7 +894,7 @@ export class TagPath {
|
|
|
842
894
|
if (tag.type === GapTag && !wasLeaving && !isGapNode(path.node)) {
|
|
843
895
|
let refIndex = childrenIndex - 1;
|
|
844
896
|
let refTag;
|
|
845
|
-
let prevTag =
|
|
897
|
+
let prevTag = sumtree.getAt(childrenIndex - 1, path.node.children);
|
|
846
898
|
|
|
847
899
|
if (prevTag.type === ShiftTag) {
|
|
848
900
|
// continue
|
|
@@ -851,12 +903,12 @@ export class TagPath {
|
|
|
851
903
|
|
|
852
904
|
if (
|
|
853
905
|
!['#', '@'].includes(refTag.value.name) &&
|
|
854
|
-
(!refTag.value.isArray || path.
|
|
906
|
+
(!refTag.value.isArray || getChildPropertyIndex(path.node, refIndex) != null)
|
|
855
907
|
) {
|
|
856
908
|
const { name, isArray, flags } = refTag.value;
|
|
857
909
|
let resolvedReference = refTag;
|
|
858
910
|
if (isArray) {
|
|
859
|
-
let index = path.
|
|
911
|
+
let index = getChildPropertyIndex(path.node, refIndex);
|
|
860
912
|
resolvedReference =
|
|
861
913
|
index === -1 ? null : buildReferenceTag(name, index != null, flags, index);
|
|
862
914
|
}
|
|
@@ -877,7 +929,7 @@ export class TagPath {
|
|
|
877
929
|
}
|
|
878
930
|
|
|
879
931
|
// over
|
|
880
|
-
if (path.node && childrenIndex + 1 <
|
|
932
|
+
if (path.node && childrenIndex + 1 < sumtree.getSize(path.node.children)) {
|
|
881
933
|
childrenIndex--;
|
|
882
934
|
continue;
|
|
883
935
|
}
|
|
@@ -904,27 +956,33 @@ export class TagPath {
|
|
|
904
956
|
}
|
|
905
957
|
|
|
906
958
|
get innerPath() {
|
|
907
|
-
let { tag, previousSibling:
|
|
959
|
+
let { tag, previousSibling: refPath } = this;
|
|
908
960
|
|
|
909
|
-
if (tag.type !== GapTag || isGapNode(this.node)
|
|
961
|
+
if (tag.type !== GapTag || isGapNode(this.node)) {
|
|
910
962
|
return null;
|
|
911
963
|
}
|
|
912
964
|
|
|
913
|
-
|
|
965
|
+
let shiftPath = null;
|
|
966
|
+
if (refPath.tag.type === ShiftTag) {
|
|
967
|
+
shiftPath = refPath;
|
|
968
|
+
refPath = TagPath.from(this.path, this.childrenIndex - refPath.tag.value.index * 2 - 1);
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
if (refPath.tag.type !== ReferenceTag) throw new Error();
|
|
914
972
|
|
|
915
|
-
let resolvedRef =
|
|
973
|
+
let resolvedRef = refPath.tag;
|
|
916
974
|
|
|
917
|
-
if (
|
|
918
|
-
const { name, flags, isArray } =
|
|
975
|
+
if (refPath.tag.value.isArray) {
|
|
976
|
+
const { name, flags, isArray } = refPath.tag.value;
|
|
919
977
|
resolvedRef = buildReferenceTag(
|
|
920
978
|
name,
|
|
921
979
|
isArray,
|
|
922
980
|
flags,
|
|
923
|
-
|
|
981
|
+
getChildPropertyIndex(refPath.path.node, refPath.childrenIndex),
|
|
924
982
|
);
|
|
925
983
|
}
|
|
926
984
|
|
|
927
|
-
return this.path.get(resolvedRef);
|
|
985
|
+
return this.path.get(resolvedRef, shiftPath?.tag.value.index);
|
|
928
986
|
}
|
|
929
987
|
|
|
930
988
|
equalTo(tagPath) {
|