@bablr/bablr-vm 0.20.1 → 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,36 +1,34 @@
1
1
  import {
2
+ buildBindingTag,
2
3
  buildCloseNodeTag,
3
4
  buildGapTag,
4
5
  buildOpenNodeTag,
5
6
  buildReferenceTag,
6
7
  buildStubNode,
8
+ fragmentFlags,
7
9
  isNullNode,
8
- parseReference,
9
10
  } from '@bablr/agast-helpers/tree';
10
- import { getStreamIterator } from '@bablr/agast-helpers/stream';
11
- import { agast } from '@bablr/agast-vm';
12
- import * as sumtree from '@bablr/agast-helpers/sumtree';
13
- import { Pump } from './utils/pump.js';
14
- import { OpenNodeTag, ReferenceTag } from '@bablr/agast-helpers/symbols';
11
+ import { NullTag, OpenNodeTag, PropertyWrapper, ReferenceTag } from '@bablr/agast-helpers/symbols';
15
12
  import {
13
+ buildFullPathSegment,
16
14
  buildFullRange,
17
- get,
18
- getProperties,
19
- getPropertyChildrenIndex,
15
+ buildPathSegment,
16
+ buildTypePathSegment,
20
17
  } from '@bablr/agast-helpers/path';
21
- import { isArray } from '@bablr/helpers/object';
18
+ import { hasOwn, isArray } from '@bablr/helpers/object';
22
19
 
23
20
  export const states = new WeakMap();
24
- export const internalStates = new WeakMap();
25
21
 
26
- const { hasOwn } = Object;
22
+ export const isFragmentNode = (node) => {
23
+ return node.type === null && node.sigilTag.type === OpenNodeTag;
24
+ };
27
25
 
28
26
  export const FragmentFacade = class BABLRFragmentFacade {
29
27
  static wrapNode(
30
28
  node,
31
29
  context,
32
30
  transparent = false,
33
- childrenIndexRange = null,
31
+ tagsIndexRange = null,
34
32
  dotPropertyReference = null,
35
33
  dotPropertyIndex = null,
36
34
  ) {
@@ -41,7 +39,7 @@ export const FragmentFacade = class BABLRFragmentFacade {
41
39
  context,
42
40
  transparent,
43
41
  false,
44
- childrenIndexRange,
42
+ tagsIndexRange,
45
43
  dotPropertyReference,
46
44
  dotPropertyIndex,
47
45
  )
@@ -52,7 +50,7 @@ export const FragmentFacade = class BABLRFragmentFacade {
52
50
  node,
53
51
  context,
54
52
  transparent = false,
55
- childrenIndexRange = null,
53
+ tagsIndexRange = null,
56
54
  dotPropertyReference = null,
57
55
  dotPropertyIndex = null,
58
56
  ) {
@@ -63,7 +61,7 @@ export const FragmentFacade = class BABLRFragmentFacade {
63
61
  context,
64
62
  transparent,
65
63
  true,
66
- childrenIndexRange,
64
+ tagsIndexRange,
67
65
  dotPropertyReference,
68
66
  dotPropertyIndex,
69
67
  )
@@ -74,47 +72,49 @@ export const FragmentFacade = class BABLRFragmentFacade {
74
72
  node,
75
73
  context,
76
74
  transparent = false,
77
- isFragmentNode = true,
78
- childrenIndexRange = null,
75
+ isFragmentFacade = true,
76
+ tagsIndexRange = null,
79
77
  dotPropertyReference = null,
80
78
  dotPropertyIndex = null,
81
79
  ) {
82
- if (!node) throw new Error();
80
+ if (!node || hasOwn(node, 'tags')) throw new Error();
81
+ if (isNaN(dotPropertyIndex)) throw new Error();
83
82
 
84
- if (childrenIndexRange && (childrenIndexRange[0] == null || !childrenIndexRange[1] == null)) {
83
+ if (tagsIndexRange && (tagsIndexRange[0] == null || !tagsIndexRange[1] == null)) {
85
84
  throw new Error();
86
85
  }
87
86
 
88
87
  if (!context) throw new Error();
89
88
 
90
- if (dotPropertyReference && !hasOwn(node.properties, dotPropertyReference.value.name))
91
- throw new Error();
89
+ if (dotPropertyReference && !node.properties.get(dotPropertyReference.name)) throw new Error();
92
90
 
93
- if (isArray(dotPropertyReference?.value.isArray && dotPropertyIndex == null)) throw new Error();
91
+ if (dotPropertyReference?.isArray && dotPropertyIndex == null) throw new Error();
94
92
 
95
93
  let resolvedNode = node;
96
94
  let fragmentNode = node;
97
95
 
98
96
  if (dotPropertyReference) {
99
- let { name, isArray, flags } = dotPropertyReference.value;
97
+ let { type, name } = dotPropertyReference;
100
98
 
101
- let dotReference = buildReferenceTag(name, isArray, flags, dotPropertyIndex);
102
-
103
- resolvedNode = get(dotReference, fragmentNode);
99
+ resolvedNode = fragmentNode.get(buildFullPathSegment(type, name, dotPropertyIndex));
104
100
  }
105
101
 
102
+ if (dotPropertyReference?.value) throw new Error();
103
+
106
104
  states.set(this, {
107
105
  context,
108
- openTag: buildOpenNodeTag(),
106
+ openTag: buildOpenNodeTag(fragmentFlags),
109
107
  closeTag: buildCloseNodeTag(),
110
108
  node: resolvedNode,
111
- fragmentNode: node,
109
+ fragmentNode,
112
110
  transparent,
113
- isFragmentNode,
114
- childrenIndexRange,
111
+ isFragmentFacade,
112
+ tagsIndexRange,
115
113
  dotPropertyReference,
116
114
  dotPropertyIndex,
117
115
  });
116
+
117
+ Object.freeze(this);
118
118
  }
119
119
 
120
120
  get dotPropertyName() {
@@ -127,21 +127,26 @@ export const FragmentFacade = class BABLRFragmentFacade {
127
127
 
128
128
  get isNull() {
129
129
  let { node } = states.get(this);
130
- return isNullNode(node);
130
+ return node.sigilTag.type === NullTag;
131
131
  }
132
132
 
133
- get children() {
134
- let { node, isFragmentNode, transparent, childrenIndexRange } = states.get(this);
133
+ get tagsInner() {
134
+ let { node, isFragmentNode, transparent, tagsIndexRange } = states.get(this);
135
135
 
136
- childrenIndexRange =
137
- isFragmentNode || !childrenIndexRange ? buildFullRange(node) : childrenIndexRange;
136
+ tagsIndexRange = isFragmentNode || !tagsIndexRange ? buildFullRange(node) : tagsIndexRange;
138
137
 
139
138
  return {
140
139
  *[Symbol.iterator]() {
141
- for (let i = childrenIndexRange[0]; i <= childrenIndexRange[1]; i++) {
142
- const interpolated = false; // TODO
143
- if (!interpolated || transparent) {
144
- yield sumtree.getAt(i, node.children);
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
+ }
145
150
  }
146
151
  }
147
152
  },
@@ -149,14 +154,14 @@ export const FragmentFacade = class BABLRFragmentFacade {
149
154
  }
150
155
 
151
156
  getRootIndex() {
152
- const { node, dotPropertyName, childrenIndexRange } = states.get(this);
157
+ const { node, dotPropertyName, tagsIndexRange } = states.get(this);
153
158
 
154
- if (!childrenIndexRange) return null;
159
+ if (!tagsIndexRange) return null;
155
160
 
156
- if (childrenIndexRange[0] > childrenIndexRange[1]) throw new Error();
161
+ if (tagsIndexRange[0] > tagsIndexRange[1]) throw new Error();
157
162
 
158
- for (let i = childrenIndexRange[0]; i <= childrenIndexRange[1]; i++) {
159
- let tag = sumtree.getAt(i, node.children);
163
+ for (let i = tagsIndexRange[0]; i <= tagsIndexRange[1]; i++) {
164
+ let tag = node.tags.at(i);
160
165
  if (tag.type === ReferenceTag) {
161
166
  const { name, isArray } = tag.value;
162
167
  let resolvedTagName = name === '.' ? dotPropertyName : name;
@@ -171,41 +176,36 @@ export const FragmentFacade = class BABLRFragmentFacade {
171
176
  }
172
177
 
173
178
  get flags() {
174
- const { openTag } = this;
175
-
176
- return openTag.type === OpenNodeTag ? openTag.value.flags : null;
177
- }
178
-
179
- get language() {
180
- let { node, isFragmentNode } = states.get(this);
179
+ const { node } = states.get(this);
180
+ let openTag = node.sigilTag;
181
181
 
182
- return isFragmentNode ? null : node.language;
182
+ return openTag?.value.flags;
183
183
  }
184
184
 
185
185
  get type() {
186
- let { node, isFragmentNode } = states.get(this);
186
+ let { node } = states.get(this);
187
+ let openTag = node.sigilTag;
187
188
 
188
- return isFragmentNode ? null : node.type;
189
+ return openTag?.value.type;
189
190
  }
190
191
 
191
192
  get attributes() {
192
- let { node, isFragmentNode } = states.get(this);
193
+ let { node } = states.get(this);
194
+ let openTag = node.sigilTag;
193
195
 
194
- return isFragmentNode ? {} : node.attributes;
196
+ return openTag?.value.attributes;
195
197
  }
196
198
 
197
199
  get openTag() {
198
- const { node, openTag, isFragmentNode } = states.get(this);
200
+ const { node, openTag, isFragmentFacade } = states.get(this);
199
201
 
200
- return isFragmentNode ? openTag : sumtree.getAt(0, node.children);
202
+ return isFragmentNode(node) ? node.tags.at(1) : isFragmentFacade ? openTag : node.tags.at(0);
201
203
  }
202
204
 
203
205
  get closeTag() {
204
- const { node, closeTag, isFragmentNode } = states.get(this);
206
+ const { node, closeTag, isFragmentFacade } = states.get(this);
205
207
 
206
- return isFragmentNode
207
- ? closeTag
208
- : sumtree.getAt(sumtree.getSize(node.children) - 1, node.children);
208
+ return isFragmentFacade ? (isFragmentNode(node) ? node.closeTag : closeTag) : node.tags.at(-1);
209
209
  }
210
210
 
211
211
  merge(targetFragment) {
@@ -213,12 +213,11 @@ export const FragmentFacade = class BABLRFragmentFacade {
213
213
  fragmentNode,
214
214
  context,
215
215
  transparent,
216
- isFragmentNode,
217
- childrenIndexRange,
216
+ isFragmentFacade,
218
217
  dotPropertyReference,
219
218
  dotPropertyIndex,
220
219
  } = states.get(this);
221
- const { fragmentNode: targetFragmentNode, childrenIndexRange: targetChildrenIndexRange } =
220
+ const { fragmentNode: targetFragmentNode, tagsIndexRange: targetTagsIndexRange } =
222
221
  states.get(targetFragment);
223
222
  if (fragmentNode === targetFragmentNode) {
224
223
  // TODO restrict what is legal here
@@ -227,8 +226,8 @@ export const FragmentFacade = class BABLRFragmentFacade {
227
226
  fragmentNode,
228
227
  context,
229
228
  transparent,
230
- isFragmentNode,
231
- targetChildrenIndexRange,
229
+ isFragmentFacade,
230
+ targetTagsIndexRange,
232
231
  dotPropertyReference,
233
232
  dotPropertyIndex,
234
233
  );
@@ -240,85 +239,89 @@ export const FragmentFacade = class BABLRFragmentFacade {
240
239
  get(path) {
241
240
  let {
242
241
  node: ownNode,
243
- fragmentNode,
244
242
  context,
245
243
  transparent,
246
- isFragmentNode,
247
- childrenIndexRange,
244
+ isFragmentFacade,
245
+ tagsIndexRange,
248
246
  dotPropertyReference: dotReference,
249
247
  dotPropertyIndex: dotIndex,
250
248
  } = states.get(this);
251
- const parsedRef = parseReference(path);
252
249
 
253
- let node = fragmentNode;
250
+ if (typeof path === 'string') {
251
+ path = [path];
252
+ }
253
+
254
+ if (!isArray(path)) throw new Error();
254
255
 
255
- if (parsedRef.value.name !== '.') {
256
- if (dotReference) {
257
- fragmentNode = ownNode;
258
- dotReference = parsedRef;
256
+ let node = ownNode;
257
+ let ref = dotReference;
258
+ let index = dotIndex;
259
+ let outerNode;
259
260
 
260
- isFragmentNode = false;
261
- } else {
262
- dotReference = parsedRef;
263
- dotIndex = parsedRef.value.index;
261
+ for (let i = 0; i < path.length; i++) {
262
+ let name = path[i];
263
+ let seg = typeof name === 'string' ? buildPathSegment(name) : name;
264
+ outerNode = node;
265
+
266
+ node = node.get(seg);
267
+ if (node?.sigilTag.type === NullTag) {
268
+ node = null;
264
269
  }
265
270
 
266
- let { name, isArray, flags } = parsedRef.value;
267
- let resolvedReference = buildReferenceTag(name, isArray, flags, dotIndex);
268
- let refIndex = getPropertyChildrenIndex(fragmentNode, resolvedReference);
269
- childrenIndexRange = [refIndex, refIndex + 1];
271
+ if (!node) break;
272
+ let refIndex = outerNode.getPropertyTagsIndex(null, seg.name, seg.index);
273
+ tagsIndexRange = [refIndex, refIndex];
274
+
275
+ let boundRef = outerNode.properties.referenceAt(seg.name, seg.index);
270
276
 
271
- const binding = getProperties(parsedRef, fragmentNode.properties);
277
+ if (!node) return null;
272
278
 
273
- if (!binding) return null;
279
+ let arraySize = outerNode.countList(seg.name);
274
280
 
275
- const ref = binding.reference;
281
+ ref = boundRef;
282
+ index = seg.index < 0 ? arraySize + seg.index : seg.index;
276
283
 
277
284
  node =
278
- (ref && ref.type === ReferenceTag && !ref.value.flags.hasGap) || transparent
279
- ? binding.node
285
+ (ref && ref.type === ReferenceTag && !ref.flags.hasGap) || transparent
286
+ ? node
280
287
  : buildStubNode(buildGapTag());
281
288
  }
282
289
 
283
- return isNullNode(node)
290
+ return !node || isNullNode(node)
284
291
  ? null
285
292
  : new FragmentFacade(
286
- fragmentNode,
293
+ outerNode,
287
294
  context,
288
295
  transparent,
289
- isFragmentNode,
290
- childrenIndexRange,
291
- dotReference,
292
- dotIndex,
296
+ isFragmentFacade,
297
+ tagsIndexRange,
298
+ ref,
299
+ index,
293
300
  );
294
301
  }
295
302
 
296
303
  has(path) {
297
- return hasOwn(states.get(this).node.properties, parseReference(path).value.name);
304
+ let node = states.get(this).node;
305
+ let path_ = path;
306
+ if (typeof path === 'string') {
307
+ path_ = [path];
308
+ }
309
+
310
+ if (!isArray(path_)) throw new Error();
311
+
312
+ for (let i = 0; i < path_.length; i++) {
313
+ if (!node.properties.has(path_[i])) return false;
314
+ if (i < path.length - 1) {
315
+ node = node.properties.get(path_[i]);
316
+ }
317
+ }
318
+
319
+ return true;
320
+ }
321
+
322
+ hasRoot() {
323
+ return this.type != null ? false : !!states.get(this).node.get([buildTypePathSegment('.')]);
298
324
  }
299
325
  };
300
326
 
301
327
  Object.seal(FragmentFacade);
302
-
303
- export const buildInternalState = () => {
304
- let instructionsPump = new Pump();
305
- let expressionsPump = new Pump();
306
- let agastState = null;
307
- let agast_ = getStreamIterator(
308
- agast(
309
- (ctx, s) => {
310
- agastState = s;
311
- return instructionsPump;
312
- },
313
- { expressions: expressionsPump },
314
- ),
315
- );
316
- let internalState = {
317
- instructionsPump,
318
- expressionsPump,
319
- agastState,
320
- agast: agast_,
321
- path: agastState.path,
322
- };
323
- return internalState;
324
- };