@bablr/agast-helpers 0.8.0 → 0.9.0
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 +62 -44
- package/lib/path-facade.js +18 -13
- package/lib/path.js +631 -345
- package/lib/print.js +34 -20
- package/lib/shorthand.js +1 -1
- package/lib/stream.js +37 -165
- package/lib/symbols.js +3 -1
- package/lib/tags.js +236 -0
- package/lib/template.js +11 -7
- package/lib/tree.js +224 -292
- package/package.json +6 -4
- package/lib/children.js +0 -120
package/lib/path.js
CHANGED
|
@@ -1,19 +1,42 @@
|
|
|
1
1
|
import { WeakStackFrame } from '@bablr/weak-stack';
|
|
2
|
-
import * as
|
|
3
|
-
import * as
|
|
2
|
+
import * as BTree from '@bablr/agast-helpers/btree';
|
|
3
|
+
import * as Tags from './tags.js';
|
|
4
4
|
import {
|
|
5
5
|
ReferenceTag,
|
|
6
6
|
InitializerTag,
|
|
7
7
|
DoctypeTag,
|
|
8
|
-
OpenNodeTag,
|
|
9
8
|
CloseNodeTag,
|
|
10
9
|
GapTag,
|
|
11
10
|
NullTag,
|
|
12
11
|
ShiftTag,
|
|
13
12
|
BindingTag,
|
|
13
|
+
PropertyWrapper,
|
|
14
14
|
Property,
|
|
15
15
|
} from './symbols.js';
|
|
16
|
-
import { isString } from './object.js';
|
|
16
|
+
import { isPlainObject, isString } from './object.js';
|
|
17
|
+
import { buildBinding, buildChild, buildProperty, buildPropertyWrapper } from './builders.js';
|
|
18
|
+
import { buildReferenceTag, finalizeNode } from './tree.js';
|
|
19
|
+
|
|
20
|
+
export const wrapperIsFull = (wrapper) => {
|
|
21
|
+
let { tags } = wrapper.value;
|
|
22
|
+
|
|
23
|
+
if (tags[1]?.type === InitializerTag) {
|
|
24
|
+
return true;
|
|
25
|
+
} else {
|
|
26
|
+
return tags.length === 3;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const offsetForTag = (tag) => {
|
|
31
|
+
switch (tag.type) {
|
|
32
|
+
case ReferenceTag:
|
|
33
|
+
case ShiftTag:
|
|
34
|
+
return 0;
|
|
35
|
+
case BindingTag:
|
|
36
|
+
case InitializerTag:
|
|
37
|
+
return 1;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
17
40
|
|
|
18
41
|
export const buildPathSegment = (name, index = null, shiftIndex = null) => {
|
|
19
42
|
if (!name) throw new Error();
|
|
@@ -29,18 +52,26 @@ export const buildFullPathSegment = (type, name, index = null, shiftIndex = null
|
|
|
29
52
|
return { type, name, index, shiftIndex };
|
|
30
53
|
};
|
|
31
54
|
|
|
32
|
-
export const
|
|
55
|
+
export const getRootProperty = (node, index = 0) => {
|
|
33
56
|
if (node == null || !isFragmentNode(node)) {
|
|
34
|
-
return
|
|
57
|
+
return null;
|
|
35
58
|
}
|
|
36
|
-
let idx =
|
|
59
|
+
let idx = getPropertyTagsIndex(node, '.', null, index);
|
|
37
60
|
|
|
38
61
|
if (idx == null) return null;
|
|
39
62
|
|
|
40
|
-
let tag =
|
|
63
|
+
let tag = Tags.getAt(idx, node.tags);
|
|
64
|
+
|
|
65
|
+
if (tag.type !== PropertyWrapper) throw new Error();
|
|
66
|
+
return tag.value.property;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export const getRoot = (node, index = 0) => {
|
|
70
|
+
if (!isFragmentNode(node)) {
|
|
71
|
+
return node;
|
|
72
|
+
}
|
|
41
73
|
|
|
42
|
-
|
|
43
|
-
return tag.value.node;
|
|
74
|
+
return getRootProperty(node, index)?.node;
|
|
44
75
|
};
|
|
45
76
|
|
|
46
77
|
export const getRootArray = (node) => {
|
|
@@ -57,62 +88,67 @@ export const getRootArray = (node) => {
|
|
|
57
88
|
};
|
|
58
89
|
|
|
59
90
|
export const getOpenTag = (node) => {
|
|
60
|
-
|
|
61
|
-
let tag = Children.getAt(0, node.children);
|
|
62
|
-
if (tag.type === NullTag || tag.type === GapTag) return null;
|
|
63
|
-
if (tag.type === DoctypeTag) {
|
|
64
|
-
tag = Children.getAt(1, node.children);
|
|
65
|
-
}
|
|
66
|
-
if (tag && tag.type !== OpenNodeTag) throw new Error();
|
|
67
|
-
return tag;
|
|
91
|
+
return Tags.getValues(node.tags)[0];
|
|
68
92
|
};
|
|
69
93
|
|
|
70
94
|
export const getCloseTag = (node) => {
|
|
71
|
-
|
|
72
|
-
const tag = Children.getAt(-1, children);
|
|
73
|
-
if (tag.type !== CloseNodeTag) return null;
|
|
74
|
-
return tag;
|
|
95
|
+
return Tags.getValues(node.tags)[2];
|
|
75
96
|
};
|
|
76
97
|
|
|
77
98
|
export const isNullNode = (node) => {
|
|
78
|
-
return node && node.type === null &&
|
|
99
|
+
return node && node.type === null && Tags.getAt(0, node.tags).type === NullTag;
|
|
79
100
|
};
|
|
80
101
|
|
|
81
102
|
export const isFragmentNode = (node) => {
|
|
82
|
-
return node && node.type === null && getOpenTag(node)?.value
|
|
103
|
+
return node && node.type === null && getOpenTag(node)?.value?.type === null;
|
|
83
104
|
};
|
|
84
105
|
|
|
85
106
|
export const isGapNode = (node) => {
|
|
86
|
-
return node && node.type === null &&
|
|
107
|
+
return node && node.type === null && Tags.getAt(0, node.tags).type === GapTag;
|
|
87
108
|
};
|
|
88
109
|
|
|
89
110
|
export const isStubNode = (node) => {
|
|
90
|
-
return (
|
|
91
|
-
|
|
92
|
-
|
|
111
|
+
return node && node.type === null && [GapTag, NullTag].includes(Tags.getAt(0, node.tags).type);
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
export const isStubTag = (tag) => {
|
|
115
|
+
return [GapTag, NullTag].includes(tag.type);
|
|
93
116
|
};
|
|
94
117
|
|
|
95
|
-
export const getChildPropertyIndex = (agAstNode,
|
|
96
|
-
let child =
|
|
118
|
+
export const getChildPropertyIndex = (agAstNode, tagsIndex) => {
|
|
119
|
+
let child = Tags.getAt(tagsIndex, agAstNode.tags);
|
|
120
|
+
|
|
121
|
+
if (child.type !== PropertyWrapper) return null;
|
|
97
122
|
|
|
98
|
-
let
|
|
123
|
+
let tag = child.value.tags[0];
|
|
99
124
|
|
|
100
|
-
let
|
|
125
|
+
let refIndex = tag.type === ShiftTag ? tagsIndex - tag.value.index : tagsIndex;
|
|
126
|
+
|
|
127
|
+
let stack = Tags.findPath(refIndex, agAstNode.tags);
|
|
101
128
|
let { node, index: leafIdx } = stack.value;
|
|
102
|
-
let leaf =
|
|
129
|
+
let leaf = Tags.getAt(leafIdx, node);
|
|
130
|
+
|
|
131
|
+
if (leaf.type !== PropertyWrapper) {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
103
134
|
|
|
104
|
-
|
|
135
|
+
let leafRefTag = leaf.value.tags[0];
|
|
105
136
|
|
|
106
|
-
|
|
137
|
+
if (leafRefTag.type !== ReferenceTag) return null;
|
|
138
|
+
|
|
139
|
+
let { name, isArray } = leafRefTag.value;
|
|
107
140
|
let count = -1;
|
|
108
141
|
|
|
109
142
|
if (!isArray) return null;
|
|
110
143
|
|
|
111
144
|
for (let i = leafIdx; i >= 0; i--) {
|
|
112
|
-
let value =
|
|
145
|
+
let value = Tags.getAt(i, node);
|
|
146
|
+
if (value.type === PropertyWrapper) {
|
|
147
|
+
let firstTag = value.value.tags[0];
|
|
113
148
|
|
|
114
|
-
|
|
115
|
-
|
|
149
|
+
if (firstTag.type === ReferenceTag && firstTag.value.name === name) {
|
|
150
|
+
count++;
|
|
151
|
+
}
|
|
116
152
|
}
|
|
117
153
|
}
|
|
118
154
|
stack = stack.pop();
|
|
@@ -123,11 +159,17 @@ export const getChildPropertyIndex = (agAstNode, childrenIndex) => {
|
|
|
123
159
|
|
|
124
160
|
do {
|
|
125
161
|
for (let i = leafIdx - 1; i >= 0; i--) {
|
|
126
|
-
let
|
|
127
|
-
let { references } = Children.getSums(childNode);
|
|
162
|
+
let value = Tags.getValues(node)[i];
|
|
128
163
|
|
|
129
|
-
if (
|
|
130
|
-
|
|
164
|
+
if (Array.isArray(value)) {
|
|
165
|
+
let childNode = value;
|
|
166
|
+
let { references } = Tags.getSums(childNode);
|
|
167
|
+
|
|
168
|
+
let res;
|
|
169
|
+
if ((res = Tags.getAtName(name, references))) {
|
|
170
|
+
count += res;
|
|
171
|
+
}
|
|
172
|
+
} else {
|
|
131
173
|
}
|
|
132
174
|
}
|
|
133
175
|
stack = stack.pop();
|
|
@@ -141,69 +183,129 @@ export const getChildPropertyIndex = (agAstNode, childrenIndex) => {
|
|
|
141
183
|
return count - 1;
|
|
142
184
|
};
|
|
143
185
|
|
|
144
|
-
export const
|
|
145
|
-
let
|
|
146
|
-
let
|
|
147
|
-
let initializerOffset =
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
186
|
+
export const getPropertyTagsIndex = (agAstNode, type, name, index, shiftIndex) => {
|
|
187
|
+
let firstPropsIndex = __getPropertyTagsIndex(agAstNode, type, name, 0);
|
|
188
|
+
let prop = firstPropsIndex == null ? null : Tags.getAt(firstPropsIndex, agAstNode.tags);
|
|
189
|
+
let initializerOffset = prop?.value.tags[1]?.type === InitializerTag ? 1 : 0;
|
|
190
|
+
let ref = prop?.value.property.reference;
|
|
191
|
+
let sums = Tags.getSums(agAstNode.tags);
|
|
192
|
+
|
|
193
|
+
if (ref?.isArray) {
|
|
194
|
+
if (index < 0) {
|
|
195
|
+
if (name) {
|
|
196
|
+
index = Tags.getAtName(name, sums.references) - initializerOffset + index;
|
|
153
197
|
} else {
|
|
154
|
-
index =
|
|
198
|
+
index = Tags.getAtName(type, sums.specialTypes) - initializerOffset + index;
|
|
155
199
|
}
|
|
200
|
+
} else if (index == null) {
|
|
201
|
+
if (name) {
|
|
202
|
+
index = Tags.getAtName(name, sums.references) - 1 - initializerOffset;
|
|
203
|
+
} else {
|
|
204
|
+
index = Tags.getAtName(type, sums.specialTypes) - 1 - initializerOffset;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (index < 0) return null;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
let parentIndex = __getPropertyTagsIndex(agAstNode, type, name, (index ?? 0) + initializerOffset);
|
|
212
|
+
|
|
213
|
+
if (ref?.flags.expression) {
|
|
214
|
+
let shiftIndex_ = shiftIndex == null ? -1 : shiftIndex;
|
|
215
|
+
if (shiftIndex_ < 0) {
|
|
216
|
+
let shifts = 0;
|
|
217
|
+
// TODO speed this up for deeply nested shifts
|
|
218
|
+
// algorithm: make big jump forward, then look at shift index to see if we overshot completely
|
|
219
|
+
// works because we know the size of the thing and a bigger thing doesn't fit in a smaller one
|
|
220
|
+
while (Tags.getAt(parentIndex + shifts + 1, agAstNode.tags, 0)?.type === ShiftTag) {
|
|
221
|
+
shifts++;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (-shiftIndex_ > shifts + 1) return null;
|
|
225
|
+
|
|
226
|
+
return parentIndex + shifts + shiftIndex_ + 1;
|
|
227
|
+
} else {
|
|
228
|
+
if (parentIndex + shiftIndex_ >= Tags.getSize(agAstNode.tags)) {
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return parentIndex + shiftIndex_;
|
|
156
233
|
}
|
|
157
234
|
}
|
|
158
235
|
|
|
159
|
-
return
|
|
236
|
+
return parentIndex;
|
|
160
237
|
};
|
|
161
238
|
|
|
162
|
-
export const
|
|
163
|
-
let { type, name } =
|
|
164
|
-
|
|
239
|
+
export const getInitializerTagsIndex = (agAstNode, referenceTag) => {
|
|
240
|
+
let { type, name } = referenceTag.value;
|
|
241
|
+
|
|
242
|
+
if (type === '#') return null;
|
|
243
|
+
|
|
244
|
+
let index = __getPropertyTagsIndex(agAstNode, type, name, 0);
|
|
245
|
+
|
|
246
|
+
if (index == null) return null;
|
|
247
|
+
|
|
248
|
+
let nextTag = Tags.getAt(index, agAstNode.tags, 1);
|
|
249
|
+
|
|
250
|
+
return nextTag?.type === InitializerTag ? index : null;
|
|
165
251
|
};
|
|
166
252
|
|
|
167
|
-
const
|
|
253
|
+
const __getPropertyTagsIndex = (agAstNode, type, name, index) => {
|
|
168
254
|
let nameCount = 0;
|
|
169
|
-
let node = agAstNode.
|
|
255
|
+
let node = Tags.getValues(agAstNode.tags)[1];
|
|
170
256
|
let idx = -1;
|
|
171
257
|
|
|
172
258
|
// drill into subtrees, passing over subtrees with too few references of the desired name
|
|
173
259
|
outer: while (node) {
|
|
174
|
-
let
|
|
175
|
-
|
|
176
|
-
|
|
260
|
+
let sums = Tags.getSums(node);
|
|
261
|
+
|
|
262
|
+
if (!sums) return null;
|
|
263
|
+
|
|
264
|
+
let valueNameCount =
|
|
265
|
+
name != null
|
|
266
|
+
? Tags.getAtName(name, sums.references)
|
|
267
|
+
: Tags.getAtName(type, sums.specialTypes);
|
|
177
268
|
|
|
178
269
|
if (nameCount + valueNameCount < index) {
|
|
179
270
|
return null;
|
|
180
271
|
}
|
|
181
272
|
|
|
182
|
-
for (const value of
|
|
183
|
-
if (
|
|
273
|
+
for (const value of Tags.getValues(node)) {
|
|
274
|
+
if (!isArray(value)) {
|
|
184
275
|
idx++;
|
|
185
276
|
let tag = value;
|
|
186
|
-
if (
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
277
|
+
if (tag.type === PropertyWrapper) {
|
|
278
|
+
let { tags, property } = tag.value;
|
|
279
|
+
let { reference } = property;
|
|
280
|
+
if (tags[0].type === ReferenceTag) {
|
|
281
|
+
if (
|
|
282
|
+
(name != null && reference.name === name) ||
|
|
283
|
+
(type != null && reference.type === type)
|
|
284
|
+
) {
|
|
285
|
+
nameCount += 1;
|
|
286
|
+
if (nameCount > index) {
|
|
287
|
+
return idx + 1;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
193
290
|
}
|
|
194
291
|
}
|
|
195
292
|
} else {
|
|
196
|
-
let valueSums =
|
|
293
|
+
let valueSums = Tags.getSums(value);
|
|
197
294
|
if (
|
|
198
|
-
nameCount +
|
|
295
|
+
nameCount +
|
|
296
|
+
(name != null
|
|
297
|
+
? Tags.getAtName(name, valueSums.references)
|
|
298
|
+
: Tags.getAtName(type, valueSums.specialTypes)) >
|
|
199
299
|
index
|
|
200
300
|
) {
|
|
201
301
|
node = value;
|
|
202
302
|
continue outer;
|
|
203
303
|
} else {
|
|
204
304
|
nameCount +=
|
|
205
|
-
(
|
|
206
|
-
|
|
305
|
+
(name != null
|
|
306
|
+
? Tags.getAtName(name, valueSums.references)
|
|
307
|
+
: Tags.getAtName(type, valueSums.specialTypes)) ?? 0;
|
|
308
|
+
idx += Tags.getSize(value);
|
|
207
309
|
}
|
|
208
310
|
}
|
|
209
311
|
}
|
|
@@ -218,10 +320,9 @@ const { hasOwn, freeze } = Object;
|
|
|
218
320
|
const { isArray } = Array;
|
|
219
321
|
|
|
220
322
|
export const getOriginalFirstNode = (node, height = 1) => {
|
|
221
|
-
for (let child of
|
|
222
|
-
if (child.type ===
|
|
223
|
-
return
|
|
224
|
-
.node;
|
|
323
|
+
for (let child of Tags.traverse(node.tags)) {
|
|
324
|
+
if (child.type === PropertyWrapper) {
|
|
325
|
+
return child.value.property.node;
|
|
225
326
|
}
|
|
226
327
|
}
|
|
227
328
|
return null;
|
|
@@ -232,26 +333,16 @@ export const getFirstNode = (node) => {
|
|
|
232
333
|
};
|
|
233
334
|
|
|
234
335
|
export const getFirstNodeProperty = (node) => {
|
|
235
|
-
for (let child of
|
|
236
|
-
if (child.type ===
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
export const getFirstNodeShiftStack = (node) => {
|
|
244
|
-
for (let child of Children.traverse(node.children)) {
|
|
245
|
-
if (child.type === Property) {
|
|
246
|
-
let { reference } = child.value;
|
|
247
|
-
|
|
248
|
-
if (!reference.flags.expression) return null;
|
|
249
|
-
|
|
250
|
-
let property = node.properties[reference.name];
|
|
251
|
-
if (reference.isArray) {
|
|
252
|
-
property = btree.getAt(-1, property.node);
|
|
336
|
+
for (let child of Tags.traverse(node.tags)) {
|
|
337
|
+
if (child.type === PropertyWrapper) {
|
|
338
|
+
let ref = child.value.reference;
|
|
339
|
+
if (!ref.flags.expression) {
|
|
340
|
+
return child.value;
|
|
341
|
+
} else {
|
|
342
|
+
let tagsIndex = getPropertyTagsIndex(node, ref.type, ref.name, 0, -1);
|
|
343
|
+
return Tags.getAt(tagsIndex, node.tags + 2)?.value.node;
|
|
253
344
|
}
|
|
254
|
-
|
|
345
|
+
// is it shifted?
|
|
255
346
|
}
|
|
256
347
|
}
|
|
257
348
|
return null;
|
|
@@ -260,40 +351,59 @@ export const getFirstNodeShiftStack = (node) => {
|
|
|
260
351
|
export const referencesAreEqual = (a, b) => {
|
|
261
352
|
return (
|
|
262
353
|
a === b ||
|
|
263
|
-
(a.
|
|
264
|
-
a.
|
|
265
|
-
a.
|
|
266
|
-
a.
|
|
354
|
+
(a.type === b.type &&
|
|
355
|
+
a.name === b.name &&
|
|
356
|
+
a.isArray === b.isArray &&
|
|
357
|
+
a.flags.hasGap === b.flags.hasGap &&
|
|
358
|
+
a.flags.expression === b.flags.expression)
|
|
267
359
|
);
|
|
268
360
|
};
|
|
269
361
|
|
|
270
|
-
export const
|
|
271
|
-
|
|
272
|
-
if (!hasOwn(pathSegment_, 'shiftIndex')) throw new Error();
|
|
273
|
-
let { name, index, shiftIndex } = pathSegment_;
|
|
274
|
-
|
|
275
|
-
if (hasOwn(properties, name)) {
|
|
276
|
-
let prop = properties[name];
|
|
362
|
+
export const isDefined = (obj, key) => hasOwn(obj, key) && obj[key] !== undefined;
|
|
363
|
+
export const isUndefined = (obj, key) => !hasOwn(obj, key) || obj[key] === undefined;
|
|
277
364
|
|
|
278
|
-
|
|
279
|
-
|
|
365
|
+
export function* relatedNodes(node) {
|
|
366
|
+
for (const child of Tags.traverse(node.tags)) {
|
|
367
|
+
if (child.type === PropertyWrapper) {
|
|
368
|
+
yield child.node;
|
|
280
369
|
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
281
372
|
|
|
282
|
-
|
|
373
|
+
export const getProperty = (pathSegment, node) => {
|
|
374
|
+
if (!node) throw new Error();
|
|
283
375
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
376
|
+
if (pathSegment == null) throw new Error('Bad path segment');
|
|
377
|
+
|
|
378
|
+
let { name, type, index, shiftIndex } =
|
|
379
|
+
typeof pathSegment === 'string' ? buildPathSegment(pathSegment) : pathSegment;
|
|
380
|
+
|
|
381
|
+
let propIndex = getPropertyTagsIndex(node, type, name, index, shiftIndex);
|
|
382
|
+
|
|
383
|
+
if (propIndex == null) return null;
|
|
384
|
+
|
|
385
|
+
return Tags.getAt(propIndex, node.tags)?.value.property;
|
|
386
|
+
};
|
|
287
387
|
|
|
288
|
-
|
|
388
|
+
export const has = (path, node) => {
|
|
389
|
+
if (!isArray(path)) {
|
|
390
|
+
path = [path];
|
|
289
391
|
}
|
|
290
|
-
|
|
392
|
+
|
|
393
|
+
let pathArr = [...path];
|
|
394
|
+
let node_ = get(pathArr.slice(0, -1), node);
|
|
395
|
+
let seg = pathArr[pathArr.length - 1];
|
|
396
|
+
let name = typeof seg === 'string' ? seg : seg.name;
|
|
397
|
+
|
|
398
|
+
return (
|
|
399
|
+
!!getProperty(seg, node_) ||
|
|
400
|
+
getInitializerTagsIndex(node_, buildReferenceTag(null, name)) != null
|
|
401
|
+
);
|
|
291
402
|
};
|
|
292
403
|
|
|
293
|
-
export const
|
|
294
|
-
export const isUndefined = (obj, key) => !hasOwn(obj, key) || obj[key] === undefined;
|
|
404
|
+
export const get = (path, node) => getOr(null, path, node);
|
|
295
405
|
|
|
296
|
-
export const
|
|
406
|
+
export const getOr = (defaultValue, path, node) => {
|
|
297
407
|
if (!node) throw new Error();
|
|
298
408
|
|
|
299
409
|
if (path == null) throw new Error('Bad path');
|
|
@@ -302,42 +412,57 @@ export const get = (path, node) => {
|
|
|
302
412
|
path = [path];
|
|
303
413
|
}
|
|
304
414
|
|
|
305
|
-
let
|
|
306
|
-
|
|
415
|
+
let root = getRoot(node);
|
|
416
|
+
let result = root || node;
|
|
417
|
+
|
|
418
|
+
let start = 0;
|
|
419
|
+
if (path[0]?.type === '.') {
|
|
420
|
+
if (!root) return null;
|
|
421
|
+
start = 1;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
for (let i = start; i < path.length; i++) {
|
|
307
425
|
let nameOrSeg = path[i];
|
|
308
426
|
let isName = typeof nameOrSeg === 'string';
|
|
309
427
|
let property;
|
|
428
|
+
let index = path[i + 1];
|
|
310
429
|
|
|
311
|
-
if (
|
|
430
|
+
if (typeof index === 'number') {
|
|
431
|
+
i++;
|
|
432
|
+
} else {
|
|
433
|
+
index = undefined;
|
|
434
|
+
}
|
|
312
435
|
|
|
313
|
-
|
|
436
|
+
if (!isName && (!nameOrSeg || !hasOwn(nameOrSeg, 'shiftIndex'))) throw new Error('Bad path');
|
|
314
437
|
|
|
315
|
-
|
|
316
|
-
let { index } = nameOrSeg;
|
|
438
|
+
let seg = isName ? buildPathSegment(nameOrSeg, index) : nameOrSeg;
|
|
317
439
|
|
|
318
|
-
|
|
319
|
-
isName ? buildPathSegment(name, index) : nameOrSeg,
|
|
320
|
-
node_.properties,
|
|
321
|
-
);
|
|
440
|
+
property = getProperty(seg, result);
|
|
322
441
|
|
|
323
|
-
|
|
324
|
-
} else if (!isName) {
|
|
325
|
-
let { type } = nameOrSeg;
|
|
326
|
-
if (type !== '.') throw new Error('not implemented');
|
|
442
|
+
if (!property) return defaultValue;
|
|
327
443
|
|
|
328
|
-
|
|
444
|
+
result = property.node;
|
|
445
|
+
}
|
|
329
446
|
|
|
330
|
-
|
|
447
|
+
return result;
|
|
448
|
+
};
|
|
331
449
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
throw new Error();
|
|
335
|
-
}
|
|
450
|
+
export function* list(name, node) {
|
|
451
|
+
let count = countList(name, node);
|
|
336
452
|
|
|
337
|
-
|
|
453
|
+
for (let i = 0; i < count; i++) {
|
|
454
|
+
yield get(buildPathSegment(name, i, -1), node);
|
|
338
455
|
}
|
|
456
|
+
}
|
|
339
457
|
|
|
340
|
-
|
|
458
|
+
export const countList = (name, node) => {
|
|
459
|
+
if (!node) throw new Error();
|
|
460
|
+
|
|
461
|
+
if (name == null) throw new Error('Bad path');
|
|
462
|
+
|
|
463
|
+
let hasInitializer = getInitializerTagsIndex(node, buildReferenceTag(null, name)) != null;
|
|
464
|
+
|
|
465
|
+
return Tags.getAtName(name, Tags.getSums(node.tags).references) - (hasInitializer ? 1 : 0);
|
|
341
466
|
};
|
|
342
467
|
|
|
343
468
|
export function* allTagPathsFor(range, options = {}) {
|
|
@@ -362,21 +487,17 @@ export function* allTagPathsFor(range, options = {}) {
|
|
|
362
487
|
|
|
363
488
|
yield path;
|
|
364
489
|
|
|
365
|
-
if (
|
|
366
|
-
endPath &&
|
|
367
|
-
path.childrenIndex === endPath.childrenIndex &&
|
|
368
|
-
path.path.node === endPath.path.node
|
|
369
|
-
) {
|
|
490
|
+
if (endPath && path.tagsIndex === endPath.tagsIndex && path.path.node === endPath.path.node) {
|
|
370
491
|
return;
|
|
371
492
|
}
|
|
372
493
|
|
|
373
|
-
let gapPath = path.path.parent && TagPath.from(path.path.parent, path.path.
|
|
494
|
+
let gapPath = path.path.parent && TagPath.from(path.path.parent, path.path.parentIndex, 1);
|
|
374
495
|
|
|
375
496
|
if (
|
|
376
497
|
endPath &&
|
|
377
498
|
path.tag.type === CloseNodeTag &&
|
|
378
499
|
gapPath &&
|
|
379
|
-
gapPath.
|
|
500
|
+
gapPath.tagsIndex === endPath.tagsIndex &&
|
|
380
501
|
gapPath.path.node === endPath.path.node
|
|
381
502
|
) {
|
|
382
503
|
return;
|
|
@@ -392,7 +513,7 @@ export function* allTagsFor(range, options = {}) {
|
|
|
392
513
|
}
|
|
393
514
|
|
|
394
515
|
export const buildFullRange = (node) => {
|
|
395
|
-
let sum =
|
|
516
|
+
let sum = Tags.getSize(node.tags);
|
|
396
517
|
return sum ? [0, sum - 1] : null;
|
|
397
518
|
};
|
|
398
519
|
|
|
@@ -404,10 +525,10 @@ export function* ownTagPathsFor(range) {
|
|
|
404
525
|
|
|
405
526
|
if (startPath.parent.node !== endPath.parent.node) throw new Error();
|
|
406
527
|
|
|
407
|
-
let {
|
|
528
|
+
let { tags } = startPath.parent.node;
|
|
408
529
|
|
|
409
|
-
for (let i = startPath.
|
|
410
|
-
yield
|
|
530
|
+
for (let i = startPath.tagsIndex; i < endPath.tagsIndex; i++) {
|
|
531
|
+
yield tags[i];
|
|
411
532
|
}
|
|
412
533
|
}
|
|
413
534
|
|
|
@@ -462,14 +583,14 @@ export let pathForTagPath = (tagPath) => {
|
|
|
462
583
|
let isShift = tagPath.tag.type === ShiftTag;
|
|
463
584
|
|
|
464
585
|
if (isShift) {
|
|
465
|
-
refTagPath = tagPath.siblingAt(tagPath.
|
|
586
|
+
refTagPath = tagPath.siblingAt(tagPath.tagsIndex - tagPath.tag.value.index);
|
|
466
587
|
}
|
|
467
588
|
|
|
468
589
|
let { type, name } = refTagPath.tag.value;
|
|
469
590
|
|
|
470
591
|
if (refTagPath.tag.type !== ReferenceTag) throw new Error();
|
|
471
592
|
|
|
472
|
-
let index = getChildPropertyIndex(tagPath.node, refTagPath.
|
|
593
|
+
let index = getChildPropertyIndex(tagPath.node, refTagPath.tagsIndex);
|
|
473
594
|
let shiftIndex = isShift ? (tagPath.tag.value.index ?? 0) + 1 : null;
|
|
474
595
|
|
|
475
596
|
return [{ type, name, index, shiftIndex }];
|
|
@@ -477,37 +598,42 @@ export let pathForTagPath = (tagPath) => {
|
|
|
477
598
|
|
|
478
599
|
export const Path = class AgastPath extends WeakStackFrame {
|
|
479
600
|
static from(node) {
|
|
480
|
-
|
|
601
|
+
let node_ = isPlainObject(node) ? node : node.node;
|
|
602
|
+
return node_ && this.create(node_);
|
|
481
603
|
}
|
|
482
604
|
|
|
483
|
-
constructor(parent, node,
|
|
605
|
+
constructor(parent, node, parentIndex = null) {
|
|
484
606
|
super(parent);
|
|
485
607
|
|
|
486
|
-
if (!(hasOwn(node, 'type') && hasOwn(node, '
|
|
608
|
+
if (!node || !(hasOwn(node, 'type') && hasOwn(node, 'tags'))) throw new Error();
|
|
487
609
|
|
|
488
|
-
if (parent &&
|
|
610
|
+
if (parent && parentIndex == null) throw new Error();
|
|
489
611
|
if (!node) throw new Error();
|
|
490
612
|
if (isArray(node)) throw new Error();
|
|
491
613
|
|
|
492
614
|
this.node = node;
|
|
493
|
-
this.
|
|
615
|
+
this.parentIndex = parentIndex; // in the parent
|
|
494
616
|
|
|
495
|
-
let
|
|
496
|
-
referenceIndex != null && Children.getAt(referenceIndex, parent.node.children);
|
|
617
|
+
let parentTag = parent && Tags.getAt(parentIndex, parent.node.tags);
|
|
497
618
|
|
|
498
|
-
if (
|
|
619
|
+
if (parentTag && parentTag.type !== PropertyWrapper) {
|
|
499
620
|
throw new Error();
|
|
500
621
|
}
|
|
501
622
|
|
|
502
|
-
|
|
623
|
+
parentIndex != null && parentTag?.value.tags[0];
|
|
624
|
+
|
|
625
|
+
if (
|
|
626
|
+
parent &&
|
|
627
|
+
(!this.referenceTag || ![ReferenceTag, ShiftTag].includes(this.referenceTag.type))
|
|
628
|
+
) {
|
|
503
629
|
throw new Error();
|
|
504
630
|
}
|
|
505
631
|
|
|
506
632
|
// if (
|
|
507
633
|
// parent &&
|
|
508
|
-
// (['#', '@'].includes(this.
|
|
509
|
-
// ? parent.tagPathAt(
|
|
510
|
-
// : get(pathForTagPath(parent.tagPathAt(
|
|
634
|
+
// (['#', '@'].includes(this.referenceTag.value.type)
|
|
635
|
+
// ? parent.tagPathAt(parentIndex, 1).tag.value
|
|
636
|
+
// : get(pathForTagPath(parent.tagPathAt(parentIndex)), parent.node)) !== node
|
|
511
637
|
// ) {
|
|
512
638
|
// throw new Error('Path not reachable');
|
|
513
639
|
// }
|
|
@@ -541,18 +667,54 @@ export const Path = class AgastPath extends WeakStackFrame {
|
|
|
541
667
|
return this.closeTagPath.tag;
|
|
542
668
|
}
|
|
543
669
|
|
|
544
|
-
tagPathAt(idx) {
|
|
545
|
-
return TagPath.from(this, idx);
|
|
670
|
+
tagPathAt(idx, offset) {
|
|
671
|
+
return TagPath.from(this, idx, offset);
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
get binding() {
|
|
675
|
+
return this.bindingTag?.value ?? null;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
get bindingTag() {
|
|
679
|
+
return this.bindingTagPath?.tag ?? null;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
get bindingTagPath() {
|
|
683
|
+
return (this.parent?.node ?? null) && new TagPath(this.parent, this.parentIndex, 1);
|
|
546
684
|
}
|
|
547
685
|
|
|
548
686
|
get reference() {
|
|
549
|
-
return
|
|
550
|
-
|
|
551
|
-
|
|
687
|
+
return this.referenceTag?.value ?? null;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
get referenceTag() {
|
|
691
|
+
return this.referenceTagPath?.tag ?? null;
|
|
552
692
|
}
|
|
553
693
|
|
|
554
694
|
get referenceTagPath() {
|
|
555
|
-
|
|
695
|
+
if (!this.parent?.node) {
|
|
696
|
+
return null;
|
|
697
|
+
}
|
|
698
|
+
let path = new TagPath(this.parent, this.parentIndex, 0);
|
|
699
|
+
if (path.tag.type === ShiftTag) {
|
|
700
|
+
path = new TagPath(this.parent, this.parentIndex - path.tag.value.index, 0);
|
|
701
|
+
}
|
|
702
|
+
return path;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
get parentPropertyPath() {
|
|
706
|
+
if (!this.parent?.node) {
|
|
707
|
+
return null;
|
|
708
|
+
}
|
|
709
|
+
let path = new TagPath(this.parent, this.parentIndex);
|
|
710
|
+
if (path.tag.type === ShiftTag) {
|
|
711
|
+
path = new TagPath(this.parent, this.parentIndex - path.tag.value.index);
|
|
712
|
+
}
|
|
713
|
+
return path;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
get parentProperty() {
|
|
717
|
+
return this.parentPropertyPath?.tag ?? null;
|
|
556
718
|
}
|
|
557
719
|
|
|
558
720
|
get(path) {
|
|
@@ -563,37 +725,167 @@ export const Path = class AgastPath extends WeakStackFrame {
|
|
|
563
725
|
if (!isArray(path_)) throw new Error();
|
|
564
726
|
|
|
565
727
|
let pathInst = this;
|
|
728
|
+
|
|
729
|
+
if (!pathInst.node.type && pathInst.node.flags.cover) {
|
|
730
|
+
if (pathInst.depth) throw new Error();
|
|
731
|
+
pathInst = pathInst.push(
|
|
732
|
+
getRoot(pathInst.node),
|
|
733
|
+
getPropertyTagsIndex(pathInst.node, '.', null, 0),
|
|
734
|
+
);
|
|
735
|
+
}
|
|
736
|
+
|
|
566
737
|
for (let i = 0; i < path_.length; i++) {
|
|
567
738
|
let nameOrSeg = path_[i];
|
|
568
739
|
|
|
740
|
+
let seg = nameOrSeg;
|
|
569
741
|
if (isString(nameOrSeg)) {
|
|
570
|
-
|
|
742
|
+
let index = path_[i + 1];
|
|
743
|
+
if (typeof index === 'number') {
|
|
744
|
+
i++;
|
|
745
|
+
} else {
|
|
746
|
+
index = undefined;
|
|
747
|
+
}
|
|
748
|
+
seg = buildPathSegment(nameOrSeg, index);
|
|
571
749
|
}
|
|
572
750
|
|
|
573
|
-
let
|
|
751
|
+
let tagsIndex = getPropertyTagsIndex(
|
|
752
|
+
pathInst.node,
|
|
753
|
+
seg.type,
|
|
754
|
+
seg.name,
|
|
755
|
+
seg.index,
|
|
756
|
+
seg.shiftIndex,
|
|
757
|
+
);
|
|
758
|
+
|
|
759
|
+
let { property } = Tags.getAt(tagsIndex, pathInst.node.tags).value;
|
|
574
760
|
|
|
575
761
|
if (!property) return null;
|
|
576
762
|
|
|
577
|
-
let { node
|
|
763
|
+
let { node } = property;
|
|
578
764
|
|
|
579
|
-
|
|
765
|
+
pathInst = pathInst.push(node, tagsIndex);
|
|
766
|
+
}
|
|
580
767
|
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
768
|
+
return pathInst;
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
replaceWith(node, binding = buildBinding()) {
|
|
772
|
+
return this.replaceAt([], node, binding);
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
replaceAt(path, node, binding = buildBinding()) {
|
|
776
|
+
throw new Error('not working yet');
|
|
777
|
+
|
|
778
|
+
let built;
|
|
779
|
+
let path_ = path;
|
|
780
|
+
if (typeof path_ === 'string') {
|
|
781
|
+
path_ = [path_];
|
|
782
|
+
}
|
|
783
|
+
if (!isArray(path_)) throw new Error();
|
|
586
784
|
|
|
587
|
-
|
|
785
|
+
let pathInst = this;
|
|
588
786
|
|
|
787
|
+
if (!pathInst.node.type && pathInst.node.flags.cover) {
|
|
788
|
+
if (pathInst.depth) throw new Error();
|
|
589
789
|
pathInst = pathInst.push(
|
|
590
|
-
node,
|
|
591
|
-
|
|
592
|
-
shiftOffset,
|
|
790
|
+
getRoot(pathInst.node),
|
|
791
|
+
getPropertyTagsIndex(pathInst.node, '.', null, 0),
|
|
593
792
|
);
|
|
594
793
|
}
|
|
595
794
|
|
|
596
|
-
|
|
795
|
+
for (let i = 0; i < path_.length; i++) {
|
|
796
|
+
let nameOrSeg = path_[i];
|
|
797
|
+
|
|
798
|
+
built = { ...pathInst.node };
|
|
799
|
+
|
|
800
|
+
let seg = nameOrSeg;
|
|
801
|
+
if (isString(nameOrSeg)) {
|
|
802
|
+
let index = path_[i + 1];
|
|
803
|
+
if (typeof index === 'number') {
|
|
804
|
+
i++;
|
|
805
|
+
} else {
|
|
806
|
+
index = undefined;
|
|
807
|
+
}
|
|
808
|
+
seg = buildPathSegment(nameOrSeg, index);
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
let tagsIndex = getPropertyTagsIndex(
|
|
812
|
+
pathInst.node,
|
|
813
|
+
seg.type,
|
|
814
|
+
seg.name,
|
|
815
|
+
seg.index,
|
|
816
|
+
seg.shiftIndex,
|
|
817
|
+
);
|
|
818
|
+
|
|
819
|
+
let tagPath = TagPath.from(pathInst, tagsIndex);
|
|
820
|
+
|
|
821
|
+
let {
|
|
822
|
+
property,
|
|
823
|
+
tags: { 0: refTag },
|
|
824
|
+
} = tagPath.tag.value;
|
|
825
|
+
|
|
826
|
+
if (refTag.type === ShiftTag) {
|
|
827
|
+
let { index } = refTag.value;
|
|
828
|
+
|
|
829
|
+
for (let i = 0; i < index - 1; i++) {
|
|
830
|
+
// update bounds!
|
|
831
|
+
}
|
|
832
|
+
tagsIndex -= index;
|
|
833
|
+
pathInst = pathInst.replace(built, tagsIndex);
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
if (!property) return null;
|
|
837
|
+
|
|
838
|
+
let { node } = property;
|
|
839
|
+
|
|
840
|
+
pathInst = pathInst.push(node, tagsIndex);
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
let node_ = isPlainObject(node) ? node : node.node;
|
|
844
|
+
|
|
845
|
+
if (!node_) throw new Error();
|
|
846
|
+
|
|
847
|
+
path = pathInst.parent;
|
|
848
|
+
let replacementPath = [];
|
|
849
|
+
|
|
850
|
+
let targetReference = pathInst.reference;
|
|
851
|
+
let targetBinding = binding;
|
|
852
|
+
let targetParentIndex = pathInst.parentIndex;
|
|
853
|
+
|
|
854
|
+
while (path) {
|
|
855
|
+
let value = built;
|
|
856
|
+
built = { ...path.node };
|
|
857
|
+
|
|
858
|
+
let { tags } = Tags.getAt(targetParentIndex, path.node.tags).value;
|
|
859
|
+
let property = buildProperty(targetReference, targetBinding, value);
|
|
860
|
+
|
|
861
|
+
let tags_ = [tags[0], buildChild(BindingTag, targetBinding), buildChild(Property, property)];
|
|
862
|
+
|
|
863
|
+
built.tags = Tags.replaceAt(
|
|
864
|
+
targetParentIndex,
|
|
865
|
+
built.tags,
|
|
866
|
+
buildChild(PropertyWrapper, buildPropertyWrapper(tags_, property)),
|
|
867
|
+
);
|
|
868
|
+
|
|
869
|
+
finalizeNode(built);
|
|
870
|
+
|
|
871
|
+
if (targetReference.name) {
|
|
872
|
+
replacementPath.push(
|
|
873
|
+
buildPathSegment(
|
|
874
|
+
targetReference.name,
|
|
875
|
+
getChildPropertyIndex(path.node, targetParentIndex),
|
|
876
|
+
),
|
|
877
|
+
);
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
targetReference = path.reference;
|
|
881
|
+
targetBinding = path.binding;
|
|
882
|
+
targetParentIndex = path.parentIndex;
|
|
883
|
+
path = path.parent;
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
replacementPath.reverse();
|
|
887
|
+
|
|
888
|
+
return Path.from(built).get(replacementPath).atDepth(this.depth);
|
|
597
889
|
}
|
|
598
890
|
|
|
599
891
|
atDepth(depth) {
|
|
@@ -603,34 +895,50 @@ export const Path = class AgastPath extends WeakStackFrame {
|
|
|
603
895
|
|
|
604
896
|
export const tagPathsAreEqual = (a, b) => {
|
|
605
897
|
if (a == null || b == null) return b == a;
|
|
606
|
-
return a.path.node === b.path.node && a.
|
|
898
|
+
return a.path.node === b.path.node && a.tagsIndex === b.tagsIndex;
|
|
607
899
|
};
|
|
608
900
|
|
|
609
901
|
export class TagPath {
|
|
610
|
-
constructor(path,
|
|
611
|
-
if (path == null ||
|
|
902
|
+
constructor(path, tagsIndex, wrapperIndex) {
|
|
903
|
+
if (path == null || tagsIndex == null) throw new Error();
|
|
612
904
|
|
|
613
|
-
let tag =
|
|
905
|
+
let tag = Tags.getAt(tagsIndex, path.node.tags);
|
|
614
906
|
|
|
615
907
|
if (tag == null) throw new Error();
|
|
616
908
|
|
|
909
|
+
if (tag.type === PropertyWrapper && wrapperIndex != null) {
|
|
910
|
+
tag = tag.value.tags[wrapperIndex];
|
|
911
|
+
}
|
|
912
|
+
|
|
617
913
|
this.path = path;
|
|
618
914
|
this.node = path.node;
|
|
619
915
|
this.tag = tag;
|
|
620
|
-
this.
|
|
916
|
+
this.tagsIndex = tagsIndex;
|
|
917
|
+
this.wrapperIndex = wrapperIndex;
|
|
621
918
|
|
|
622
919
|
freeze(this);
|
|
623
920
|
}
|
|
624
921
|
|
|
625
|
-
static from(path,
|
|
626
|
-
let size =
|
|
627
|
-
let index =
|
|
922
|
+
static from(path, tagsIndex, wrapperIndex) {
|
|
923
|
+
let size = Tags.getSize(path.node.tags);
|
|
924
|
+
let index = tagsIndex < 0 ? size + tagsIndex : tagsIndex;
|
|
925
|
+
|
|
926
|
+
let tag = Tags.getAt(index, path.node.tags);
|
|
628
927
|
|
|
629
|
-
|
|
928
|
+
if (!tag) return null;
|
|
929
|
+
|
|
930
|
+
let offset =
|
|
931
|
+
wrapperIndex == null || tag.type !== PropertyWrapper
|
|
932
|
+
? null
|
|
933
|
+
: wrapperIndex < 0
|
|
934
|
+
? tag.value.tags.length + wrapperIndex
|
|
935
|
+
: wrapperIndex;
|
|
936
|
+
|
|
937
|
+
return index >= 0 && index < size ? new TagPath(path, index, offset) : null;
|
|
630
938
|
}
|
|
631
939
|
|
|
632
|
-
static fromNode(node,
|
|
633
|
-
return TagPath.from(Path.from(node),
|
|
940
|
+
static fromNode(node, tagsIndex, wrapperIndex) {
|
|
941
|
+
return TagPath.from(Path.from(node), tagsIndex, wrapperIndex);
|
|
634
942
|
}
|
|
635
943
|
|
|
636
944
|
get child() {
|
|
@@ -642,117 +950,129 @@ export class TagPath {
|
|
|
642
950
|
}
|
|
643
951
|
|
|
644
952
|
get nextSibling() {
|
|
645
|
-
const { path,
|
|
953
|
+
const { path, tagsIndex, wrapperIndex } = this;
|
|
646
954
|
|
|
647
|
-
|
|
648
|
-
childrenIndex + 1 >= Children.getSize(path.node.children)
|
|
649
|
-
? null
|
|
650
|
-
: Children.getAt(childrenIndex + 1, path.node.children);
|
|
955
|
+
let propPath = new TagPath(path, tagsIndex);
|
|
651
956
|
|
|
652
|
-
|
|
957
|
+
if (wrapperIndex != null && wrapperIndex + 1 < Tags.getSize(propPath.tag.value.tags)) {
|
|
958
|
+
return new TagPath(path, tagsIndex, wrapperIndex + 1);
|
|
959
|
+
} else if (tagsIndex + 1 < Tags.getSize(path.node.tags)) {
|
|
960
|
+
return new TagPath(path, tagsIndex + 1, 0);
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
return TagPath.from(path, tagsIndex + 1, 0);
|
|
653
964
|
}
|
|
654
965
|
|
|
655
966
|
get next() {
|
|
656
|
-
let { path,
|
|
967
|
+
let { path, tagsIndex, wrapperIndex } = this;
|
|
657
968
|
|
|
658
969
|
let leaving = false;
|
|
659
970
|
|
|
660
971
|
for (;;) {
|
|
661
|
-
let
|
|
662
|
-
let tag =
|
|
663
|
-
let
|
|
972
|
+
let lastRef = Tags.getAt(tagsIndex, path.node.tags, 0);
|
|
973
|
+
let tag = Tags.getAt(tagsIndex, path.node.tags);
|
|
974
|
+
let wrapperTag = tag;
|
|
975
|
+
let isInitialTag =
|
|
976
|
+
path.node === this.path.node &&
|
|
977
|
+
tagsIndex === this.tagsIndex &&
|
|
978
|
+
wrapperIndex === this.wrapperIndex;
|
|
664
979
|
let wasLeaving = leaving;
|
|
665
980
|
leaving = false;
|
|
666
981
|
|
|
667
982
|
if (!tag) return null;
|
|
668
983
|
|
|
984
|
+
wrapperIndex =
|
|
985
|
+
tag.type === PropertyWrapper ? (wrapperIndex == null ? 0 : wrapperIndex) : null;
|
|
986
|
+
|
|
987
|
+
if (wrapperIndex != null) {
|
|
988
|
+
wrapperTag = tag.value.tags[wrapperIndex];
|
|
989
|
+
}
|
|
990
|
+
|
|
669
991
|
// done
|
|
670
|
-
if (!isInitialTag &&
|
|
671
|
-
return new TagPath(path,
|
|
992
|
+
if (!isInitialTag && wrapperTag.type !== Property) {
|
|
993
|
+
return new TagPath(path, tagsIndex, wrapperIndex);
|
|
672
994
|
}
|
|
673
995
|
|
|
674
996
|
// in
|
|
675
|
-
if (
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
(
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
997
|
+
if (wrapperTag.type === Property && !wasLeaving) {
|
|
998
|
+
if (tag.value.tags[1]?.type === InitializerTag || !tag.value.property.node) {
|
|
999
|
+
} else {
|
|
1000
|
+
// jump to gap tag?
|
|
1001
|
+
let tag1;
|
|
1002
|
+
if (
|
|
1003
|
+
path.parent &&
|
|
1004
|
+
tag.value.property.reference.flags.expression &&
|
|
1005
|
+
(tagsIndex === 1 ||
|
|
1006
|
+
(tagsIndex === 2 &&
|
|
1007
|
+
(tag1 = Tags.getAt(1, path.node.tags)).type === PropertyWrapper &&
|
|
1008
|
+
tag1.value.tags[1].type === InitializerTag)) &&
|
|
1009
|
+
Tags.getAt(path.parentIndex, path.parent.node.tags, 0)?.type === ShiftTag
|
|
1010
|
+
) {
|
|
1011
|
+
let shiftStack = tag.value.property.node.bounds[0];
|
|
1012
|
+
|
|
1013
|
+
let gapNode = BTree.getAt(-1, shiftStack).node;
|
|
687
1014
|
|
|
688
|
-
|
|
689
|
-
|
|
1015
|
+
path = new Path(path, gapNode, tagsIndex);
|
|
1016
|
+
tagsIndex = 0;
|
|
1017
|
+
continue;
|
|
690
1018
|
}
|
|
691
|
-
let gapNode = btree.getAt(0, shiftStack).node;
|
|
692
1019
|
|
|
693
|
-
path = new Path(path,
|
|
694
|
-
|
|
1020
|
+
path = new Path(path, tag.value.property.node, tagsIndex);
|
|
1021
|
+
tagsIndex = 0;
|
|
695
1022
|
continue;
|
|
696
1023
|
}
|
|
697
|
-
|
|
698
|
-
path = path.push(tag.value.node, childrenIndex - 2);
|
|
699
|
-
childrenIndex = 0;
|
|
700
|
-
continue;
|
|
701
1024
|
}
|
|
702
1025
|
|
|
1026
|
+
tag;
|
|
703
1027
|
// shift
|
|
704
|
-
if (
|
|
705
|
-
let refIndex =
|
|
1028
|
+
if (wrapperTag.type === BindingTag && lastRef.type === ShiftTag) {
|
|
1029
|
+
let refIndex = tagsIndex - lastRef.value.index;
|
|
706
1030
|
if (refIndex < 0) throw new Error();
|
|
707
|
-
let refTag =
|
|
708
|
-
|
|
709
|
-
const { name, isArray } = refTag.value;
|
|
710
|
-
let pathDesc = buildPathSegment(name);
|
|
711
|
-
let index;
|
|
712
|
-
if (isArray) {
|
|
713
|
-
index = getChildPropertyIndex(path.node, refIndex);
|
|
714
|
-
pathDesc = buildPathSegment(name, index);
|
|
715
|
-
}
|
|
1031
|
+
let refTag = Tags.getAt(refIndex, path.node.tags, 0);
|
|
716
1032
|
|
|
717
|
-
|
|
718
|
-
pathDesc.shiftIndex = prevTag.value.height;
|
|
1033
|
+
if (refTag.type !== ReferenceTag) throw new Error();
|
|
719
1034
|
|
|
720
|
-
if (
|
|
721
|
-
path = path.
|
|
1035
|
+
if (Tags.getAt(refIndex, path.node.tags, 1).type !== InitializerTag) {
|
|
1036
|
+
path = new Path(path, tag.value.property.node, tagsIndex);
|
|
722
1037
|
|
|
723
1038
|
if (!path) return null;
|
|
724
1039
|
|
|
725
|
-
|
|
1040
|
+
tagsIndex = 0;
|
|
726
1041
|
continue;
|
|
727
1042
|
}
|
|
728
1043
|
}
|
|
729
1044
|
|
|
730
1045
|
// over
|
|
731
|
-
if (
|
|
732
|
-
|
|
1046
|
+
if (tag.type === PropertyWrapper && wrapperIndex + 1 < tag.value.tags.length) {
|
|
1047
|
+
wrapperIndex++;
|
|
1048
|
+
continue;
|
|
1049
|
+
} else if (path.node && tagsIndex + 1 < Tags.getSize(path.node.tags)) {
|
|
1050
|
+
tagsIndex++;
|
|
1051
|
+
wrapperIndex = 0;
|
|
733
1052
|
continue;
|
|
734
1053
|
}
|
|
735
1054
|
|
|
736
1055
|
// out
|
|
737
|
-
if (path.
|
|
1056
|
+
if (path.parentIndex != null && path.parent) {
|
|
738
1057
|
do {
|
|
739
1058
|
if (
|
|
740
1059
|
path.parent &&
|
|
741
|
-
|
|
1060
|
+
Tags.getAt(path.parentIndex, path.parent.node.tags, 0)?.type === ShiftTag
|
|
742
1061
|
) {
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
? path.
|
|
1062
|
+
tagsIndex =
|
|
1063
|
+
Tags.getSize(path.parent.node.tags) > path.parentIndex + 1
|
|
1064
|
+
? path.parentIndex + 1
|
|
746
1065
|
: null;
|
|
747
1066
|
} else {
|
|
748
|
-
|
|
1067
|
+
tagsIndex = path.parentIndex + 1;
|
|
749
1068
|
}
|
|
750
1069
|
|
|
1070
|
+
wrapperIndex = 0;
|
|
751
1071
|
path = path.parent;
|
|
752
1072
|
leaving = true;
|
|
753
1073
|
|
|
754
1074
|
if (!path) return null;
|
|
755
|
-
} while (
|
|
1075
|
+
} while (tagsIndex == null);
|
|
756
1076
|
|
|
757
1077
|
leaving = true;
|
|
758
1078
|
continue;
|
|
@@ -763,64 +1083,77 @@ export class TagPath {
|
|
|
763
1083
|
}
|
|
764
1084
|
|
|
765
1085
|
get nextUnshifted() {
|
|
766
|
-
let { path,
|
|
1086
|
+
let { path, tagsIndex, wrapperIndex } = this;
|
|
767
1087
|
|
|
768
1088
|
let leaving = false;
|
|
769
1089
|
|
|
770
1090
|
for (;;) {
|
|
771
|
-
let tag =
|
|
772
|
-
let
|
|
1091
|
+
let tag = Tags.getAt(tagsIndex, path.node.tags);
|
|
1092
|
+
let wrapperTag = tag;
|
|
1093
|
+
let isInitialTag =
|
|
1094
|
+
path.node === this.path.node &&
|
|
1095
|
+
tagsIndex === this.tagsIndex &&
|
|
1096
|
+
wrapperIndex === this.wrapperIndex;
|
|
773
1097
|
let wasLeaving = leaving;
|
|
774
1098
|
leaving = false;
|
|
775
1099
|
|
|
776
1100
|
if (!tag) return null;
|
|
777
1101
|
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
1102
|
+
wrapperIndex =
|
|
1103
|
+
tag.type === PropertyWrapper ? (wrapperIndex == null ? 0 : wrapperIndex) : null;
|
|
1104
|
+
|
|
1105
|
+
if (wrapperIndex != null) {
|
|
1106
|
+
wrapperTag = tag.value.tags[wrapperIndex];
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
if (wrapperTag.type === ReferenceTag && wrapperTag.value.flags.expression) {
|
|
1110
|
+
// move past shifts
|
|
785
1111
|
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
1112
|
+
let shifts = 0;
|
|
1113
|
+
let tag = Tags.getAt(tagsIndex + 1, path.node.tags);
|
|
1114
|
+
|
|
1115
|
+
while (tag?.type === PropertyWrapper && tag.value.tags[0].type === ShiftTag) {
|
|
1116
|
+
shifts++;
|
|
1117
|
+
wrapperIndex = 1;
|
|
1118
|
+
tag = Tags.getAt(tagsIndex + shifts + 1, path.node.tags);
|
|
1119
|
+
}
|
|
1120
|
+
if (shifts) {
|
|
1121
|
+
tagsIndex += shifts;
|
|
1122
|
+
continue;
|
|
790
1123
|
}
|
|
791
1124
|
}
|
|
792
1125
|
|
|
793
1126
|
// done
|
|
794
|
-
if (!isInitialTag &&
|
|
795
|
-
return new TagPath(path,
|
|
1127
|
+
if (!isInitialTag && wrapperTag.type !== Property) {
|
|
1128
|
+
return new TagPath(path, tagsIndex, wrapperIndex);
|
|
796
1129
|
}
|
|
797
1130
|
|
|
798
1131
|
// in
|
|
799
|
-
if (
|
|
800
|
-
tag.
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
1132
|
+
if (tag.type === PropertyWrapper) {
|
|
1133
|
+
if (wrapperIndex + 1 < tag.value.tags.length) {
|
|
1134
|
+
wrapperIndex++;
|
|
1135
|
+
continue;
|
|
1136
|
+
} else if (!wasLeaving && tag.value.tags[1] && tag.value.tags[1].type !== InitializerTag) {
|
|
1137
|
+
path = path.push(tag.value.property.node, tagsIndex);
|
|
1138
|
+
tagsIndex = 0;
|
|
1139
|
+
continue;
|
|
1140
|
+
}
|
|
808
1141
|
}
|
|
809
1142
|
|
|
810
1143
|
// over
|
|
811
|
-
if (path.node &&
|
|
812
|
-
|
|
1144
|
+
if (path.node && tagsIndex + 1 < Tags.getSize(path.node.tags)) {
|
|
1145
|
+
tagsIndex++;
|
|
813
1146
|
continue;
|
|
814
1147
|
}
|
|
815
1148
|
|
|
816
1149
|
// out
|
|
817
|
-
if (path.
|
|
1150
|
+
if (path.parentIndex != null) {
|
|
818
1151
|
do {
|
|
819
|
-
|
|
1152
|
+
tagsIndex = path.parentIndex + 1;
|
|
820
1153
|
|
|
821
1154
|
path = path.parent;
|
|
822
1155
|
leaving = true;
|
|
823
|
-
} while (
|
|
1156
|
+
} while (tagsIndex == null);
|
|
824
1157
|
|
|
825
1158
|
leaving = true;
|
|
826
1159
|
continue;
|
|
@@ -831,63 +1164,15 @@ export class TagPath {
|
|
|
831
1164
|
}
|
|
832
1165
|
|
|
833
1166
|
get previousSibling() {
|
|
834
|
-
const { path,
|
|
835
|
-
|
|
836
|
-
const child = childrenIndex - 1 < 0 ? null : btree.getAt(childrenIndex - 1, path.node.children);
|
|
837
|
-
|
|
838
|
-
return child && new TagPath(path, childrenIndex - 1);
|
|
839
|
-
}
|
|
840
|
-
|
|
841
|
-
get previous() {
|
|
842
|
-
throw new Error('not implemented');
|
|
843
|
-
}
|
|
1167
|
+
const { path, tagsIndex, wrapperIndex } = this;
|
|
844
1168
|
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
let leaving = false;
|
|
849
|
-
|
|
850
|
-
for (;;) {
|
|
851
|
-
let tag = Children.getAt(childrenIndex, path.node.children);
|
|
852
|
-
let isInitialTag = path.node === this.path.node && childrenIndex === this.childrenIndex;
|
|
853
|
-
let wasLeaving = leaving;
|
|
854
|
-
leaving = false;
|
|
855
|
-
|
|
856
|
-
if (!tag) return null;
|
|
857
|
-
|
|
858
|
-
// done
|
|
859
|
-
if (!isInitialTag && tag.type !== ShiftTag && tag.type !== Property) {
|
|
860
|
-
return new TagPath(path, childrenIndex);
|
|
861
|
-
}
|
|
862
|
-
|
|
863
|
-
// in
|
|
864
|
-
if (tag.type === Property && !wasLeaving) {
|
|
865
|
-
path = path.push(tag.value.node, childrenIndex - 1);
|
|
866
|
-
childrenIndex = Children.getSize(tag.value.children) - 1;
|
|
867
|
-
continue;
|
|
868
|
-
}
|
|
869
|
-
|
|
870
|
-
// over
|
|
871
|
-
if (path.node && childrenIndex + 1 < Children.getSize(path.node.children)) {
|
|
872
|
-
childrenIndex--;
|
|
873
|
-
continue;
|
|
874
|
-
}
|
|
875
|
-
|
|
876
|
-
// out
|
|
877
|
-
if (path.referenceIndex != null) {
|
|
878
|
-
do {
|
|
879
|
-
childrenIndex = path.referenceIndex;
|
|
880
|
-
|
|
881
|
-
path = path.parent;
|
|
882
|
-
leaving = true;
|
|
883
|
-
} while (childrenIndex == null);
|
|
1169
|
+
if (wrapperIndex > 0) {
|
|
1170
|
+
return new TagPath(path, tagsIndex, wrapperIndex - 1);
|
|
1171
|
+
}
|
|
884
1172
|
|
|
885
|
-
|
|
886
|
-
continue;
|
|
887
|
-
}
|
|
1173
|
+
const child = tagsIndex - 1 < 0 ? null : BTree.getAt(tagsIndex - 1, path.node.tags);
|
|
888
1174
|
|
|
889
|
-
|
|
890
|
-
}
|
|
1175
|
+
return child && TagPath.from(path, tagsIndex - 1, -1);
|
|
891
1176
|
}
|
|
892
1177
|
|
|
893
1178
|
get innerNode() {
|
|
@@ -895,18 +1180,19 @@ export class TagPath {
|
|
|
895
1180
|
}
|
|
896
1181
|
|
|
897
1182
|
get inner() {
|
|
898
|
-
let { tag, previousSibling } = this;
|
|
1183
|
+
let { path, tagsIndex, tag, previousSibling } = this;
|
|
899
1184
|
|
|
900
|
-
let refPath =
|
|
1185
|
+
let refPath = TagPath.from(path, tagsIndex, 0);
|
|
901
1186
|
|
|
902
|
-
if (tag.type !==
|
|
1187
|
+
if (tag.type !== PropertyWrapper) {
|
|
903
1188
|
return null;
|
|
904
1189
|
}
|
|
905
1190
|
|
|
906
1191
|
let shiftPath = null;
|
|
907
1192
|
if (refPath.tag.type === ShiftTag) {
|
|
908
1193
|
shiftPath = refPath;
|
|
909
|
-
|
|
1194
|
+
throw new Error('not implemented');
|
|
1195
|
+
refPath = TagPath.from(this.path, this.tagsIndex - refPath.tag.value.index - 2);
|
|
910
1196
|
}
|
|
911
1197
|
|
|
912
1198
|
if (refPath.tag.type !== ReferenceTag) throw new Error();
|
|
@@ -917,13 +1203,13 @@ export class TagPath {
|
|
|
917
1203
|
buildFullPathSegment(
|
|
918
1204
|
type,
|
|
919
1205
|
name,
|
|
920
|
-
getChildPropertyIndex(refPath.path.node, refPath.
|
|
1206
|
+
getChildPropertyIndex(refPath.path.node, refPath.tagsIndex),
|
|
921
1207
|
shiftPath?.tag.value.index,
|
|
922
1208
|
),
|
|
923
1209
|
]);
|
|
924
1210
|
}
|
|
925
1211
|
|
|
926
1212
|
equalTo(tagPath) {
|
|
927
|
-
return this.node === tagPath.node && this.
|
|
1213
|
+
return this.node === tagPath.node && this.tagsIndex === tagPath.tagsIndex;
|
|
928
1214
|
}
|
|
929
1215
|
}
|