@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/context.js +28 -12
- package/lib/evaluate.js +133 -126
- package/lib/match.js +127 -101
- package/lib/node.js +155 -57
- package/lib/source.js +3 -1
- package/lib/state.js +207 -62
- package/lib/utils/pattern.js +31 -2
- package/package.json +6 -6
- package/lib/strategy.js +0 -327
package/lib/strategy.js
DELETED
|
@@ -1,327 +0,0 @@
|
|
|
1
|
-
import { Coroutine } from '@bablr/coroutine';
|
|
2
|
-
import {
|
|
3
|
-
buildCall,
|
|
4
|
-
buildReferenceTag,
|
|
5
|
-
buildNullTag,
|
|
6
|
-
buildEmbeddedTag,
|
|
7
|
-
buildArrayTag,
|
|
8
|
-
} from '@bablr/agast-helpers/builders';
|
|
9
|
-
import { StreamGenerator } from '@bablr/agast-helpers/stream';
|
|
10
|
-
import { formatType } from './utils/format.js';
|
|
11
|
-
import { facades } from './facades.js';
|
|
12
|
-
import { State } from './state.js';
|
|
13
|
-
import { updateSpans } from './spans.js';
|
|
14
|
-
import {
|
|
15
|
-
DoctypeTag,
|
|
16
|
-
OpenNodeTag,
|
|
17
|
-
CloseNodeTag,
|
|
18
|
-
ReferenceTag,
|
|
19
|
-
ShiftTag,
|
|
20
|
-
GapTag,
|
|
21
|
-
NullTag,
|
|
22
|
-
LiteralTag,
|
|
23
|
-
} from '@bablr/agast-helpers/symbols';
|
|
24
|
-
import { NodeFacade } from './node.js';
|
|
25
|
-
import { treeFromStreamSync } from '@bablr/agast-helpers/tree';
|
|
26
|
-
|
|
27
|
-
const getSourceLength = (tags) => {
|
|
28
|
-
let i = 0;
|
|
29
|
-
for (const tag of tags) {
|
|
30
|
-
if (tag.type === LiteralTag) {
|
|
31
|
-
i += tag.value.length;
|
|
32
|
-
} else if (tag.type === GapTag) {
|
|
33
|
-
i += 1;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
return i;
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
const { hasOwn } = Object;
|
|
40
|
-
|
|
41
|
-
export const createBablrStrategy = (ctx, rootSource, strategy) => {
|
|
42
|
-
return (agastCtx, agastState) => {
|
|
43
|
-
if (agastCtx !== ctx.agast.facade) throw new Error();
|
|
44
|
-
return new StreamGenerator(__strategy(ctx, rootSource, agastState, strategy));
|
|
45
|
-
};
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
const resolvedLanguages = new WeakMap();
|
|
49
|
-
|
|
50
|
-
const __strategy = function* bablrStrategy(ctx, rootSource, agastState, strategy) {
|
|
51
|
-
let s = State.from(rootSource, agastState, ctx);
|
|
52
|
-
|
|
53
|
-
let co = new Coroutine(strategy(facades.get(s), facades.get(ctx)));
|
|
54
|
-
|
|
55
|
-
co.advance();
|
|
56
|
-
|
|
57
|
-
{
|
|
58
|
-
s.source.advance();
|
|
59
|
-
|
|
60
|
-
const sourceStep = s.source.fork.head.step;
|
|
61
|
-
|
|
62
|
-
if (sourceStep instanceof Promise) {
|
|
63
|
-
yield sourceStep;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
for (;;) {
|
|
68
|
-
if (co.current instanceof Promise) {
|
|
69
|
-
co.current = yield co.current;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (co.done) break;
|
|
73
|
-
|
|
74
|
-
const instr = co.value;
|
|
75
|
-
let returnValue = undefined;
|
|
76
|
-
|
|
77
|
-
const { verb } = instr;
|
|
78
|
-
|
|
79
|
-
switch (verb) {
|
|
80
|
-
case 'advance': {
|
|
81
|
-
const { arguments: { 0: embeddedTag } = [] } = instr;
|
|
82
|
-
|
|
83
|
-
const tag = embeddedTag.value;
|
|
84
|
-
|
|
85
|
-
switch (tag?.type || NullTag) {
|
|
86
|
-
case DoctypeTag: {
|
|
87
|
-
const doctypeTag = yield instr;
|
|
88
|
-
|
|
89
|
-
returnValue = doctypeTag;
|
|
90
|
-
break;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
case OpenNodeTag: {
|
|
94
|
-
const { type } = tag.value;
|
|
95
|
-
|
|
96
|
-
const openTag = yield instr;
|
|
97
|
-
|
|
98
|
-
if (type) {
|
|
99
|
-
updateSpans(ctx, s, s.node, 'open');
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
returnValue = openTag;
|
|
103
|
-
break;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
case CloseNodeTag: {
|
|
107
|
-
const { node } = s;
|
|
108
|
-
|
|
109
|
-
if (node.flags.escape) {
|
|
110
|
-
const cooked = node.flags.hasGap
|
|
111
|
-
? null
|
|
112
|
-
: ctx.languages
|
|
113
|
-
.get(node.language)
|
|
114
|
-
.getCooked?.(NodeFacade.wrap(node, ctx, true), s.span.name, facades.get(ctx)) ||
|
|
115
|
-
null;
|
|
116
|
-
|
|
117
|
-
yield buildCall('bindAttribute', 'cooked', cooked);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const closeTag = yield instr;
|
|
121
|
-
|
|
122
|
-
if (s.path) {
|
|
123
|
-
updateSpans(ctx, s, node, 'close');
|
|
124
|
-
} else {
|
|
125
|
-
if (!s.source.done) {
|
|
126
|
-
throw new Error('Parser failed to consume input');
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
if (s.balanced.size) {
|
|
130
|
-
throw new Error('Parser did not match all balanced nodes');
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
returnValue = closeTag;
|
|
135
|
-
break;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
case LiteralTag: {
|
|
139
|
-
const { value: pattern } = tag;
|
|
140
|
-
|
|
141
|
-
let result = s.guardedMatch(pattern);
|
|
142
|
-
|
|
143
|
-
if (result instanceof Promise) {
|
|
144
|
-
result = yield result;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
if (result) {
|
|
148
|
-
let sourceStep = s.source.advance(getSourceLength(result));
|
|
149
|
-
|
|
150
|
-
if (sourceStep instanceof Promise) {
|
|
151
|
-
sourceStep = yield sourceStep;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
returnValue = yield instr;
|
|
155
|
-
} else {
|
|
156
|
-
throw new Error('Failed to advance literal');
|
|
157
|
-
}
|
|
158
|
-
break;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
case GapTag: {
|
|
162
|
-
if (s.source.value == null && !s.source.done) {
|
|
163
|
-
if (s.source.holding) {
|
|
164
|
-
s.source.unshift();
|
|
165
|
-
} else {
|
|
166
|
-
const sourceStep = s.source.advance(1);
|
|
167
|
-
|
|
168
|
-
if (sourceStep instanceof Promise) {
|
|
169
|
-
yield sourceStep;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
returnValue = yield instr;
|
|
174
|
-
} else {
|
|
175
|
-
throw new Error('Failed to advance gap');
|
|
176
|
-
}
|
|
177
|
-
break;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
case ShiftTag: {
|
|
181
|
-
s.source.shift();
|
|
182
|
-
|
|
183
|
-
returnValue = yield instr;
|
|
184
|
-
break;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
default: {
|
|
188
|
-
returnValue = yield instr;
|
|
189
|
-
break;
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
break;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
case 'match': {
|
|
197
|
-
let { arguments: { 0: pattern } = [] } = instr;
|
|
198
|
-
|
|
199
|
-
let result = s.guardedMatch(pattern);
|
|
200
|
-
|
|
201
|
-
if (result instanceof Promise) {
|
|
202
|
-
result = yield result;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
returnValue = result && NodeFacade.wrap(treeFromStreamSync(result), ctx, true);
|
|
206
|
-
break;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
case 'branch': {
|
|
210
|
-
const baseState = s;
|
|
211
|
-
let { source, agast, context, balanced, spans, node } = baseState;
|
|
212
|
-
|
|
213
|
-
agast = yield instr;
|
|
214
|
-
|
|
215
|
-
s = s.push(source.branch(), agast, context, balanced, spans);
|
|
216
|
-
|
|
217
|
-
if (node) {
|
|
218
|
-
resolvedLanguages.set(s.node, resolvedLanguages.get(node));
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
returnValue = facades.get(s);
|
|
222
|
-
break;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
case 'accept': {
|
|
226
|
-
const accepted = s;
|
|
227
|
-
|
|
228
|
-
s.status = 'accepted';
|
|
229
|
-
|
|
230
|
-
const agastState = yield instr;
|
|
231
|
-
|
|
232
|
-
s = s.parent;
|
|
233
|
-
|
|
234
|
-
if (!s) {
|
|
235
|
-
throw new Error('accepted the root state');
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
s.spans = accepted.spans;
|
|
239
|
-
s.balanced = accepted.balanced;
|
|
240
|
-
|
|
241
|
-
s.source.accept(accepted.source);
|
|
242
|
-
s.agast = agastState;
|
|
243
|
-
|
|
244
|
-
returnValue = facades.get(s);
|
|
245
|
-
break;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
case 'reject': {
|
|
249
|
-
const rejectedState = s;
|
|
250
|
-
|
|
251
|
-
s.status = 'rejected';
|
|
252
|
-
|
|
253
|
-
yield instr;
|
|
254
|
-
|
|
255
|
-
s = s.parent;
|
|
256
|
-
|
|
257
|
-
if (s.path.depth && rejectedState.path.depth >= s.path.depth) {
|
|
258
|
-
// const didShift = rejectedState.node.at(sNodeDepth) === s.node;
|
|
259
|
-
const didShift =
|
|
260
|
-
s.nodeForPath(s.path) && !s.nodeForPath(rejectedState.path.at(s.path.depth));
|
|
261
|
-
const lowPath = rejectedState.path.at(
|
|
262
|
-
Math.min(
|
|
263
|
-
s.path.depth + (didShift || s.result.type === ReferenceTag ? 0 : 1),
|
|
264
|
-
rejectedState.path.depth,
|
|
265
|
-
),
|
|
266
|
-
);
|
|
267
|
-
const lowNode = s.node || s.parentNode;
|
|
268
|
-
|
|
269
|
-
const { name, isArray, hasGap } = lowPath.reference?.value || {};
|
|
270
|
-
|
|
271
|
-
if (
|
|
272
|
-
!didShift &&
|
|
273
|
-
!hasOwn(lowNode.properties, name) &&
|
|
274
|
-
!(s.result.type === ReferenceTag && s.result.value.name === name)
|
|
275
|
-
) {
|
|
276
|
-
if (isArray) {
|
|
277
|
-
yield buildCall('advance', buildEmbeddedTag(buildReferenceTag(name, true, hasGap)));
|
|
278
|
-
yield buildCall('advance', buildEmbeddedTag(buildArrayTag()));
|
|
279
|
-
} else {
|
|
280
|
-
yield buildCall(
|
|
281
|
-
'advance',
|
|
282
|
-
buildEmbeddedTag(buildReferenceTag(name, isArray, hasGap)),
|
|
283
|
-
);
|
|
284
|
-
yield buildCall('advance', buildEmbeddedTag(buildNullTag()));
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
if (!s) throw new Error('rejected root state');
|
|
290
|
-
|
|
291
|
-
rejectedState.source.reject();
|
|
292
|
-
|
|
293
|
-
returnValue = facades.get(s);
|
|
294
|
-
break;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
case 'openSpan': {
|
|
298
|
-
let { arguments: { 0: name } = [] } = instr;
|
|
299
|
-
s.spans = s.spans.push({ guard: null, name, path: s.path, type: 'Instruction' });
|
|
300
|
-
break;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
case 'closeSpan': {
|
|
304
|
-
if (s.spans.value.type !== 'Instruction') throw new Error();
|
|
305
|
-
s.spans = s.spans.pop();
|
|
306
|
-
break;
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
case 'write':
|
|
310
|
-
case 'bindAttribute': {
|
|
311
|
-
returnValue = yield instr;
|
|
312
|
-
break;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
case 'getState': {
|
|
316
|
-
returnValue = facades.get(s);
|
|
317
|
-
break;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
default: {
|
|
321
|
-
throw new Error(`Unexpected call of {type: ${formatType(verb)}}`);
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
co.advance(returnValue);
|
|
326
|
-
}
|
|
327
|
-
};
|