@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/context.js +9 -8
- package/lib/evaluate.js +329 -159
- package/lib/match.js +278 -115
- package/lib/node.js +123 -120
- package/lib/source.js +111 -114
- package/lib/spans.js +1 -4
- package/lib/state.js +184 -223
- package/lib/utils/pattern.js +116 -18
- package/package.json +8 -8
- 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/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 {
|
|
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
|
-
|
|
18
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
78
|
-
|
|
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 (
|
|
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 && !
|
|
91
|
-
throw new Error();
|
|
89
|
+
if (dotPropertyReference && !node.properties.get(dotPropertyReference.name)) throw new Error();
|
|
92
90
|
|
|
93
|
-
if (
|
|
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 {
|
|
97
|
+
let { type, name } = dotPropertyReference;
|
|
100
98
|
|
|
101
|
-
|
|
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
|
|
109
|
+
fragmentNode,
|
|
112
110
|
transparent,
|
|
113
|
-
|
|
114
|
-
|
|
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
|
|
130
|
+
return node.sigilTag.type === NullTag;
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
-
get
|
|
134
|
-
let { node, isFragmentNode, transparent,
|
|
133
|
+
get tagsInner() {
|
|
134
|
+
let { node, isFragmentNode, transparent, tagsIndexRange } = states.get(this);
|
|
135
135
|
|
|
136
|
-
|
|
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
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
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,
|
|
157
|
+
const { node, dotPropertyName, tagsIndexRange } = states.get(this);
|
|
153
158
|
|
|
154
|
-
if (!
|
|
159
|
+
if (!tagsIndexRange) return null;
|
|
155
160
|
|
|
156
|
-
if (
|
|
161
|
+
if (tagsIndexRange[0] > tagsIndexRange[1]) throw new Error();
|
|
157
162
|
|
|
158
|
-
for (let i =
|
|
159
|
-
let tag =
|
|
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 {
|
|
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
|
|
182
|
+
return openTag?.value.flags;
|
|
183
183
|
}
|
|
184
184
|
|
|
185
185
|
get type() {
|
|
186
|
-
let { node
|
|
186
|
+
let { node } = states.get(this);
|
|
187
|
+
let openTag = node.sigilTag;
|
|
187
188
|
|
|
188
|
-
return
|
|
189
|
+
return openTag?.value.type;
|
|
189
190
|
}
|
|
190
191
|
|
|
191
192
|
get attributes() {
|
|
192
|
-
let { node
|
|
193
|
+
let { node } = states.get(this);
|
|
194
|
+
let openTag = node.sigilTag;
|
|
193
195
|
|
|
194
|
-
return
|
|
196
|
+
return openTag?.value.attributes;
|
|
195
197
|
}
|
|
196
198
|
|
|
197
199
|
get openTag() {
|
|
198
|
-
const { node, openTag,
|
|
200
|
+
const { node, openTag, isFragmentFacade } = states.get(this);
|
|
199
201
|
|
|
200
|
-
return isFragmentNode ? openTag :
|
|
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,
|
|
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
|
-
|
|
217
|
-
childrenIndexRange,
|
|
216
|
+
isFragmentFacade,
|
|
218
217
|
dotPropertyReference,
|
|
219
218
|
dotPropertyIndex,
|
|
220
219
|
} = states.get(this);
|
|
221
|
-
const { fragmentNode: targetFragmentNode,
|
|
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
|
-
|
|
231
|
-
|
|
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
|
-
|
|
247
|
-
|
|
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
|
-
|
|
250
|
+
if (typeof path === 'string') {
|
|
251
|
+
path = [path];
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (!isArray(path)) throw new Error();
|
|
254
255
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
256
|
+
let node = ownNode;
|
|
257
|
+
let ref = dotReference;
|
|
258
|
+
let index = dotIndex;
|
|
259
|
+
let outerNode;
|
|
259
260
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
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
|
-
|
|
267
|
-
let
|
|
268
|
-
|
|
269
|
-
|
|
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
|
-
|
|
277
|
+
if (!node) return null;
|
|
272
278
|
|
|
273
|
-
|
|
279
|
+
let arraySize = outerNode.countList(seg.name);
|
|
274
280
|
|
|
275
|
-
|
|
281
|
+
ref = boundRef;
|
|
282
|
+
index = seg.index < 0 ? arraySize + seg.index : seg.index;
|
|
276
283
|
|
|
277
284
|
node =
|
|
278
|
-
(ref && ref.type === ReferenceTag && !ref.
|
|
279
|
-
?
|
|
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
|
-
|
|
293
|
+
outerNode,
|
|
287
294
|
context,
|
|
288
295
|
transparent,
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
296
|
+
isFragmentFacade,
|
|
297
|
+
tagsIndexRange,
|
|
298
|
+
ref,
|
|
299
|
+
index,
|
|
293
300
|
);
|
|
294
301
|
}
|
|
295
302
|
|
|
296
303
|
has(path) {
|
|
297
|
-
|
|
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
|
-
};
|