@bablr/bablr-vm 0.21.0 → 0.22.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/node.js CHANGED
@@ -1,12 +1,14 @@
1
1
  import {
2
+ buildBindingTag,
2
3
  buildCloseNodeTag,
3
4
  buildGapTag,
4
5
  buildOpenNodeTag,
6
+ buildReferenceTag,
5
7
  buildStubNode,
6
8
  fragmentFlags,
7
9
  isNullNode,
8
10
  } from '@bablr/agast-helpers/tree';
9
- import { NullTag, OpenNodeTag, ReferenceTag } from '@bablr/agast-helpers/symbols';
11
+ import { NullTag, OpenNodeTag, PropertyWrapper, ReferenceTag } from '@bablr/agast-helpers/symbols';
10
12
  import {
11
13
  buildFullPathSegment,
12
14
  buildFullRange,
@@ -26,7 +28,7 @@ export const FragmentFacade = class BABLRFragmentFacade {
26
28
  node,
27
29
  context,
28
30
  transparent = false,
29
- childrenIndexRange = null,
31
+ tagsIndexRange = null,
30
32
  dotPropertyReference = null,
31
33
  dotPropertyIndex = null,
32
34
  ) {
@@ -37,7 +39,7 @@ export const FragmentFacade = class BABLRFragmentFacade {
37
39
  context,
38
40
  transparent,
39
41
  false,
40
- childrenIndexRange,
42
+ tagsIndexRange,
41
43
  dotPropertyReference,
42
44
  dotPropertyIndex,
43
45
  )
@@ -48,7 +50,7 @@ export const FragmentFacade = class BABLRFragmentFacade {
48
50
  node,
49
51
  context,
50
52
  transparent = false,
51
- childrenIndexRange = null,
53
+ tagsIndexRange = null,
52
54
  dotPropertyReference = null,
53
55
  dotPropertyIndex = null,
54
56
  ) {
@@ -59,7 +61,7 @@ export const FragmentFacade = class BABLRFragmentFacade {
59
61
  context,
60
62
  transparent,
61
63
  true,
62
- childrenIndexRange,
64
+ tagsIndexRange,
63
65
  dotPropertyReference,
64
66
  dotPropertyIndex,
65
67
  )
@@ -71,19 +73,20 @@ export const FragmentFacade = class BABLRFragmentFacade {
71
73
  context,
72
74
  transparent = false,
73
75
  isFragmentFacade = true,
74
- childrenIndexRange = null,
76
+ tagsIndexRange = null,
75
77
  dotPropertyReference = null,
76
78
  dotPropertyIndex = null,
77
79
  ) {
78
- if (!node || hasOwn(node, 'properties')) throw new Error();
80
+ if (!node || hasOwn(node, 'tags')) throw new Error();
81
+ if (isNaN(dotPropertyIndex)) throw new Error();
79
82
 
80
- if (childrenIndexRange && (childrenIndexRange[0] == null || !childrenIndexRange[1] == null)) {
83
+ if (tagsIndexRange && (tagsIndexRange[0] == null || !tagsIndexRange[1] == null)) {
81
84
  throw new Error();
82
85
  }
83
86
 
84
87
  if (!context) throw new Error();
85
88
 
86
- if (dotPropertyReference && !node.properties.at(dotPropertyReference.name)) throw new Error();
89
+ if (dotPropertyReference && !node.properties.get(dotPropertyReference.name)) throw new Error();
87
90
 
88
91
  if (dotPropertyReference?.isArray && dotPropertyIndex == null) throw new Error();
89
92
 
@@ -106,7 +109,7 @@ export const FragmentFacade = class BABLRFragmentFacade {
106
109
  fragmentNode,
107
110
  transparent,
108
111
  isFragmentFacade,
109
- childrenIndexRange,
112
+ tagsIndexRange,
110
113
  dotPropertyReference,
111
114
  dotPropertyIndex,
112
115
  });
@@ -127,18 +130,23 @@ export const FragmentFacade = class BABLRFragmentFacade {
127
130
  return node.sigilTag.type === NullTag;
128
131
  }
129
132
 
130
- get children() {
131
- let { node, isFragmentNode, transparent, childrenIndexRange } = states.get(this);
133
+ get tagsInner() {
134
+ let { node, isFragmentNode, transparent, tagsIndexRange } = states.get(this);
132
135
 
133
- childrenIndexRange =
134
- isFragmentNode || !childrenIndexRange ? buildFullRange(node) : childrenIndexRange;
136
+ tagsIndexRange = isFragmentNode || !tagsIndexRange ? buildFullRange(node) : tagsIndexRange;
135
137
 
136
138
  return {
137
139
  *[Symbol.iterator]() {
138
- for (let i = childrenIndexRange[0]; i <= childrenIndexRange[1]; i++) {
139
- const interpolated = false; // TODO
140
- if (!interpolated || transparent) {
141
- yield node.children.at(i);
140
+ for (let tag of node.tags) {
141
+ if (tag.type === PropertyWrapper) {
142
+ let { property, tags } = tag.value;
143
+ if (transparent || !property.reference.flags.hasGap) {
144
+ yield* tags;
145
+ } else {
146
+ yield buildReferenceTag(property.reference);
147
+ yield buildBindingTag();
148
+ yield buildGapTag();
149
+ }
142
150
  }
143
151
  }
144
152
  },
@@ -146,14 +154,14 @@ export const FragmentFacade = class BABLRFragmentFacade {
146
154
  }
147
155
 
148
156
  getRootIndex() {
149
- const { node, dotPropertyName, childrenIndexRange } = states.get(this);
157
+ const { node, dotPropertyName, tagsIndexRange } = states.get(this);
150
158
 
151
- if (!childrenIndexRange) return null;
159
+ if (!tagsIndexRange) return null;
152
160
 
153
- if (childrenIndexRange[0] > childrenIndexRange[1]) throw new Error();
161
+ if (tagsIndexRange[0] > tagsIndexRange[1]) throw new Error();
154
162
 
155
- for (let i = childrenIndexRange[0]; i <= childrenIndexRange[1]; i++) {
156
- let tag = node.children.at(i);
163
+ for (let i = tagsIndexRange[0]; i <= tagsIndexRange[1]; i++) {
164
+ let tag = node.tags.at(i);
157
165
  if (tag.type === ReferenceTag) {
158
166
  const { name, isArray } = tag.value;
159
167
  let resolvedTagName = name === '.' ? dotPropertyName : name;
@@ -191,21 +199,13 @@ export const FragmentFacade = class BABLRFragmentFacade {
191
199
  get openTag() {
192
200
  const { node, openTag, isFragmentFacade } = states.get(this);
193
201
 
194
- return isFragmentNode(node)
195
- ? node.children.at(1)
196
- : isFragmentFacade
197
- ? openTag
198
- : node.children.at(0);
202
+ return isFragmentNode(node) ? node.tags.at(1) : isFragmentFacade ? openTag : node.tags.at(0);
199
203
  }
200
204
 
201
205
  get closeTag() {
202
206
  const { node, closeTag, isFragmentFacade } = states.get(this);
203
207
 
204
- return isFragmentFacade
205
- ? isFragmentNode(node)
206
- ? node.closeTag
207
- : closeTag
208
- : node.children.at(-1);
208
+ return isFragmentFacade ? (isFragmentNode(node) ? node.closeTag : closeTag) : node.tags.at(-1);
209
209
  }
210
210
 
211
211
  merge(targetFragment) {
@@ -217,7 +217,7 @@ export const FragmentFacade = class BABLRFragmentFacade {
217
217
  dotPropertyReference,
218
218
  dotPropertyIndex,
219
219
  } = states.get(this);
220
- const { fragmentNode: targetFragmentNode, childrenIndexRange: targetChildrenIndexRange } =
220
+ const { fragmentNode: targetFragmentNode, tagsIndexRange: targetTagsIndexRange } =
221
221
  states.get(targetFragment);
222
222
  if (fragmentNode === targetFragmentNode) {
223
223
  // TODO restrict what is legal here
@@ -227,7 +227,7 @@ export const FragmentFacade = class BABLRFragmentFacade {
227
227
  context,
228
228
  transparent,
229
229
  isFragmentFacade,
230
- targetChildrenIndexRange,
230
+ targetTagsIndexRange,
231
231
  dotPropertyReference,
232
232
  dotPropertyIndex,
233
233
  );
@@ -242,7 +242,7 @@ export const FragmentFacade = class BABLRFragmentFacade {
242
242
  context,
243
243
  transparent,
244
244
  isFragmentFacade,
245
- childrenIndexRange,
245
+ tagsIndexRange,
246
246
  dotPropertyReference: dotReference,
247
247
  dotPropertyIndex: dotIndex,
248
248
  } = states.get(this);
@@ -269,15 +269,17 @@ export const FragmentFacade = class BABLRFragmentFacade {
269
269
  }
270
270
 
271
271
  if (!node) break;
272
- let refIndex = outerNode.getPropertyChildrenIndex(null, seg.name, seg.index);
273
- childrenIndexRange = [refIndex, refIndex + 2];
272
+ let refIndex = outerNode.getPropertyTagsIndex(null, seg.name, seg.index);
273
+ tagsIndexRange = [refIndex, refIndex];
274
274
 
275
275
  let boundRef = outerNode.properties.referenceAt(seg.name, seg.index);
276
276
 
277
277
  if (!node) return null;
278
278
 
279
+ let arraySize = outerNode.countList(seg.name);
280
+
279
281
  ref = boundRef;
280
- index = seg.index === -1 ? outerNode.properties.at(seg.name).size + seg.index : seg.index;
282
+ index = seg.index < 0 ? arraySize + seg.index : seg.index;
281
283
 
282
284
  node =
283
285
  (ref && ref.type === ReferenceTag && !ref.flags.hasGap) || transparent
@@ -292,7 +294,7 @@ export const FragmentFacade = class BABLRFragmentFacade {
292
294
  context,
293
295
  transparent,
294
296
  isFragmentFacade,
295
- childrenIndexRange,
297
+ tagsIndexRange,
296
298
  ref,
297
299
  index,
298
300
  );
@@ -310,7 +312,7 @@ export const FragmentFacade = class BABLRFragmentFacade {
310
312
  for (let i = 0; i < path_.length; i++) {
311
313
  if (!node.properties.has(path_[i])) return false;
312
314
  if (i < path.length - 1) {
313
- node = node.properties.at(path_[i]);
315
+ node = node.properties.get(path_[i]);
314
316
  }
315
317
  }
316
318
 
package/lib/source.js CHANGED
@@ -1,12 +1,6 @@
1
- import { maybeWait, getStreamIterator, StreamIterable } from '@bablr/agast-helpers/stream';
1
+ import { maybeWait, getStreamIterator } from '@bablr/agast-helpers/stream';
2
2
  import { facades, actuals } from './facades.js';
3
-
4
- function* __concat(...iterables) {
5
- for (let iter of iterables) {
6
- yield* getStreamIterator(iter);
7
- }
8
- }
9
- const concat = (...iterables) => new StreamIterable(__concat(...iterables));
3
+ import { streamIteratorSymbol } from '@bablr/stream-iterator';
10
4
 
11
5
  // Queue item instances are shared between all sources.
12
6
  class QueueItem {
@@ -35,9 +29,9 @@ class Exchange {
35
29
  }
36
30
 
37
31
  allocateSource(source) {
38
- const { head = this.tail, exchange = this, index, holding } = source || {};
32
+ const { head = this.tail, exchange = this, index, holding, prevValue } = source || {};
39
33
  ++this.sources;
40
- return new Source(head, exchange, index, holding);
34
+ return new Source(head, exchange, index, holding, prevValue);
41
35
  }
42
36
 
43
37
  releaseSource(source) {
@@ -108,7 +102,7 @@ class SourceIterator {
108
102
  return this;
109
103
  }
110
104
 
111
- [Symbol.for('@@streamIterator')]() {
105
+ [streamIteratorSymbol]() {
112
106
  return this;
113
107
  }
114
108
  }
@@ -124,8 +118,8 @@ export const SourceFacade = class BABLRSourceFacade {
124
118
  Object.freeze(this);
125
119
  }
126
120
 
127
- [Symbol.for('@@streamIterator')]() {
128
- return actuals.get(this)[Symbol.for('@@streamIterator')]();
121
+ [streamIteratorSymbol]() {
122
+ return actuals.get(this)[streamIteratorSymbol]();
129
123
  }
130
124
 
131
125
  get done() {
@@ -151,13 +145,14 @@ export const Source = class BABLRSource {
151
145
  return exchange.allocateSource();
152
146
  }
153
147
 
154
- constructor(head, exchange, index = -1, holding = false) {
148
+ constructor(head, exchange, index = -1, holding = false, prevValue = undefined) {
155
149
  if (!head || !exchange) throw new Error();
156
150
 
157
151
  this.head = head;
158
152
  this.exchange = exchange;
159
153
  this.index = index;
160
154
  this.holding = holding;
155
+ this.prevValue = prevValue;
161
156
 
162
157
  new SourceFacade(this);
163
158
  }
@@ -195,7 +190,7 @@ export const Source = class BABLRSource {
195
190
  if (this.done) {
196
191
  throw new Error('cannot advance a source that is done');
197
192
  } else {
198
- let { head } = this;
193
+ let { head, value } = this;
199
194
 
200
195
  let nextItem = head.next;
201
196
 
@@ -205,6 +200,7 @@ export const Source = class BABLRSource {
205
200
  }
206
201
 
207
202
  this.head = head = nextItem;
203
+ this.prevValue = value;
208
204
 
209
205
  if (head.step?.done) {
210
206
  exchange.releaseSource(this);
@@ -240,6 +236,7 @@ export const Source = class BABLRSource {
240
236
  this.head = source.head;
241
237
  this.index = source.index;
242
238
  this.holding = source.holding;
239
+ this.prevValue = source.prevValue;
243
240
 
244
241
  source.release();
245
242
  }
@@ -252,7 +249,7 @@ export const Source = class BABLRSource {
252
249
  return SourceIterator.from(this);
253
250
  }
254
251
 
255
- [Symbol.for('@@streamIterator')]() {
252
+ [streamIteratorSymbol]() {
256
253
  return SourceIterator.from(this);
257
254
  }
258
255
 
package/lib/spans.js CHANGED
@@ -1,15 +1,12 @@
1
1
  import { ReferenceTag } from '@bablr/agast-helpers/symbols';
2
- import { getOpenTag } from '@bablr/agast-helpers/tree';
3
2
 
4
3
  export function updateSpans(m, node, phase) {
5
4
  const { state: s } = m;
6
- const { flags, attributes } = node;
5
+ const { attributes } = node;
7
6
  const refPath = m.reference;
8
7
 
9
8
  if (refPath && refPath.tag.type !== ReferenceTag) throw new Error();
10
9
 
11
- const openTag = getOpenTag(node);
12
-
13
10
  const intrinsic = !refPath || (refPath.tag.type === ReferenceTag && !refPath.tag.value.hasGap);
14
11
 
15
12
  switch (phase) {
package/lib/state.js CHANGED
@@ -1,16 +1,13 @@
1
- import {
2
- agast as createAgast,
3
- TagPathFacade as TagPath,
4
- PathFacade as Path,
5
- } from '@bablr/agast-vm';
1
+ import { agast as createAgast, TagPathFacade as TagPath } from '@bablr/agast-vm';
6
2
  import emptyStack from '@iter-tools/imm-stack';
7
3
  import { WeakStackFrame } from '@bablr/weak-stack';
8
4
  import { getCooked, maybeWait } from '@bablr/agast-helpers/stream';
5
+ import * as Tags from '@bablr/agast-helpers/tags';
9
6
  import { reifyExpression } from '@bablr/agast-vm-helpers';
10
7
  import {
11
- EmbeddedMatcher,
12
- EmbeddedNode,
13
- EmbeddedRegex,
8
+ Matcher,
9
+ Node,
10
+ Regex,
14
11
  GapTag,
15
12
  InitializerTag,
16
13
  OpenNodeTag,
@@ -18,6 +15,7 @@ import {
18
15
  ShiftTag,
19
16
  Property,
20
17
  BindingTag,
18
+ PropertyWrapper,
21
19
  } from '@bablr/agast-vm-helpers/symbols';
22
20
  import {
23
21
  buildBindingTag,
@@ -25,13 +23,17 @@ import {
25
23
  buildInitializerTag,
26
24
  buildNullNode,
27
25
  buildProperty,
26
+ buildPropertyWrapper,
27
+ buildReferenceTag,
28
+ getOr,
29
+ multiFragmentFlags,
28
30
  } from '@bablr/agast-helpers/tree';
29
31
  import { match, guardWithPattern } from './utils/pattern.js';
30
32
  import { facades, actuals } from './facades.js';
31
33
  import { FragmentFacade } from './node.js';
32
- import { buildFullPathSegment } from '@bablr/agast-helpers/path';
34
+ import { wrapperIsFull } from '@bablr/agast-helpers/path';
33
35
 
34
- const { hasOwn, freeze } = Object;
36
+ const { freeze } = Object;
35
37
 
36
38
  export const nodeStates = new WeakMap();
37
39
 
@@ -61,8 +63,8 @@ export const StateFacade = class BABLRStateFacade {
61
63
  return actuals.get(this).result;
62
64
  }
63
65
 
64
- get reference() {
65
- return actuals.get(this).reference;
66
+ get referenceTag() {
67
+ return actuals.get(this).referenceTag;
66
68
  }
67
69
 
68
70
  get referenceTagPath() {
@@ -77,11 +79,6 @@ export const StateFacade = class BABLRStateFacade {
77
79
  return actuals.get(this).holding;
78
80
  }
79
81
 
80
- // FACADEME
81
- get path() {
82
- return actuals.get(this).path;
83
- }
84
-
85
82
  get language() {
86
83
  return actuals.get(this).language;
87
84
  }
@@ -164,7 +161,12 @@ export const State = class BABLRState extends WeakStackFrame {
164
161
  }
165
162
 
166
163
  static from(source, context, language, expressions = []) {
167
- return State.create(source, context, language, emptyStack.push(...expressions));
164
+ return State.create(
165
+ source,
166
+ context,
167
+ language,
168
+ emptyStack.push(...emptyStack.push(...expressions).valuesReverse()),
169
+ );
168
170
  }
169
171
 
170
172
  get node() {
@@ -182,7 +184,7 @@ export const State = class BABLRState extends WeakStackFrame {
182
184
  let referenceTagPath = previousSibling;
183
185
 
184
186
  if (isShift) {
185
- let refIndex = previousSibling.childrenIndex - 1 - previousSibling.tag.value.index * 3;
187
+ let refIndex = previousSibling.tagsIndex - 1 - previousSibling.tag.value.index * 3;
186
188
  referenceTagPath = previousSibling.siblingAt(refIndex);
187
189
  }
188
190
  return referenceTagPath;
@@ -200,7 +202,7 @@ export const State = class BABLRState extends WeakStackFrame {
200
202
  }
201
203
 
202
204
  get path() {
203
- throw new Error('not implemented');
205
+ return this.agast?.state.path;
204
206
  }
205
207
 
206
208
  get result() {
@@ -215,7 +217,7 @@ export const State = class BABLRState extends WeakStackFrame {
215
217
  return !!this.held;
216
218
  }
217
219
 
218
- get reference() {
220
+ get referenceTag() {
219
221
  return this.referenceTagPath?.tag;
220
222
  }
221
223
 
@@ -227,39 +229,26 @@ export const State = class BABLRState extends WeakStackFrame {
227
229
  return !!this.parent;
228
230
  }
229
231
 
230
- guardedMatch(pattern) {
232
+ guardedMatch(pattern, attributes = {}) {
231
233
  let { span, source } = this;
232
234
  let { guard } = span;
233
235
 
234
236
  let pattern_ = pattern;
235
- if (pattern.type === EmbeddedMatcher) {
237
+ if (pattern.type === Matcher) {
236
238
  pattern_ = reifyExpression(pattern.value).nodeMatcher;
237
- } else if (pattern.type === EmbeddedRegex || pattern.type === EmbeddedNode) {
239
+ } else if (pattern.type === Regex || pattern.type === Node) {
238
240
  pattern_ = pattern.value;
239
241
  } else if (typeof pattern !== 'string') {
240
242
  throw new Error();
241
243
  }
242
244
 
243
- let openNode =
244
- this.resultPath.tag.type === OpenNodeTag && this.resultPath.tag.value.flags.token
245
- ? this.resultPath.node
246
- : typeof pattern_ === 'string'
247
- ? null
248
- : pattern_;
249
-
250
- if (
251
- span.type === 'Lexical' &&
252
- openNode &&
253
- (openNode.flags.token
254
- ? openNode.attributes.balancer || openNode.attributes.balanced
255
- : openNode.attributes?.balancer)
256
- ) {
245
+ if (span.type === 'Lexical' && attributes.balancer) {
257
246
  // also check that the open node starts a lexical span?
258
247
  guard = null;
259
248
  }
260
249
 
261
- if (pattern_?.intrinsicValue) {
262
- pattern_ = pattern_.intrinsicValue || getCooked(pattern_.children);
250
+ if (pattern_?.literalValue) {
251
+ pattern_ = pattern_.literalValue || getCooked(pattern_.tags);
263
252
 
264
253
  if (pattern_.type === Symbol.for('String')) {
265
254
  pattern_ = reifyExpression(pattern_);
@@ -301,27 +290,29 @@ export const State = class BABLRState extends WeakStackFrame {
301
290
 
302
291
  let newAgast = createAgast(agast.options);
303
292
 
304
- for (let tagPath = TagPath.fromNode(node, 0); tagPath; tagPath = tagPath.nextSibling) {
305
- let { tag } = tagPath;
306
-
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),
293
+ let fragRefTag = buildReferenceTag('_', null, false, multiFragmentFlags);
294
+
295
+ if (node.tags.openTag) newAgast.vm.next(node.tags.openTag);
296
+ if (node.tags.childrenNode) {
297
+ let property = buildProperty(fragRefTag.value, null, node.tags.childrenNode);
298
+ newAgast.vm.next(
299
+ buildChild(
300
+ PropertyWrapper,
301
+ buildPropertyWrapper(
302
+ [fragRefTag, buildBindingTag(), buildChild(Property, property)],
303
+ property,
312
304
  ),
313
- );
314
- } else {
315
- newAgast.vm.next(tag);
316
- }
305
+ ),
306
+ );
317
307
  }
308
+ if (node.tags.closeTag) newAgast.vm.next(node.tags.closeTag);
318
309
 
319
310
  let newNode = newAgast.state.node;
320
311
  let nodeState = nodeStates.get(node);
321
312
  let newResultPath;
322
313
 
323
314
  if (resultPath.path.node === node) {
324
- newResultPath = TagPath.fromNode(newNode, resultPath.childrenIndex);
315
+ newResultPath = TagPath.fromNode(newNode, resultPath.tagsIndex);
325
316
  } else {
326
317
  newResultPath = resultPath;
327
318
  }
@@ -357,14 +348,30 @@ export const State = class BABLRState extends WeakStackFrame {
357
348
  }
358
349
 
359
350
  if (parent.depths.path === accepted.depths.path) {
360
- let parentChildren = parent.node.children;
351
+ let parentChildren = parent.node.tags;
361
352
 
362
353
  if (parent.node.type !== accepted.node.type) throw new Error();
363
354
 
364
- for (let i = parentChildren.size; i < accepted.node.children.size; i++) {
365
- let tag = accepted.node.children.at(i);
355
+ let lastParentProp = parentChildren.at(-1);
356
+
357
+ let partialOffset =
358
+ lastParentProp.type === PropertyWrapper && !wrapperIsFull(lastParentProp) ? -1 : 0;
366
359
 
367
- parent.agast.vm.next(tag);
360
+ for (let i = parentChildren.size + partialOffset; i < accepted.node.tags.size; i++) {
361
+ let acceptedTag = accepted.node.tags.at(i);
362
+ let tag = parentChildren.at(i);
363
+
364
+ // let wrapperTag =
365
+
366
+ for (
367
+ let i = tag ? Tags.getSize(tag.value.tags) : 0;
368
+ i < Tags.getSize(acceptedTag.value.tags);
369
+ i++
370
+ ) {
371
+ let tag = Tags.getAt(i, acceptedTag.value.tags);
372
+
373
+ parent.agast.vm.next(tag);
374
+ }
368
375
  }
369
376
  }
370
377
 
@@ -377,7 +384,7 @@ export const State = class BABLRState extends WeakStackFrame {
377
384
  parent.expressions = accepted.expressions;
378
385
 
379
386
  if (parent.depths.result + 1 === accepted.depths.result) {
380
- parent.resultPath = parent.resultPath.siblingAt(accepted.resultPath.childrenIndex);
387
+ parent.resultPath = parent.resultPath.siblingAt(accepted.resultPath.tagsIndex);
381
388
  } else {
382
389
  parent.resultPath = accepted.resultPath;
383
390
  }
@@ -406,10 +413,9 @@ export const State = class BABLRState extends WeakStackFrame {
406
413
  : this.parent;
407
414
 
408
415
  if (!abandon && shallower) {
409
- let parentChildren = shallower.node.children;
410
- let ourChildren = finishedMatch.fragmentNode.children;
416
+ let parentChildren = shallower.node.tags;
417
+ let ourChildren = finishedMatch.fragmentNode.tags;
411
418
  let refTag;
412
- let bindTag;
413
419
 
414
420
  if (shallower.node.type) {
415
421
  if (shallower.node.type !== rejectedState.node.type) throw new Error();
@@ -417,51 +423,52 @@ export const State = class BABLRState extends WeakStackFrame {
417
423
  for (let i = parentChildren.size; i < ourChildren.size; i++) {
418
424
  let tag = ourChildren.at(i);
419
425
 
420
- if (tag.type === ReferenceTag) {
421
- refTag = tag;
422
- }
423
- if (tag.type === BindingTag) {
424
- bindTag = tag;
425
- }
426
-
427
- if ([InitializerTag, GapTag].includes(tag.type)) {
428
- let previousSibling = ourChildren.at(i - 1);
429
- let isShift = previousSibling.type === ShiftTag;
430
-
431
- let reference = previousSibling;
432
-
433
- if (isShift) {
434
- let refIndex = i - 1 - previousSibling.value.index * 3;
435
- reference = ourChildren.at(refIndex);
436
- }
437
-
438
- if (
439
- !['#', '@'].includes(reference.value.type) &&
440
- !reference.value.isArray &&
441
- !hasOwn(shallower.node.properties, reference.value.name) &&
442
- refTag !== ShiftTag
443
- ) {
444
- if (refTag !== ReferenceTag) {
445
- shallower.agast.vm.next(refTag);
426
+ if (tag.type === PropertyWrapper) {
427
+ for (let wrappedTag of tag.value.tags) {
428
+ if (wrappedTag.type === ReferenceTag) {
429
+ refTag = wrappedTag;
446
430
  }
447
431
 
448
- if (bind || tag.type === GapTag) {
449
- shallower.agast.vm.next(
450
- buildChild(Property, buildProperty(refTag.value, null, buildNullNode())),
451
- );
452
- } else {
453
- shallower.agast.vm.next(tag);
432
+ if ([InitializerTag, GapTag].includes(wrappedTag.type)) {
433
+ let previousSibling = ourChildren.at(i, 0);
434
+ let isShift = previousSibling.type === ShiftTag;
435
+
436
+ let referenceTag = previousSibling;
437
+
438
+ if (isShift) {
439
+ let refIndex = i - 1 - previousSibling.value.index;
440
+ referenceTag = ourChildren.at(refIndex, 0);
441
+ }
442
+
443
+ if (
444
+ !['#', '@'].includes(referenceTag.value.type) &&
445
+ !referenceTag.value.isArray &&
446
+ getOr(0, referenceTag.value.name, shallower.node) === 0 &&
447
+ refTag !== ShiftTag
448
+ ) {
449
+ if (refTag !== ReferenceTag) {
450
+ shallower.agast.vm.next(refTag);
451
+ }
452
+
453
+ if (bind || wrappedTag.type === GapTag) {
454
+ shallower.agast.vm.next(
455
+ buildChild(Property, buildProperty(refTag.value, null, buildNullNode())),
456
+ );
457
+ } else {
458
+ shallower.agast.vm.next(wrappedTag);
459
+ }
460
+ }
461
+ refTag = null;
454
462
  }
455
463
  }
456
- refTag = null;
457
464
  }
458
465
  }
459
466
 
460
467
  if (refTag?.type === ReferenceTag) {
461
468
  if (
462
- !['#', '@'].includes(refTag.value.type) &&
469
+ refTag.value.name &&
463
470
  !refTag.value.isArray &&
464
- !hasOwn(shallower.node.properties, refTag.value.name)
471
+ !shallower.node.properties.has(refTag.value.name)
465
472
  ) {
466
473
  if (bind) {
467
474
  shallower.agast.vm.next(refTag);