@bablr/bablr-vm 0.20.0 → 0.21.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 +6 -6
- package/lib/evaluate.js +297 -149
- package/lib/match.js +252 -103
- package/lib/node.js +100 -99
- package/lib/source.js +110 -110
- package/lib/state.js +121 -167
- package/lib/utils/pattern.js +80 -13
- package/package.json +7 -7
- package/lib/utils/array.js +0 -13
- package/lib/utils/format.js +0 -9
- package/lib/utils/object.js +0 -97
- package/lib/utils/pump.js +0 -20
- package/lib/utils/token.js +0 -30
package/lib/state.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
|
+
import {
|
|
2
|
+
agast as createAgast,
|
|
3
|
+
TagPathFacade as TagPath,
|
|
4
|
+
PathFacade as Path,
|
|
5
|
+
} from '@bablr/agast-vm';
|
|
1
6
|
import emptyStack from '@iter-tools/imm-stack';
|
|
2
7
|
import { WeakStackFrame } from '@bablr/weak-stack';
|
|
3
|
-
import { getCooked } from '@bablr/agast-helpers/stream';
|
|
8
|
+
import { getCooked, maybeWait } from '@bablr/agast-helpers/stream';
|
|
4
9
|
import { reifyExpression } from '@bablr/agast-vm-helpers';
|
|
5
10
|
import {
|
|
6
|
-
CloseNodeTag,
|
|
7
11
|
EmbeddedMatcher,
|
|
8
12
|
EmbeddedNode,
|
|
9
13
|
EmbeddedRegex,
|
|
@@ -12,29 +16,29 @@ import {
|
|
|
12
16
|
OpenNodeTag,
|
|
13
17
|
ReferenceTag,
|
|
14
18
|
ShiftTag,
|
|
19
|
+
Property,
|
|
20
|
+
BindingTag,
|
|
15
21
|
} from '@bablr/agast-vm-helpers/symbols';
|
|
16
|
-
import * as btree from '@bablr/agast-helpers/btree';
|
|
17
|
-
import * as sumtree from '@bablr/agast-helpers/sumtree';
|
|
18
22
|
import {
|
|
19
|
-
|
|
23
|
+
buildBindingTag,
|
|
24
|
+
buildChild,
|
|
20
25
|
buildInitializerTag,
|
|
21
26
|
buildNullNode,
|
|
22
|
-
|
|
23
|
-
buildStubNode,
|
|
27
|
+
buildProperty,
|
|
24
28
|
} from '@bablr/agast-helpers/tree';
|
|
25
|
-
import { getShifted, TagPath } from '@bablr/agast-helpers/path';
|
|
26
29
|
import { match, guardWithPattern } from './utils/pattern.js';
|
|
27
30
|
import { facades, actuals } from './facades.js';
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
31
|
+
import { FragmentFacade } from './node.js';
|
|
32
|
+
import { buildFullPathSegment } from '@bablr/agast-helpers/path';
|
|
30
33
|
|
|
31
|
-
const { hasOwn } = Object;
|
|
34
|
+
const { hasOwn, freeze } = Object;
|
|
32
35
|
|
|
33
36
|
export const nodeStates = new WeakMap();
|
|
34
37
|
|
|
35
38
|
export const StateFacade = class BABLRStateFacade {
|
|
36
39
|
constructor(state) {
|
|
37
40
|
facades.set(state, this);
|
|
41
|
+
freeze(this);
|
|
38
42
|
}
|
|
39
43
|
|
|
40
44
|
static from(source) {
|
|
@@ -61,18 +65,19 @@ export const StateFacade = class BABLRStateFacade {
|
|
|
61
65
|
return actuals.get(this).reference;
|
|
62
66
|
}
|
|
63
67
|
|
|
64
|
-
get
|
|
65
|
-
return actuals.get(this).
|
|
68
|
+
get referenceTagPath() {
|
|
69
|
+
return actuals.get(this).referenceTagPath;
|
|
66
70
|
}
|
|
67
71
|
|
|
68
|
-
get
|
|
69
|
-
return actuals.get(this).
|
|
72
|
+
get referencePath() {
|
|
73
|
+
return actuals.get(this).referencePath;
|
|
70
74
|
}
|
|
71
75
|
|
|
72
76
|
get holding() {
|
|
73
77
|
return actuals.get(this).holding;
|
|
74
78
|
}
|
|
75
79
|
|
|
80
|
+
// FACADEME
|
|
76
81
|
get path() {
|
|
77
82
|
return actuals.get(this).path;
|
|
78
83
|
}
|
|
@@ -82,13 +87,13 @@ export const StateFacade = class BABLRStateFacade {
|
|
|
82
87
|
}
|
|
83
88
|
|
|
84
89
|
get depths() {
|
|
85
|
-
const { path, result } = actuals.get(this).depths;
|
|
86
|
-
return { path, result };
|
|
90
|
+
const { path, result, shift, nodeShift } = actuals.get(this).depths;
|
|
91
|
+
return { path, result, shift, nodeShift };
|
|
87
92
|
}
|
|
88
93
|
|
|
89
94
|
get held() {
|
|
90
95
|
const { held } = actuals.get(this);
|
|
91
|
-
return held && FragmentFacade.wrapNode(held, this.ctx);
|
|
96
|
+
return held && FragmentFacade.wrapNode(held.node, this.ctx);
|
|
92
97
|
}
|
|
93
98
|
|
|
94
99
|
get node() {
|
|
@@ -129,11 +134,11 @@ export const State = class BABLRState extends WeakStackFrame {
|
|
|
129
134
|
expressions = emptyStack,
|
|
130
135
|
balanced = emptyStack,
|
|
131
136
|
spans = emptyStack.push({ name: 'Bare' }),
|
|
132
|
-
|
|
137
|
+
referenceTagPath = null,
|
|
133
138
|
resultPath = null,
|
|
134
|
-
depths = { path: -1, result: -1, emitted: -1 },
|
|
139
|
+
depths = { path: -1, result: -1, emitted: -1, shift: 0, nodeShift: 0 },
|
|
135
140
|
held = null,
|
|
136
|
-
|
|
141
|
+
agast = null,
|
|
137
142
|
) {
|
|
138
143
|
super(parent);
|
|
139
144
|
|
|
@@ -145,11 +150,11 @@ export const State = class BABLRState extends WeakStackFrame {
|
|
|
145
150
|
this.expressions = expressions;
|
|
146
151
|
this.balanced = balanced;
|
|
147
152
|
this.spans = spans;
|
|
148
|
-
this.
|
|
153
|
+
this.referenceTagPath = referenceTagPath;
|
|
149
154
|
this.resultPath = resultPath;
|
|
150
155
|
this.depths = depths;
|
|
151
156
|
this.held = held;
|
|
152
|
-
this.
|
|
157
|
+
this.agast = agast;
|
|
153
158
|
|
|
154
159
|
this.status = 'active';
|
|
155
160
|
|
|
@@ -162,30 +167,30 @@ export const State = class BABLRState extends WeakStackFrame {
|
|
|
162
167
|
return State.create(source, context, language, emptyStack.push(...expressions));
|
|
163
168
|
}
|
|
164
169
|
|
|
165
|
-
get
|
|
166
|
-
|
|
170
|
+
get node() {
|
|
171
|
+
return this.agast?.state.node;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
get referencePath() {
|
|
175
|
+
let refPath = this.referenceTagPath;
|
|
167
176
|
|
|
168
177
|
if (!refPath) return null;
|
|
169
178
|
|
|
170
179
|
let { previousSibling } = refPath;
|
|
171
180
|
let isShift = previousSibling.tag.type === ShiftTag;
|
|
172
181
|
|
|
173
|
-
let
|
|
182
|
+
let referenceTagPath = previousSibling;
|
|
174
183
|
|
|
175
184
|
if (isShift) {
|
|
176
|
-
let refIndex = previousSibling.childrenIndex - 1 - previousSibling.tag.value.index *
|
|
177
|
-
|
|
185
|
+
let refIndex = previousSibling.childrenIndex - 1 - previousSibling.tag.value.index * 3;
|
|
186
|
+
referenceTagPath = previousSibling.siblingAt(refIndex);
|
|
178
187
|
}
|
|
179
|
-
return
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
get undefinedAttributes() {
|
|
183
|
-
return nodeStates.get(this.node).undefinedAttributes;
|
|
188
|
+
return referenceTagPath;
|
|
184
189
|
}
|
|
185
190
|
|
|
186
191
|
get guardedSource() {
|
|
187
|
-
|
|
188
|
-
|
|
192
|
+
let { source, span } = this;
|
|
193
|
+
let { guard } = span;
|
|
189
194
|
|
|
190
195
|
return guard ? guardWithPattern(guard, source) : source;
|
|
191
196
|
}
|
|
@@ -211,7 +216,7 @@ export const State = class BABLRState extends WeakStackFrame {
|
|
|
211
216
|
}
|
|
212
217
|
|
|
213
218
|
get reference() {
|
|
214
|
-
return this.
|
|
219
|
+
return this.referenceTagPath?.tag;
|
|
215
220
|
}
|
|
216
221
|
|
|
217
222
|
get isGap() {
|
|
@@ -222,24 +227,6 @@ export const State = class BABLRState extends WeakStackFrame {
|
|
|
222
227
|
return !!this.parent;
|
|
223
228
|
}
|
|
224
229
|
|
|
225
|
-
advance(tag) {
|
|
226
|
-
const { path, instructionsPump, expressionsPump, agast } = internalStates.get(this.node);
|
|
227
|
-
|
|
228
|
-
if (tag.type === GapTag) {
|
|
229
|
-
expressionsPump.queue(
|
|
230
|
-
this.expressions.size ? this.expressions.value : buildStubNode(buildGapTag()),
|
|
231
|
-
);
|
|
232
|
-
this.expressions = this.expressions.pop();
|
|
233
|
-
}
|
|
234
|
-
instructionsPump.queue(buildCall('advance', buildEmbeddedTag(tag)));
|
|
235
|
-
agast.next();
|
|
236
|
-
|
|
237
|
-
if (tag.type === OpenNodeTag) this.depths.result++;
|
|
238
|
-
if (tag.type === CloseNodeTag) this.depths.result--;
|
|
239
|
-
|
|
240
|
-
this.resultPath = TagPath.from(path, -1);
|
|
241
|
-
}
|
|
242
|
-
|
|
243
230
|
guardedMatch(pattern) {
|
|
244
231
|
let { span, source } = this;
|
|
245
232
|
let { guard } = span;
|
|
@@ -279,7 +266,16 @@ export const State = class BABLRState extends WeakStackFrame {
|
|
|
279
266
|
}
|
|
280
267
|
}
|
|
281
268
|
|
|
282
|
-
|
|
269
|
+
let guardedSource = guard && guardWithPattern(guard, source);
|
|
270
|
+
|
|
271
|
+
let result = match(pattern_, guardedSource || source);
|
|
272
|
+
|
|
273
|
+
return maybeWait(result, (result) => {
|
|
274
|
+
if (guardedSource && !guardedSource.done) {
|
|
275
|
+
guardedSource.return();
|
|
276
|
+
}
|
|
277
|
+
return result;
|
|
278
|
+
});
|
|
283
279
|
}
|
|
284
280
|
|
|
285
281
|
match(pattern) {
|
|
@@ -287,52 +283,41 @@ export const State = class BABLRState extends WeakStackFrame {
|
|
|
287
283
|
}
|
|
288
284
|
|
|
289
285
|
branch() {
|
|
290
|
-
|
|
286
|
+
let baseState = this;
|
|
291
287
|
let {
|
|
288
|
+
agast,
|
|
292
289
|
source,
|
|
293
290
|
context,
|
|
294
291
|
balanced,
|
|
295
292
|
spans,
|
|
296
293
|
resultPath,
|
|
297
294
|
depths,
|
|
298
|
-
|
|
295
|
+
referenceTagPath,
|
|
299
296
|
held,
|
|
300
297
|
node,
|
|
301
298
|
language,
|
|
302
299
|
expressions,
|
|
303
300
|
} = baseState;
|
|
304
301
|
|
|
305
|
-
|
|
302
|
+
let newAgast = createAgast(agast.options);
|
|
306
303
|
|
|
307
304
|
for (let tagPath = TagPath.fromNode(node, 0); tagPath; tagPath = tagPath.nextSibling) {
|
|
308
305
|
let { tag } = tagPath;
|
|
309
306
|
|
|
310
|
-
if (tag.type ===
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
let { name, isArray, flags } = firstRef.value;
|
|
317
|
-
const resolvedPath = buildReferenceTag(
|
|
318
|
-
name,
|
|
319
|
-
isArray,
|
|
320
|
-
flags,
|
|
321
|
-
isArray ? btree.getSize(internalState.path.node.properties[name]) : null,
|
|
307
|
+
if (tag.type === Property) {
|
|
308
|
+
newAgast.vm.next(
|
|
309
|
+
buildChild(
|
|
310
|
+
Property,
|
|
311
|
+
buildProperty(tag.value.reference, tag.value.binding, tag.value.node.node),
|
|
312
|
+
),
|
|
322
313
|
);
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
} else if (tag.type === EmbeddedNode) {
|
|
326
|
-
internalState.expressionsPump.queue(tag.value);
|
|
327
|
-
tag = buildGapTag();
|
|
314
|
+
} else {
|
|
315
|
+
newAgast.vm.next(tag);
|
|
328
316
|
}
|
|
329
|
-
|
|
330
|
-
internalState.instructionsPump.queue(buildCall('advance', buildEmbeddedTag(tag)));
|
|
331
|
-
internalState.agast.next();
|
|
332
317
|
}
|
|
333
318
|
|
|
334
|
-
|
|
335
|
-
|
|
319
|
+
let newNode = newAgast.state.node;
|
|
320
|
+
let nodeState = nodeStates.get(node);
|
|
336
321
|
let newResultPath;
|
|
337
322
|
|
|
338
323
|
if (resultPath.path.node === node) {
|
|
@@ -342,89 +327,50 @@ export const State = class BABLRState extends WeakStackFrame {
|
|
|
342
327
|
}
|
|
343
328
|
|
|
344
329
|
nodeStates.set(newNode, { ...nodeState });
|
|
345
|
-
internalStates.set(newNode, internalState);
|
|
346
330
|
|
|
347
|
-
|
|
331
|
+
let child = this.push(
|
|
348
332
|
source.branch(),
|
|
349
333
|
context,
|
|
350
334
|
language,
|
|
351
335
|
expressions,
|
|
352
336
|
balanced,
|
|
353
337
|
spans,
|
|
354
|
-
|
|
338
|
+
referenceTagPath,
|
|
355
339
|
newResultPath,
|
|
356
340
|
{ ...depths },
|
|
357
341
|
held,
|
|
358
|
-
|
|
342
|
+
newAgast,
|
|
359
343
|
);
|
|
360
344
|
|
|
361
345
|
return child;
|
|
362
346
|
}
|
|
363
347
|
|
|
364
348
|
accept() {
|
|
365
|
-
|
|
349
|
+
let accepted = this;
|
|
366
350
|
|
|
367
351
|
this.status = 'accepted';
|
|
368
352
|
|
|
369
|
-
|
|
353
|
+
let { parent } = this;
|
|
370
354
|
|
|
371
355
|
if (!parent) {
|
|
372
356
|
throw new Error('accepted the root state');
|
|
373
357
|
}
|
|
374
358
|
|
|
375
359
|
if (parent.depths.path === accepted.depths.path) {
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
const internalState = internalStates.get(parent.node);
|
|
379
|
-
const { path: parentPath } = internalState;
|
|
360
|
+
let parentChildren = parent.node.children;
|
|
380
361
|
|
|
381
362
|
if (parent.node.type !== accepted.node.type) throw new Error();
|
|
382
363
|
|
|
383
|
-
for (
|
|
384
|
-
let
|
|
385
|
-
i < sumtree.getSize(accepted.node.children);
|
|
386
|
-
i++
|
|
387
|
-
) {
|
|
388
|
-
let tag = sumtree.getAt(i, accepted.node.children);
|
|
389
|
-
|
|
390
|
-
if (tag.type === GapTag) {
|
|
391
|
-
let previousSibling = sumtree.getAt(i - 1, accepted.node.children);
|
|
392
|
-
let isShift = previousSibling.type === ShiftTag;
|
|
393
|
-
let reference = previousSibling;
|
|
394
|
-
|
|
395
|
-
if (isShift) {
|
|
396
|
-
reference = sumtree.getAt(
|
|
397
|
-
i - 1 - previousSibling.value.index * 2,
|
|
398
|
-
accepted.node.children,
|
|
399
|
-
);
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
let { name, isArray, flags } = reference.value;
|
|
403
|
-
const resolvedPath = buildReferenceTag(
|
|
404
|
-
name,
|
|
405
|
-
isArray,
|
|
406
|
-
flags,
|
|
407
|
-
isArray ? btree.getSize(parentPath.node.properties[name]) - (isShift ? 1 : 0) : null,
|
|
408
|
-
);
|
|
409
|
-
const expr = getShifted(
|
|
410
|
-
isShift ? previousSibling.value.index : null,
|
|
411
|
-
resolvedPath,
|
|
412
|
-
accepted.node,
|
|
413
|
-
);
|
|
414
|
-
internalState.expressionsPump.queue(expr);
|
|
415
|
-
} else if (tag.type === EmbeddedNode) {
|
|
416
|
-
internalState.expressionsPump.queue(tag.value);
|
|
417
|
-
tag = buildGapTag();
|
|
418
|
-
}
|
|
364
|
+
for (let i = parentChildren.size; i < accepted.node.children.size; i++) {
|
|
365
|
+
let tag = accepted.node.children.at(i);
|
|
419
366
|
|
|
420
|
-
|
|
421
|
-
internalState.agast.next();
|
|
367
|
+
parent.agast.vm.next(tag);
|
|
422
368
|
}
|
|
423
369
|
}
|
|
424
370
|
|
|
425
371
|
parent.spans = accepted.spans;
|
|
426
372
|
parent.balanced = accepted.balanced;
|
|
427
|
-
parent.
|
|
373
|
+
parent.referenceTagPath = accepted.referenceTagPath;
|
|
428
374
|
parent.held = accepted.held;
|
|
429
375
|
parent.depths = accepted.depths;
|
|
430
376
|
parent.language = accepted.language;
|
|
@@ -453,75 +399,83 @@ export const State = class BABLRState extends WeakStackFrame {
|
|
|
453
399
|
(!finishedMatch.isNode && !didBranch) ||
|
|
454
400
|
finishedMatch.cover ||
|
|
455
401
|
finishedMatch.effects.success === 'none';
|
|
456
|
-
let shallower =
|
|
402
|
+
let shallower =
|
|
403
|
+
finishedMatch.coveredBoundary.didShift &&
|
|
404
|
+
finishedMatch.coveredBoundary.shiftMatch.state.depth === this.depth - 2
|
|
405
|
+
? finishedMatch.coveredBoundary.shiftMatch.state
|
|
406
|
+
: this.parent;
|
|
457
407
|
|
|
458
|
-
if (shallower) {
|
|
408
|
+
if (!abandon && shallower) {
|
|
459
409
|
let parentChildren = shallower.node.children;
|
|
460
410
|
let ourChildren = finishedMatch.fragmentNode.children;
|
|
461
|
-
let
|
|
411
|
+
let refTag;
|
|
412
|
+
let bindTag;
|
|
462
413
|
|
|
463
|
-
if (
|
|
414
|
+
if (shallower.node.type) {
|
|
464
415
|
if (shallower.node.type !== rejectedState.node.type) throw new Error();
|
|
465
416
|
|
|
466
|
-
for (let i =
|
|
467
|
-
let tag =
|
|
417
|
+
for (let i = parentChildren.size; i < ourChildren.size; i++) {
|
|
418
|
+
let tag = ourChildren.at(i);
|
|
419
|
+
|
|
420
|
+
if (tag.type === ReferenceTag) {
|
|
421
|
+
refTag = tag;
|
|
422
|
+
}
|
|
423
|
+
if (tag.type === BindingTag) {
|
|
424
|
+
bindTag = tag;
|
|
425
|
+
}
|
|
468
426
|
|
|
469
427
|
if ([InitializerTag, GapTag].includes(tag.type)) {
|
|
470
|
-
let previousSibling =
|
|
428
|
+
let previousSibling = ourChildren.at(i - 1);
|
|
471
429
|
let isShift = previousSibling.type === ShiftTag;
|
|
472
430
|
|
|
473
431
|
let reference = previousSibling;
|
|
474
432
|
|
|
475
433
|
if (isShift) {
|
|
476
|
-
let refIndex = i - 1 - previousSibling.value.index *
|
|
477
|
-
reference =
|
|
434
|
+
let refIndex = i - 1 - previousSibling.value.index * 3;
|
|
435
|
+
reference = ourChildren.at(refIndex);
|
|
478
436
|
}
|
|
479
437
|
|
|
480
|
-
let lastParentTag = TagPath.from(internalState.path, -1).tag.type;
|
|
481
|
-
|
|
482
438
|
if (
|
|
483
|
-
!['#', '@'].includes(reference.value.
|
|
439
|
+
!['#', '@'].includes(reference.value.type) &&
|
|
484
440
|
!reference.value.isArray &&
|
|
485
441
|
!hasOwn(shallower.node.properties, reference.value.name) &&
|
|
486
|
-
|
|
442
|
+
refTag !== ShiftTag
|
|
487
443
|
) {
|
|
488
|
-
if (
|
|
489
|
-
|
|
490
|
-
buildCall('advance', buildEmbeddedTag(reference)),
|
|
491
|
-
);
|
|
492
|
-
internalState.agast.next();
|
|
444
|
+
if (refTag !== ReferenceTag) {
|
|
445
|
+
shallower.agast.vm.next(refTag);
|
|
493
446
|
}
|
|
447
|
+
|
|
494
448
|
if (bind || tag.type === GapTag) {
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
buildCall('advance', buildEmbeddedTag(buildGapTag())),
|
|
449
|
+
shallower.agast.vm.next(
|
|
450
|
+
buildChild(Property, buildProperty(refTag.value, null, buildNullNode())),
|
|
498
451
|
);
|
|
499
452
|
} else {
|
|
500
|
-
|
|
453
|
+
shallower.agast.vm.next(tag);
|
|
501
454
|
}
|
|
502
|
-
internalState.agast.next();
|
|
503
455
|
}
|
|
456
|
+
refTag = null;
|
|
504
457
|
}
|
|
505
458
|
}
|
|
506
459
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
if (!ref.value.flags.expression) {
|
|
518
|
-
internalState.instructionsPump.queue(
|
|
519
|
-
buildCall('advance', buildEmbeddedTag(buildInitializerTag(ref.value.isArray))),
|
|
460
|
+
if (refTag?.type === ReferenceTag) {
|
|
461
|
+
if (
|
|
462
|
+
!['#', '@'].includes(refTag.value.type) &&
|
|
463
|
+
!refTag.value.isArray &&
|
|
464
|
+
!hasOwn(shallower.node.properties, refTag.value.name)
|
|
465
|
+
) {
|
|
466
|
+
if (bind) {
|
|
467
|
+
shallower.agast.vm.next(refTag);
|
|
468
|
+
shallower.agast.vm.next(
|
|
469
|
+
buildChild(Property, buildProperty(refTag.value, [], buildNullNode())),
|
|
520
470
|
);
|
|
521
|
-
|
|
471
|
+
} else {
|
|
472
|
+
if (!refTag.value.flags.expression) {
|
|
473
|
+
shallower.agast.vm.next(refTag);
|
|
474
|
+
shallower.agast.vm.next(buildInitializerTag(refTag.value.isArray));
|
|
475
|
+
}
|
|
522
476
|
}
|
|
523
477
|
}
|
|
524
|
-
shallower.
|
|
478
|
+
shallower.referenceTagPath = null;
|
|
525
479
|
shallower.resultPath = TagPath.fromNode(shallower.node, -1);
|
|
526
480
|
}
|
|
527
481
|
}
|
package/lib/utils/pattern.js
CHANGED
|
@@ -2,7 +2,7 @@ import isString from 'iter-tools-es/methods/is-string';
|
|
|
2
2
|
import isEmpty from 'iter-tools-es/methods/is-empty';
|
|
3
3
|
import { generateMatches } from '@bablr/regex-vm';
|
|
4
4
|
import { getStreamIterator, maybeWait, printType } from '@bablr/agast-helpers/stream';
|
|
5
|
-
import * as sumtree from '@bablr/agast-helpers/
|
|
5
|
+
import * as sumtree from '@bablr/agast-helpers/children';
|
|
6
6
|
import * as l from '@bablr/agast-vm-helpers/languages';
|
|
7
7
|
import {
|
|
8
8
|
buildAlternative,
|
|
@@ -14,10 +14,14 @@ import {
|
|
|
14
14
|
} from '@bablr/helpers/builders';
|
|
15
15
|
import { buildEmbeddedRegex } from '@bablr/agast-vm-helpers/builders';
|
|
16
16
|
import { GapTag, LiteralTag } from '@bablr/agast-helpers/symbols';
|
|
17
|
+
import {
|
|
18
|
+
buildCloseNodeTag,
|
|
19
|
+
buildLiteralTag,
|
|
20
|
+
buildOpenNodeTag,
|
|
21
|
+
tokenFlags,
|
|
22
|
+
} from '@bablr/agast-helpers/builders';
|
|
17
23
|
|
|
18
24
|
export const assertValidRegex = (expr) => {
|
|
19
|
-
const { flags } = expr;
|
|
20
|
-
|
|
21
25
|
if (!expr.language === 'Spamex' && expr.type === 'Regex') {
|
|
22
26
|
throw new Error();
|
|
23
27
|
}
|
|
@@ -28,7 +32,7 @@ export const assertValidRegex = (expr) => {
|
|
|
28
32
|
const buildStringRegex = (str) => {
|
|
29
33
|
return buildPattern(
|
|
30
34
|
buildAlternatives([
|
|
31
|
-
buildAlternative(buildElements([...str].map((chr) => buildToken(
|
|
35
|
+
buildAlternative(buildElements([...str].map((chr) => buildToken('Character', chr)))),
|
|
32
36
|
]),
|
|
33
37
|
);
|
|
34
38
|
};
|
|
@@ -41,7 +45,7 @@ const buildFragmentRegex = (frag) => {
|
|
|
41
45
|
[...sumtree.traverse(frag.children)].flatMap((tag) => {
|
|
42
46
|
if (tag.type === LiteralTag) {
|
|
43
47
|
let str = tag.value;
|
|
44
|
-
return [...str].map((chr) => buildToken(
|
|
48
|
+
return [...str].map((chr) => buildToken('Character', chr));
|
|
45
49
|
} else if (tag.type === GapTag) {
|
|
46
50
|
return [buildRegexGap()];
|
|
47
51
|
} else {
|
|
@@ -54,7 +58,64 @@ const buildFragmentRegex = (frag) => {
|
|
|
54
58
|
);
|
|
55
59
|
};
|
|
56
60
|
|
|
61
|
+
const promiseCo = (gen) => {
|
|
62
|
+
return (...args) => {
|
|
63
|
+
let generator = gen(...args);
|
|
64
|
+
|
|
65
|
+
const fn = (step) => {
|
|
66
|
+
if (step.done) {
|
|
67
|
+
return step.value;
|
|
68
|
+
} else if (step.value instanceof Promise) {
|
|
69
|
+
return step.value.then((value) => {
|
|
70
|
+
return fn(generator.next(value));
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
return fn(generator.next());
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
function* __stringEqual(str, iterable) {
|
|
80
|
+
let strIter = str[Symbol.iterator]();
|
|
81
|
+
let iter = getStreamIterator(iterable);
|
|
82
|
+
|
|
83
|
+
let strStep = strIter.next();
|
|
84
|
+
let step = iter.next();
|
|
85
|
+
|
|
86
|
+
while (!strStep.done) {
|
|
87
|
+
if (step instanceof Promise) {
|
|
88
|
+
step = yield step;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (step.value !== strStep.value) {
|
|
92
|
+
iter.return();
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
strStep = strIter.next();
|
|
97
|
+
step = iter.next();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
iter.return();
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const stringEqual = (str, iterable) => {
|
|
105
|
+
return promiseCo(__stringEqual)(str, iterable);
|
|
106
|
+
};
|
|
107
|
+
|
|
57
108
|
export const match = (pattern, source) => {
|
|
109
|
+
if (typeof pattern === 'string' && pattern.length === 1) {
|
|
110
|
+
return pattern === source.value
|
|
111
|
+
? [buildOpenNodeTag(tokenFlags), buildLiteralTag(pattern), buildCloseNodeTag()]
|
|
112
|
+
: null;
|
|
113
|
+
} else if (typeof pattern === 'string') {
|
|
114
|
+
return stringEqual(pattern, source)
|
|
115
|
+
? [buildOpenNodeTag(tokenFlags), buildLiteralTag(pattern), buildCloseNodeTag()]
|
|
116
|
+
: null;
|
|
117
|
+
}
|
|
118
|
+
|
|
58
119
|
const pattern_ =
|
|
59
120
|
pattern.type === null && pattern.flags.token
|
|
60
121
|
? buildFragmentRegex(pattern)
|
|
@@ -72,6 +133,7 @@ export const match = (pattern, source) => {
|
|
|
72
133
|
|
|
73
134
|
return maybeWait(step, (step) => {
|
|
74
135
|
const result = step.done ? null : step.value[0];
|
|
136
|
+
iter.return();
|
|
75
137
|
return isEmpty(result) ? null : result;
|
|
76
138
|
});
|
|
77
139
|
};
|
|
@@ -79,28 +141,33 @@ export const match = (pattern, source) => {
|
|
|
79
141
|
class GuardedIterator {
|
|
80
142
|
constructor(pattern, source) {
|
|
81
143
|
this.pattern = pattern;
|
|
82
|
-
this.
|
|
144
|
+
this.source = source.branch();
|
|
83
145
|
this.done = false;
|
|
84
146
|
}
|
|
85
147
|
|
|
148
|
+
get value() {
|
|
149
|
+
return this.source.value;
|
|
150
|
+
}
|
|
151
|
+
|
|
86
152
|
next() {
|
|
87
|
-
const { pattern,
|
|
153
|
+
const { pattern, source } = this;
|
|
88
154
|
|
|
89
|
-
const guardMatch = match(pattern,
|
|
155
|
+
const guardMatch = match(pattern, source);
|
|
90
156
|
|
|
91
157
|
return maybeWait(guardMatch, (guardMatch) => {
|
|
92
|
-
if (guardMatch ||
|
|
158
|
+
if (guardMatch || source.done) {
|
|
93
159
|
this.done = true;
|
|
160
|
+
source.release();
|
|
94
161
|
return { value: undefined, done: true };
|
|
95
162
|
} else {
|
|
96
|
-
const { value } =
|
|
97
|
-
return maybeWait(
|
|
163
|
+
const { value } = source;
|
|
164
|
+
return maybeWait(source.advance(), (_) => ({ value, done: false }));
|
|
98
165
|
}
|
|
99
166
|
});
|
|
100
167
|
}
|
|
101
168
|
|
|
102
169
|
return() {
|
|
103
|
-
this.
|
|
170
|
+
this.source.release();
|
|
104
171
|
}
|
|
105
172
|
|
|
106
173
|
[Symbol.for('@@streamIterator')]() {
|
|
@@ -109,5 +176,5 @@ class GuardedIterator {
|
|
|
109
176
|
}
|
|
110
177
|
|
|
111
178
|
export const guardWithPattern = (pattern, source) => {
|
|
112
|
-
return new GuardedIterator(pattern, source
|
|
179
|
+
return new GuardedIterator(pattern, source);
|
|
113
180
|
};
|