@bablr/boot 0.8.1 → 0.9.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/index.js +28 -8
- package/lib/languages/cstml.js +58 -40
- package/lib/languages/json.js +2 -2
- package/lib/languages/regex.js +3 -3
- package/lib/languages/spamex.js +22 -8
- package/lib/miniparser.js +36 -51
- package/lib/path.js +1 -13
- package/lib/utils.js +2 -2
- package/package.json +4 -4
package/lib/index.js
CHANGED
|
@@ -6,12 +6,22 @@ import * as instruction from './languages/instruction.js';
|
|
|
6
6
|
import { TemplateParser } from './miniparser.js';
|
|
7
7
|
import { buildEmbeddedMatcher, buildEmbeddedRegex } from '@bablr/agast-vm-helpers/builders';
|
|
8
8
|
|
|
9
|
+
const trees = new WeakMap();
|
|
10
|
+
|
|
9
11
|
export const buildTag = (language, defaultType) => {
|
|
10
12
|
const defaultTag = (quasis, ...exprs) => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
13
|
+
let tree;
|
|
14
|
+
if (trees.has(quasis) && !exprs.length) {
|
|
15
|
+
tree = trees.get(quasis);
|
|
16
|
+
} else {
|
|
17
|
+
tree = new TemplateParser(language, quasis.raw, exprs).eval({
|
|
18
|
+
language: language.name,
|
|
19
|
+
type: defaultType,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
trees.set(quasis, tree);
|
|
23
|
+
}
|
|
24
|
+
return tree;
|
|
15
25
|
};
|
|
16
26
|
|
|
17
27
|
return new Proxy(defaultTag, {
|
|
@@ -20,11 +30,21 @@ export const buildTag = (language, defaultType) => {
|
|
|
20
30
|
},
|
|
21
31
|
|
|
22
32
|
get(_, type) {
|
|
33
|
+
const trees = new WeakMap();
|
|
34
|
+
|
|
23
35
|
return (quasis, ...exprs) => {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
36
|
+
let tree;
|
|
37
|
+
if (trees.has(quasis) && !exprs.length) {
|
|
38
|
+
tree = trees.get(quasis);
|
|
39
|
+
} else {
|
|
40
|
+
tree = new TemplateParser(language, quasis.raw, exprs).eval({
|
|
41
|
+
language: language.name,
|
|
42
|
+
type,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
trees.set(quasis, tree);
|
|
46
|
+
}
|
|
47
|
+
return tree;
|
|
28
48
|
};
|
|
29
49
|
},
|
|
30
50
|
});
|
package/lib/languages/cstml.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as sym from '@bablr/agast-vm-helpers/symbols';
|
|
2
2
|
import * as JSON from './json.js';
|
|
3
|
+
import { isArray } from 'iter-tools-es';
|
|
3
4
|
|
|
4
5
|
const _ = /\s+/y;
|
|
5
6
|
const PN = 'Punctuator';
|
|
@@ -33,16 +34,15 @@ export const covers = new Map([
|
|
|
33
34
|
'OpenNodeTag',
|
|
34
35
|
'CloseNodeTag',
|
|
35
36
|
'LiteralTag',
|
|
36
|
-
'
|
|
37
|
+
'BindingTag',
|
|
38
|
+
'InitializerTag',
|
|
39
|
+
'AttributeDefinition',
|
|
37
40
|
'Number',
|
|
38
41
|
'Digit',
|
|
39
42
|
'Content',
|
|
40
43
|
'NodeFlags',
|
|
41
44
|
]),
|
|
42
45
|
],
|
|
43
|
-
['TagType', new Set(['Identifier', 'GlobalIdentifier'])],
|
|
44
|
-
['Tag', new Set(['LiteralTag', 'Trivia'])],
|
|
45
|
-
['PropertyValue', new Set(['GapTag', 'Node', 'NullTag'])],
|
|
46
46
|
]);
|
|
47
47
|
|
|
48
48
|
export const grammar = class CSTMLMiniparserGrammar {
|
|
@@ -80,6 +80,22 @@ export const grammar = class CSTMLMiniparserGrammar {
|
|
|
80
80
|
p.eat('<//>', PN, { path: 'sigilToken' });
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
// @Node
|
|
84
|
+
LiteralTag(p) {
|
|
85
|
+
p.eatProduction('JSON:String', { path: 'value' });
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
//@Node
|
|
89
|
+
InitializerTag(p) {
|
|
90
|
+
let isArray;
|
|
91
|
+
if ((isArray = p.match('['))) {
|
|
92
|
+
p.eat('[]', PN, { path: 'sigilToken' });
|
|
93
|
+
} else {
|
|
94
|
+
p.eat('undefined', PN, { path: 'sigilToken' });
|
|
95
|
+
}
|
|
96
|
+
return { attrs: { isArray } };
|
|
97
|
+
}
|
|
98
|
+
|
|
83
99
|
// @Node
|
|
84
100
|
Node(p, props) {
|
|
85
101
|
let open = p.eatProduction('OpenNodeTag', { path: 'open' }, props);
|
|
@@ -90,9 +106,12 @@ export const grammar = class CSTMLMiniparserGrammar {
|
|
|
90
106
|
p.eatProduction('NodeChild', { path: 'children[]' }, { token: true });
|
|
91
107
|
p.eatMatchTrivia(_);
|
|
92
108
|
} else if (!open.properties.selfClosingTagToken) {
|
|
109
|
+
let lastIndex = p.idx;
|
|
93
110
|
while (!(p.match('</') || p.done)) {
|
|
94
111
|
p.eatProduction('NodeChild', { path: 'children[]' });
|
|
95
112
|
p.eatMatchTrivia(_);
|
|
113
|
+
if (p.idx === lastIndex) break;
|
|
114
|
+
lastIndex = p.idx;
|
|
96
115
|
}
|
|
97
116
|
}
|
|
98
117
|
|
|
@@ -104,6 +123,10 @@ export const grammar = class CSTMLMiniparserGrammar {
|
|
|
104
123
|
NodeChild(p, props) {
|
|
105
124
|
const { token } = props || {};
|
|
106
125
|
|
|
126
|
+
if (p.match('{')) {
|
|
127
|
+
p.eatProduction('AttributeDefinition');
|
|
128
|
+
}
|
|
129
|
+
|
|
107
130
|
if (token) {
|
|
108
131
|
if (p.match(/<\*?@/y)) {
|
|
109
132
|
p.eatProduction('Node');
|
|
@@ -111,9 +134,7 @@ export const grammar = class CSTMLMiniparserGrammar {
|
|
|
111
134
|
p.eatProduction('LiteralTag');
|
|
112
135
|
}
|
|
113
136
|
} else {
|
|
114
|
-
if (p.match(
|
|
115
|
-
p.eatProduction('Node');
|
|
116
|
-
} else if (p.match(/[a-zA-Z`\\\u{80}-\u{10ffff}.]|[.#@]/uy)) {
|
|
137
|
+
if (p.match(/[:<a-zA-Z`\\\u{80}-\u{10ffff}.]|[.#@]/uy)) {
|
|
117
138
|
p.eatProduction('Property');
|
|
118
139
|
} else if (p.match(/['"]/y)) {
|
|
119
140
|
p.eatProduction('LiteralTag');
|
|
@@ -121,16 +142,37 @@ export const grammar = class CSTMLMiniparserGrammar {
|
|
|
121
142
|
}
|
|
122
143
|
}
|
|
123
144
|
|
|
145
|
+
// @Node
|
|
146
|
+
AttributeDefinition(p) {
|
|
147
|
+
p.eat('{', PN, { path: 'openToken', balanced: '}' });
|
|
148
|
+
p.eatMatchTrivia(_);
|
|
149
|
+
p.eatProduction('IdentifierPath', { path: 'key' });
|
|
150
|
+
p.eatMatchTrivia(_);
|
|
151
|
+
p.eat(':', PN, { path: 'sigilToken' });
|
|
152
|
+
p.eatMatchTrivia(_);
|
|
153
|
+
p.eatProduction('JSON:Expression', { path: 'value' });
|
|
154
|
+
p.eatMatchTrivia(_);
|
|
155
|
+
p.eat('}', PN, { path: 'closeToken', balancer: true });
|
|
156
|
+
}
|
|
157
|
+
|
|
124
158
|
// @Node
|
|
125
159
|
Property(p) {
|
|
126
|
-
p.
|
|
160
|
+
if (p.match(/[a-zA-Z`\\\u{80}-\u{10ffff}.]|[.#@]/uy)) {
|
|
161
|
+
p.eatProduction('ReferenceTag', { path: 'reference' });
|
|
162
|
+
}
|
|
127
163
|
p.eatMatchTrivia(_);
|
|
164
|
+
if (p.match(':')) {
|
|
165
|
+
p.eatProduction('BindingTag', { path: 'binding' });
|
|
166
|
+
p.eatMatchTrivia(_);
|
|
167
|
+
}
|
|
128
168
|
p.eatProduction('PropertyValue', { path: 'value' });
|
|
129
169
|
}
|
|
130
170
|
|
|
131
171
|
PropertyValue(p) {
|
|
132
172
|
if (p.match('null')) {
|
|
133
173
|
p.eatProduction('NullTag');
|
|
174
|
+
} else if (p.match(/\[\]|undefined/y)) {
|
|
175
|
+
p.eatProduction('InitializerTag');
|
|
134
176
|
} else if (p.match('<//>')) {
|
|
135
177
|
p.eatProduction('GapTag');
|
|
136
178
|
} else {
|
|
@@ -164,7 +206,7 @@ export const grammar = class CSTMLMiniparserGrammar {
|
|
|
164
206
|
}
|
|
165
207
|
|
|
166
208
|
if (!flags.properties.fragmentToken) {
|
|
167
|
-
p.eatProduction('
|
|
209
|
+
p.eatProduction('Identifier', { path: 'type' });
|
|
168
210
|
|
|
169
211
|
sp = p.eatMatchTrivia(_);
|
|
170
212
|
|
|
@@ -181,7 +223,7 @@ export const grammar = class CSTMLMiniparserGrammar {
|
|
|
181
223
|
}
|
|
182
224
|
|
|
183
225
|
if (p.match('{') || p.atExpression) {
|
|
184
|
-
p.eatProduction('Object');
|
|
226
|
+
p.eatProduction('JSON:Object');
|
|
185
227
|
sp = p.eatMatchTrivia(_);
|
|
186
228
|
}
|
|
187
229
|
|
|
@@ -197,25 +239,13 @@ export const grammar = class CSTMLMiniparserGrammar {
|
|
|
197
239
|
p.eat('>', PN, { path: 'closeToken', endSpan: 'Tag', balancer: true });
|
|
198
240
|
}
|
|
199
241
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
) {
|
|
205
|
-
p.eatProduction('LanguageReference', { path: 'language' });
|
|
206
|
-
p.eat(':', PN, { path: 'namespaceSeparatorToken' });
|
|
207
|
-
p.eatProduction('Identifier', { path: 'type' });
|
|
208
|
-
} else {
|
|
209
|
-
p.eatProduction('Identifier', { path: 'type' });
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
LanguageReference(p) {
|
|
214
|
-
if (p.match(/['"]/y)) {
|
|
215
|
-
p.eatProduction('JSON:String');
|
|
216
|
-
} else {
|
|
242
|
+
// @Node
|
|
243
|
+
BindingTag(p) {
|
|
244
|
+
p.eat(':', PN, { path: 'openToken', startSpan: 'Tag', balanced: ':' });
|
|
245
|
+
if (!p.match(':')) {
|
|
217
246
|
p.eatProduction('IdentifierPath');
|
|
218
247
|
}
|
|
248
|
+
p.eat(':', PN, { path: 'closeToken', endSpan: 'Tag', balancer: true });
|
|
219
249
|
}
|
|
220
250
|
|
|
221
251
|
IdentifierPath(p) {
|
|
@@ -268,24 +298,12 @@ export const grammar = class CSTMLMiniparserGrammar {
|
|
|
268
298
|
ReferenceTag(p) {
|
|
269
299
|
let name;
|
|
270
300
|
if ((name = p.match(/[.#@]/y))) {
|
|
271
|
-
p.eat(name, PN, { path: '
|
|
301
|
+
p.eat(name, PN, { path: 'type' });
|
|
272
302
|
} else {
|
|
273
303
|
p.eatProduction('Identifier', { path: 'name' });
|
|
274
304
|
}
|
|
275
305
|
p.eatMatchTrivia(_);
|
|
276
|
-
let open = p.eatMatch('[', PN, { path: 'openIndex', startSpan: 'Index', balanced: ']' });
|
|
277
306
|
|
|
278
|
-
if (open) {
|
|
279
|
-
p.eatMatchTrivia(_);
|
|
280
|
-
|
|
281
|
-
if (p.match(/\d/)) {
|
|
282
|
-
p.eatProduction('UnsignedInteger', { path: 'index' });
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
p.eatMatchTrivia(_);
|
|
286
|
-
p.eat(']', PN, { path: 'closeIndex', endSpan: 'Index', balancer: true });
|
|
287
|
-
}
|
|
288
|
-
p.eatMatchTrivia(_);
|
|
289
307
|
if (p.match(/[+$]/y)) {
|
|
290
308
|
p.eatProduction('ReferenceFlags', { path: 'flags' });
|
|
291
309
|
p.eatMatchTrivia(_);
|
package/lib/languages/json.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import objectEntries from 'iter-tools/methods/object-entries';
|
|
1
|
+
import objectEntries from 'iter-tools-es/methods/object-entries';
|
|
2
2
|
import * as sym from '@bablr/agast-vm-helpers/symbols';
|
|
3
3
|
import * as Spamex from './spamex.js';
|
|
4
4
|
import * as CSTML from './cstml.js';
|
|
@@ -68,7 +68,7 @@ export const cookEscape = (escape, span) => {
|
|
|
68
68
|
return String.fromCodePoint(parseInt(hexMatch[1], 16));
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
const litPattern = span === 'Single' ? /\\([\\gnrt0'])/y : /\\([\\gnrt0"])/y;
|
|
71
|
+
const litPattern = span.type === 'Single' ? /\\([\\gnrt0'])/y : /\\([\\gnrt0"])/y;
|
|
72
72
|
const litMatch = litPattern.exec(escape);
|
|
73
73
|
|
|
74
74
|
if (litMatch) {
|
package/lib/languages/regex.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as sym from '@bablr/agast-vm-helpers/symbols';
|
|
2
|
-
import when from 'iter-tools/methods/when';
|
|
2
|
+
import when from 'iter-tools-es/methods/when';
|
|
3
3
|
import { escapables } from './json.js';
|
|
4
4
|
|
|
5
5
|
export const name = 'Regex';
|
|
@@ -91,7 +91,7 @@ const unique = (flags) => flags.length === new Set(flags).size;
|
|
|
91
91
|
const getSpecialPattern = (span) => {
|
|
92
92
|
const { type } = span;
|
|
93
93
|
if (type === 'Bare') {
|
|
94
|
-
return /[
|
|
94
|
+
return /[*+?{}\[\]()\.^$|\\\n\/><]/y;
|
|
95
95
|
} else if (type === 'CharacterClass') {
|
|
96
96
|
return /[\]\\]/y;
|
|
97
97
|
} else if (type === 'CharacterClass:First') {
|
|
@@ -206,7 +206,7 @@ export const grammar = class RegexMiniparserGrammar {
|
|
|
206
206
|
}
|
|
207
207
|
|
|
208
208
|
if (p.match(/[*+?]|{/y)) {
|
|
209
|
-
|
|
209
|
+
return { shift: 'Quantifier' };
|
|
210
210
|
}
|
|
211
211
|
}
|
|
212
212
|
|
package/lib/languages/spamex.js
CHANGED
|
@@ -26,6 +26,7 @@ export const covers = new Map([
|
|
|
26
26
|
'ArrayNodeMatcher',
|
|
27
27
|
'NullNodeMatcher',
|
|
28
28
|
'ReferenceMatcher',
|
|
29
|
+
'BindingMatcher',
|
|
29
30
|
'OpenNodeMatcher',
|
|
30
31
|
'CloseNodeMatcher',
|
|
31
32
|
'Literal',
|
|
@@ -44,7 +45,7 @@ export const covers = new Map([
|
|
|
44
45
|
export const grammar = class SpamexMiniparserGrammar {
|
|
45
46
|
// @Cover
|
|
46
47
|
Matcher(p) {
|
|
47
|
-
if (p.match(/[a-zA-Z
|
|
48
|
+
if (p.match(/[a-zA-Z.#@<:]/y)) {
|
|
48
49
|
p.eatProduction('PropertyMatcher');
|
|
49
50
|
} else if (p.match(/['"/]/y)) {
|
|
50
51
|
p.eatProduction('StringMatcher');
|
|
@@ -80,6 +81,12 @@ export const grammar = class SpamexMiniparserGrammar {
|
|
|
80
81
|
|
|
81
82
|
p.eatMatchTrivia(_);
|
|
82
83
|
|
|
84
|
+
if (p.match(':')) {
|
|
85
|
+
p.eatProduction('BindingMatcher', { path: 'bindingMatcher' });
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
p.eatMatchTrivia(_);
|
|
89
|
+
|
|
83
90
|
p.eatProduction('NodeMatcher', { path: 'nodeMatcher' });
|
|
84
91
|
}
|
|
85
92
|
|
|
@@ -87,7 +94,7 @@ export const grammar = class SpamexMiniparserGrammar {
|
|
|
87
94
|
ReferenceMatcher(p) {
|
|
88
95
|
let name;
|
|
89
96
|
if ((name = p.match(/[.#@]/y))) {
|
|
90
|
-
name = p.eat(name, PN, { path: '
|
|
97
|
+
name = p.eat(name, PN, { path: 'type' });
|
|
91
98
|
} else if (p.match(/[A-Za-z]/y)) {
|
|
92
99
|
name = p.eatProduction('CSTML:Identifier', { path: 'name' });
|
|
93
100
|
}
|
|
@@ -108,6 +115,15 @@ export const grammar = class SpamexMiniparserGrammar {
|
|
|
108
115
|
p.eat(':', PN, { path: 'mapToken' });
|
|
109
116
|
}
|
|
110
117
|
|
|
118
|
+
// @Node
|
|
119
|
+
BindingMatcher(p) {
|
|
120
|
+
p.eat(':', PN, { path: 'openToken' });
|
|
121
|
+
p.eatMatchTrivia(_);
|
|
122
|
+
p.eatProduction('CSTML:IdentifierPath', { path: 'languagePath' });
|
|
123
|
+
p.eatMatchTrivia(_);
|
|
124
|
+
p.eat(':', PN, { path: 'closeToken' });
|
|
125
|
+
}
|
|
126
|
+
|
|
111
127
|
NodeMatcher(p) {
|
|
112
128
|
if (p.match('<//>')) {
|
|
113
129
|
p.eatProduction('GapNodeMatcher');
|
|
@@ -152,14 +168,12 @@ export const grammar = class SpamexMiniparserGrammar {
|
|
|
152
168
|
p.eatProduction('CSTML:NodeFlags', { path: 'flags' });
|
|
153
169
|
}
|
|
154
170
|
|
|
155
|
-
if (p.match(/[
|
|
156
|
-
p.eatProduction('CSTML:
|
|
171
|
+
if (p.match(/[a-zA-Z]/y) || p.atExpression) {
|
|
172
|
+
p.eatProduction('CSTML:Identifier', { path: 'type' });
|
|
157
173
|
} else if (p.match('?')) {
|
|
158
174
|
p.eat('?', PN, { path: 'type' });
|
|
159
|
-
} else if (p.match('
|
|
160
|
-
p.
|
|
161
|
-
} else {
|
|
162
|
-
p.eatProduction('CSTML:Identifier', { path: 'type' });
|
|
175
|
+
} else if (p.match('_')) {
|
|
176
|
+
p.eat('_', PN, { path: 'type' });
|
|
163
177
|
}
|
|
164
178
|
|
|
165
179
|
let sp = p.eatMatchTrivia(_);
|
package/lib/miniparser.js
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import escapeRegex from 'escape-string-regexp';
|
|
2
|
-
import arrayLast from 'iter-tools/methods/array-last';
|
|
3
|
-
import isString from 'iter-tools/methods/is-string';
|
|
4
|
-
import isObject from 'iter-tools/methods/is-object';
|
|
5
|
-
import find from 'iter-tools/methods/find';
|
|
6
|
-
import every from 'iter-tools/methods/every';
|
|
2
|
+
import arrayLast from 'iter-tools-es/methods/array-last';
|
|
3
|
+
import isString from 'iter-tools-es/methods/is-string';
|
|
4
|
+
import isObject from 'iter-tools-es/methods/is-object';
|
|
5
|
+
import find from 'iter-tools-es/methods/find';
|
|
6
|
+
import every from 'iter-tools-es/methods/every';
|
|
7
7
|
import * as sym from '@bablr/agast-vm-helpers/symbols';
|
|
8
8
|
import { Match } from './match.js';
|
|
9
|
-
import { parsePath } from './path.js';
|
|
10
9
|
import { isRegex, isArray, getPrototypeOf } from './utils.js';
|
|
11
10
|
import { ReferenceTag, LiteralTag } from '@bablr/agast-helpers/symbols';
|
|
12
11
|
import {
|
|
@@ -16,9 +15,10 @@ import {
|
|
|
16
15
|
buildReferenceTag,
|
|
17
16
|
nodeFlags,
|
|
18
17
|
} from '@bablr/agast-helpers/builders';
|
|
19
|
-
import { add, buildToken } from '@bablr/agast-helpers/tree';
|
|
20
|
-
import * as sumtree from '@bablr/agast-helpers/
|
|
21
|
-
import { get } from '@bablr/agast-helpers/path';
|
|
18
|
+
import { add, buildToken, shift } from '@bablr/agast-helpers/tree';
|
|
19
|
+
import * as sumtree from '@bablr/agast-helpers/children';
|
|
20
|
+
import { buildPathSegment, get } from '@bablr/agast-helpers/path';
|
|
21
|
+
import { parseReference } from '@bablr/agast-helpers/shorthand';
|
|
22
22
|
|
|
23
23
|
const Escape = Symbol.for('Escape');
|
|
24
24
|
|
|
@@ -138,7 +138,7 @@ export class TemplateParser {
|
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
-
eval(id, attrs = {}, props = {},
|
|
141
|
+
eval(id, attrs = {}, props = {}, shift_ = null) {
|
|
142
142
|
const parentMatch = this.m;
|
|
143
143
|
const parentPath = this.path?.node ? this.path : this.path?.parent;
|
|
144
144
|
const { type } = id;
|
|
@@ -176,7 +176,7 @@ export class TemplateParser {
|
|
|
176
176
|
|
|
177
177
|
if (parentPath?.node && (isNode || covers.has(type))) {
|
|
178
178
|
const { node } = parentPath;
|
|
179
|
-
const path =
|
|
179
|
+
const path = parseReference(this.m.attrs.path);
|
|
180
180
|
|
|
181
181
|
if (isArray(result)) {
|
|
182
182
|
for (const value of result) {
|
|
@@ -201,10 +201,7 @@ export class TemplateParser {
|
|
|
201
201
|
|
|
202
202
|
if (isNode) {
|
|
203
203
|
let { node } = this.path;
|
|
204
|
-
node.children = sumtree.push(
|
|
205
|
-
node.children,
|
|
206
|
-
buildOpenNodeTag(nodeFlags, node.language, node.type),
|
|
207
|
-
);
|
|
204
|
+
node.children = sumtree.push(node.children, buildOpenNodeTag(nodeFlags, node.type));
|
|
208
205
|
}
|
|
209
206
|
|
|
210
207
|
const result = getPrototypeOf(grammar)[type].call(grammar, this, props);
|
|
@@ -220,18 +217,26 @@ export class TemplateParser {
|
|
|
220
217
|
node.children = sumtree.replaceAt(
|
|
221
218
|
0,
|
|
222
219
|
node.children,
|
|
223
|
-
buildOpenNodeTag(nodeFlags, node.
|
|
220
|
+
buildOpenNodeTag(nodeFlags, node.type, result.attrs),
|
|
224
221
|
);
|
|
225
222
|
}
|
|
226
223
|
|
|
227
224
|
node.children = sumtree.push(node.children, buildCloseNodeTag());
|
|
228
225
|
|
|
229
226
|
if (parentPath?.node && !covers.has(type)) {
|
|
230
|
-
const path =
|
|
227
|
+
const path = parseReference(this.m.attrs.path);
|
|
231
228
|
|
|
232
|
-
|
|
229
|
+
if (shift_ == null) {
|
|
230
|
+
add(parentPath.node, path, node);
|
|
231
|
+
} else {
|
|
232
|
+
shift(parentPath.node, path, node);
|
|
233
|
+
}
|
|
233
234
|
}
|
|
234
235
|
}
|
|
236
|
+
|
|
237
|
+
if (result?.shift) {
|
|
238
|
+
this.shiftProduction(result.shift);
|
|
239
|
+
}
|
|
235
240
|
}
|
|
236
241
|
|
|
237
242
|
this.m = this.m.parent;
|
|
@@ -245,7 +250,6 @@ export class TemplateParser {
|
|
|
245
250
|
throw new Error('strings must be wrapped in nodes');
|
|
246
251
|
}
|
|
247
252
|
}
|
|
248
|
-
|
|
249
253
|
return path.node;
|
|
250
254
|
}
|
|
251
255
|
|
|
@@ -289,21 +293,20 @@ export class TemplateParser {
|
|
|
289
293
|
|
|
290
294
|
this.held = null;
|
|
291
295
|
|
|
292
|
-
const path =
|
|
296
|
+
const path = parseReference(attrs.path);
|
|
293
297
|
|
|
294
|
-
add(node, path, held
|
|
298
|
+
add(node, path, held);
|
|
295
299
|
|
|
296
300
|
return held;
|
|
297
301
|
}
|
|
298
302
|
|
|
299
303
|
shiftProduction(id, attrs = {}, props = {}) {
|
|
300
304
|
const { node } = this;
|
|
301
|
-
const { properties } = node;
|
|
302
305
|
// don't push a new path onto the stack
|
|
303
306
|
|
|
304
307
|
// get the most recently produced node and detach it from its parent
|
|
305
308
|
|
|
306
|
-
const ref = sumtree.getAt(-
|
|
309
|
+
const ref = sumtree.getAt(-3, node.children);
|
|
307
310
|
|
|
308
311
|
if (!ref.value.flags.expression) throw new Error();
|
|
309
312
|
|
|
@@ -311,13 +314,13 @@ export class TemplateParser {
|
|
|
311
314
|
throw new Error();
|
|
312
315
|
}
|
|
313
316
|
|
|
314
|
-
this.held = get(ref, node);
|
|
317
|
+
this.held = get(buildPathSegment(ref.value.name, -1), node);
|
|
315
318
|
|
|
316
319
|
let id_ = this.buildId(id);
|
|
317
320
|
|
|
318
321
|
const shifted = this.eval(id_, attrs, props, 1);
|
|
319
322
|
|
|
320
|
-
//
|
|
323
|
+
// shift(node, ref, shifted);
|
|
321
324
|
|
|
322
325
|
return shifted;
|
|
323
326
|
}
|
|
@@ -336,10 +339,9 @@ export class TemplateParser {
|
|
|
336
339
|
|
|
337
340
|
this.updateSpans(attrs);
|
|
338
341
|
|
|
339
|
-
const path_ =
|
|
340
|
-
const language = this.language.canonicalURL;
|
|
342
|
+
const path_ = parseReference(attrs.path);
|
|
341
343
|
|
|
342
|
-
add(this.node, path_, buildToken(
|
|
344
|
+
add(this.node, path_, buildToken(type, result, _attrs));
|
|
343
345
|
|
|
344
346
|
return result;
|
|
345
347
|
}
|
|
@@ -360,10 +362,9 @@ export class TemplateParser {
|
|
|
360
362
|
|
|
361
363
|
this.idx += result.length;
|
|
362
364
|
|
|
363
|
-
const path =
|
|
364
|
-
const language = this.language.canonicalURL;
|
|
365
|
+
const path = parseReference(attrs.path);
|
|
365
366
|
|
|
366
|
-
add(this.node, path, buildToken(
|
|
367
|
+
add(this.node, path, buildToken(type, result));
|
|
367
368
|
}
|
|
368
369
|
return result;
|
|
369
370
|
}
|
|
@@ -375,11 +376,7 @@ export class TemplateParser {
|
|
|
375
376
|
|
|
376
377
|
this.idx += result.length;
|
|
377
378
|
|
|
378
|
-
add(
|
|
379
|
-
this.node,
|
|
380
|
-
buildReferenceTag('#'),
|
|
381
|
-
buildToken('https://bablr.org/languages/core/en/space-tab-newline', 'Space', result),
|
|
382
|
-
);
|
|
379
|
+
add(this.node, buildReferenceTag('#'), buildToken('Space', result));
|
|
383
380
|
|
|
384
381
|
return result;
|
|
385
382
|
}
|
|
@@ -390,11 +387,7 @@ export class TemplateParser {
|
|
|
390
387
|
if (result) {
|
|
391
388
|
this.idx += result.length;
|
|
392
389
|
|
|
393
|
-
add(
|
|
394
|
-
this.node,
|
|
395
|
-
buildReferenceTag('#'),
|
|
396
|
-
buildToken('https://bablr.org/languages/core/en/space-tab-newline', 'Space', result),
|
|
397
|
-
);
|
|
390
|
+
add(this.node, buildReferenceTag('#'), buildToken('Space', result));
|
|
398
391
|
}
|
|
399
392
|
|
|
400
393
|
return result;
|
|
@@ -411,11 +404,7 @@ export class TemplateParser {
|
|
|
411
404
|
const cooked = this.language.cookEscape(result, this.span);
|
|
412
405
|
const attributes = { cooked };
|
|
413
406
|
|
|
414
|
-
add(
|
|
415
|
-
this.node,
|
|
416
|
-
buildReferenceTag('@'),
|
|
417
|
-
buildToken(this.language.canonicalURL, 'Escape', raw, attributes),
|
|
418
|
-
);
|
|
407
|
+
add(this.node, buildReferenceTag('@'), buildToken('Escape', raw, attributes));
|
|
419
408
|
|
|
420
409
|
return result;
|
|
421
410
|
}
|
|
@@ -430,11 +419,7 @@ export class TemplateParser {
|
|
|
430
419
|
const cooked = this.language.cookEscape(result, this.span);
|
|
431
420
|
const attributes = { cooked };
|
|
432
421
|
|
|
433
|
-
add(
|
|
434
|
-
this.node,
|
|
435
|
-
buildReferenceTag('@'),
|
|
436
|
-
buildToken(this.language.canonicalURL, 'Escape', raw, attributes),
|
|
437
|
-
);
|
|
422
|
+
add(this.node, buildReferenceTag('@'), buildToken('Escape', raw, attributes));
|
|
438
423
|
}
|
|
439
424
|
|
|
440
425
|
return result;
|
package/lib/path.js
CHANGED
|
@@ -1,18 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const { hasOwn, freeze } = Object;
|
|
1
|
+
const { hasOwn } = Object;
|
|
4
2
|
const { isArray } = Array;
|
|
5
3
|
|
|
6
|
-
export const parsePath = (str) => {
|
|
7
|
-
const match = /^([a-zA-Z]+)(\[\])?(\+)?(\$)?$/.exec(str);
|
|
8
|
-
|
|
9
|
-
if (!match) throw new Error();
|
|
10
|
-
|
|
11
|
-
let flags = freeze({ expression: !!match[3], hasGap: !!match[4] });
|
|
12
|
-
|
|
13
|
-
return buildReferenceTag(match[1], !!match[2], flags);
|
|
14
|
-
};
|
|
15
|
-
|
|
16
4
|
export class Path {
|
|
17
5
|
constructor(id, attributes, parent = null) {
|
|
18
6
|
this.id = id;
|
package/lib/utils.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bablr/boot",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Compile-time tools for bootstrapping BABLR VM",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=12.0.0"
|
|
@@ -20,11 +20,11 @@
|
|
|
20
20
|
],
|
|
21
21
|
"sideEffects": false,
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@bablr/agast-helpers": "0.
|
|
24
|
-
"@bablr/agast-vm-helpers": "0.
|
|
23
|
+
"@bablr/agast-helpers": "0.8.0",
|
|
24
|
+
"@bablr/agast-vm-helpers": "0.8.0",
|
|
25
25
|
"@iter-tools/imm-stack": "1.1.0",
|
|
26
26
|
"escape-string-regexp": "5.0.0",
|
|
27
|
-
"iter-tools": "^7.
|
|
27
|
+
"iter-tools-es": "^7.0.2"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@babel/cli": "^7.23.0",
|