@bablr/bablr-vm 0.22.1 → 0.23.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/context.js +2 -44
- package/lib/evaluate.js +147 -378
- package/lib/facades.js +34 -0
- package/lib/match.js +468 -325
- package/lib/source.js +9 -58
- package/lib/spans.js +29 -68
- package/lib/state.js +58 -336
- package/lib/utils/pattern.js +58 -28
- package/package.json +11 -8
- package/lib/node.js +0 -327
package/lib/match.js
CHANGED
|
@@ -1,31 +1,45 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getProduction } from '@bablr/helpers/grammar';
|
|
2
2
|
import { WeakStackFrame } from '@bablr/weak-stack';
|
|
3
3
|
|
|
4
|
-
import { agast
|
|
4
|
+
import { agast } from '@bablr/agast-vm';
|
|
5
|
+
import * as Tags from '@bablr/agast-helpers/tags';
|
|
6
|
+
import * as BTree from '@bablr/agast-helpers/btree';
|
|
5
7
|
import {
|
|
6
|
-
buildOpenNodeTag,
|
|
7
|
-
buildProperty,
|
|
8
8
|
buildReference,
|
|
9
|
-
|
|
9
|
+
buildReferenceTag,
|
|
10
|
+
getFlagsWithGap,
|
|
10
11
|
mergeReferences,
|
|
12
|
+
printBinding,
|
|
13
|
+
printType,
|
|
14
|
+
buildPropertyTag,
|
|
15
|
+
buildOpenFragmentTag,
|
|
16
|
+
nodeFlags,
|
|
17
|
+
streamFromTree,
|
|
11
18
|
} from '@bablr/agast-helpers/tree';
|
|
12
|
-
import { effectsFor } from '@bablr/agast-vm-helpers';
|
|
13
|
-
import { FragmentFacade } from './node.js';
|
|
19
|
+
import { effectsFor, reifyExpression, shouldBranch } from '@bablr/agast-vm-helpers';
|
|
14
20
|
|
|
15
21
|
import { facades, actuals } from './facades.js';
|
|
16
22
|
import {
|
|
17
23
|
CloseNodeTag,
|
|
18
24
|
OpenNodeTag,
|
|
19
|
-
ReferenceTag,
|
|
20
|
-
ShiftTag,
|
|
21
25
|
AttributeDefinition,
|
|
22
26
|
Property,
|
|
23
|
-
|
|
24
|
-
InitializerTag,
|
|
27
|
+
ReferenceTag,
|
|
25
28
|
BindingTag,
|
|
26
|
-
|
|
29
|
+
ShiftTag,
|
|
30
|
+
TreeNode,
|
|
27
31
|
} from '@bablr/agast-helpers/symbols';
|
|
28
|
-
import {
|
|
32
|
+
import {
|
|
33
|
+
buildNullNode,
|
|
34
|
+
endsNode,
|
|
35
|
+
getCloseTag,
|
|
36
|
+
getTags,
|
|
37
|
+
has,
|
|
38
|
+
isMultiFragment,
|
|
39
|
+
Path,
|
|
40
|
+
TagPath,
|
|
41
|
+
} from '@bablr/agast-helpers/path';
|
|
42
|
+
import { updateSpans } from './spans.js';
|
|
29
43
|
|
|
30
44
|
export class MatchFacade {
|
|
31
45
|
constructor(match) {
|
|
@@ -53,6 +67,10 @@ export class MatchFacade {
|
|
|
53
67
|
return actuals.get(this).propertyMatcher;
|
|
54
68
|
}
|
|
55
69
|
|
|
70
|
+
get rawPropertyMatcher() {
|
|
71
|
+
return actuals.get(this).rawPropertyMatcher;
|
|
72
|
+
}
|
|
73
|
+
|
|
56
74
|
get depth() {
|
|
57
75
|
return actuals.get(this).depth;
|
|
58
76
|
}
|
|
@@ -62,43 +80,7 @@ export class MatchFacade {
|
|
|
62
80
|
}
|
|
63
81
|
|
|
64
82
|
get fragment() {
|
|
65
|
-
|
|
66
|
-
ctx,
|
|
67
|
-
effects,
|
|
68
|
-
isCoverBoundary,
|
|
69
|
-
isNode,
|
|
70
|
-
fragmentNode,
|
|
71
|
-
node,
|
|
72
|
-
mergedReference,
|
|
73
|
-
rangePreviousIndex,
|
|
74
|
-
rangeFinalIndex,
|
|
75
|
-
} = actuals.get(this);
|
|
76
|
-
|
|
77
|
-
const { name, isArray } = mergedReference;
|
|
78
|
-
|
|
79
|
-
let prev =
|
|
80
|
-
rangePreviousIndex != null
|
|
81
|
-
? (fragmentNode || node).tags.at(rangePreviousIndex)
|
|
82
|
-
: rangePreviousIndex;
|
|
83
|
-
|
|
84
|
-
let offset = [ReferenceTag, ShiftTag].includes(prev?.type) ? 0 : 1;
|
|
85
|
-
|
|
86
|
-
if ((isNode || isCoverBoundary) && name) {
|
|
87
|
-
return new FragmentFacade(
|
|
88
|
-
effects.success !== 'none' ? fragmentNode : null,
|
|
89
|
-
ctx,
|
|
90
|
-
false,
|
|
91
|
-
true,
|
|
92
|
-
[rangePreviousIndex + offset, rangeFinalIndex],
|
|
93
|
-
mergedReference,
|
|
94
|
-
isArray ? fragmentNode.getChildPropertyIndex(rangePreviousIndex + offset) : null,
|
|
95
|
-
);
|
|
96
|
-
} else {
|
|
97
|
-
return new FragmentFacade(fragmentNode || node, ctx, false, true, [
|
|
98
|
-
rangePreviousIndex + offset,
|
|
99
|
-
rangeFinalIndex,
|
|
100
|
-
]);
|
|
101
|
-
}
|
|
83
|
+
return actuals.get(this).fragment;
|
|
102
84
|
}
|
|
103
85
|
|
|
104
86
|
get pathDepth() {
|
|
@@ -109,13 +91,8 @@ export class MatchFacade {
|
|
|
109
91
|
return actuals.get(this).pathName;
|
|
110
92
|
}
|
|
111
93
|
|
|
112
|
-
get pathParent() {
|
|
113
|
-
return actuals.get(this).pathParent;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
94
|
get node() {
|
|
117
|
-
|
|
118
|
-
return FragmentFacade.wrap(node, ctx, false);
|
|
95
|
+
return actuals.get(this).node;
|
|
119
96
|
}
|
|
120
97
|
|
|
121
98
|
get props() {
|
|
@@ -150,6 +127,10 @@ export class MatchFacade {
|
|
|
150
127
|
return facades.get(actuals.get(this).coveredBoundary);
|
|
151
128
|
}
|
|
152
129
|
|
|
130
|
+
get nodeMatch() {
|
|
131
|
+
return facades.get(actuals.get(this).nodeMatch);
|
|
132
|
+
}
|
|
133
|
+
|
|
153
134
|
get cover() {
|
|
154
135
|
return facades.get(actuals.get(this).cover);
|
|
155
136
|
}
|
|
@@ -158,15 +139,6 @@ export class MatchFacade {
|
|
|
158
139
|
return facades.get(actuals.get(this).coveredBoundary.shiftMatch);
|
|
159
140
|
}
|
|
160
141
|
|
|
161
|
-
get captured() {
|
|
162
|
-
return actuals.get(this).captured;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
get range() {
|
|
166
|
-
let { range } = actuals.get(this);
|
|
167
|
-
return range && [range[0], range[1]];
|
|
168
|
-
}
|
|
169
|
-
|
|
170
142
|
get effects() {
|
|
171
143
|
return actuals.get(this).effects;
|
|
172
144
|
}
|
|
@@ -180,118 +152,186 @@ export class MatchFacade {
|
|
|
180
152
|
}
|
|
181
153
|
|
|
182
154
|
get state() {
|
|
183
|
-
return
|
|
155
|
+
return actuals.get(this).s.getPublic();
|
|
184
156
|
}
|
|
185
157
|
|
|
186
158
|
get s() {
|
|
187
|
-
return
|
|
159
|
+
return actuals.get(this).s.getPublic();
|
|
188
160
|
}
|
|
189
161
|
|
|
190
|
-
|
|
191
|
-
return actuals.get(this).
|
|
162
|
+
ancestors(...args) {
|
|
163
|
+
return actuals.get(this).ancestors(...args);
|
|
192
164
|
}
|
|
165
|
+
}
|
|
193
166
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
167
|
+
const normalizeBindingPath = (path) => {
|
|
168
|
+
if (path.length <= 1) return path;
|
|
169
|
+
};
|
|
197
170
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
171
|
+
export class Match extends WeakStackFrame {
|
|
172
|
+
static startFrame(ctx, s, m, finishedMatch, verb, matcher, options) {
|
|
173
|
+
let effects = effectsFor(verb.description);
|
|
174
|
+
let isShift = verb.description.startsWith('shift'); // should this be didShift?
|
|
201
175
|
|
|
202
|
-
|
|
203
|
-
return actuals.get(this).rangeFinal;
|
|
204
|
-
}
|
|
176
|
+
let parentMatch = m;
|
|
205
177
|
|
|
206
|
-
|
|
207
|
-
return actuals.get(this).rangeFinalIndex;
|
|
208
|
-
}
|
|
178
|
+
if (!s) throw new Error('not initialized');
|
|
209
179
|
|
|
210
|
-
|
|
211
|
-
return actuals.get(this).mergedLanguagePath;
|
|
212
|
-
}
|
|
180
|
+
let matcher_ = reifyExpression(matcher);
|
|
213
181
|
|
|
214
|
-
|
|
215
|
-
|
|
182
|
+
if (parentMatch && parentMatch.cover && !parentMatch.isNode) {
|
|
183
|
+
if (matcher_.refMatcher) {
|
|
184
|
+
let m = matcher_.refMatcher;
|
|
185
|
+
if (!['_', '#'].includes(m.type) || m.flags.expression || m.flags.hasGap || m.flags.array) {
|
|
186
|
+
throw new Error('no references inside covers');
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (isShift && matcher_.nodeMatcher.type === '__') {
|
|
192
|
+
throw new Error();
|
|
193
|
+
}
|
|
194
|
+
if (isShift && !parentMatch) throw new Error();
|
|
195
|
+
|
|
196
|
+
if (shouldBranch(effects)) {
|
|
197
|
+
s = s.branch();
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
s.languages = isShift
|
|
201
|
+
? finishedMatch.languages
|
|
202
|
+
: parentMatch
|
|
203
|
+
? parentMatch.languages
|
|
204
|
+
: s.languages;
|
|
205
|
+
|
|
206
|
+
m = parentMatch
|
|
207
|
+
? parentMatch.startFrame(s, matcher, effects, isShift ? finishedMatch : null, options)
|
|
208
|
+
: Match.from(ctx, s, matcher, null, options);
|
|
209
|
+
|
|
210
|
+
updateSpans(m, 'open');
|
|
211
|
+
|
|
212
|
+
if (m.name && !getProduction(m.grammar, m.name))
|
|
213
|
+
throw new Error(`Production {type: ${printType(m.name)}} does not exist`);
|
|
214
|
+
|
|
215
|
+
if (m.flags.token && !m.isNode) {
|
|
216
|
+
throw new Error('tokens must be nodes');
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
finishedMatch = null;
|
|
220
|
+
|
|
221
|
+
if (!m.parent && m.type === '__') {
|
|
222
|
+
s.node = m.rootNode;
|
|
223
|
+
}
|
|
224
|
+
return m;
|
|
216
225
|
}
|
|
217
|
-
}
|
|
218
226
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
if (!context || !language || !state) {
|
|
227
|
+
constructor(parent, context, state, rawMatcher, effects, shiftMatch = null, options = {}) {
|
|
228
|
+
if (!context || !state) {
|
|
222
229
|
throw new Error('Invalid arguments to Match constructor');
|
|
223
230
|
}
|
|
231
|
+
let matcher = reifyExpression(rawMatcher);
|
|
224
232
|
|
|
225
233
|
super(parent);
|
|
226
234
|
|
|
227
235
|
this.context = context;
|
|
228
|
-
this.language = language;
|
|
229
236
|
this.state = state;
|
|
237
|
+
this.rawPropertyMatcher = rawMatcher;
|
|
230
238
|
this.propertyMatcher = matcher;
|
|
231
239
|
this.effects = effects;
|
|
232
240
|
this.shiftMatch = shiftMatch;
|
|
241
|
+
this.emittedMatch = parent?.emittedMatch || this;
|
|
233
242
|
|
|
234
|
-
this.rangePreviousIndex = null;
|
|
235
|
-
this.rangeFinalIndex = null;
|
|
236
243
|
this.agast = null;
|
|
237
|
-
this.agastFragment = null; // why do it this way?
|
|
238
|
-
this.node = null;
|
|
239
244
|
this.cover = null;
|
|
240
245
|
this.running = null;
|
|
241
246
|
this.options = options;
|
|
242
247
|
|
|
243
|
-
let isNode = !matcher.nodeMatcher.
|
|
244
|
-
let isCover = matcher.nodeMatcher.
|
|
248
|
+
let isNode = !matcher.nodeMatcher.type;
|
|
249
|
+
let isCover = matcher.nodeMatcher.type === '_';
|
|
245
250
|
|
|
246
|
-
this.
|
|
247
|
-
this.
|
|
251
|
+
this.languages = state.languages;
|
|
252
|
+
this.nodeMatch = isNode || !parent ? this : parent.nodeMatch;
|
|
253
|
+
this.expressionMatch = shiftMatch
|
|
254
|
+
? shiftMatch.expressionMatch
|
|
255
|
+
: parent?.expressionMatch || (matcher.refMatcher?.flags.expression ? this : null);
|
|
256
|
+
this.languageMatch =
|
|
257
|
+
normalizeBindingPath(matcher.bindingMatchers).length || !parent ? this : parent.languageMatch;
|
|
258
|
+
this.agast = null;
|
|
248
259
|
this.cover =
|
|
249
|
-
|
|
250
|
-
? null
|
|
251
|
-
: !parent?.isNode && parent?.cover
|
|
260
|
+
!parent?.isNode && parent?.cover && matcher.refMatcher?.type !== '#'
|
|
252
261
|
? parent.cover
|
|
253
262
|
: isCover && parent
|
|
254
263
|
? this
|
|
255
264
|
: null;
|
|
265
|
+
this.rootNode = null;
|
|
266
|
+
this.nodeDepth = (parent?.nodeDepth ?? 0) + (isNode ? 1 : 0);
|
|
267
|
+
this.parentPreviousTagPath = this.parent && TagPath.from(this.parent.path, -1, -1);
|
|
268
|
+
this.emitted = this.parent?.emitted || null;
|
|
256
269
|
|
|
257
|
-
if (
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
+
if (!this.language) {
|
|
271
|
+
throw new Error(`Unknown language ${printBinding(matcher.bindingMatcher)}`);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
let held = null;
|
|
275
|
+
if (this.coveredBoundary.shiftMatch) {
|
|
276
|
+
held = state.held;
|
|
277
|
+
}
|
|
278
|
+
this.agast = agast({ held });
|
|
279
|
+
|
|
280
|
+
let parentHasGap = !this.parent
|
|
281
|
+
? this.matcher.flags.hasGap
|
|
282
|
+
: this.parent.nodeMatch.node.value.flags.hasGap;
|
|
283
|
+
|
|
284
|
+
this.agast.vm.next(buildOpenFragmentTag(parentHasGap ? getFlagsWithGap(nodeFlags) : nodeFlags));
|
|
285
|
+
if (!this.parent) {
|
|
286
|
+
if (isNode || isCover) {
|
|
287
|
+
this.agast.vm.next(buildReferenceTag());
|
|
270
288
|
}
|
|
289
|
+
} else if (shiftMatch) {
|
|
290
|
+
this.agast.vm.next(shiftMatch.rootNode);
|
|
271
291
|
}
|
|
292
|
+
this.rootNode = this.agast.getState().node;
|
|
272
293
|
|
|
273
294
|
new MatchFacade(this);
|
|
274
295
|
}
|
|
275
296
|
|
|
276
|
-
static from(context,
|
|
277
|
-
return Match.create(context,
|
|
297
|
+
static from(context, state, matcher, props, options) {
|
|
298
|
+
return Match.create(context, state, matcher, effectsFor('eat'), props, options);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
get language() {
|
|
302
|
+
return BTree.getAt(-1, this.languages);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
get emitting() {
|
|
306
|
+
return this.emittedMatch === this;
|
|
278
307
|
}
|
|
279
308
|
|
|
280
309
|
get isCoverBoundary() {
|
|
281
|
-
let { cover } = this;
|
|
282
|
-
return cover === this;
|
|
310
|
+
let { cover, isNode } = this;
|
|
311
|
+
return cover === this || (!cover && isNode);
|
|
283
312
|
}
|
|
284
313
|
|
|
285
314
|
get matcher() {
|
|
286
315
|
return this.propertyMatcher?.nodeMatcher;
|
|
287
316
|
}
|
|
288
317
|
|
|
318
|
+
get node() {
|
|
319
|
+
let { rootNode } = this;
|
|
320
|
+
|
|
321
|
+
if (this.matcher.type === '__') {
|
|
322
|
+
return rootNode;
|
|
323
|
+
}
|
|
324
|
+
if (Tags.getSize(getTags(rootNode)) <= 1) return null;
|
|
325
|
+
|
|
326
|
+
return Tags.getAt(-1, rootNode.value.children).value.node;
|
|
327
|
+
}
|
|
328
|
+
|
|
289
329
|
get vm() {
|
|
290
330
|
return this.agast.vm;
|
|
291
331
|
}
|
|
292
332
|
|
|
293
333
|
get mergedReference() {
|
|
294
|
-
let ref = buildReference(
|
|
334
|
+
let ref = buildReference();
|
|
295
335
|
|
|
296
336
|
let first = true;
|
|
297
337
|
let m = this;
|
|
@@ -305,7 +345,7 @@ export class Match extends WeakStackFrame {
|
|
|
305
345
|
|
|
306
346
|
if (lastName && (lastName !== name || lastRefType !== refType)) break;
|
|
307
347
|
ref = ['#', '@'].includes(ref.type) ? ref : mergeReferences(ref, parentRef);
|
|
308
|
-
if (refType !== '
|
|
348
|
+
if (refType !== '_') {
|
|
309
349
|
lastName = name;
|
|
310
350
|
lastRefType = refType;
|
|
311
351
|
}
|
|
@@ -316,22 +356,6 @@ export class Match extends WeakStackFrame {
|
|
|
316
356
|
return ref;
|
|
317
357
|
}
|
|
318
358
|
|
|
319
|
-
get mergedLanguagePath() {
|
|
320
|
-
let languagePath = [];
|
|
321
|
-
|
|
322
|
-
let first = true;
|
|
323
|
-
let m = this;
|
|
324
|
-
do {
|
|
325
|
-
if (m.isNode && !first) break;
|
|
326
|
-
if (m.propertyMatcher.bindingMatcher) {
|
|
327
|
-
languagePath = m.propertyMatcher.bindingMatcher.languagePath.concat(languagePath);
|
|
328
|
-
}
|
|
329
|
-
first = false;
|
|
330
|
-
} while ((m = m.shiftMatch || m.parent));
|
|
331
|
-
|
|
332
|
-
return Object.freeze(languagePath);
|
|
333
|
-
}
|
|
334
|
-
|
|
335
359
|
get pathName() {
|
|
336
360
|
return this.mergedReference.name;
|
|
337
361
|
}
|
|
@@ -339,26 +363,13 @@ export class Match extends WeakStackFrame {
|
|
|
339
363
|
get path() {
|
|
340
364
|
let { agast } = this;
|
|
341
365
|
|
|
342
|
-
return agast.
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
get pathParent() {
|
|
346
|
-
let m = this;
|
|
347
|
-
|
|
348
|
-
do {
|
|
349
|
-
m = m.parent;
|
|
350
|
-
} while (m && !m.isNode);
|
|
351
|
-
return m;
|
|
366
|
+
return agast.getState().path || agast.getState().resultPath?.path;
|
|
352
367
|
}
|
|
353
368
|
|
|
354
369
|
get coveredBoundary() {
|
|
355
370
|
return this.cover || this;
|
|
356
371
|
}
|
|
357
372
|
|
|
358
|
-
get parentPath() {
|
|
359
|
-
return this.pathParent?.path;
|
|
360
|
-
}
|
|
361
|
-
|
|
362
373
|
get ctx() {
|
|
363
374
|
return this.context;
|
|
364
375
|
}
|
|
@@ -375,153 +386,90 @@ export class Match extends WeakStackFrame {
|
|
|
375
386
|
return this.matcher?.type || null;
|
|
376
387
|
}
|
|
377
388
|
|
|
378
|
-
get
|
|
379
|
-
return this.matcher?.
|
|
389
|
+
get name() {
|
|
390
|
+
return this.matcher?.name || null;
|
|
380
391
|
}
|
|
381
392
|
|
|
382
|
-
get
|
|
383
|
-
return
|
|
393
|
+
get flags() {
|
|
394
|
+
return this.matcher?.flags;
|
|
384
395
|
}
|
|
385
396
|
|
|
386
397
|
get allowEmpty() {
|
|
387
|
-
return !!this.grammar.emptyables?.has(this.
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
get fragmentNode() {
|
|
391
|
-
if (!this.agastFragment) return null;
|
|
392
|
-
|
|
393
|
-
let { node, resultPath } = this.agastFragment.state;
|
|
394
|
-
return resultPath?.tag.type === CloseNodeTag ? resultPath.node : node;
|
|
398
|
+
return !!this.grammar.emptyables?.has(this.name) || this.options.allowEmpty;
|
|
395
399
|
}
|
|
396
400
|
|
|
397
|
-
get
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
let { path, resultPath } = this.agastFragment.state;
|
|
401
|
-
return resultPath?.tag.type === CloseNodeTag ? resultPath.path : path;
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
get rangePrevious() {
|
|
405
|
-
let path = this.fragmentPath || this.path;
|
|
406
|
-
|
|
407
|
-
return this.rangePreviousIndex == null || path == null
|
|
408
|
-
? null
|
|
409
|
-
: TagPath.from(path, this.rangePreviousIndex, -1);
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
setRangePreviousIndex(value) {
|
|
413
|
-
if ((value != null && !Number.isFinite(value)) || value < 0) throw new Error();
|
|
414
|
-
this.rangePreviousIndex = value;
|
|
415
|
-
if (
|
|
416
|
-
value != null &&
|
|
417
|
-
(!this.rangePrevious ||
|
|
418
|
-
(this.isNode &&
|
|
419
|
-
![OpenNodeTag, Property, InitializerTag, LiteralTag, AttributeDefinition].includes(
|
|
420
|
-
this.rangePrevious.tag.type,
|
|
421
|
-
)))
|
|
422
|
-
)
|
|
423
|
-
throw new Error();
|
|
401
|
+
get didShift() {
|
|
402
|
+
return !!this.shiftMatch;
|
|
424
403
|
}
|
|
425
404
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
this.rangeFinalIndex = value;
|
|
429
|
-
this.rangeFinal;
|
|
405
|
+
get isNode() {
|
|
406
|
+
return !this.matcher.type;
|
|
430
407
|
}
|
|
431
408
|
|
|
432
|
-
get
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
return this.rangeFinalIndex == null || path == null
|
|
436
|
-
? null
|
|
437
|
-
: TagPath.from(path, this.rangeFinalIndex, -1);
|
|
409
|
+
get isCover() {
|
|
410
|
+
return this.propertyMatcher.nodeMatcher.type === '_';
|
|
438
411
|
}
|
|
439
412
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
if (!rangePrevious) return rangePrevious;
|
|
444
|
-
|
|
445
|
-
if (isNode) return TagPath.from(fragmentPath || path, rangePreviousIndex + 1, 0);
|
|
413
|
+
advance(tag) {
|
|
414
|
+
let { vm, getState } = this.agast;
|
|
415
|
+
let s = this.state;
|
|
446
416
|
|
|
447
|
-
|
|
448
|
-
}
|
|
417
|
+
let result = vm.next(tag);
|
|
449
418
|
|
|
450
|
-
|
|
451
|
-
const { rangeInitial, rangeFinal } = this;
|
|
452
|
-
return rangeInitial === null ? null : [rangeInitial, rangeFinal];
|
|
453
|
-
}
|
|
419
|
+
if (!result || result.done) throw new Error();
|
|
454
420
|
|
|
455
|
-
|
|
456
|
-
return !!this.shiftMatch;
|
|
457
|
-
}
|
|
421
|
+
let agastState = getState();
|
|
458
422
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
423
|
+
if (tag.type === OpenNodeTag) {
|
|
424
|
+
s.depths.result++;
|
|
425
|
+
} else if (tag.type === CloseNodeTag) {
|
|
426
|
+
s.depths.result--;
|
|
462
427
|
}
|
|
463
428
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
let ref = TagPath.from(parentPath, this.rangePreviousIndex + 1, 0);
|
|
467
|
-
|
|
468
|
-
if (!ref) return null;
|
|
469
|
-
|
|
470
|
-
if (ref.tag.type === ShiftTag) {
|
|
471
|
-
let refIndex = ref.tagsIndex - ref.tag.value.index;
|
|
472
|
-
ref = TagPath.from(ref.path, refIndex, 0);
|
|
473
|
-
}
|
|
429
|
+
this.rootNode = agastState.path.atDepth(0).node;
|
|
474
430
|
|
|
475
|
-
|
|
476
|
-
return ref;
|
|
477
|
-
}
|
|
431
|
+
s.resultPath = agastState.resultPath;
|
|
478
432
|
|
|
479
|
-
|
|
480
|
-
let { flags } = this.matcher;
|
|
481
|
-
return !this.parent || !flags.fragment;
|
|
482
|
-
}
|
|
433
|
+
// if (this.emitted?.depth > 1) throw new Error();
|
|
483
434
|
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
}
|
|
435
|
+
if (this.emittedMatch === this) {
|
|
436
|
+
let emittedPath = this.emitted || null;
|
|
487
437
|
|
|
488
|
-
|
|
489
|
-
let { vm, state: agastState } = s.agast;
|
|
438
|
+
let newEmitted = emittedPath && emittedPath.mapOnto(this.rootNode);
|
|
490
439
|
|
|
491
|
-
|
|
440
|
+
if (emittedPath) {
|
|
441
|
+
if (!newEmitted) throw new Error();
|
|
442
|
+
// if (newEmitted.tag.depth !== this.emitted.tag.depth) throw new Error();
|
|
443
|
+
}
|
|
492
444
|
|
|
493
|
-
|
|
494
|
-
s.depths.result++;
|
|
495
|
-
this.node = s.node || s.resultPath.node;
|
|
496
|
-
} else if (tag.type === CloseNodeTag) {
|
|
497
|
-
s.depths.result--;
|
|
445
|
+
this.emitted = newEmitted;
|
|
498
446
|
}
|
|
499
447
|
|
|
500
|
-
s.resultPath =
|
|
501
|
-
(agastState.path || agastState.resultPath?.path) &&
|
|
502
|
-
TagPath.from(
|
|
503
|
-
agastState.path || agastState.resultPath?.path,
|
|
504
|
-
-1,
|
|
505
|
-
tag.type === PropertyWrapper ? -1 : offsetForTag(tag),
|
|
506
|
-
);
|
|
507
448
|
return result.value;
|
|
508
449
|
}
|
|
509
450
|
|
|
510
|
-
startFrame(state,
|
|
451
|
+
startFrame(state, rawMatcher, effects, shiftMatch, options) {
|
|
511
452
|
let { context } = this;
|
|
512
|
-
const { bindingMatcher } = propertyMatcher;
|
|
513
453
|
|
|
514
|
-
let language =
|
|
454
|
+
let language = this.language;
|
|
455
|
+
|
|
456
|
+
// TODO stop wasting CPU cycles doing this twice or more!
|
|
457
|
+
let matcher = reifyExpression(rawMatcher);
|
|
458
|
+
let { bindingMatchers } = matcher;
|
|
515
459
|
|
|
516
|
-
|
|
517
|
-
|
|
460
|
+
for (let bindingMatcher of bindingMatchers) {
|
|
461
|
+
let { segments } = bindingMatcher || { segments: [] };
|
|
518
462
|
|
|
519
|
-
|
|
520
|
-
|
|
463
|
+
for (let segment of segments) {
|
|
464
|
+
language = segment.type
|
|
465
|
+
? BTree.getAt(-2, state.languages)
|
|
466
|
+
: language.dependencies[segment.name];
|
|
521
467
|
}
|
|
468
|
+
|
|
469
|
+
state.languages = BTree.push(state.languages, language);
|
|
522
470
|
}
|
|
523
471
|
|
|
524
|
-
let m = this.push(context,
|
|
472
|
+
let m = this.push(context, state, rawMatcher, effects, shiftMatch, options);
|
|
525
473
|
|
|
526
474
|
this.running = m;
|
|
527
475
|
|
|
@@ -531,55 +479,129 @@ export class Match extends WeakStackFrame {
|
|
|
531
479
|
endFrame() {
|
|
532
480
|
const finishedMatch = this;
|
|
533
481
|
const m = finishedMatch.parent;
|
|
482
|
+
let s = finishedMatch.state;
|
|
483
|
+
|
|
484
|
+
if (finishedMatch.shiftMatch) {
|
|
485
|
+
s.held = null;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
let matchers = finishedMatch.propertyMatcher.bindingMatchers || [];
|
|
489
|
+
|
|
490
|
+
for (let matcher of matchers) {
|
|
491
|
+
let { segments } = matcher;
|
|
492
|
+
let normalizedSegments = normalizeBindingPath(segments);
|
|
493
|
+
if (normalizedSegments.length) {
|
|
494
|
+
finishedMatch.state.languages = BTree.pop(finishedMatch.state.languages);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
534
497
|
|
|
535
498
|
if (!m) return m;
|
|
536
499
|
|
|
537
|
-
|
|
500
|
+
updateSpans(finishedMatch, 'close');
|
|
538
501
|
|
|
539
|
-
|
|
502
|
+
if (shouldBranch(finishedMatch.effects)) {
|
|
503
|
+
if (finishedMatch.effects.success !== 'none') {
|
|
504
|
+
s = s.accept();
|
|
505
|
+
} else {
|
|
506
|
+
s = s.reject(finishedMatch);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
m.emitted = finishedMatch.emitted;
|
|
511
|
+
m.emittedMatch = finishedMatch.emittedMatch;
|
|
512
|
+
|
|
513
|
+
if (finishedMatch.effects.success !== 'none') {
|
|
514
|
+
// for a shift, only copy the parts of the stack that aren't already present from the last successful shift frame
|
|
515
|
+
|
|
516
|
+
if (finishedMatch.shiftMatch) {
|
|
517
|
+
let property = Tags.getAt(-2, finishedMatch.rootNode.value.tags);
|
|
518
|
+
s.node = property.value.node;
|
|
519
|
+
m.advance(property.value.tags[0]);
|
|
520
|
+
for (let bindingTag of property.value.tags[1]) {
|
|
521
|
+
m.advance(bindingTag);
|
|
522
|
+
}
|
|
523
|
+
m.advance(property.value.node);
|
|
524
|
+
} else {
|
|
525
|
+
s.node = finishedMatch.rootNode;
|
|
526
|
+
m.advance(s.node);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
540
529
|
|
|
541
530
|
return m;
|
|
542
531
|
}
|
|
543
532
|
|
|
544
533
|
throw_() {
|
|
545
|
-
|
|
546
|
-
|
|
534
|
+
let { bind } = this.options;
|
|
535
|
+
let finishedMatch = this;
|
|
536
|
+
let m = finishedMatch.parent;
|
|
537
|
+
let s = finishedMatch.state;
|
|
547
538
|
|
|
548
539
|
if (!m) return m;
|
|
549
540
|
|
|
550
541
|
m.running = null;
|
|
551
542
|
|
|
552
|
-
|
|
543
|
+
// TODO don't do this if we're falling back to a successful shift either
|
|
544
|
+
if (bind) {
|
|
545
|
+
for (let tag of Tags.traverse(this.rootNode.value.children)) {
|
|
546
|
+
if (tag.type === Property) {
|
|
547
|
+
let { reference, shift, tags } = tag.value;
|
|
548
|
+
|
|
549
|
+
if (
|
|
550
|
+
!['#', '@'].includes(reference.type) &&
|
|
551
|
+
!reference.flags.array &&
|
|
552
|
+
!has(reference.name, m.node) &&
|
|
553
|
+
!shift
|
|
554
|
+
) {
|
|
555
|
+
m.advance(buildPropertyTag([tags[0], [], buildNullNode()]));
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
if (s.status === 'active') {
|
|
562
|
+
s.reject(finishedMatch);
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// restore successful parts of shift stack here
|
|
566
|
+
|
|
567
|
+
// if (
|
|
568
|
+
// finishedMatch.isCoverBoundary &&
|
|
569
|
+
// finishedMatch.shiftMatch &&
|
|
570
|
+
// finishedMatch.effects.failure === 'none'
|
|
571
|
+
// ) {
|
|
572
|
+
// m.advance(finishedMatch.shiftMatch.rootNode);
|
|
573
|
+
|
|
574
|
+
// s.node = finishedMatch.shiftMatch.node;
|
|
575
|
+
// }
|
|
576
|
+
|
|
577
|
+
m.state.resultPath = TagPath.fromNode(m.state.node, -1);
|
|
553
578
|
|
|
554
579
|
return m;
|
|
555
580
|
}
|
|
556
581
|
|
|
557
582
|
*emit(options) {
|
|
558
|
-
let { state } = this;
|
|
559
|
-
let { emitted } = state;
|
|
583
|
+
let { state, emitted, emittedMatch } = this;
|
|
560
584
|
|
|
561
|
-
let m =
|
|
585
|
+
let m = emittedMatch;
|
|
562
586
|
|
|
563
587
|
if (!state.depth) {
|
|
564
|
-
let
|
|
588
|
+
let node = m.node || m.rootNode;
|
|
565
589
|
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
let tagPath = emitted?.tagPath || (path.node.tags.size ? TagPath.from(path, 0) : null);
|
|
590
|
+
let tagPath = emitted
|
|
591
|
+
? emitted
|
|
592
|
+
: Tags.getSize(getTags(node))
|
|
593
|
+
? TagPath.fromNode(m.rootNode, 0)
|
|
594
|
+
: null;
|
|
573
595
|
|
|
574
596
|
while (tagPath) {
|
|
575
|
-
if (
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
) {
|
|
581
|
-
|
|
582
|
-
}
|
|
597
|
+
// if (
|
|
598
|
+
// options.holdUndefinedAttributes &&
|
|
599
|
+
// tagPath.tag.type === OpenNodeTag &&
|
|
600
|
+
// tagPath.tag.value.name
|
|
601
|
+
// && (countUndefinedAttributes(m.node) ?? 0) > 0
|
|
602
|
+
// ) {
|
|
603
|
+
// break;
|
|
604
|
+
// }
|
|
583
605
|
|
|
584
606
|
if (
|
|
585
607
|
tagPath.tag.type === OpenNodeTag &&
|
|
@@ -588,70 +610,191 @@ export class Match extends WeakStackFrame {
|
|
|
588
610
|
)
|
|
589
611
|
break;
|
|
590
612
|
|
|
591
|
-
let
|
|
613
|
+
let holdingShifted =
|
|
592
614
|
options.holdShiftedNodes &&
|
|
593
615
|
tagPath.tag.type === ReferenceTag &&
|
|
594
|
-
tagPath.tag.value.flags.expression
|
|
616
|
+
tagPath.tag.value.flags.expression &&
|
|
617
|
+
tagPath.depth <= 1;
|
|
595
618
|
|
|
596
|
-
if (
|
|
597
|
-
|
|
619
|
+
if (holdingShifted) {
|
|
620
|
+
if (!tagPath.equalTo(m.emitted)) {
|
|
621
|
+
m.emitted = emitted = tagPath;
|
|
622
|
+
this.emittedMatch = m;
|
|
598
623
|
|
|
599
|
-
|
|
600
|
-
state.depths.emitted++;
|
|
601
|
-
} else if (tagPath.tag.type === CloseNodeTag) {
|
|
602
|
-
state.depths.emitted--;
|
|
624
|
+
yield tagPath.tag;
|
|
603
625
|
}
|
|
604
626
|
|
|
627
|
+
if (
|
|
628
|
+
m.expressionMatch &&
|
|
629
|
+
(m.expressionMatch.running || !getCloseTag(m.expressionMatch.rootNode))
|
|
630
|
+
) {
|
|
631
|
+
break;
|
|
632
|
+
} else {
|
|
633
|
+
let { parentPreviousTagPath } = m;
|
|
634
|
+
let nextTag =
|
|
635
|
+
parentPreviousTagPath &&
|
|
636
|
+
Tags.getAt(parentPreviousTagPath.tagsIndex + 2, m.parent.node.value.tags);
|
|
637
|
+
|
|
638
|
+
let doneShifting = !(nextTag?.type === Property && nextTag.value.shift);
|
|
639
|
+
|
|
640
|
+
// todo monomorph
|
|
641
|
+
let shiftIndex = nextTag?.type === Property ? nextTag?.value.shift?.index ?? 0 : 0;
|
|
642
|
+
while (!doneShifting && nextTag) {
|
|
643
|
+
nextTag =
|
|
644
|
+
Tags.getAt(
|
|
645
|
+
[parentPreviousTagPath.tagsIndex + 2 + shiftIndex, 1],
|
|
646
|
+
m.parent.node.value.tags,
|
|
647
|
+
) ||
|
|
648
|
+
Tags.getAt(
|
|
649
|
+
parentPreviousTagPath.tagsIndex + 2 + shiftIndex,
|
|
650
|
+
m.parent.node.value.tags,
|
|
651
|
+
);
|
|
652
|
+
doneShifting = nextTag && !(nextTag.type === Property && nextTag.value.shift);
|
|
653
|
+
if (!doneShifting) {
|
|
654
|
+
shiftIndex++;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
if ((parentPreviousTagPath && !nextTag) || !doneShifting) {
|
|
659
|
+
break;
|
|
660
|
+
} else {
|
|
661
|
+
if (m.parent.rootNode) {
|
|
662
|
+
if (shiftIndex) {
|
|
663
|
+
m = m.parent;
|
|
664
|
+
tagPath = Path.from(m.rootNode)
|
|
665
|
+
.tagPathAt(1)
|
|
666
|
+
.inner.tagPathAt(1 + shiftIndex, 0).nextSibling;
|
|
667
|
+
if (tagPath?.tag.type === TreeNode) {
|
|
668
|
+
tagPath = tagPath.inner.tagPathAt(0);
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
if (!tagPath) break;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
if (tagPath.depth === 0 && endsNode(tagPath.tag)) {
|
|
679
|
+
let finishedMatch = m;
|
|
680
|
+
m = m.parent;
|
|
681
|
+
|
|
682
|
+
let parentRoot = Path.from(m.rootNode);
|
|
683
|
+
|
|
684
|
+
if (m.type !== '__') {
|
|
685
|
+
parentRoot = parentRoot.tagPathAt(getCloseTag(m.rootNode) ? -2 : -1).inner;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
let finishedChildren =
|
|
689
|
+
finishedMatch.type !== '__' ? 1 : Tags.getSize(finishedMatch.rootNode.value.children);
|
|
690
|
+
|
|
691
|
+
let parentNextTagPath = parentRoot?.tagPathAt(
|
|
692
|
+
finishedMatch.parentPreviousTagPath.tagsIndex + finishedChildren + 1,
|
|
693
|
+
);
|
|
694
|
+
|
|
695
|
+
tagPath = parentNextTagPath;
|
|
696
|
+
|
|
697
|
+
if (!tagPath) {
|
|
698
|
+
if (m.running) {
|
|
699
|
+
m = m.running;
|
|
700
|
+
|
|
701
|
+
let shiftIndex =
|
|
702
|
+
finishedMatch.parentPreviousTagPath.tag.type === Property &&
|
|
703
|
+
finishedMatch.parentPreviousTagPath.tag.value.shift
|
|
704
|
+
? finishedMatch.parentPreviousTagPath.tag.value.shift.index
|
|
705
|
+
: m.didShift
|
|
706
|
+
? 1
|
|
707
|
+
: 0;
|
|
708
|
+
|
|
709
|
+
tagPath = TagPath.fromNode(m.rootNode, 1 + shiftIndex);
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
if (tagPath?.tag.type === Property) {
|
|
714
|
+
tagPath = tagPath.next;
|
|
715
|
+
}
|
|
716
|
+
continue;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
if (!m.emitted || !tagPath.equalTo(m.emitted)) {
|
|
605
720
|
if (
|
|
606
721
|
!(
|
|
607
|
-
(tagPath.tag.type
|
|
608
|
-
|
|
722
|
+
[OpenNodeTag, CloseNodeTag].includes(tagPath.tag.type) &&
|
|
723
|
+
tagPath.depth === 0 &&
|
|
724
|
+
isMultiFragment(tagPath.node) &&
|
|
725
|
+
(m.depth || !(m.matcher.type === '__'))
|
|
609
726
|
)
|
|
610
727
|
) {
|
|
611
|
-
|
|
728
|
+
m.emitted = emitted = tagPath;
|
|
729
|
+
this.emittedMatch = m;
|
|
730
|
+
|
|
731
|
+
if (tagPath.tag.type === OpenNodeTag && !tagPath.tag.value.selfClosing) {
|
|
732
|
+
state.depths.emitted++;
|
|
733
|
+
} else if (tagPath.tag.type === CloseNodeTag) {
|
|
734
|
+
state.depths.emitted--;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
if (
|
|
738
|
+
tagPath.tag.type !== Property &&
|
|
739
|
+
!(tagPath.tag.type === BindingTag && !tagPath.tag.value.segments?.length) &&
|
|
740
|
+
!(tagPath.tag.type === ShiftTag && options.holdShiftedNodes) &&
|
|
741
|
+
!(tagPath.tag.type === AttributeDefinition && options.holdUndefinedAttributes) &&
|
|
742
|
+
!(m.depth === 0 && !tagPath.depth && tagPath.tag.type === ReferenceTag)
|
|
743
|
+
) {
|
|
744
|
+
yield tagPath.tag;
|
|
745
|
+
}
|
|
612
746
|
}
|
|
613
747
|
}
|
|
614
748
|
|
|
615
749
|
if (
|
|
616
|
-
(tagPath.tag
|
|
617
|
-
|
|
618
|
-
!tagPath.next
|
|
750
|
+
endsNode(tagPath.tag) ||
|
|
751
|
+
(!holdingShifted && !tagPath.nextSibling && !tagPath.tag.type === Property)
|
|
619
752
|
) {
|
|
620
|
-
|
|
753
|
+
let nextPath = tagPath.next;
|
|
754
|
+
if (nextPath) {
|
|
755
|
+
tagPath = nextPath;
|
|
756
|
+
continue;
|
|
757
|
+
}
|
|
621
758
|
|
|
622
759
|
do {
|
|
623
|
-
|
|
624
|
-
|
|
760
|
+
if (m.running) {
|
|
761
|
+
m = m.running;
|
|
762
|
+
// TODO is -1 ok
|
|
763
|
+
let shiftIndex = m.didShift ? -1 : 0;
|
|
764
|
+
tagPath = TagPath.fromNode(m.rootNode, shiftIndex);
|
|
765
|
+
} else if (m.parent && (!m.parent.running || m.parent.running !== m)) {
|
|
766
|
+
tagPath = m.parentPreviousTagPath;
|
|
767
|
+
|
|
768
|
+
tagPath = TagPath.from(
|
|
769
|
+
tagPath.path,
|
|
770
|
+
tagPath.tagsIndex +
|
|
771
|
+
1 +
|
|
772
|
+
(m.matcher.type === '__' ? Tags.getSize(m.rootNode.value.children) : 1),
|
|
773
|
+
0,
|
|
774
|
+
);
|
|
775
|
+
|
|
776
|
+
m = m.parent;
|
|
777
|
+
} else {
|
|
778
|
+
m = null;
|
|
779
|
+
break;
|
|
780
|
+
}
|
|
781
|
+
} while (m && !tagPath);
|
|
625
782
|
|
|
626
783
|
if (!m) break;
|
|
627
784
|
|
|
628
785
|
continue;
|
|
629
786
|
}
|
|
630
787
|
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
break;
|
|
638
|
-
} else {
|
|
639
|
-
running = running.running;
|
|
640
|
-
}
|
|
641
|
-
}
|
|
788
|
+
tagPath =
|
|
789
|
+
tagPath.tag.type === Property
|
|
790
|
+
? tagPath.nextProperty?.next || tagPath.nextSibling
|
|
791
|
+
: options.holdShiftedNodes
|
|
792
|
+
? tagPath.nextUnshifted
|
|
793
|
+
: tagPath.next;
|
|
642
794
|
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
break;
|
|
647
|
-
}
|
|
648
|
-
tagPath = TagPath.from(m.path, 0);
|
|
649
|
-
} else {
|
|
650
|
-
if (holdShifted) {
|
|
651
|
-
tagPath = tagPath.nextUnshifted;
|
|
652
|
-
} else {
|
|
653
|
-
tagPath = tagPath.next;
|
|
654
|
-
}
|
|
795
|
+
if (!tagPath && m.running) {
|
|
796
|
+
m = m.running;
|
|
797
|
+
tagPath = TagPath.fromNode(m.rootNode, 0);
|
|
655
798
|
}
|
|
656
799
|
}
|
|
657
800
|
}
|