@bablr/bablr-vm 0.19.1 → 0.20.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/context.js +28 -12
- package/lib/evaluate.js +133 -126
- package/lib/match.js +127 -101
- package/lib/node.js +155 -57
- package/lib/source.js +3 -1
- package/lib/state.js +207 -62
- package/lib/utils/pattern.js +31 -2
- package/package.json +6 -6
- package/lib/strategy.js +0 -327
package/lib/match.js
CHANGED
|
@@ -1,32 +1,16 @@
|
|
|
1
1
|
import { resolveLanguage } from '@bablr/helpers/grammar';
|
|
2
2
|
import { WeakStackFrame } from '@bablr/weak-stack';
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
8
|
-
buildCall,
|
|
9
|
-
buildEmbeddedNode,
|
|
10
|
-
buildEmbeddedTag,
|
|
11
|
-
buildGapTag,
|
|
12
|
-
buildReferenceTag,
|
|
13
|
-
mergeReferences,
|
|
14
|
-
} from '@bablr/agast-helpers/tree';
|
|
15
|
-
import { effectsFor, shouldBranch } from '@bablr/agast-vm-helpers';
|
|
4
|
+
import { getChildPropertyIndex, Path, TagPath } from '@bablr/agast-helpers/path';
|
|
5
|
+
import * as sumtree from '@bablr/agast-helpers/sumtree';
|
|
6
|
+
import { buildGapTag, buildReferenceTag, mergeReferences } from '@bablr/agast-helpers/tree';
|
|
7
|
+
import { effectsFor } from '@bablr/agast-vm-helpers';
|
|
16
8
|
import { buildInternalState, internalStates, FragmentFacade } from './node.js';
|
|
17
9
|
|
|
18
10
|
import { facades, actuals } from './facades.js';
|
|
19
|
-
import {
|
|
20
|
-
CloseNodeTag,
|
|
21
|
-
EmbeddedNode,
|
|
22
|
-
GapTag,
|
|
23
|
-
OpenNodeTag,
|
|
24
|
-
ReferenceTag,
|
|
25
|
-
ShiftTag,
|
|
26
|
-
} from '@bablr/agast-helpers/symbols';
|
|
11
|
+
import { CloseNodeTag, OpenNodeTag } from '@bablr/agast-helpers/symbols';
|
|
27
12
|
import { nodeStates } from './state.js';
|
|
28
|
-
|
|
29
|
-
const nodeTopType = Symbol.for('@bablr/node');
|
|
13
|
+
import { buildCall, buildEmbeddedTag } from '@bablr/agast-vm-helpers/builders';
|
|
30
14
|
|
|
31
15
|
const tagPathsAreEqual = (a, b) => {
|
|
32
16
|
return !a || !b ? a == b : a.path.node === b.path.node && a.childrenIndex === b.childrenIndex;
|
|
@@ -45,6 +29,10 @@ export class MatchFacade {
|
|
|
45
29
|
return actuals.get(this).matcher;
|
|
46
30
|
}
|
|
47
31
|
|
|
32
|
+
get options() {
|
|
33
|
+
return actuals.get(this).options;
|
|
34
|
+
}
|
|
35
|
+
|
|
48
36
|
get mergedReference() {
|
|
49
37
|
return actuals.get(this).mergedReference;
|
|
50
38
|
}
|
|
@@ -65,6 +53,37 @@ export class MatchFacade {
|
|
|
65
53
|
return actuals.get(this).innerPath;
|
|
66
54
|
}
|
|
67
55
|
|
|
56
|
+
get fragment() {
|
|
57
|
+
const {
|
|
58
|
+
ctx,
|
|
59
|
+
path,
|
|
60
|
+
isNode,
|
|
61
|
+
fragmentNode,
|
|
62
|
+
mergedReference,
|
|
63
|
+
rangePreviousIndex,
|
|
64
|
+
rangeFinalIndex,
|
|
65
|
+
} = actuals.get(this);
|
|
66
|
+
|
|
67
|
+
const { name, isArray } = mergedReference.value;
|
|
68
|
+
|
|
69
|
+
if (isNode && !['#', '@'].includes(name)) {
|
|
70
|
+
return new FragmentFacade(
|
|
71
|
+
fragmentNode,
|
|
72
|
+
ctx,
|
|
73
|
+
false,
|
|
74
|
+
true,
|
|
75
|
+
[rangePreviousIndex + 1, rangeFinalIndex],
|
|
76
|
+
mergedReference,
|
|
77
|
+
isArray ? getChildPropertyIndex(fragmentNode, rangePreviousIndex + 1) : null,
|
|
78
|
+
);
|
|
79
|
+
} else {
|
|
80
|
+
return new FragmentFacade(fragmentNode || path.node, ctx, false, true, [
|
|
81
|
+
rangePreviousIndex + 1,
|
|
82
|
+
rangeFinalIndex,
|
|
83
|
+
]);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
68
87
|
get pathDepth() {
|
|
69
88
|
return actuals.get(this).depths.path;
|
|
70
89
|
}
|
|
@@ -82,14 +101,8 @@ export class MatchFacade {
|
|
|
82
101
|
return FragmentFacade.wrap(node, ctx, false);
|
|
83
102
|
}
|
|
84
103
|
|
|
85
|
-
get fragmentNode() {
|
|
86
|
-
const { fragmentNode, ctx } = actuals.get(this);
|
|
87
|
-
return FragmentFacade.wrap(fragmentNode, ctx, false);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
104
|
get props() {
|
|
91
|
-
|
|
92
|
-
return FragmentFacade.wrap(props, ctx, false);
|
|
105
|
+
return actuals.get(this).props;
|
|
93
106
|
}
|
|
94
107
|
|
|
95
108
|
get type() {
|
|
@@ -104,8 +117,24 @@ export class MatchFacade {
|
|
|
104
117
|
return actuals.get(this).isCover;
|
|
105
118
|
}
|
|
106
119
|
|
|
120
|
+
get allowEmpty() {
|
|
121
|
+
return actuals.get(this).allowEmpty;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
get didShift() {
|
|
125
|
+
return actuals.get(this).didShift;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
get isCoverBoundary() {
|
|
129
|
+
return actuals.get(this).isCoverBoundary;
|
|
130
|
+
}
|
|
131
|
+
|
|
107
132
|
get cover() {
|
|
108
|
-
return actuals.get(this).cover;
|
|
133
|
+
return facades.get(actuals.get(this).cover);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
get shiftMatch() {
|
|
137
|
+
return facades.get(actuals.get(this).shiftMatch);
|
|
109
138
|
}
|
|
110
139
|
|
|
111
140
|
get captured() {
|
|
@@ -162,16 +191,7 @@ export class MatchFacade {
|
|
|
162
191
|
}
|
|
163
192
|
|
|
164
193
|
export class Match extends WeakStackFrame {
|
|
165
|
-
constructor(
|
|
166
|
-
parent,
|
|
167
|
-
context,
|
|
168
|
-
language,
|
|
169
|
-
state,
|
|
170
|
-
matcher,
|
|
171
|
-
effects,
|
|
172
|
-
didShift = false,
|
|
173
|
-
suppressNode = false,
|
|
174
|
-
) {
|
|
194
|
+
constructor(parent, context, language, state, matcher, effects, shiftMatch = null, options = {}) {
|
|
175
195
|
if (!context || !language || !state) {
|
|
176
196
|
throw new Error('Invalid arguments to Match constructor');
|
|
177
197
|
}
|
|
@@ -180,26 +200,28 @@ export class Match extends WeakStackFrame {
|
|
|
180
200
|
|
|
181
201
|
this.context = context;
|
|
182
202
|
this.language = language;
|
|
183
|
-
this.state =
|
|
203
|
+
this.state = state;
|
|
184
204
|
this.propertyMatcher = matcher;
|
|
185
205
|
this.effects = effects;
|
|
186
|
-
this.
|
|
206
|
+
this.shiftMatch = shiftMatch;
|
|
187
207
|
|
|
188
208
|
this.rangePreviousIndex = null;
|
|
189
209
|
this.rangeFinalIndex = null;
|
|
190
210
|
this.node = null;
|
|
191
211
|
this.fragmentNode = null; // why do it this way?
|
|
192
212
|
this.cover = null;
|
|
193
|
-
this.
|
|
213
|
+
this.options = options;
|
|
194
214
|
|
|
195
215
|
let internalState;
|
|
196
|
-
let { isNode
|
|
216
|
+
let { isNode } = this;
|
|
217
|
+
const { grammar, type } = this;
|
|
218
|
+
let isCover = grammar.covers?.has(type);
|
|
197
219
|
|
|
198
|
-
this.cover =
|
|
220
|
+
this.cover = isNode ? null : parent?.cover || (isCover ? this : null);
|
|
199
221
|
|
|
200
|
-
let
|
|
222
|
+
let isCoverBoundary = ((isNode || isCover) && !this.cover) || !parent;
|
|
201
223
|
|
|
202
|
-
if (
|
|
224
|
+
if (isCoverBoundary) {
|
|
203
225
|
internalState = buildInternalState();
|
|
204
226
|
internalState.path.node;
|
|
205
227
|
} else {
|
|
@@ -221,8 +243,12 @@ export class Match extends WeakStackFrame {
|
|
|
221
243
|
new MatchFacade(this);
|
|
222
244
|
}
|
|
223
245
|
|
|
224
|
-
static from(context, language, state, matcher, props,
|
|
225
|
-
return Match.create(context, language, state, matcher, effectsFor('eat'), props,
|
|
246
|
+
static from(context, language, state, matcher, props, options) {
|
|
247
|
+
return Match.create(context, language, state, matcher, effectsFor('eat'), props, options);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
get isCoverBoundary() {
|
|
251
|
+
return (this.isNode && !this.parent.cover) || this.cover === this;
|
|
226
252
|
}
|
|
227
253
|
|
|
228
254
|
get matcher() {
|
|
@@ -233,15 +259,21 @@ export class Match extends WeakStackFrame {
|
|
|
233
259
|
let ref = buildReferenceTag('.');
|
|
234
260
|
|
|
235
261
|
let first = true;
|
|
236
|
-
|
|
262
|
+
let m = this;
|
|
263
|
+
let lastName = null;
|
|
264
|
+
do {
|
|
237
265
|
if (m.isNode && !first) break;
|
|
238
266
|
if (m.propertyMatcher.refMatcher) {
|
|
239
267
|
const { name, isArray, flags } = m.propertyMatcher.refMatcher;
|
|
240
268
|
const parentRef = buildReferenceTag(name, isArray, flags);
|
|
269
|
+
if (lastName && lastName !== name) break;
|
|
241
270
|
ref = ['#', '@'].includes(ref.value.name) ? ref : mergeReferences(ref, parentRef);
|
|
271
|
+
if (name !== '.') {
|
|
272
|
+
lastName = name;
|
|
273
|
+
}
|
|
242
274
|
}
|
|
243
275
|
first = false;
|
|
244
|
-
}
|
|
276
|
+
} while ((m = m.shiftMatch || m.parent));
|
|
245
277
|
|
|
246
278
|
return ref;
|
|
247
279
|
}
|
|
@@ -264,6 +296,10 @@ export class Match extends WeakStackFrame {
|
|
|
264
296
|
return m;
|
|
265
297
|
}
|
|
266
298
|
|
|
299
|
+
get coveredBoundary() {
|
|
300
|
+
return this.isNode ? this.parent.cover || this : this.cover || this;
|
|
301
|
+
}
|
|
302
|
+
|
|
267
303
|
get parentPath() {
|
|
268
304
|
return this.pathParent?.path;
|
|
269
305
|
}
|
|
@@ -293,11 +329,13 @@ export class Match extends WeakStackFrame {
|
|
|
293
329
|
}
|
|
294
330
|
|
|
295
331
|
get allowEmpty() {
|
|
296
|
-
return !!this.grammar.emptyables?.has(this.type);
|
|
332
|
+
return !!this.grammar.emptyables?.has(this.type) || this.options.allowEmpty;
|
|
297
333
|
}
|
|
298
334
|
|
|
299
335
|
get rangePrevious() {
|
|
300
|
-
return this.rangePreviousIndex == null
|
|
336
|
+
return this.rangePreviousIndex == null
|
|
337
|
+
? null
|
|
338
|
+
: TagPath.from(this.path, this.rangePreviousIndex);
|
|
301
339
|
}
|
|
302
340
|
|
|
303
341
|
setRangePreviousIndex(value) {
|
|
@@ -311,7 +349,7 @@ export class Match extends WeakStackFrame {
|
|
|
311
349
|
}
|
|
312
350
|
|
|
313
351
|
get rangeFinal() {
|
|
314
|
-
const path =
|
|
352
|
+
const path = Path.from(this.fragmentNode || this.node);
|
|
315
353
|
|
|
316
354
|
return this.rangeFinalIndex == null ? null : new TagPath(path, this.rangeFinalIndex);
|
|
317
355
|
}
|
|
@@ -321,13 +359,6 @@ export class Match extends WeakStackFrame {
|
|
|
321
359
|
|
|
322
360
|
if (!rangePrevious) return rangePrevious;
|
|
323
361
|
|
|
324
|
-
if (rangePrevious.tag.type === ShiftTag) {
|
|
325
|
-
let tagPath = rangePrevious;
|
|
326
|
-
while (tagPath.tag.type !== ReferenceTag) {
|
|
327
|
-
tagPath = tagPath.previousSibling;
|
|
328
|
-
}
|
|
329
|
-
return tagPath;
|
|
330
|
-
}
|
|
331
362
|
return rangePrevious?.nextSibling;
|
|
332
363
|
}
|
|
333
364
|
|
|
@@ -336,7 +367,11 @@ export class Match extends WeakStackFrame {
|
|
|
336
367
|
return rangeInitial === null ? null : [rangeInitial, rangeFinal];
|
|
337
368
|
}
|
|
338
369
|
|
|
339
|
-
get
|
|
370
|
+
get didShift() {
|
|
371
|
+
return !!this.shiftMatch;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
get unshiftedReferencePath() {
|
|
340
375
|
const previous = this.rangePrevious;
|
|
341
376
|
|
|
342
377
|
if (!this.isNode) {
|
|
@@ -344,28 +379,24 @@ export class Match extends WeakStackFrame {
|
|
|
344
379
|
}
|
|
345
380
|
|
|
346
381
|
if (this.parent.cover) {
|
|
347
|
-
return previous
|
|
382
|
+
return previous;
|
|
348
383
|
}
|
|
349
384
|
|
|
350
385
|
if (this.didShift) {
|
|
351
|
-
let
|
|
352
|
-
|
|
353
|
-
tagPath = tagPath.previousSibling;
|
|
354
|
-
}
|
|
355
|
-
return tagPath;
|
|
386
|
+
let refIndex = previous.childrenIndex - previous.tag.value.index * 2;
|
|
387
|
+
return previous.siblingPathAt(refIndex);
|
|
356
388
|
}
|
|
357
389
|
|
|
358
|
-
return previous
|
|
390
|
+
return previous;
|
|
359
391
|
}
|
|
360
392
|
|
|
361
393
|
get isNode() {
|
|
362
|
-
|
|
363
|
-
return !
|
|
394
|
+
let { flags, type } = this.matcher;
|
|
395
|
+
return !flags.fragment && type !== Symbol.for('@bablr/fragment');
|
|
364
396
|
}
|
|
365
397
|
|
|
366
398
|
get isCover() {
|
|
367
|
-
|
|
368
|
-
return grammar.covers?.has(type);
|
|
399
|
+
return this.cover === this;
|
|
369
400
|
}
|
|
370
401
|
|
|
371
402
|
get innerPath() {
|
|
@@ -373,9 +404,8 @@ export class Match extends WeakStackFrame {
|
|
|
373
404
|
}
|
|
374
405
|
|
|
375
406
|
add(node) {
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
);
|
|
407
|
+
let internalState = internalStates.get(this.fragmentNode);
|
|
408
|
+
const { expressionsPump, instructionsPump, agast, agastState } = internalState;
|
|
379
409
|
|
|
380
410
|
expressionsPump.queue(node);
|
|
381
411
|
instructionsPump.queue(buildCall('advance', buildEmbeddedTag(buildGapTag())));
|
|
@@ -383,7 +413,7 @@ export class Match extends WeakStackFrame {
|
|
|
383
413
|
agast.next();
|
|
384
414
|
}
|
|
385
415
|
|
|
386
|
-
startFrame(state, propertyMatcher, effects, didShift,
|
|
416
|
+
startFrame(state, propertyMatcher, effects, didShift, options) {
|
|
387
417
|
let { context } = this;
|
|
388
418
|
const { nodeMatcher } = propertyMatcher;
|
|
389
419
|
|
|
@@ -393,37 +423,29 @@ export class Match extends WeakStackFrame {
|
|
|
393
423
|
throw new Error(`Unknown language ${nodeMatcher.language.join('.')}`);
|
|
394
424
|
}
|
|
395
425
|
|
|
396
|
-
return this.push(context, language, state, propertyMatcher, effects, didShift,
|
|
426
|
+
return this.push(context, language, state, propertyMatcher, effects, didShift, options);
|
|
397
427
|
}
|
|
398
428
|
|
|
399
429
|
endFrame() {
|
|
400
430
|
const finishedMatch = this;
|
|
401
431
|
const m = finishedMatch.parent;
|
|
402
|
-
let finishedState = finishedMatch.state;
|
|
403
432
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
433
|
+
if (!m) return m;
|
|
434
|
+
|
|
435
|
+
finishedMatch.setRangeFinalIndex(
|
|
436
|
+
sumtree.getSize((finishedMatch.fragmentNode || m.node).children) - 1,
|
|
437
|
+
);
|
|
438
|
+
|
|
439
|
+
return m;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
throw_() {
|
|
443
|
+
const finishedMatch = this;
|
|
444
|
+
const m = finishedMatch.parent;
|
|
410
445
|
|
|
411
446
|
if (!m) return m;
|
|
412
447
|
|
|
413
|
-
|
|
414
|
-
if (
|
|
415
|
-
(!isEmpty(allTagsFor(finishedMatch.range)) || finishedMatch.allowEmpty) &&
|
|
416
|
-
finishedMatch.state.status !== 'rejected'
|
|
417
|
-
) {
|
|
418
|
-
finishedState.accept();
|
|
419
|
-
finishedMatch.setRangeFinalIndex(btree.getSum(m.fragmentNode.children) - 1);
|
|
420
|
-
} else {
|
|
421
|
-
finishedState.reject();
|
|
422
|
-
finishedMatch.setRangePreviousIndex(null);
|
|
423
|
-
}
|
|
424
|
-
} else {
|
|
425
|
-
finishedMatch.setRangeFinalIndex(btree.getSum((m.fragmentNode || m.node).children) - 1);
|
|
426
|
-
}
|
|
448
|
+
finishedMatch.setRangePreviousIndex(null);
|
|
427
449
|
|
|
428
450
|
return m;
|
|
429
451
|
}
|
|
@@ -434,9 +456,13 @@ export class Match extends WeakStackFrame {
|
|
|
434
456
|
if (!state.depth) {
|
|
435
457
|
let { node, emitted } = state;
|
|
436
458
|
|
|
459
|
+
if (!node) {
|
|
460
|
+
node = state.resultPath.node;
|
|
461
|
+
}
|
|
462
|
+
|
|
437
463
|
let { path } = internalStates.get(node);
|
|
438
464
|
|
|
439
|
-
let tagPath = emitted || (
|
|
465
|
+
let tagPath = emitted || (sumtree.getSize(path.node.children) ? new TagPath(path, 0) : null);
|
|
440
466
|
|
|
441
467
|
// two basic cases:
|
|
442
468
|
// emitted can move
|
|
@@ -446,7 +472,7 @@ export class Match extends WeakStackFrame {
|
|
|
446
472
|
if (
|
|
447
473
|
tagPath.tag.type === OpenNodeTag &&
|
|
448
474
|
tagPath.tag.value.type &&
|
|
449
|
-
nodeStates.get(tagPath.path.node)
|
|
475
|
+
nodeStates.get(tagPath.path.node)?.undefinedAttributes?.size
|
|
450
476
|
) {
|
|
451
477
|
break;
|
|
452
478
|
}
|