@bablr/agast-vm 0.6.0 → 0.7.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 +13 -70
- package/lib/evaluate.js +34 -171
- package/lib/index.js +1 -1
- package/lib/path.js +2 -75
- package/lib/state.js +167 -362
- package/lib/utils/iterable.js +13 -0
- package/package.json +3 -3
package/lib/context.js
CHANGED
|
@@ -1,34 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
getCooked as getCookedFromTree,
|
|
4
|
-
sourceTextFor as sourceTextForTree,
|
|
5
|
-
} from '@bablr/agast-helpers/tree';
|
|
6
|
-
import {
|
|
7
|
-
getCooked as getCookedFromStream,
|
|
8
|
-
sourceTextFor as sourceTextForStream,
|
|
9
|
-
} from '@bablr/agast-helpers/stream';
|
|
10
|
-
import { OpenNodeTag, CloseNodeTag } from '@bablr/agast-helpers/symbols';
|
|
11
|
-
import { facades, actuals } from './facades.js';
|
|
12
|
-
|
|
13
|
-
const { isArray } = Array;
|
|
14
|
-
|
|
15
|
-
function* allTagsFor(range, nextTags) {
|
|
16
|
-
if (!range) return;
|
|
17
|
-
const { 0: start, 1: end } = range;
|
|
1
|
+
import { reifyExpression } from '@bablr/agast-vm-helpers';
|
|
2
|
+
import { sourceTextFor as sourceTextForTree } from '@bablr/agast-helpers/tree';
|
|
18
3
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
for (let tag = start; tag && tag !== pastEnd; tag = nextTags.get(tag)) {
|
|
22
|
-
yield tag;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
4
|
+
import { allTagPathsFor } from './path.js';
|
|
5
|
+
import { facades, actuals } from './facades.js';
|
|
25
6
|
|
|
26
7
|
export const ContextFacade = class AgastContextFacade {
|
|
27
|
-
|
|
8
|
+
getPreviousTagPath(token) {
|
|
28
9
|
return actuals.get(this).prevTags.get(token);
|
|
29
10
|
}
|
|
30
11
|
|
|
31
|
-
|
|
12
|
+
getNextTagPath(token) {
|
|
32
13
|
return actuals.get(this).nextTags.get(token);
|
|
33
14
|
}
|
|
34
15
|
|
|
@@ -36,10 +17,6 @@ export const ContextFacade = class AgastContextFacade {
|
|
|
36
17
|
return actuals.get(this).allTagsFor(range);
|
|
37
18
|
}
|
|
38
19
|
|
|
39
|
-
getCooked(range) {
|
|
40
|
-
return actuals.get(this).getCooked(range);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
20
|
reifyExpression(range) {
|
|
44
21
|
return actuals.get(this).reifyExpression(range);
|
|
45
22
|
}
|
|
@@ -52,8 +29,8 @@ export const ContextFacade = class AgastContextFacade {
|
|
|
52
29
|
return actuals.get(this).buildRange(tags);
|
|
53
30
|
}
|
|
54
31
|
|
|
55
|
-
|
|
56
|
-
return actuals.get(this).
|
|
32
|
+
nodeForTag(tag) {
|
|
33
|
+
return actuals.get(this).nodeForTag(tag);
|
|
57
34
|
}
|
|
58
35
|
};
|
|
59
36
|
|
|
@@ -63,41 +40,22 @@ export const Context = class AgastContext {
|
|
|
63
40
|
}
|
|
64
41
|
|
|
65
42
|
constructor() {
|
|
66
|
-
this.
|
|
67
|
-
this.nextTags = new WeakMap();
|
|
68
|
-
this.unboxedValues = new WeakMap();
|
|
43
|
+
this.tagNodes = new WeakMap();
|
|
69
44
|
this.facade = new ContextFacade();
|
|
70
45
|
|
|
71
46
|
facades.set(this, this.facade);
|
|
72
47
|
}
|
|
73
48
|
|
|
74
|
-
isEmpty(range) {
|
|
75
|
-
const { path, parent } = this;
|
|
76
|
-
|
|
77
|
-
if (range[0]?.type === OpenNodeTag && path !== parent.path) {
|
|
78
|
-
const nextTag = this.nextTags.get(range[0]);
|
|
79
|
-
if (!nextTag || nextTag.type === CloseNodeTag) {
|
|
80
|
-
return null;
|
|
81
|
-
}
|
|
82
|
-
} else {
|
|
83
|
-
return range[0] === range[1];
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
49
|
allTagsFor(range) {
|
|
88
|
-
return
|
|
50
|
+
return allTagPathsFor(range);
|
|
89
51
|
}
|
|
90
52
|
|
|
91
53
|
allTagsReverseFor(range) {
|
|
92
|
-
|
|
54
|
+
throw new Error('not implemented');
|
|
93
55
|
}
|
|
94
56
|
|
|
95
|
-
|
|
96
|
-
return this.
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
getNextTag(token) {
|
|
100
|
-
return this.nextTags.get(token);
|
|
57
|
+
nodeForTag(tag) {
|
|
58
|
+
return this.tagNodes.get(tag);
|
|
101
59
|
}
|
|
102
60
|
|
|
103
61
|
sourceTextFor(node) {
|
|
@@ -124,22 +82,7 @@ export const Context = class AgastContext {
|
|
|
124
82
|
return start ? [start, end] : null;
|
|
125
83
|
}
|
|
126
84
|
|
|
127
|
-
unbox(value) {
|
|
128
|
-
const { unboxedValues } = this;
|
|
129
|
-
if (!unboxedValues.has(value)) {
|
|
130
|
-
unboxedValues.set(value, reifyExpressionShallow(value));
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
return unboxedValues.get(value);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
85
|
reifyExpression(value) {
|
|
137
86
|
return reifyExpression(value);
|
|
138
87
|
}
|
|
139
|
-
|
|
140
|
-
getCooked(nodeOrRange) {
|
|
141
|
-
return isArray(nodeOrRange)
|
|
142
|
-
? getCookedFromStream(this.allTagsFor(nodeOrRange))
|
|
143
|
-
: getCookedFromTree(nodeOrRange);
|
|
144
|
-
}
|
|
145
88
|
};
|
package/lib/evaluate.js
CHANGED
|
@@ -5,21 +5,14 @@ import {
|
|
|
5
5
|
buildShiftTag,
|
|
6
6
|
buildReferenceTag,
|
|
7
7
|
buildLiteralTag,
|
|
8
|
-
buildWriteEffect,
|
|
9
8
|
buildDoctypeTag,
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
buildOpenNodeTag,
|
|
10
|
+
buildCloseNodeTag,
|
|
12
11
|
} from '@bablr/agast-vm-helpers/internal-builders';
|
|
13
|
-
import {
|
|
12
|
+
import { getEmbeddedTag } from '@bablr/agast-vm-helpers/deembed';
|
|
14
13
|
import { StreamIterable, getStreamIterator } from '@bablr/agast-helpers/stream';
|
|
15
14
|
import { printExpression } from '@bablr/agast-helpers/print';
|
|
16
|
-
import {
|
|
17
|
-
getRange,
|
|
18
|
-
getOpenTag,
|
|
19
|
-
buildArrayTag,
|
|
20
|
-
buildFragmentCloseTag,
|
|
21
|
-
buildFragmentOpenTag,
|
|
22
|
-
} from '@bablr/agast-helpers/tree';
|
|
15
|
+
import { buildArrayInitializerTag } from '@bablr/agast-helpers/tree';
|
|
23
16
|
import {
|
|
24
17
|
DoctypeTag,
|
|
25
18
|
OpenNodeTag,
|
|
@@ -28,22 +21,22 @@ import {
|
|
|
28
21
|
ShiftTag,
|
|
29
22
|
GapTag,
|
|
30
23
|
NullTag,
|
|
31
|
-
|
|
24
|
+
ArrayInitializerTag,
|
|
32
25
|
LiteralTag,
|
|
33
|
-
CloseFragmentTag,
|
|
34
|
-
OpenFragmentTag,
|
|
35
26
|
} from '@bablr/agast-helpers/symbols';
|
|
36
|
-
import * as btree from '@bablr/agast-helpers/btree';
|
|
37
27
|
import { State } from './state.js';
|
|
28
|
+
import { Context } from './context.js';
|
|
38
29
|
import { facades } from './facades.js';
|
|
39
30
|
|
|
40
|
-
export const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const __evaluate = function* agast(ctx, strategy, options = {}) {
|
|
31
|
+
export const agast = (strategy, options = {}) => {
|
|
32
|
+
const ctx = Context.create();
|
|
44
33
|
let s = State.from(ctx, options.expressions);
|
|
45
34
|
|
|
46
|
-
|
|
35
|
+
return new StreamIterable(__agast(ctx, s, strategy(facades.get(ctx), facades.get(s))));
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
function* __agast(ctx, s, instructions) {
|
|
39
|
+
const co = new Coroutine(getStreamIterator(instructions));
|
|
47
40
|
|
|
48
41
|
co.advance();
|
|
49
42
|
|
|
@@ -61,35 +54,10 @@ const __evaluate = function* agast(ctx, strategy, options = {}) {
|
|
|
61
54
|
const { verb, arguments: args = [] } = instr;
|
|
62
55
|
|
|
63
56
|
switch (verb) {
|
|
64
|
-
case 'branch': {
|
|
65
|
-
s = s.branch();
|
|
66
|
-
|
|
67
|
-
returnValue = facades.get(s);
|
|
68
|
-
break;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
case 'accept': {
|
|
72
|
-
s = s.accept();
|
|
73
|
-
|
|
74
|
-
if (s.depth === 0) {
|
|
75
|
-
yield* s.emit();
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
returnValue = facades.get(s);
|
|
79
|
-
break;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
case 'reject': {
|
|
83
|
-
s = s.reject();
|
|
84
|
-
|
|
85
|
-
returnValue = facades.get(s);
|
|
86
|
-
break;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
57
|
case 'advance': {
|
|
90
|
-
const { 0:
|
|
58
|
+
const { 0: embeddedTags } = args;
|
|
91
59
|
|
|
92
|
-
const tag =
|
|
60
|
+
const tag = getEmbeddedTag(embeddedTags);
|
|
93
61
|
|
|
94
62
|
if (
|
|
95
63
|
s.held &&
|
|
@@ -102,7 +70,7 @@ const __evaluate = function* agast(ctx, strategy, options = {}) {
|
|
|
102
70
|
case DoctypeTag: {
|
|
103
71
|
const { attributes } = tag.value;
|
|
104
72
|
|
|
105
|
-
if (s.path) {
|
|
73
|
+
if (s.path.depth !== 0) {
|
|
106
74
|
throw new Error();
|
|
107
75
|
}
|
|
108
76
|
|
|
@@ -124,56 +92,47 @@ const __evaluate = function* agast(ctx, strategy, options = {}) {
|
|
|
124
92
|
}
|
|
125
93
|
|
|
126
94
|
case ReferenceTag: {
|
|
127
|
-
const { name, isArray,
|
|
95
|
+
const { name, isArray, flags } = tag.value;
|
|
128
96
|
|
|
129
|
-
if (s.
|
|
130
|
-
throw new Error('A reference must have a non-reference value');
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
if (s.node?.flags.token) {
|
|
97
|
+
if (s.node?.flags.token && name !== '@') {
|
|
134
98
|
throw new Error('A token node cannot contain a reference');
|
|
135
99
|
}
|
|
136
100
|
|
|
137
|
-
returnValue = s.advance(buildReferenceTag(name, isArray,
|
|
101
|
+
returnValue = s.advance(buildReferenceTag(name, isArray, flags));
|
|
138
102
|
break;
|
|
139
103
|
}
|
|
140
104
|
|
|
141
105
|
case GapTag: {
|
|
142
|
-
const reference = s.result;
|
|
143
|
-
|
|
144
|
-
if (reference?.type !== ReferenceTag) throw new Error();
|
|
145
|
-
|
|
146
106
|
returnValue = s.advance(buildGapTag());
|
|
147
107
|
break;
|
|
148
108
|
}
|
|
149
109
|
|
|
150
110
|
case NullTag: {
|
|
151
|
-
const reference = s.result;
|
|
152
|
-
|
|
153
|
-
if (reference?.type !== ReferenceTag) throw new Error();
|
|
154
|
-
|
|
155
111
|
returnValue = s.advance(buildNullTag());
|
|
156
112
|
break;
|
|
157
113
|
}
|
|
158
114
|
|
|
159
|
-
case
|
|
160
|
-
const reference = s
|
|
115
|
+
case ArrayInitializerTag: {
|
|
116
|
+
const { reference } = s;
|
|
161
117
|
|
|
162
118
|
if (reference?.type !== ReferenceTag) throw new Error();
|
|
163
119
|
if (!reference.value.isArray) throw new Error();
|
|
164
120
|
|
|
165
|
-
returnValue = s.advance(
|
|
121
|
+
returnValue = s.advance(buildArrayInitializerTag());
|
|
166
122
|
break;
|
|
167
123
|
}
|
|
168
124
|
|
|
169
125
|
case ShiftTag: {
|
|
170
|
-
const
|
|
126
|
+
const { index } = tag.value;
|
|
127
|
+
if (s.resultPath.tag.type !== GapTag) throw new Error();
|
|
128
|
+
|
|
129
|
+
const refPath = s.resultPath.previousSibling;
|
|
171
130
|
|
|
172
|
-
if (!
|
|
131
|
+
if (!refPath.tag.value.flags.expression) {
|
|
173
132
|
throw new Error();
|
|
174
133
|
}
|
|
175
134
|
|
|
176
|
-
returnValue = s.advance(buildShiftTag());
|
|
135
|
+
returnValue = s.advance(buildShiftTag(index));
|
|
177
136
|
break;
|
|
178
137
|
}
|
|
179
138
|
|
|
@@ -184,29 +143,12 @@ const __evaluate = function* agast(ctx, strategy, options = {}) {
|
|
|
184
143
|
throw new Error('Expected an absolute-language tag');
|
|
185
144
|
}
|
|
186
145
|
|
|
187
|
-
returnValue = s.advance(
|
|
188
|
-
buildNodeOpenTag(flags, language, type, attributes),
|
|
189
|
-
getEmbeddedExpression(options),
|
|
190
|
-
);
|
|
191
|
-
break;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
case OpenFragmentTag: {
|
|
195
|
-
const { flags } = tag.value;
|
|
196
|
-
|
|
197
|
-
returnValue = s.advance(buildFragmentOpenTag(flags), getEmbeddedExpression(options));
|
|
146
|
+
returnValue = s.advance(buildOpenNodeTag(flags, language, type, attributes));
|
|
198
147
|
break;
|
|
199
148
|
}
|
|
200
149
|
|
|
201
150
|
case CloseNodeTag: {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
returnValue = s.advance(buildNodeCloseTag(type, language));
|
|
205
|
-
break;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
case CloseFragmentTag: {
|
|
209
|
-
returnValue = s.advance(buildFragmentCloseTag());
|
|
151
|
+
returnValue = s.advance(buildCloseNodeTag());
|
|
210
152
|
break;
|
|
211
153
|
}
|
|
212
154
|
|
|
@@ -214,90 +156,11 @@ const __evaluate = function* agast(ctx, strategy, options = {}) {
|
|
|
214
156
|
throw new Error();
|
|
215
157
|
}
|
|
216
158
|
|
|
217
|
-
yield
|
|
159
|
+
yield returnValue;
|
|
218
160
|
|
|
219
161
|
break;
|
|
220
162
|
}
|
|
221
163
|
|
|
222
|
-
case 'bindAttribute': {
|
|
223
|
-
const { 0: key, 1: value } = args;
|
|
224
|
-
|
|
225
|
-
const { unboundAttributes } = s;
|
|
226
|
-
|
|
227
|
-
if (!unboundAttributes || !unboundAttributes.has(key)) {
|
|
228
|
-
throw new Error('No unbound attribute to bind');
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
if (!s.node.type) {
|
|
232
|
-
throw new Error('Cannot bind attribute to fragment');
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
if (key === 'span') throw new Error('too late');
|
|
236
|
-
|
|
237
|
-
// if (stateIsDifferent) {
|
|
238
|
-
// // we can't allow effects to cross state branches
|
|
239
|
-
// throw new Error();
|
|
240
|
-
// }
|
|
241
|
-
|
|
242
|
-
unboundAttributes.delete(key);
|
|
243
|
-
|
|
244
|
-
const openTag = getOpenTag(s.node);
|
|
245
|
-
|
|
246
|
-
if (value != null) {
|
|
247
|
-
const { flags, language, type } = openTag.value;
|
|
248
|
-
const attributes = { ...openTag.value.attributes, [key]: value };
|
|
249
|
-
const newOpenTag = buildNodeOpenTag(flags, language, type, attributes);
|
|
250
|
-
|
|
251
|
-
let openNext = ctx.nextTags.get(openTag);
|
|
252
|
-
let startPrev = ctx.prevTags.get(openTag);
|
|
253
|
-
|
|
254
|
-
ctx.prevTags.set(newOpenTag, startPrev);
|
|
255
|
-
ctx.nextTags.set(startPrev, newOpenTag);
|
|
256
|
-
|
|
257
|
-
if (s.node !== s.tagNodes.get(openTag)) throw new Error();
|
|
258
|
-
if (s.path !== s.tagPaths.get(openTag)) throw new Error();
|
|
259
|
-
|
|
260
|
-
s.node.attributes = attributes;
|
|
261
|
-
|
|
262
|
-
s.tagNodes.set(newOpenTag, s.node);
|
|
263
|
-
s.tagPaths.set(newOpenTag, s.path);
|
|
264
|
-
|
|
265
|
-
if (openNext) {
|
|
266
|
-
ctx.nextTags.set(newOpenTag, openNext);
|
|
267
|
-
ctx.prevTags.set(openNext, newOpenTag);
|
|
268
|
-
} else {
|
|
269
|
-
// could this tag be stored anywhere else?
|
|
270
|
-
s.result = newOpenTag;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
s.node.children = btree.replaceAt(0, s.node.children, newOpenTag);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
if (!unboundAttributes.size) {
|
|
277
|
-
yield* s.emit();
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
returnValue = getRange(s.node);
|
|
281
|
-
break;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
case 'getState': {
|
|
285
|
-
returnValue = facades.get(s);
|
|
286
|
-
break;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
case 'getContext': {
|
|
290
|
-
returnValue = facades.get(ctx);
|
|
291
|
-
break;
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
case 'write': {
|
|
295
|
-
if (options.emitEffects) {
|
|
296
|
-
yield buildWriteEffect(args[0], args[1].value);
|
|
297
|
-
}
|
|
298
|
-
break;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
164
|
default: {
|
|
302
165
|
throw new Error(`Unexpected call of {type: ${printExpression(verb)}}`);
|
|
303
166
|
}
|
|
@@ -310,9 +173,9 @@ const __evaluate = function* agast(ctx, strategy, options = {}) {
|
|
|
310
173
|
throw new Error('Did not unwind state stack');
|
|
311
174
|
}
|
|
312
175
|
|
|
313
|
-
if (s.path
|
|
176
|
+
if (s.path) {
|
|
314
177
|
throw new Error('Did not unwind path stack');
|
|
315
178
|
}
|
|
316
179
|
|
|
317
|
-
return s.
|
|
318
|
-
}
|
|
180
|
+
return s.resultPath.path.node;
|
|
181
|
+
}
|
package/lib/index.js
CHANGED
package/lib/path.js
CHANGED
|
@@ -1,76 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
import { DoctypeTag, ReferenceTag } from '@bablr/agast-helpers/symbols';
|
|
3
|
-
import { skipToDepth, buildSkips } from './utils/skip.js';
|
|
4
|
-
import { facades, actuals } from './facades.js';
|
|
1
|
+
export { Path } from '@bablr/agast-helpers/path';
|
|
5
2
|
|
|
6
|
-
export
|
|
7
|
-
constructor(path) {
|
|
8
|
-
facades.set(path, this);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
get reference() {
|
|
12
|
-
return actuals.get(this).reference;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
get parent() {
|
|
16
|
-
return facades.get(actuals.get(this).parent);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
get depth() {
|
|
20
|
-
return actuals.get(this).depth;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
at(depth) {
|
|
24
|
-
return facades.get(actuals.get(this).at(depth));
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
*parents(includeSelf = false) {
|
|
28
|
-
if (includeSelf) yield this;
|
|
29
|
-
let parent = this;
|
|
30
|
-
while ((parent = parent.parent)) {
|
|
31
|
-
yield parent;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
export const Path = class AgastPath extends WeakStackFrame {
|
|
37
|
-
static from(context, tag, childrenIndex) {
|
|
38
|
-
return Path.create(context, tag, childrenIndex);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
constructor(context, reference, childrenIndex = -1) {
|
|
42
|
-
super();
|
|
43
|
-
|
|
44
|
-
if (reference && reference.type !== ReferenceTag && reference.type !== DoctypeTag) {
|
|
45
|
-
throw new Error('Invalid reference for path');
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
this.context = context;
|
|
49
|
-
this.reference = reference;
|
|
50
|
-
this.childrenIndex = childrenIndex;
|
|
51
|
-
|
|
52
|
-
buildSkips(this);
|
|
53
|
-
|
|
54
|
-
new PathFacade(this);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
get name() {
|
|
58
|
-
return this.reference?.value.name;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
get isArray() {
|
|
62
|
-
return this.reference?.value.isArray || false;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
at(depth) {
|
|
66
|
-
return skipToDepth(depth, this);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
*parents(includeSelf = false) {
|
|
70
|
-
if (includeSelf) yield this;
|
|
71
|
-
let parent = this;
|
|
72
|
-
while ((parent = parent.parent)) {
|
|
73
|
-
yield parent;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
};
|
|
3
|
+
export { allTagPathsFor, ownTagPathsFor } from '@bablr/agast-helpers/path';
|
package/lib/state.js
CHANGED
|
@@ -1,23 +1,18 @@
|
|
|
1
|
-
import
|
|
1
|
+
import isArray from 'iter-tools-es/methods/is-array';
|
|
2
2
|
import { WeakStackFrame } from '@bablr/weak-stack';
|
|
3
3
|
import {
|
|
4
4
|
Resolver,
|
|
5
5
|
add,
|
|
6
|
-
createNode,
|
|
7
|
-
getOpenTag,
|
|
8
|
-
getCloseTag,
|
|
9
|
-
branchNode,
|
|
10
|
-
acceptNode,
|
|
11
6
|
finalizeNode,
|
|
12
7
|
getRoot,
|
|
13
|
-
printType,
|
|
14
8
|
buildStubNode,
|
|
9
|
+
getRange,
|
|
10
|
+
buildNullTag,
|
|
11
|
+
treeFromStream,
|
|
12
|
+
createNode,
|
|
15
13
|
} from '@bablr/agast-helpers/tree';
|
|
16
14
|
import * as btree from '@bablr/agast-helpers/btree';
|
|
17
|
-
import {
|
|
18
|
-
buildBeginningOfStreamToken,
|
|
19
|
-
buildEmbeddedNode,
|
|
20
|
-
} from '@bablr/agast-vm-helpers/internal-builders';
|
|
15
|
+
import { TagPath, updatePath } from '@bablr/agast-helpers/path';
|
|
21
16
|
import {
|
|
22
17
|
DoctypeTag,
|
|
23
18
|
OpenNodeTag,
|
|
@@ -26,25 +21,12 @@ import {
|
|
|
26
21
|
ShiftTag,
|
|
27
22
|
GapTag,
|
|
28
23
|
NullTag,
|
|
29
|
-
|
|
24
|
+
ArrayInitializerTag,
|
|
30
25
|
LiteralTag,
|
|
31
|
-
OpenFragmentTag,
|
|
32
|
-
CloseFragmentTag,
|
|
33
26
|
} from '@bablr/agast-helpers/symbols';
|
|
34
27
|
import { facades, actuals } from './facades.js';
|
|
35
28
|
import { Path } from './path.js';
|
|
36
|
-
import {
|
|
37
|
-
|
|
38
|
-
const { hasOwn } = Object;
|
|
39
|
-
|
|
40
|
-
const createNodeWithState = (openTag, options = {}) => {
|
|
41
|
-
const { unboundAttributes } = options;
|
|
42
|
-
const node = createNode(openTag);
|
|
43
|
-
nodeStates.set(node, {
|
|
44
|
-
unboundAttributes: new Set(unboundAttributes || []),
|
|
45
|
-
});
|
|
46
|
-
return node;
|
|
47
|
-
};
|
|
29
|
+
import { Coroutine } from '@bablr/coroutine';
|
|
48
30
|
|
|
49
31
|
export const StateFacade = class AgastStateFacade {
|
|
50
32
|
constructor(state) {
|
|
@@ -55,8 +37,16 @@ export const StateFacade = class AgastStateFacade {
|
|
|
55
37
|
return State.from(actuals.get(context));
|
|
56
38
|
}
|
|
57
39
|
|
|
58
|
-
get
|
|
59
|
-
return actuals.get(this).
|
|
40
|
+
get resultPath() {
|
|
41
|
+
return actuals.get(this).resultPath;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
get reference() {
|
|
45
|
+
return actuals.get(this).reference;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
get referencePath() {
|
|
49
|
+
return actuals.get(this).referencePath;
|
|
60
50
|
}
|
|
61
51
|
|
|
62
52
|
get context() {
|
|
@@ -64,7 +54,7 @@ export const StateFacade = class AgastStateFacade {
|
|
|
64
54
|
}
|
|
65
55
|
|
|
66
56
|
get path() {
|
|
67
|
-
return
|
|
57
|
+
return actuals.get(this).path;
|
|
68
58
|
}
|
|
69
59
|
|
|
70
60
|
get node() {
|
|
@@ -87,16 +77,8 @@ export const StateFacade = class AgastStateFacade {
|
|
|
87
77
|
return this.context;
|
|
88
78
|
}
|
|
89
79
|
|
|
90
|
-
|
|
91
|
-
return
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
pathForTag(tag) {
|
|
95
|
-
return facades.get(actuals.get(this).pathForTag(tag));
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
nodeForTag(tag) {
|
|
99
|
-
return actuals.get(this).nodeForTag(tag);
|
|
80
|
+
get parent() {
|
|
81
|
+
return facades.get(actuals.get(this).parent);
|
|
100
82
|
}
|
|
101
83
|
};
|
|
102
84
|
|
|
@@ -104,345 +86,230 @@ export const nodeStates = new WeakMap();
|
|
|
104
86
|
|
|
105
87
|
export const State = class AgastState extends WeakStackFrame {
|
|
106
88
|
constructor(
|
|
89
|
+
parent,
|
|
107
90
|
context,
|
|
108
|
-
expressions =
|
|
109
|
-
path =
|
|
110
|
-
node = null,
|
|
111
|
-
result = buildBeginningOfStreamToken(),
|
|
112
|
-
emitted = null,
|
|
91
|
+
expressions = [],
|
|
92
|
+
path = Path.from(createNode()),
|
|
113
93
|
held = null,
|
|
94
|
+
resultPath = null,
|
|
114
95
|
resolver = new Resolver(),
|
|
115
|
-
internalContext = {
|
|
116
|
-
pathNodes: new WeakMap(),
|
|
117
|
-
tagPaths: new WeakMap(),
|
|
118
|
-
tagNodes: new WeakMap(),
|
|
119
|
-
},
|
|
120
96
|
) {
|
|
121
|
-
super();
|
|
97
|
+
super(parent);
|
|
122
98
|
|
|
123
|
-
if (!context) throw new Error('invalid args to tagState');
|
|
99
|
+
if (!context || !path || !expressions) throw new Error('invalid args to tagState');
|
|
124
100
|
|
|
125
101
|
this.context = context;
|
|
126
|
-
this.expressions = expressions;
|
|
102
|
+
this.expressions = new Coroutine(expressions[Symbol.iterator]());
|
|
127
103
|
this.path = path;
|
|
128
|
-
this.node = node;
|
|
129
|
-
this.result = result;
|
|
130
|
-
this.emitted = emitted;
|
|
131
104
|
this.held = held;
|
|
105
|
+
this.resultPath = resultPath;
|
|
132
106
|
this.resolver = resolver;
|
|
133
|
-
|
|
107
|
+
|
|
108
|
+
if (!this.node) throw new Error();
|
|
134
109
|
|
|
135
110
|
new StateFacade(this);
|
|
136
111
|
}
|
|
137
112
|
|
|
138
113
|
static from(context, expressions = []) {
|
|
139
|
-
return State.create(context,
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
get pathNodes() {
|
|
143
|
-
return this.internalContext.pathNodes;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
get tagPaths() {
|
|
147
|
-
return this.internalContext.tagPaths;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
get tagNodes() {
|
|
151
|
-
return this.internalContext.tagNodes;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
get unboundAttributes() {
|
|
155
|
-
return nodeStates.get(this.node).unboundAttributes;
|
|
114
|
+
return State.create(context, expressions);
|
|
156
115
|
}
|
|
157
116
|
|
|
158
117
|
get holding() {
|
|
159
118
|
return !!this.held;
|
|
160
119
|
}
|
|
161
120
|
|
|
162
|
-
|
|
163
|
-
return this.pathNodes.get(path);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
pathForTag(ref) {
|
|
167
|
-
return this.tagPaths.get(ref);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
nodeForTag(tag) {
|
|
171
|
-
return this.tagNodes.get(tag);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
advance(tag, options = {}) {
|
|
121
|
+
advance(tag) {
|
|
175
122
|
const ctx = this.context;
|
|
176
|
-
const { prevTags, nextTags } = ctx;
|
|
177
123
|
|
|
178
|
-
if (tag)
|
|
179
|
-
if (prevTags.has(tag)) {
|
|
180
|
-
throw new Error('Double emit');
|
|
181
|
-
}
|
|
124
|
+
if (!tag) throw new Error();
|
|
182
125
|
|
|
183
|
-
|
|
184
|
-
this.result?.type === ReferenceTag &&
|
|
185
|
-
![OpenNodeTag, GapTag, NullTag, ArrayTag].includes(tag.type)
|
|
186
|
-
) {
|
|
187
|
-
throw new Error(`${printType(tag.type)} is not a valid reference target`);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
prevTags.set(tag, this.result);
|
|
191
|
-
nextTags.set(this.result, tag);
|
|
126
|
+
let targetPath = this.path;
|
|
192
127
|
|
|
193
|
-
|
|
128
|
+
switch (tag.type) {
|
|
129
|
+
case DoctypeTag: {
|
|
130
|
+
const { path, node } = this;
|
|
194
131
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
this.path = Path.from(ctx, tag);
|
|
132
|
+
node.children = btree.push(node.children, tag);
|
|
133
|
+
node.attributes = tag.value.attributes;
|
|
198
134
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
}
|
|
135
|
+
this.resolver.advance(tag);
|
|
136
|
+
updatePath(this.path, tag);
|
|
202
137
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
this.node = createNodeWithState(tag, options);
|
|
207
|
-
|
|
208
|
-
const reference = this.result;
|
|
138
|
+
targetPath = path;
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
209
141
|
|
|
210
|
-
|
|
142
|
+
case ReferenceTag: {
|
|
143
|
+
this.resolver.advance(tag);
|
|
211
144
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
reference.type !== ReferenceTag &&
|
|
215
|
-
reference.type !== ShiftTag &&
|
|
216
|
-
reference.type !== OpenNodeTag &&
|
|
217
|
-
!reference.value.type
|
|
218
|
-
) {
|
|
219
|
-
throw new Error('Invalid location for OpenNodeTag');
|
|
220
|
-
}
|
|
221
|
-
} else {
|
|
222
|
-
this.path = this.path.push(ctx, null, btree.getSum(this.node.children));
|
|
223
|
-
}
|
|
145
|
+
this.node.children = btree.push(this.node.children, tag);
|
|
146
|
+
updatePath(this.path, tag);
|
|
224
147
|
|
|
225
|
-
|
|
226
|
-
this.pathNodes.set(this.path, this.node);
|
|
148
|
+
const { hasGap } = tag.value;
|
|
227
149
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
break;
|
|
150
|
+
if (hasGap && !this.node.flags.hasGap) {
|
|
151
|
+
throw new Error('gap reference in gapless node');
|
|
231
152
|
}
|
|
232
153
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
this.node = createNodeWithState(tag, options);
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
236
156
|
|
|
237
|
-
|
|
157
|
+
case OpenNodeTag: {
|
|
158
|
+
const parentNode = this.node;
|
|
238
159
|
|
|
239
|
-
|
|
240
|
-
this.node.children = btree.push(this.node.children, reference);
|
|
160
|
+
targetPath = this.path;
|
|
241
161
|
|
|
162
|
+
if (!this.path.depth) {
|
|
163
|
+
this.node.flags = tag.value.flags;
|
|
242
164
|
this.node.children = btree.push(this.node.children, tag);
|
|
243
|
-
|
|
244
|
-
this.
|
|
245
|
-
this.
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
this.
|
|
249
|
-
|
|
165
|
+
this.node.type = tag.value.type;
|
|
166
|
+
this.node.language = tag.value.language;
|
|
167
|
+
this.node.attributes = tag.value.attributes || {};
|
|
168
|
+
} else {
|
|
169
|
+
let node = createNode(tag);
|
|
170
|
+
this.path = this.path.push(node, btree.getSum(parentNode.children) - 2);
|
|
171
|
+
add(parentNode, this.reference, node);
|
|
250
172
|
}
|
|
251
173
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
const { flags, type: openType } = openTag.value;
|
|
255
|
-
const closeTag = tag;
|
|
256
|
-
const { type } = closeTag.value;
|
|
257
|
-
|
|
258
|
-
this.node.children = btree.push(this.node.children, tag);
|
|
259
|
-
|
|
260
|
-
if (this.node.unboundAttributes?.size)
|
|
261
|
-
throw new Error('Grammar failed to bind all attributes');
|
|
262
|
-
|
|
263
|
-
if (!type) throw new Error(`CloseNodeTag must have type`);
|
|
264
|
-
|
|
265
|
-
if (type !== openType)
|
|
266
|
-
throw new Error(
|
|
267
|
-
`Grammar close {type: ${printType(type)}} did not match open {type: ${printType(
|
|
268
|
-
openType,
|
|
269
|
-
)}}`,
|
|
270
|
-
);
|
|
271
|
-
|
|
272
|
-
if (!flags.escape && !flags.trivia) {
|
|
273
|
-
add(this.parentNode, this.path.reference, this.node);
|
|
274
|
-
} else if (this.parentNode) {
|
|
275
|
-
this.parentNode.children = btree.push(
|
|
276
|
-
this.parentNode.children,
|
|
277
|
-
buildEmbeddedNode(this.node),
|
|
278
|
-
);
|
|
279
|
-
}
|
|
174
|
+
this.resolver.advance(tag);
|
|
175
|
+
updatePath(this.path, tag);
|
|
280
176
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
finalizeNode(this.node);
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
285
179
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
180
|
+
case CloseNodeTag: {
|
|
181
|
+
this.resolver.advance(tag);
|
|
182
|
+
this.node.children = btree.push(this.node.children, tag);
|
|
183
|
+
updatePath(this.path, tag);
|
|
290
184
|
|
|
291
|
-
|
|
292
|
-
|
|
185
|
+
if (this.node.unboundAttributes?.size)
|
|
186
|
+
throw new Error('Grammar failed to bind all attributes');
|
|
293
187
|
|
|
294
|
-
|
|
188
|
+
finalizeNode(this.node);
|
|
295
189
|
|
|
296
|
-
|
|
297
|
-
|
|
190
|
+
this.path = this.path.parent;
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
298
193
|
|
|
299
|
-
|
|
194
|
+
case GapTag: {
|
|
195
|
+
let target;
|
|
196
|
+
let lastTagPath = TagPath.from(this.path, -1);
|
|
197
|
+
let refPath = lastTagPath;
|
|
300
198
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
break;
|
|
199
|
+
while (refPath && refPath.tag.type !== ReferenceTag) {
|
|
200
|
+
refPath = refPath.previousSibling;
|
|
304
201
|
}
|
|
305
202
|
|
|
306
|
-
|
|
307
|
-
this.node.children = btree.push(this.node.children, tag);
|
|
308
|
-
|
|
309
|
-
const { isArray, name, hasGap } = tag.value;
|
|
310
|
-
|
|
311
|
-
if (hasGap && !this.node.flags.hasGap) {
|
|
312
|
-
throw new Error('gap reference in gapless node');
|
|
313
|
-
}
|
|
203
|
+
this.resolver.advance(tag);
|
|
314
204
|
|
|
315
|
-
|
|
316
|
-
this.node.properties[name] = [];
|
|
317
|
-
} else {
|
|
318
|
-
this.path = this.path.push(ctx, tag, btree.getSum(this.node.children));
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
this.tagPaths.set(tag, this.path);
|
|
322
|
-
break;
|
|
323
|
-
}
|
|
205
|
+
let wasHeld = this.held;
|
|
324
206
|
|
|
325
|
-
|
|
326
|
-
this.
|
|
207
|
+
if (this.held && lastTagPath.tag.type !== ShiftTag) {
|
|
208
|
+
target = this.held.node;
|
|
327
209
|
|
|
328
|
-
|
|
329
|
-
|
|
210
|
+
this.held = null;
|
|
211
|
+
} else if (refPath) {
|
|
212
|
+
this.expressions.advance();
|
|
330
213
|
|
|
331
|
-
if (
|
|
214
|
+
if (!this.expressions.done) {
|
|
215
|
+
const expression = this.expressions.value;
|
|
332
216
|
|
|
333
|
-
|
|
334
|
-
|
|
217
|
+
if (isArray(expression)) {
|
|
218
|
+
throw new Error('Invalid array interpolation');
|
|
219
|
+
}
|
|
335
220
|
|
|
336
|
-
|
|
221
|
+
if (expression == null) {
|
|
222
|
+
target = treeFromStream(buildNullTag());
|
|
223
|
+
} else {
|
|
224
|
+
target = getRoot(expression);
|
|
225
|
+
}
|
|
337
226
|
} else {
|
|
338
227
|
if (!this.node.flags.hasGap) throw new Error('Node must allow gaps');
|
|
339
228
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
if (isArray(expression)) {
|
|
344
|
-
throw new Error('Invalid array interpolation');
|
|
345
|
-
} else {
|
|
346
|
-
target = expression != null ? getRoot(expression) : buildStubNode(tag);
|
|
229
|
+
target = buildStubNode(tag);
|
|
230
|
+
}
|
|
347
231
|
|
|
348
|
-
|
|
349
|
-
|
|
232
|
+
this.held = null;
|
|
233
|
+
} else {
|
|
234
|
+
this.node.language = null;
|
|
235
|
+
this.node.type = null;
|
|
236
|
+
target = this.node;
|
|
237
|
+
}
|
|
350
238
|
|
|
351
|
-
|
|
239
|
+
const range = getRange(target);
|
|
352
240
|
|
|
353
|
-
|
|
354
|
-
// the stream still contains a gap token, even if expressions were specified
|
|
355
|
-
// get rid of the gap token in the stream!
|
|
356
|
-
} else {
|
|
357
|
-
target = buildStubNode(tag);
|
|
358
|
-
}
|
|
359
|
-
}
|
|
241
|
+
this.resultPath = range ? range[1] : this.resultPath;
|
|
360
242
|
|
|
361
|
-
|
|
243
|
+
if (refPath) {
|
|
244
|
+
add(this.path.node, refPath.tag, target, wasHeld);
|
|
245
|
+
}
|
|
362
246
|
|
|
363
|
-
|
|
364
|
-
|
|
247
|
+
updatePath(this.path, tag);
|
|
248
|
+
break;
|
|
249
|
+
}
|
|
365
250
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
}
|
|
251
|
+
case NullTag: {
|
|
252
|
+
const { node: parentNode, reference } = this;
|
|
253
|
+
const { name } = reference.value;
|
|
369
254
|
|
|
370
|
-
|
|
371
|
-
|
|
255
|
+
this.resolver.advance(tag);
|
|
256
|
+
updatePath(this.path, tag);
|
|
372
257
|
|
|
373
|
-
|
|
374
|
-
const { isArray, name } = this.result.value;
|
|
258
|
+
if (!name) throw new Error();
|
|
375
259
|
|
|
376
|
-
|
|
260
|
+
let stubNode = buildStubNode(tag);
|
|
377
261
|
|
|
378
|
-
|
|
379
|
-
properties[name] = newNode;
|
|
380
|
-
}
|
|
262
|
+
add(parentNode, reference, stubNode);
|
|
381
263
|
|
|
382
|
-
|
|
264
|
+
targetPath = this.path.push(stubNode, btree.getSum(this.node.children) - 2);
|
|
265
|
+
break;
|
|
266
|
+
}
|
|
383
267
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
268
|
+
case ArrayInitializerTag: {
|
|
269
|
+
const { node, reference } = this;
|
|
270
|
+
this.resolver.advance(tag);
|
|
387
271
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
const { properties } = this.node;
|
|
272
|
+
add(node, reference, []);
|
|
273
|
+
updatePath(this.path, tag);
|
|
274
|
+
break;
|
|
275
|
+
}
|
|
393
276
|
|
|
394
|
-
|
|
277
|
+
case ShiftTag: {
|
|
278
|
+
this.resolver.advance(tag);
|
|
279
|
+
updatePath(this.path, tag);
|
|
395
280
|
|
|
396
|
-
|
|
281
|
+
const finishedPath = this.resultPath.innerPath;
|
|
282
|
+
const finishedNode = finishedPath.node;
|
|
283
|
+
const ref = this.resultPath.previousSibling.tag;
|
|
397
284
|
|
|
398
|
-
|
|
285
|
+
this.held = { node: finishedNode, path: finishedPath };
|
|
399
286
|
|
|
400
|
-
|
|
401
|
-
node = btree.getAt(-1, node);
|
|
402
|
-
properties[ref.value.name] = btree.pop(properties[ref.value.name]);
|
|
403
|
-
} else {
|
|
404
|
-
properties[ref.value.name] = null;
|
|
405
|
-
}
|
|
287
|
+
if (!ref.value.name) throw new Error();
|
|
406
288
|
|
|
407
|
-
|
|
408
|
-
break;
|
|
409
|
-
}
|
|
289
|
+
if (!ref.value.flags.expression) throw new Error();
|
|
410
290
|
|
|
411
|
-
|
|
412
|
-
case ArrayTag:
|
|
413
|
-
this.node.children = btree.push(this.node.children, tag);
|
|
414
|
-
break;
|
|
291
|
+
this.node.children = btree.push(this.node.children, tag);
|
|
415
292
|
|
|
416
|
-
|
|
417
|
-
|
|
293
|
+
// this.path = finishedPath;
|
|
294
|
+
targetPath = this.path;
|
|
295
|
+
break;
|
|
418
296
|
}
|
|
297
|
+
|
|
298
|
+
case LiteralTag:
|
|
299
|
+
this.resolver.advance(tag);
|
|
300
|
+
updatePath(this.path, tag);
|
|
301
|
+
this.node.children = btree.push(this.node.children, tag);
|
|
302
|
+
break;
|
|
303
|
+
|
|
304
|
+
default:
|
|
305
|
+
throw new Error();
|
|
419
306
|
}
|
|
420
307
|
|
|
421
|
-
this.
|
|
308
|
+
this.resultPath = TagPath.from(targetPath, -1);
|
|
422
309
|
|
|
423
310
|
return tag;
|
|
424
311
|
}
|
|
425
312
|
|
|
426
|
-
*emit() {
|
|
427
|
-
const { nextTags } = this.context;
|
|
428
|
-
if (!this.depth) {
|
|
429
|
-
let emittable = this.emitted ? nextTags.get(this.emitted) : this.result;
|
|
430
|
-
|
|
431
|
-
while (
|
|
432
|
-
emittable &&
|
|
433
|
-
!(
|
|
434
|
-
emittable.type === OpenNodeTag &&
|
|
435
|
-
emittable.value.type &&
|
|
436
|
-
nodeStates.get(this.nodeForTag(emittable)).unboundAttributes?.size
|
|
437
|
-
)
|
|
438
|
-
) {
|
|
439
|
-
yield emittable;
|
|
440
|
-
this.emitted = emittable;
|
|
441
|
-
emittable = nextTags.get(this.emitted);
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
|
|
446
313
|
get ctx() {
|
|
447
314
|
return this.context;
|
|
448
315
|
}
|
|
@@ -456,80 +323,18 @@ export const State = class AgastState extends WeakStackFrame {
|
|
|
456
323
|
}
|
|
457
324
|
|
|
458
325
|
get parentNode() {
|
|
459
|
-
return this.
|
|
326
|
+
return this.path.parent.node;
|
|
460
327
|
}
|
|
461
328
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
this;
|
|
465
|
-
const { pathNodes } = internalContext;
|
|
466
|
-
|
|
467
|
-
const newNode = node && branchNode(node);
|
|
468
|
-
|
|
469
|
-
const nodeState = nodeStates.get(node);
|
|
470
|
-
|
|
471
|
-
pathNodes.set(path, newNode);
|
|
472
|
-
pathNodes.set(newNode, path);
|
|
473
|
-
|
|
474
|
-
nodeStates.set(newNode, { ...nodeState });
|
|
475
|
-
|
|
476
|
-
const nodeOpen = getOpenTag(node);
|
|
477
|
-
const nodeClose = getCloseTag(node);
|
|
478
|
-
if (nodeOpen) this.tagNodes.set(nodeOpen, newNode);
|
|
479
|
-
if (nodeClose) this.tagNodes.set(nodeClose, newNode);
|
|
480
|
-
|
|
481
|
-
return this.push(
|
|
482
|
-
context,
|
|
483
|
-
expressions,
|
|
484
|
-
path,
|
|
485
|
-
newNode,
|
|
486
|
-
result,
|
|
487
|
-
emitted,
|
|
488
|
-
held,
|
|
489
|
-
resolver.branch(),
|
|
490
|
-
internalContext,
|
|
491
|
-
);
|
|
329
|
+
get reference() {
|
|
330
|
+
return this.resolver.reference;
|
|
492
331
|
}
|
|
493
332
|
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
if (!parent) {
|
|
498
|
-
return null;
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
if (this.node && parent.node) {
|
|
502
|
-
acceptNode(parent.node, this.node);
|
|
503
|
-
const nodeState = nodeStates.get(this.node);
|
|
504
|
-
Object.assign(nodeStates.get(parent.node), nodeState);
|
|
505
|
-
} else {
|
|
506
|
-
parent.node = this.node;
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
// emitted isn't used here and probably doesn't need to be part of state
|
|
510
|
-
|
|
511
|
-
parent.expressions = this.expressions;
|
|
512
|
-
parent.result = this.result;
|
|
513
|
-
parent.held = this.held;
|
|
514
|
-
parent.path = this.path;
|
|
515
|
-
parent.node = this.node;
|
|
516
|
-
parent.resolver = this.resolver;
|
|
517
|
-
|
|
518
|
-
return parent;
|
|
333
|
+
get referencePath() {
|
|
334
|
+
return this.reference && this.path.referencePath;
|
|
519
335
|
}
|
|
520
336
|
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
if (!parent) throw new Error('rejected root state');
|
|
525
|
-
|
|
526
|
-
context.nextTags.delete(parent.result);
|
|
527
|
-
|
|
528
|
-
pathNodes.set(parent.path, parent.node);
|
|
529
|
-
|
|
530
|
-
if (getOpenTag(parent.node)) tagNodes.set(getOpenTag(parent.node), parent.node);
|
|
531
|
-
if (getCloseTag(parent.node)) tagNodes.set(getCloseTag(parent.node), parent.node);
|
|
532
|
-
|
|
533
|
-
return parent;
|
|
337
|
+
get node() {
|
|
338
|
+
return this.path?.node;
|
|
534
339
|
}
|
|
535
340
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bablr/agast-vm",
|
|
3
3
|
"description": "A VM providing DOM-like guarantees about agAST trees",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.7.0",
|
|
5
5
|
"author": "Conrad Buck<conartist6@gmail.com>",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"files": [
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
},
|
|
13
13
|
"sideEffects": false,
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@bablr/agast-helpers": "
|
|
16
|
-
"@bablr/agast-vm-helpers": "
|
|
15
|
+
"@bablr/agast-helpers": "0.6.0",
|
|
16
|
+
"@bablr/agast-vm-helpers": "0.6.0",
|
|
17
17
|
"@bablr/coroutine": "0.1.0",
|
|
18
18
|
"@bablr/weak-stack": "0.1.0",
|
|
19
19
|
"@iter-tools/imm-stack": "1.1.0"
|