@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/state.js CHANGED
@@ -3,26 +3,32 @@ import { WeakStackFrame } from '@bablr/weak-stack';
3
3
  import { getCooked } from '@bablr/agast-helpers/stream';
4
4
  import { reifyExpression } from '@bablr/agast-vm-helpers';
5
5
  import {
6
+ CloseNodeTag,
6
7
  EmbeddedMatcher,
7
8
  EmbeddedNode,
8
9
  EmbeddedRegex,
9
10
  GapTag,
11
+ InitializerTag,
12
+ OpenNodeTag,
10
13
  ReferenceTag,
11
14
  ShiftTag,
12
- } from '@bablr/agast-helpers/symbols';
15
+ } from '@bablr/agast-vm-helpers/symbols';
13
16
  import * as btree from '@bablr/agast-helpers/btree';
17
+ import * as sumtree from '@bablr/agast-helpers/sumtree';
14
18
  import {
15
- buildCall,
16
- buildEmbeddedRegex,
17
- buildEmbeddedTag,
18
19
  buildGapTag,
20
+ buildInitializerTag,
21
+ buildNullNode,
19
22
  buildReferenceTag,
20
23
  buildStubNode,
21
24
  } from '@bablr/agast-helpers/tree';
22
- import { get, Path, PathResolver, TagPath, updatePath } from '@bablr/agast-helpers/path';
25
+ import { getShifted, TagPath } from '@bablr/agast-helpers/path';
23
26
  import { match, guardWithPattern } from './utils/pattern.js';
24
27
  import { facades, actuals } from './facades.js';
25
28
  import { buildInternalState, FragmentFacade, internalStates } from './node.js';
29
+ import { buildCall, buildEmbeddedTag } from '@bablr/agast-vm-helpers/builders';
30
+
31
+ const { hasOwn } = Object;
26
32
 
27
33
  export const nodeStates = new WeakMap();
28
34
 
@@ -47,6 +53,10 @@ export const StateFacade = class BABLRStateFacade {
47
53
  return actuals.get(this).resultPath;
48
54
  }
49
55
 
56
+ get result() {
57
+ return actuals.get(this).result;
58
+ }
59
+
50
60
  get reference() {
51
61
  return actuals.get(this).reference;
52
62
  }
@@ -55,6 +65,10 @@ export const StateFacade = class BABLRStateFacade {
55
65
  return actuals.get(this).referencePath;
56
66
  }
57
67
 
68
+ get unshiftedReferencePath() {
69
+ return actuals.get(this).unshiftedReferencePath;
70
+ }
71
+
58
72
  get holding() {
59
73
  return actuals.get(this).holding;
60
74
  }
@@ -63,17 +77,26 @@ export const StateFacade = class BABLRStateFacade {
63
77
  return actuals.get(this).path;
64
78
  }
65
79
 
80
+ get language() {
81
+ return actuals.get(this).language;
82
+ }
83
+
66
84
  get depths() {
67
85
  const { path, result } = actuals.get(this).depths;
68
86
  return { path, result };
69
87
  }
70
88
 
89
+ get held() {
90
+ const { held } = actuals.get(this);
91
+ return held && FragmentFacade.wrapNode(held, this.ctx);
92
+ }
93
+
71
94
  get node() {
72
- return FragmentFacade.wrap(actuals.get(this).node, this.ctx);
95
+ return FragmentFacade.wrapNode(actuals.get(this).node, this.ctx);
73
96
  }
74
97
 
75
98
  get parentNode() {
76
- return FragmentFacade.wrap(actuals.get(this).parentNode, this.ctx);
99
+ return FragmentFacade.wrapNode(actuals.get(this).parentNode, this.ctx);
77
100
  }
78
101
 
79
102
  get source() {
@@ -102,6 +125,7 @@ export const State = class BABLRState extends WeakStackFrame {
102
125
  parent,
103
126
  source,
104
127
  context,
128
+ language,
105
129
  expressions = emptyStack,
106
130
  balanced = emptyStack,
107
131
  spans = emptyStack.push({ name: 'Bare' }),
@@ -117,6 +141,7 @@ export const State = class BABLRState extends WeakStackFrame {
117
141
 
118
142
  this.source = source;
119
143
  this.context = context;
144
+ this.language = language;
120
145
  this.expressions = expressions;
121
146
  this.balanced = balanced;
122
147
  this.spans = spans;
@@ -133,12 +158,29 @@ export const State = class BABLRState extends WeakStackFrame {
133
158
  new StateFacade(this);
134
159
  }
135
160
 
136
- static from(source, context, expressions = []) {
137
- return State.create(source, context, emptyStack.push(...expressions));
161
+ static from(source, context, language, expressions = []) {
162
+ return State.create(source, context, language, emptyStack.push(...expressions));
138
163
  }
139
164
 
140
- get unboundAttributes() {
141
- return nodeStates.get(this.node).unboundAttributes;
165
+ get unshiftedReferencePath() {
166
+ let refPath = this.referencePath;
167
+
168
+ if (!refPath) return null;
169
+
170
+ let { previousSibling } = refPath;
171
+ let isShift = previousSibling.tag.type === ShiftTag;
172
+
173
+ let referencePath = previousSibling;
174
+
175
+ if (isShift) {
176
+ let refIndex = previousSibling.childrenIndex - 1 - previousSibling.tag.value.index * 2;
177
+ referencePath = previousSibling.siblingAt(refIndex);
178
+ }
179
+ return referencePath;
180
+ }
181
+
182
+ get undefinedAttributes() {
183
+ return nodeStates.get(this.node).undefinedAttributes;
142
184
  }
143
185
 
144
186
  get guardedSource() {
@@ -156,6 +198,10 @@ export const State = class BABLRState extends WeakStackFrame {
156
198
  throw new Error('not implemented');
157
199
  }
158
200
 
201
+ get result() {
202
+ return this.resultPath.tag;
203
+ }
204
+
159
205
  get parentNode() {
160
206
  throw new Error('not implemented');
161
207
  }
@@ -188,6 +234,9 @@ export const State = class BABLRState extends WeakStackFrame {
188
234
  instructionsPump.queue(buildCall('advance', buildEmbeddedTag(tag)));
189
235
  agast.next();
190
236
 
237
+ if (tag.type === OpenNodeTag) this.depths.result++;
238
+ if (tag.type === CloseNodeTag) this.depths.result--;
239
+
191
240
  this.resultPath = TagPath.from(path, -1);
192
241
  }
193
242
 
@@ -198,30 +247,31 @@ export const State = class BABLRState extends WeakStackFrame {
198
247
  let pattern_ = pattern;
199
248
  if (pattern.type === EmbeddedMatcher) {
200
249
  pattern_ = reifyExpression(pattern.value).nodeMatcher;
201
- } else if (pattern.type === EmbeddedRegex) {
250
+ } else if (pattern.type === EmbeddedRegex || pattern.type === EmbeddedNode) {
202
251
  pattern_ = pattern.value;
203
252
  } else if (typeof pattern !== 'string') {
204
253
  throw new Error();
205
254
  }
206
255
 
256
+ let openNode =
257
+ this.resultPath.tag.type === OpenNodeTag && this.resultPath.tag.value.flags.token
258
+ ? this.resultPath.node
259
+ : typeof pattern_ === 'string'
260
+ ? null
261
+ : pattern_;
262
+
207
263
  if (
208
264
  span.type === 'Lexical' &&
209
- pattern.type === EmbeddedMatcher &&
210
- (pattern_.flags.token
211
- ? pattern_.attributes.balancer || pattern_.attributes.balanced
212
- : pattern_.attributes?.balancer)
265
+ openNode &&
266
+ (openNode.flags.token
267
+ ? openNode.attributes.balancer || openNode.attributes.balanced
268
+ : openNode.attributes?.balancer)
213
269
  ) {
214
270
  // also check that the open node starts a lexical span?
215
271
  guard = null;
216
272
  }
217
273
 
218
274
  if (pattern_?.intrinsicValue) {
219
- // if (pattern.type === OpenNodeTag) {
220
-
221
- // // TODO differntiate better between self-closing tags and matchers
222
- // pattern = pattern.value;
223
- // }
224
-
225
275
  pattern_ = pattern_.intrinsicValue || getCooked(pattern_.children);
226
276
 
227
277
  if (pattern_.type === Symbol.for('String')) {
@@ -248,31 +298,35 @@ export const State = class BABLRState extends WeakStackFrame {
248
298
  referencePath,
249
299
  held,
250
300
  node,
301
+ language,
251
302
  expressions,
252
303
  } = baseState;
253
304
 
254
- let resolver = new PathResolver();
255
-
256
305
  const internalState = buildInternalState();
257
306
 
258
- for (let tag of btree.traverse(node.children)) {
307
+ for (let tagPath = TagPath.fromNode(node, 0); tagPath; tagPath = tagPath.nextSibling) {
308
+ let { tag } = tagPath;
309
+
259
310
  if (tag.type === GapTag) {
260
- let { name, isArray, flags } = resolver.reference.value;
311
+ let ref = tagPath.previousSibling.tag;
312
+ let firstRef =
313
+ ref.type === ShiftTag
314
+ ? tagPath.siblingAt(tagPath.childrenIndex - ref.value.index * 2 - 1)
315
+ : ref;
316
+ let { name, isArray, flags } = firstRef.value;
261
317
  const resolvedPath = buildReferenceTag(
262
318
  name,
263
319
  isArray,
264
320
  flags,
265
- Number.isFinite(resolver.counters[name]) ? resolver.counters[name] : null,
321
+ isArray ? btree.getSize(internalState.path.node.properties[name]) : null,
266
322
  );
267
- const expr = get(resolvedPath, node);
323
+ const expr = getShifted(ref.value.index || 0, resolvedPath, node);
268
324
  internalState.expressionsPump.queue(expr);
269
325
  } else if (tag.type === EmbeddedNode) {
270
326
  internalState.expressionsPump.queue(tag.value);
271
327
  tag = buildGapTag();
272
328
  }
273
329
 
274
- resolver.advance(tag);
275
-
276
330
  internalState.instructionsPump.queue(buildCall('advance', buildEmbeddedTag(tag)));
277
331
  internalState.agast.next();
278
332
  }
@@ -282,7 +336,7 @@ export const State = class BABLRState extends WeakStackFrame {
282
336
  let newResultPath;
283
337
 
284
338
  if (resultPath.path.node === node) {
285
- newResultPath = TagPath.from(Path.from(newNode), resultPath.childrenIndex);
339
+ newResultPath = TagPath.fromNode(newNode, resultPath.childrenIndex);
286
340
  } else {
287
341
  newResultPath = resultPath;
288
342
  }
@@ -293,12 +347,13 @@ export const State = class BABLRState extends WeakStackFrame {
293
347
  const child = this.push(
294
348
  source.branch(),
295
349
  context,
350
+ language,
296
351
  expressions,
297
352
  balanced,
298
353
  spans,
299
354
  referencePath,
300
355
  newResultPath,
301
- depths,
356
+ { ...depths },
302
357
  held,
303
358
  newNode,
304
359
  );
@@ -317,41 +372,45 @@ export const State = class BABLRState extends WeakStackFrame {
317
372
  throw new Error('accepted the root state');
318
373
  }
319
374
 
320
- parent.spans = accepted.spans;
321
- parent.balanced = accepted.balanced;
322
- parent.referencePath = accepted.referencePath;
323
- parent.held = accepted.held;
324
- parent.depths = accepted.depths;
325
- parent.expressions = accepted.expressions;
326
- // do I need this condition?
327
375
  if (parent.depths.path === accepted.depths.path) {
328
376
  const parentChildren = parent.node.children;
329
- parent.node.children = parentChildren;
330
377
 
331
378
  const internalState = internalStates.get(parent.node);
332
379
  const { path: parentPath } = internalState;
333
- // FIXME
334
- // some `properties` are not copied
335
- for (let i = btree.getSum(parentChildren); i < btree.getSum(accepted.node.children); i++) {
336
- let tag = btree.getAt(i, accepted.node.children);
380
+
381
+ if (parent.node.type !== accepted.node.type) throw new Error();
382
+
383
+ for (
384
+ let i = sumtree.getSize(parentChildren);
385
+ i < sumtree.getSize(accepted.node.children);
386
+ i++
387
+ ) {
388
+ let tag = sumtree.getAt(i, accepted.node.children);
337
389
 
338
390
  if (tag.type === GapTag) {
339
- let referenceIdx = i;
340
- let reference;
341
- let isShift = btree.getAt(i - 1, accepted.node.children).type === ShiftTag;
391
+ let previousSibling = sumtree.getAt(i - 1, accepted.node.children);
392
+ let isShift = previousSibling.type === ShiftTag;
393
+ let reference = previousSibling;
342
394
 
343
- while (
344
- (reference = btree.getAt(--referenceIdx, accepted.node.children)).type !== ReferenceTag
345
- );
395
+ if (isShift) {
396
+ reference = sumtree.getAt(
397
+ i - 1 - previousSibling.value.index * 2,
398
+ accepted.node.children,
399
+ );
400
+ }
346
401
 
347
402
  let { name, isArray, flags } = reference.value;
348
403
  const resolvedPath = buildReferenceTag(
349
404
  name,
350
405
  isArray,
351
406
  flags,
352
- isArray ? btree.getSum(parentPath.node.properties[name]) - (isShift ? 1 : 0) : null,
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,
353
413
  );
354
- const expr = get(resolvedPath, accepted.node);
355
414
  internalState.expressionsPump.queue(expr);
356
415
  } else if (tag.type === EmbeddedNode) {
357
416
  internalState.expressionsPump.queue(tag.value);
@@ -360,16 +419,23 @@ export const State = class BABLRState extends WeakStackFrame {
360
419
 
361
420
  internalState.instructionsPump.queue(buildCall('advance', buildEmbeddedTag(tag)));
362
421
  internalState.agast.next();
363
-
364
- updatePath(parentPath, tag);
365
422
  }
366
423
  }
367
424
 
368
- if (parent.depths.result === accepted.depths.result + 1) {
369
- parent.resultPath = new TagPath(parent.resultPath.path, accepted.resultPath.childrenIndex);
425
+ parent.spans = accepted.spans;
426
+ parent.balanced = accepted.balanced;
427
+ parent.referencePath = accepted.referencePath;
428
+ parent.held = accepted.held;
429
+ parent.depths = accepted.depths;
430
+ parent.language = accepted.language;
431
+ parent.expressions = accepted.expressions;
432
+
433
+ if (parent.depths.result + 1 === accepted.depths.result) {
434
+ parent.resultPath = parent.resultPath.siblingAt(accepted.resultPath.childrenIndex);
370
435
  } else {
371
436
  parent.resultPath = accepted.resultPath;
372
437
  }
438
+ if (!parent.resultPath) throw new Error();
373
439
 
374
440
  nodeStates.set(parent.node, nodeStates.get(accepted.node));
375
441
 
@@ -378,22 +444,101 @@ export const State = class BABLRState extends WeakStackFrame {
378
444
  return parent;
379
445
  }
380
446
 
381
- reject() {
382
- const rejectedState = this;
383
- const { parent } = rejectedState;
447
+ reject(finishedMatch, options) {
448
+ let { bind = false } = options;
449
+ let rejectedState = this;
450
+
451
+ let didBranch = finishedMatch.s !== finishedMatch.parent.state;
452
+ let abandon =
453
+ (!finishedMatch.isNode && !didBranch) ||
454
+ finishedMatch.cover ||
455
+ finishedMatch.effects.success === 'none';
456
+ let shallower = finishedMatch.didShift ? finishedMatch.shiftMatch.state : this.parent;
457
+
458
+ if (shallower) {
459
+ let parentChildren = shallower.node.children;
460
+ let ourChildren = finishedMatch.fragmentNode.children;
461
+ let internalState = internalStates.get(shallower.node);
462
+
463
+ if (!abandon && shallower.node.type) {
464
+ if (shallower.node.type !== rejectedState.node.type) throw new Error();
465
+
466
+ for (let i = sumtree.getSize(parentChildren); i < sumtree.getSize(ourChildren); i++) {
467
+ let tag = sumtree.getAt(i, ourChildren);
468
+
469
+ if ([InitializerTag, GapTag].includes(tag.type)) {
470
+ let previousSibling = sumtree.getAt(i - 1, ourChildren);
471
+ let isShift = previousSibling.type === ShiftTag;
472
+
473
+ let reference = previousSibling;
474
+
475
+ if (isShift) {
476
+ let refIndex = i - 1 - previousSibling.value.index * 2;
477
+ reference = sumtree.getAt(refIndex, ourChildren);
478
+ }
479
+
480
+ let lastParentTag = TagPath.from(internalState.path, -1).tag.type;
481
+
482
+ if (
483
+ !['#', '@'].includes(reference.value.name) &&
484
+ !reference.value.isArray &&
485
+ !hasOwn(shallower.node.properties, reference.value.name) &&
486
+ lastParentTag !== ShiftTag
487
+ ) {
488
+ if (lastParentTag !== ReferenceTag) {
489
+ internalState.instructionsPump.queue(
490
+ buildCall('advance', buildEmbeddedTag(reference)),
491
+ );
492
+ internalState.agast.next();
493
+ }
494
+ if (bind || tag.type === GapTag) {
495
+ internalState.expressionsPump.queue(buildNullNode());
496
+ internalState.instructionsPump.queue(
497
+ buildCall('advance', buildEmbeddedTag(buildGapTag())),
498
+ );
499
+ } else {
500
+ internalState.instructionsPump.queue(buildCall('advance', buildEmbeddedTag(tag)));
501
+ }
502
+ internalState.agast.next();
503
+ }
504
+ }
505
+ }
506
+
507
+ let lastParentTagPath = TagPath.fromNode(shallower.node, -1);
508
+ if (lastParentTagPath?.tag.type === ReferenceTag) {
509
+ let ref = lastParentTagPath?.tag;
510
+ if (bind) {
511
+ internalState.expressionsPump.queue(buildNullNode());
512
+ internalState.instructionsPump.queue(
513
+ buildCall('advance', buildEmbeddedTag(buildGapTag())),
514
+ );
515
+ internalState.agast.next();
516
+ } else {
517
+ if (!ref.value.flags.expression) {
518
+ internalState.instructionsPump.queue(
519
+ buildCall('advance', buildEmbeddedTag(buildInitializerTag(ref.value.isArray))),
520
+ );
521
+ internalState.agast.next();
522
+ }
523
+ }
524
+ shallower.referencePath = null;
525
+ shallower.resultPath = TagPath.fromNode(shallower.node, -1);
526
+ }
527
+ }
528
+ }
384
529
 
385
530
  if (this.status === 'rejected') {
386
- return parent;
531
+ return shallower;
387
532
  }
388
533
 
389
534
  if (this.status !== 'active') throw new Error();
390
535
 
391
536
  this.status = 'rejected';
392
537
 
393
- if (!parent) throw new Error('rejected root state');
538
+ if (!shallower) throw new Error('rejected root state');
394
539
 
395
540
  rejectedState.source.reject();
396
541
 
397
- return parent;
542
+ return shallower;
398
543
  }
399
544
  };
@@ -2,15 +2,18 @@ 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/sumtree';
5
6
  import * as l from '@bablr/agast-vm-helpers/languages';
6
7
  import {
7
8
  buildAlternative,
8
9
  buildAlternatives,
9
10
  buildElements,
10
11
  buildPattern,
12
+ buildRegexGap,
11
13
  buildToken,
12
14
  } from '@bablr/helpers/builders';
13
- import { buildEmbeddedRegex } from '@bablr/agast-helpers/builders';
15
+ import { buildEmbeddedRegex } from '@bablr/agast-vm-helpers/builders';
16
+ import { GapTag, LiteralTag } from '@bablr/agast-helpers/symbols';
14
17
 
15
18
  export const assertValidRegex = (expr) => {
16
19
  const { flags } = expr;
@@ -30,8 +33,34 @@ const buildStringRegex = (str) => {
30
33
  );
31
34
  };
32
35
 
36
+ const buildFragmentRegex = (frag) => {
37
+ return buildPattern(
38
+ buildAlternatives([
39
+ buildAlternative(
40
+ buildElements(
41
+ [...sumtree.traverse(frag.children)].flatMap((tag) => {
42
+ if (tag.type === LiteralTag) {
43
+ let str = tag.value;
44
+ return [...str].map((chr) => buildToken(l.Regex, 'Character', chr));
45
+ } else if (tag.type === GapTag) {
46
+ return [buildRegexGap()];
47
+ } else {
48
+ return [];
49
+ }
50
+ }),
51
+ ),
52
+ ),
53
+ ]),
54
+ );
55
+ };
56
+
33
57
  export const match = (pattern, source) => {
34
- const pattern_ = isString(pattern) ? buildStringRegex(pattern) : pattern;
58
+ const pattern_ =
59
+ pattern.type === null && pattern.flags.token
60
+ ? buildFragmentRegex(pattern)
61
+ : isString(pattern)
62
+ ? buildStringRegex(pattern)
63
+ : pattern;
35
64
 
36
65
  if (printType(pattern_.type) !== 'Pattern') throw new Error();
37
66
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bablr/bablr-vm",
3
3
  "description": "A VM for parsing using BABLR languages",
4
- "version": "0.19.1",
4
+ "version": "0.20.0",
5
5
  "author": "Conrad Buck<conartist6@gmail.com>",
6
6
  "type": "module",
7
7
  "files": [
@@ -12,12 +12,12 @@
12
12
  },
13
13
  "sideEffects": false,
14
14
  "dependencies": {
15
- "@bablr/agast-helpers": "0.6.1",
16
- "@bablr/agast-vm": "0.7.1",
17
- "@bablr/agast-vm-helpers": "0.6.1",
15
+ "@bablr/agast-helpers": "0.7.0",
16
+ "@bablr/agast-vm": "0.8.0",
17
+ "@bablr/agast-vm-helpers": "0.7.0",
18
18
  "@bablr/coroutine": "0.1.0",
19
- "@bablr/helpers": "0.21.4",
20
- "@bablr/regex-vm": "0.10.1",
19
+ "@bablr/helpers": "0.22.0",
20
+ "@bablr/regex-vm": "0.11.0",
21
21
  "@bablr/weak-stack": "1.0.0",
22
22
  "@iter-tools/imm-stack": "1.1.0",
23
23
  "iter-tools-es": "7.5.3"