@bablr/boot 0.10.0 → 0.11.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 +43 -14
- package/lib/languages/cstml.js +169 -108
- package/lib/languages/instruction.js +32 -22
- package/lib/languages/json.js +11 -29
- package/lib/languages/regex.js +6 -32
- package/lib/languages/spamex.js +81 -88
- package/lib/match.js +19 -16
- package/lib/miniparser.js +141 -112
- package/lib/path.js +5 -1
- package/package.json +7 -4
package/lib/index.js
CHANGED
|
@@ -1,26 +1,39 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
1
|
+
import cstmll from './languages/cstml.js';
|
|
2
|
+
import spamex from './languages/spamex.js';
|
|
3
|
+
import regex from './languages/regex.js';
|
|
4
|
+
import instruction from './languages/instruction.js';
|
|
5
5
|
|
|
6
6
|
import { TemplateParser } from './miniparser.js';
|
|
7
7
|
import { buildEmbeddedMatcher, buildEmbeddedRegex } from '@bablr/agast-vm-helpers/builders';
|
|
8
|
+
import { reifyExpression } from '@bablr/agast-vm-helpers';
|
|
9
|
+
import { interpolate } from '@bablr/agast-helpers/template';
|
|
10
|
+
import { buildGapTag } from '@bablr/agast-helpers/builders';
|
|
11
|
+
import { buildNode } from '@bablr/agast-helpers/path';
|
|
8
12
|
|
|
9
13
|
const trees = new WeakMap();
|
|
10
14
|
|
|
11
15
|
export const buildTag = (language, defaultType) => {
|
|
12
16
|
const defaultTag = (quasis, ...exprs) => {
|
|
13
17
|
let tree;
|
|
14
|
-
if (trees.has(quasis)
|
|
18
|
+
if (trees.has(quasis)) {
|
|
15
19
|
tree = trees.get(quasis);
|
|
16
20
|
} else {
|
|
17
|
-
tree = new TemplateParser(
|
|
21
|
+
tree = new TemplateParser(
|
|
22
|
+
language,
|
|
23
|
+
quasis.raw,
|
|
24
|
+
exprs.map((e) => buildNode(buildGapTag())),
|
|
25
|
+
).eatProduction({
|
|
18
26
|
language: language.name,
|
|
19
|
-
|
|
27
|
+
name: defaultType,
|
|
20
28
|
});
|
|
21
29
|
|
|
22
30
|
trees.set(quasis, tree);
|
|
23
31
|
}
|
|
32
|
+
|
|
33
|
+
if (exprs.length) {
|
|
34
|
+
tree = interpolate(tree, exprs);
|
|
35
|
+
}
|
|
36
|
+
|
|
24
37
|
return tree;
|
|
25
38
|
};
|
|
26
39
|
|
|
@@ -29,21 +42,30 @@ export const buildTag = (language, defaultType) => {
|
|
|
29
42
|
return defaultTag.apply(receiver, argsList);
|
|
30
43
|
},
|
|
31
44
|
|
|
32
|
-
get(_,
|
|
45
|
+
get(_, name) {
|
|
33
46
|
const trees = new WeakMap();
|
|
34
47
|
|
|
35
48
|
return (quasis, ...exprs) => {
|
|
36
49
|
let tree;
|
|
37
|
-
if (trees.has(quasis)
|
|
50
|
+
if (trees.has(quasis)) {
|
|
38
51
|
tree = trees.get(quasis);
|
|
39
52
|
} else {
|
|
40
|
-
tree = new TemplateParser(
|
|
53
|
+
tree = new TemplateParser(
|
|
54
|
+
language,
|
|
55
|
+
quasis.raw,
|
|
56
|
+
exprs.map((e) => buildNode(buildGapTag())),
|
|
57
|
+
).eatProduction({
|
|
41
58
|
language: language.name,
|
|
42
|
-
|
|
59
|
+
name,
|
|
43
60
|
});
|
|
44
61
|
|
|
45
62
|
trees.set(quasis, tree);
|
|
46
63
|
}
|
|
64
|
+
|
|
65
|
+
if (exprs.length) {
|
|
66
|
+
tree = interpolate(tree, exprs);
|
|
67
|
+
}
|
|
68
|
+
|
|
47
69
|
return tree;
|
|
48
70
|
};
|
|
49
71
|
},
|
|
@@ -52,7 +74,7 @@ export const buildTag = (language, defaultType) => {
|
|
|
52
74
|
|
|
53
75
|
export const parse = (language, type, sourceText, expressions = []) => {
|
|
54
76
|
let source = Array.isArray(sourceText) ? sourceText : [sourceText];
|
|
55
|
-
return new TemplateParser(language, source, expressions).
|
|
77
|
+
return new TemplateParser(language, source, expressions).eatProduction({
|
|
56
78
|
language: language.name,
|
|
57
79
|
type,
|
|
58
80
|
});
|
|
@@ -60,12 +82,19 @@ export const parse = (language, type, sourceText, expressions = []) => {
|
|
|
60
82
|
|
|
61
83
|
export const str = buildTag(cstmll, 'String');
|
|
62
84
|
export const num = buildTag(cstmll, 'Integer');
|
|
63
|
-
export const cst = buildTag(cstmll, '
|
|
85
|
+
export const cst = buildTag(cstmll, 'Document');
|
|
86
|
+
export const t_ = buildTag(cstmll, 'Tag');
|
|
64
87
|
export const cstml = cst;
|
|
65
|
-
export const spam_ = buildTag(spamex, '
|
|
88
|
+
export const spam_ = buildTag(spamex, 'PropertyMatcher');
|
|
66
89
|
export const re_ = buildTag(regex, 'Pattern');
|
|
67
90
|
export const i = buildTag(instruction, 'Call');
|
|
68
91
|
|
|
92
|
+
export const t = new Proxy(t_, {
|
|
93
|
+
apply(tag, _, args) {
|
|
94
|
+
return reifyExpression(tag(...args));
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
|
|
69
98
|
export const spam = new Proxy(spam_, {
|
|
70
99
|
apply(tag, _, args) {
|
|
71
100
|
return buildEmbeddedMatcher(tag(...args));
|
package/lib/languages/cstml.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import { get, sourceTextFor } from '@bablr/agast-helpers/tree';
|
|
1
|
+
import JSON from './json.js';
|
|
2
|
+
import { get } from '@bablr/agast-helpers/tree';
|
|
4
3
|
|
|
5
4
|
const _ = /\s+/y;
|
|
6
|
-
const PN =
|
|
5
|
+
const PN = null;
|
|
7
6
|
const KW = 'Keyword';
|
|
8
7
|
|
|
9
8
|
export const name = 'CSTML';
|
|
@@ -16,11 +15,11 @@ export const dependencies = {
|
|
|
16
15
|
|
|
17
16
|
export const covers = new Map([
|
|
18
17
|
[
|
|
19
|
-
|
|
18
|
+
Symbol.for('@bablr/node'),
|
|
20
19
|
new Set([
|
|
21
20
|
'Document',
|
|
22
|
-
'DocumentVersion',
|
|
23
21
|
'DoctypeTag',
|
|
22
|
+
'BoundNode',
|
|
24
23
|
'Property',
|
|
25
24
|
'ReferenceTag',
|
|
26
25
|
'ReferenceFlags',
|
|
@@ -29,31 +28,50 @@ export const covers = new Map([
|
|
|
29
28
|
'GlobalIdentifier',
|
|
30
29
|
'NullTag',
|
|
31
30
|
'GapTag',
|
|
32
|
-
'
|
|
31
|
+
'ShiftTag',
|
|
32
|
+
'TreeNode',
|
|
33
|
+
'NullNode',
|
|
34
|
+
'GapNode',
|
|
33
35
|
'IdentifierPath',
|
|
36
|
+
'BindingSegment',
|
|
34
37
|
'OpenNodeTag',
|
|
35
38
|
'CloseNodeTag',
|
|
36
39
|
'LiteralTag',
|
|
37
40
|
'BindingTag',
|
|
38
|
-
'InitializerTag',
|
|
39
41
|
'AttributeDefinition',
|
|
40
42
|
'Number',
|
|
41
43
|
'Digit',
|
|
42
|
-
'Content',
|
|
43
44
|
'NodeFlags',
|
|
44
45
|
]),
|
|
45
46
|
],
|
|
47
|
+
[
|
|
48
|
+
'Tag',
|
|
49
|
+
new Set([
|
|
50
|
+
'DoctypeTag',
|
|
51
|
+
'ReferenceTag',
|
|
52
|
+
'NullTag',
|
|
53
|
+
'GapTag',
|
|
54
|
+
'ShiftTag',
|
|
55
|
+
'OpenNodeTag',
|
|
56
|
+
'CloseNodeTag',
|
|
57
|
+
'LiteralTag',
|
|
58
|
+
'BindingTag',
|
|
59
|
+
'AttributeDefinition',
|
|
60
|
+
]),
|
|
61
|
+
],
|
|
62
|
+
[
|
|
63
|
+
'Expression',
|
|
64
|
+
new Set(['ShiftExpression', 'BindingExpression', 'TreeNode', 'NullNode', 'GapNode']),
|
|
65
|
+
],
|
|
46
66
|
]);
|
|
47
67
|
|
|
48
68
|
export const grammar = class CSTMLMiniparserGrammar {
|
|
49
|
-
// @Node
|
|
50
69
|
Document(p) {
|
|
51
70
|
p.eatProduction('DoctypeTag', { path: 'doctype' });
|
|
52
71
|
p.eatMatchTrivia(_);
|
|
53
|
-
p.eatProduction('
|
|
72
|
+
p.eatProduction('Expression', { path: 'tree' });
|
|
54
73
|
}
|
|
55
74
|
|
|
56
|
-
// @Node
|
|
57
75
|
DoctypeTag(p) {
|
|
58
76
|
p.eat('<!', PN, { path: 'openToken' });
|
|
59
77
|
p.eatProduction('JSON:UnsignedInteger', { path: 'version' });
|
|
@@ -70,39 +88,24 @@ export const grammar = class CSTMLMiniparserGrammar {
|
|
|
70
88
|
p.eat('>', PN, { path: 'closeToken' });
|
|
71
89
|
}
|
|
72
90
|
|
|
73
|
-
// @Node
|
|
74
91
|
NullTag(p) {
|
|
75
92
|
p.eat('null', KW, { path: 'sigilToken' });
|
|
76
93
|
}
|
|
77
94
|
|
|
78
|
-
// @Node
|
|
79
95
|
GapTag(p) {
|
|
80
96
|
p.eat('<//>', PN, { path: 'sigilToken' });
|
|
81
97
|
}
|
|
82
98
|
|
|
83
|
-
// @Node
|
|
84
99
|
LiteralTag(p) {
|
|
85
100
|
p.eatProduction('JSON:String', { path: 'value' });
|
|
86
101
|
}
|
|
87
102
|
|
|
88
|
-
|
|
89
|
-
|
|
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
|
-
|
|
99
|
-
// @Node
|
|
100
|
-
Node(p, props) {
|
|
101
|
-
let open = p.eatProduction('OpenNodeTag', { path: 'open', noInterpolate: true }, props);
|
|
103
|
+
TreeNode(p, props) {
|
|
104
|
+
let open = p.eatProduction('OpenNodeTag', { path: 'openTag', noInterpolate: true }, props);
|
|
102
105
|
|
|
103
106
|
p.eatMatchTrivia(_);
|
|
104
107
|
|
|
105
|
-
if (open.attributes.
|
|
108
|
+
if (open.value.attributes.selfClosing) {
|
|
106
109
|
let token = !!get(['flags', 'token'], open);
|
|
107
110
|
|
|
108
111
|
while (p.atExpression || !(p.match(/<\/[^/]/y) || p.done)) {
|
|
@@ -110,7 +113,7 @@ export const grammar = class CSTMLMiniparserGrammar {
|
|
|
110
113
|
p.eatMatchTrivia(_);
|
|
111
114
|
}
|
|
112
115
|
|
|
113
|
-
p.eatProduction('CloseNodeTag', { path: '
|
|
116
|
+
p.eatProduction('CloseNodeTag', { path: 'closeTag', noInterpolate: true });
|
|
114
117
|
}
|
|
115
118
|
}
|
|
116
119
|
|
|
@@ -138,9 +141,8 @@ export const grammar = class CSTMLMiniparserGrammar {
|
|
|
138
141
|
}
|
|
139
142
|
}
|
|
140
143
|
|
|
141
|
-
// @Node
|
|
142
144
|
AttributeDefinition(p) {
|
|
143
|
-
p.eat('{', PN, { path: 'openToken'
|
|
145
|
+
p.eat('{', PN, { path: 'openToken' });
|
|
144
146
|
p.eatMatchTrivia(_);
|
|
145
147
|
p.eatProduction('IdentifierPath', { path: 'key' });
|
|
146
148
|
p.eatMatchTrivia(_);
|
|
@@ -148,88 +150,79 @@ export const grammar = class CSTMLMiniparserGrammar {
|
|
|
148
150
|
p.eatMatchTrivia(_);
|
|
149
151
|
p.eatProduction('JSON:Expression', { path: 'value' });
|
|
150
152
|
p.eatMatchTrivia(_);
|
|
151
|
-
p.eat('}', PN, { path: 'closeToken'
|
|
153
|
+
p.eat('}', PN, { path: 'closeToken' });
|
|
152
154
|
}
|
|
153
155
|
|
|
154
|
-
// @Node
|
|
155
156
|
Property(p) {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
ref = p.eatProduction('ReferenceTag', { path: 'reference' });
|
|
157
|
+
if (p.match(/[a-zA-Z`\\\u{80}-\u{10ffff}.#@_]/uy)) {
|
|
158
|
+
p.eatProduction('ReferenceTag', { path: 'referenceTag' });
|
|
159
159
|
}
|
|
160
160
|
p.eatMatchTrivia(_);
|
|
161
|
-
|
|
162
|
-
p.eatProduction('BindingTag', { path: 'binding' });
|
|
163
|
-
p.eatMatchTrivia(_);
|
|
164
|
-
}
|
|
165
|
-
let refType = ref && get('type', ref);
|
|
166
|
-
p.eatProduction('PropertyValue', {
|
|
161
|
+
p.eatProduction('Expression', {
|
|
167
162
|
path: 'value',
|
|
168
|
-
allowFragment: refType && sourceTextFor(refType) === '_',
|
|
169
163
|
});
|
|
170
164
|
}
|
|
171
165
|
|
|
172
|
-
|
|
166
|
+
NullNode(p) {
|
|
167
|
+
p.eatProduction('NullTag', { path: 'sigilTag' });
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
GapNode(p) {
|
|
171
|
+
p.eatProduction('GapTag', { path: 'sigilTag' });
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
Node(p) {
|
|
173
175
|
if (p.match('null')) {
|
|
174
|
-
p.eatProduction('
|
|
175
|
-
} else if (p.match(/\[\]|undefined/y)) {
|
|
176
|
-
p.eatProduction('InitializerTag');
|
|
176
|
+
p.eatProduction('NullNode');
|
|
177
177
|
} else if (p.match('<//>')) {
|
|
178
|
-
p.eatProduction('
|
|
178
|
+
p.eatProduction('GapNode');
|
|
179
|
+
} else if (p.match('</>') || p.match('<!')) {
|
|
180
|
+
p.fail();
|
|
179
181
|
} else {
|
|
180
|
-
p.eatProduction('
|
|
182
|
+
p.eatProduction('TreeNode', { propertyValue: true });
|
|
181
183
|
}
|
|
182
184
|
}
|
|
183
185
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
p.eatMatch('
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
p.eatMatch('_', PN, { path: 'multiFragmentToken' });
|
|
186
|
+
NodeFlags(p, props) {
|
|
187
|
+
let token = !!(p.eatMatch('*', PN, { path: 'tokenToken' }) || props.token);
|
|
188
|
+
let hasGap = !!p.eatMatch('$', PN, { path: 'hasGapToken' });
|
|
189
|
+
|
|
190
|
+
return { attrs: { token, hasGap } };
|
|
190
191
|
}
|
|
191
192
|
|
|
192
|
-
|
|
193
|
-
OpenNodeTag(p, { forceFragment = false, allowFragment = true, propertyValue = false } = {}) {
|
|
193
|
+
OpenNodeTag(p) {
|
|
194
194
|
if (p.match(/['"]/y)) {
|
|
195
|
+
p.eatProduction('NodeFlags', { path: 'flags' }, { token: true });
|
|
195
196
|
p.eatProduction('JSON:String', { path: 'literalValue' });
|
|
196
197
|
return;
|
|
197
198
|
}
|
|
198
199
|
|
|
199
|
-
p.eat('<', PN, { path: 'openToken'
|
|
200
|
+
p.eat('<', PN, { path: 'openToken' });
|
|
200
201
|
|
|
201
|
-
let flags = null;
|
|
202
202
|
if (!p.atExpression) {
|
|
203
|
-
|
|
203
|
+
p.eatProduction('NodeFlags', { path: 'flags' });
|
|
204
204
|
}
|
|
205
205
|
|
|
206
206
|
let sp = null;
|
|
207
207
|
|
|
208
|
-
let
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
if (propertyValue && fragmentFlag && !multiFragmentFlag) throw new Error();
|
|
213
|
-
|
|
214
|
-
if (forceFragment && !fragmentFlag) throw new Error();
|
|
215
|
-
|
|
216
|
-
if (!fragmentFlag && !p.match(/./sy)) {
|
|
217
|
-
throw new Error();
|
|
208
|
+
let type;
|
|
209
|
+
if ((type = p.match(/__|_/y))) {
|
|
210
|
+
p.eat(type, null, { path: 'type' });
|
|
218
211
|
}
|
|
219
212
|
|
|
220
|
-
if (
|
|
213
|
+
if (!type && !p.match(/./sy)) {
|
|
221
214
|
throw new Error();
|
|
222
215
|
}
|
|
223
216
|
|
|
224
|
-
if (
|
|
225
|
-
p.eatProduction('Identifier', { path: '
|
|
226
|
-
|
|
227
|
-
sp = p.eatMatchTrivia(_);
|
|
217
|
+
if (type !== '__' && p.match(/[a-zA-Z`u{80}-\u{10ffff}]/uy)) {
|
|
218
|
+
p.eatProduction('Identifier', { path: 'name' });
|
|
219
|
+
}
|
|
228
220
|
|
|
229
|
-
|
|
221
|
+
sp = p.eatMatchTrivia(_);
|
|
230
222
|
|
|
223
|
+
if (!type) {
|
|
231
224
|
if (sp && (p.match(/['"]/y) || p.atExpression)) {
|
|
232
|
-
|
|
225
|
+
p.eatProduction('JSON:String', { path: 'literalValue' });
|
|
233
226
|
|
|
234
227
|
sp = p.eatMatchTrivia(_);
|
|
235
228
|
}
|
|
@@ -242,48 +235,92 @@ export const grammar = class CSTMLMiniparserGrammar {
|
|
|
242
235
|
p.eatMatchTrivia(_);
|
|
243
236
|
}
|
|
244
237
|
let sc = p.eatMatch('/', PN, { path: 'selfClosingToken' });
|
|
245
|
-
p.eat('>', PN, { path: 'closeToken'
|
|
238
|
+
p.eat('>', PN, { path: 'closeToken' });
|
|
246
239
|
|
|
247
|
-
const
|
|
240
|
+
const selfClosing = !sc && (p.path.depth > 0 || p.span.type !== 'Bare');
|
|
248
241
|
|
|
249
|
-
return { attrs: {
|
|
242
|
+
return { attrs: { selfClosing } };
|
|
250
243
|
}
|
|
251
244
|
|
|
252
|
-
// @Node
|
|
253
245
|
CloseNodeTag(p) {
|
|
254
|
-
p.eat('</', PN, { path: 'openToken'
|
|
255
|
-
p.eat('>', PN, { path: 'closeToken'
|
|
246
|
+
p.eat('</', PN, { path: 'openToken' });
|
|
247
|
+
p.eat('>', PN, { path: 'closeToken' });
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
Expression(p) {
|
|
251
|
+
p.eatProduction('BoundNode');
|
|
252
|
+
|
|
253
|
+
p.eatMatchTrivia('_');
|
|
254
|
+
|
|
255
|
+
if (p.match('^^^')) {
|
|
256
|
+
return { shift: 'ShiftExpression' };
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
BoundNode(p) {
|
|
261
|
+
while (p.match(':')) {
|
|
262
|
+
p.eatProduction('BindingTag', { path: 'bindingTags' });
|
|
263
|
+
p.eatMatchTrivia(_);
|
|
264
|
+
}
|
|
265
|
+
p.eatProduction('Node', { path: 'node' });
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
ShiftExpression(p) {
|
|
269
|
+
p.eatProduction('BoundNode', { path: 'original' });
|
|
270
|
+
p.eatMatchTrivia(_);
|
|
271
|
+
p.eatProduction('ShiftTag', { path: 'sigilTag' });
|
|
272
|
+
p.eatMatchTrivia(_);
|
|
273
|
+
p.eatProduction('TreeNode', { path: 'value' });
|
|
256
274
|
}
|
|
257
275
|
|
|
258
|
-
// @Node
|
|
259
276
|
BindingTag(p) {
|
|
260
|
-
p.eat(':', PN, { path: 'openToken'
|
|
261
|
-
|
|
262
|
-
|
|
277
|
+
p.eat(':', PN, { path: 'openToken' });
|
|
278
|
+
|
|
279
|
+
p.eatMatchTrivia(_);
|
|
280
|
+
let first = true;
|
|
281
|
+
while (!p.match(':') && (first || p.match('/'))) {
|
|
282
|
+
if (!first) {
|
|
283
|
+
p.eat('/', PN, { path: '#separatorTokens' });
|
|
284
|
+
}
|
|
285
|
+
p.eatProduction('BindingSegment', { path: 'segments[]' });
|
|
286
|
+
p.eatMatchTrivia(_);
|
|
287
|
+
first = false;
|
|
288
|
+
}
|
|
289
|
+
p.eat(':', PN, { path: 'closeToken' });
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
BindingSegment(p) {
|
|
293
|
+
p.eatMatchTrivia(_);
|
|
294
|
+
if (p.match('..')) {
|
|
295
|
+
p.eat('..', PN, { path: 'path' });
|
|
296
|
+
} else {
|
|
297
|
+
p.eatProduction('Identifier', { path: 'path' });
|
|
263
298
|
}
|
|
264
|
-
p.
|
|
299
|
+
p.eatMatchTrivia(_);
|
|
265
300
|
}
|
|
266
301
|
|
|
267
302
|
IdentifierPath(p) {
|
|
268
|
-
|
|
269
|
-
while (p.match('.')) {
|
|
270
|
-
|
|
303
|
+
let first = true;
|
|
304
|
+
while (first || p.match('.')) {
|
|
305
|
+
if (!first) {
|
|
306
|
+
p.eat('.', PN, { path: '#separatorTokens' });
|
|
307
|
+
}
|
|
308
|
+
|
|
271
309
|
p.eatProduction('Identifier', { path: 'segments[]' });
|
|
310
|
+
first = false;
|
|
272
311
|
}
|
|
273
312
|
}
|
|
274
313
|
|
|
275
|
-
// @Node
|
|
276
314
|
Identifier(p) {
|
|
277
315
|
let res, q;
|
|
278
316
|
q = p.match('`');
|
|
279
|
-
if (q) p.eat('`', PN, { path: 'openToken'
|
|
317
|
+
if (q) p.eat('`', PN, { path: 'openToken' });
|
|
280
318
|
|
|
281
|
-
p.eatProduction('IdentifierContent', { path: 'content'
|
|
319
|
+
p.eatProduction('IdentifierContent', { path: 'content' }, { quoted: !!q });
|
|
282
320
|
|
|
283
|
-
if (q) p.eat('`', PN, { path: 'closeToken'
|
|
321
|
+
if (q) p.eat('`', PN, { path: 'closeToken' });
|
|
284
322
|
}
|
|
285
323
|
|
|
286
|
-
// @Node
|
|
287
324
|
IdentifierContent(p, props) {
|
|
288
325
|
let { quoted = false } = props || {};
|
|
289
326
|
|
|
@@ -301,19 +338,37 @@ export const grammar = class CSTMLMiniparserGrammar {
|
|
|
301
338
|
} while (lit || esc);
|
|
302
339
|
}
|
|
303
340
|
|
|
304
|
-
// @Cover
|
|
305
341
|
Tag(p) {
|
|
306
|
-
|
|
342
|
+
p.eatMatchTrivia(_);
|
|
343
|
+
if (p.match('{')) {
|
|
344
|
+
p.eatProduction('AttributeDefinition');
|
|
345
|
+
} else if (p.match('null')) {
|
|
346
|
+
p.eatProduction('NullTag');
|
|
347
|
+
} else if (p.match(/[.#@_a-zA-Z\u0060\u{80}-\u{10ffff}]/uy)) {
|
|
348
|
+
p.eatProduction('ReferenceTag');
|
|
349
|
+
} else if (p.match(':')) {
|
|
350
|
+
p.eatProduction('BindingTag');
|
|
351
|
+
} else if (p.match('<!')) {
|
|
352
|
+
p.eatProduction('DoctypeTag');
|
|
353
|
+
} else if (p.match('<//>')) {
|
|
354
|
+
p.eatProduction('GapTag');
|
|
355
|
+
} else if (p.match('^^^')) {
|
|
356
|
+
p.eatProduction('ShiftTag');
|
|
357
|
+
} else if (p.match('</')) {
|
|
358
|
+
p.eatProduction('CloseNodeTag');
|
|
359
|
+
} else if (p.match('<')) {
|
|
360
|
+
p.eatProduction('OpenNodeTag');
|
|
361
|
+
} else if (p.match(/['"]/y)) {
|
|
307
362
|
p.eatProduction('LiteralTag');
|
|
308
363
|
} else {
|
|
309
364
|
throw new Error();
|
|
310
365
|
}
|
|
366
|
+
p.eatMatchTrivia(_);
|
|
311
367
|
}
|
|
312
368
|
|
|
313
|
-
// @Node
|
|
314
369
|
ReferenceTag(p) {
|
|
315
370
|
let type;
|
|
316
|
-
if ((type = p.match(
|
|
371
|
+
if ((type = p.match(/\.\.|[.#@_]/y))) {
|
|
317
372
|
p.eat(type, PN, { path: 'type' });
|
|
318
373
|
}
|
|
319
374
|
|
|
@@ -322,16 +377,22 @@ export const grammar = class CSTMLMiniparserGrammar {
|
|
|
322
377
|
}
|
|
323
378
|
p.eatMatchTrivia(_);
|
|
324
379
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
p.eatMatchTrivia(_);
|
|
328
|
-
}
|
|
380
|
+
p.eatProduction('ReferenceFlags', { path: 'flags' });
|
|
381
|
+
p.eatMatchTrivia(_);
|
|
329
382
|
p.eat(':', PN, { path: 'mapToken' });
|
|
330
383
|
}
|
|
331
384
|
|
|
332
|
-
// @Node
|
|
333
385
|
ReferenceFlags(p) {
|
|
386
|
+
p.eatMatch('[]', PN, { path: 'arrayToken' });
|
|
334
387
|
p.eatMatch('+', PN, { path: 'expressionToken' });
|
|
335
|
-
p.eatMatch('
|
|
388
|
+
let i = p.eatMatch('*', PN, { path: 'intrinsicToken' });
|
|
389
|
+
let g = p.eatMatch('$', PN, { path: 'hasGapToken' });
|
|
390
|
+
if (i && g) p.fail();
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
ShiftTag(p) {
|
|
394
|
+
p.eat('^^^', PN, { path: 'sigilToken' });
|
|
336
395
|
}
|
|
337
396
|
};
|
|
397
|
+
|
|
398
|
+
export default { name, canonicalURL, dependencies, covers, grammar };
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import * as BaseJSON from './json.js';
|
|
1
|
+
import Spamex from './spamex.js';
|
|
2
|
+
import CSTML from './cstml.js';
|
|
3
|
+
import Regex from './regex.js';
|
|
4
|
+
import BaseJSON from './json.js';
|
|
6
5
|
|
|
7
6
|
const _ = /\s+/y;
|
|
8
|
-
const PN =
|
|
7
|
+
const PN = null;
|
|
9
8
|
const ID = 'Identifier';
|
|
10
9
|
const KW = 'Keyword';
|
|
11
10
|
|
|
@@ -31,7 +30,7 @@ const JSON = {
|
|
|
31
30
|
export const dependencies = { Spamex, CSTML, Regex, JSON };
|
|
32
31
|
|
|
33
32
|
export const covers = new Map([
|
|
34
|
-
[
|
|
33
|
+
[Symbol.for('@bablr/node'), new Set(['Call'])],
|
|
35
34
|
[
|
|
36
35
|
'Expression',
|
|
37
36
|
new Set([
|
|
@@ -42,7 +41,8 @@ export const covers = new Map([
|
|
|
42
41
|
'CSTML:GapTag',
|
|
43
42
|
'RegexString',
|
|
44
43
|
'SpamexString',
|
|
45
|
-
'
|
|
44
|
+
'TagString',
|
|
45
|
+
'NodeString',
|
|
46
46
|
'Boolean',
|
|
47
47
|
'Null',
|
|
48
48
|
]),
|
|
@@ -50,12 +50,11 @@ export const covers = new Map([
|
|
|
50
50
|
]);
|
|
51
51
|
|
|
52
52
|
export const grammar = class InstructionMiniparserGrammar {
|
|
53
|
-
// @Node
|
|
54
53
|
Call(p) {
|
|
55
54
|
p.eat(/[a-zA-Z]+/y, ID, { path: 'verb' });
|
|
56
55
|
p.eatMatchTrivia(_);
|
|
57
56
|
|
|
58
|
-
p.eat('(', PN, { path: 'openToken'
|
|
57
|
+
p.eat('(', PN, { path: 'openToken' });
|
|
59
58
|
|
|
60
59
|
let sep = p.eatMatchTrivia(_);
|
|
61
60
|
|
|
@@ -66,40 +65,45 @@ export const grammar = class InstructionMiniparserGrammar {
|
|
|
66
65
|
i++;
|
|
67
66
|
}
|
|
68
67
|
|
|
69
|
-
p.eat(')', PN, { path: 'closeToken'
|
|
68
|
+
p.eat(')', PN, { path: 'closeToken' });
|
|
70
69
|
}
|
|
71
70
|
|
|
72
|
-
// @Node
|
|
73
71
|
SpamexString(p) {
|
|
74
72
|
p.eat('m', KW, { path: 'sigilToken' });
|
|
75
73
|
let quot = p.match(/['"`]/);
|
|
76
|
-
p.eat(quot, PN, { path: 'openToken'
|
|
74
|
+
p.eat(quot, PN, { path: 'openToken' });
|
|
77
75
|
p.eatProduction('Spamex:Matcher', { path: 'content' });
|
|
78
76
|
|
|
79
|
-
p.eat(quot, PN, { path: 'closeToken'
|
|
77
|
+
p.eat(quot, PN, { path: 'closeToken' });
|
|
80
78
|
}
|
|
81
79
|
|
|
82
|
-
|
|
83
|
-
CSTMLString(p) {
|
|
80
|
+
TagString(p) {
|
|
84
81
|
p.eat('t', KW, { path: 'sigilToken' });
|
|
85
82
|
let quot = p.match(/['"`]/);
|
|
86
|
-
p.eat(quot, PN, { path: 'openToken'
|
|
83
|
+
p.eat(quot, PN, { path: 'openToken' });
|
|
87
84
|
p.eatProduction('CSTML:Tag', { path: 'content' });
|
|
88
85
|
|
|
89
|
-
p.eat(quot, PN, { path: 'closeToken'
|
|
86
|
+
p.eat(quot, PN, { path: 'closeToken' });
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
NodeString(p) {
|
|
90
|
+
p.eat('n', KW, { path: 'sigilToken' });
|
|
91
|
+
let quot = p.match(/['"`]/);
|
|
92
|
+
p.eat(quot, PN, { path: 'openToken' });
|
|
93
|
+
p.eatProduction('CSTML:Node', { path: 'content' });
|
|
94
|
+
|
|
95
|
+
p.eat(quot, PN, { path: 'closeToken' });
|
|
90
96
|
}
|
|
91
97
|
|
|
92
|
-
// @Node
|
|
93
98
|
RegexString(p) {
|
|
94
99
|
p.eat('re', KW, { path: 'sigilToken' });
|
|
95
100
|
let quot = p.match(/['"`]/);
|
|
96
|
-
p.eat(quot, PN, { path: 'openToken'
|
|
101
|
+
p.eat(quot, PN, { path: 'openToken' });
|
|
97
102
|
p.eatProduction('Regex:Pattern', { path: 'content' });
|
|
98
103
|
|
|
99
|
-
p.eat(quot, PN, { path: 'closeToken'
|
|
104
|
+
p.eat(quot, PN, { path: 'closeToken' });
|
|
100
105
|
}
|
|
101
106
|
|
|
102
|
-
// @Cover
|
|
103
107
|
Expression(p) {
|
|
104
108
|
if (p.match('[')) {
|
|
105
109
|
p.eatProduction('JSON:Array');
|
|
@@ -111,6 +115,10 @@ export const grammar = class InstructionMiniparserGrammar {
|
|
|
111
115
|
p.eatProduction('RegexString');
|
|
112
116
|
} else if (p.match(/m['"`]/y)) {
|
|
113
117
|
p.eatProduction('SpamexString');
|
|
118
|
+
} else if (p.match(/t['"`]/y)) {
|
|
119
|
+
p.eatProduction('TagString');
|
|
120
|
+
} else if (p.match(/n['"`]/y)) {
|
|
121
|
+
p.eatProduction('NodeString');
|
|
114
122
|
} else if (p.match(/true|false/y)) {
|
|
115
123
|
p.eatProduction('JSON:Boolean');
|
|
116
124
|
} else if (p.match('null')) {
|
|
@@ -118,3 +126,5 @@ export const grammar = class InstructionMiniparserGrammar {
|
|
|
118
126
|
}
|
|
119
127
|
}
|
|
120
128
|
};
|
|
129
|
+
|
|
130
|
+
export default { name, canonicalURL, dependencies, covers, grammar };
|