@bablr/boot 0.9.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 CHANGED
@@ -1,26 +1,39 @@
1
- import * as cstmll from './languages/cstml.js';
2
- import * as spamex from './languages/spamex.js';
3
- import * as regex from './languages/regex.js';
4
- import * as instruction from './languages/instruction.js';
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) && !exprs.length) {
18
+ if (trees.has(quasis)) {
15
19
  tree = trees.get(quasis);
16
20
  } else {
17
- tree = new TemplateParser(language, quasis.raw, exprs).eval({
21
+ tree = new TemplateParser(
22
+ language,
23
+ quasis.raw,
24
+ exprs.map((e) => buildNode(buildGapTag())),
25
+ ).eatProduction({
18
26
  language: language.name,
19
- type: defaultType,
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,29 +42,39 @@ export const buildTag = (language, defaultType) => {
29
42
  return defaultTag.apply(receiver, argsList);
30
43
  },
31
44
 
32
- get(_, type) {
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) && !exprs.length) {
50
+ if (trees.has(quasis)) {
38
51
  tree = trees.get(quasis);
39
52
  } else {
40
- tree = new TemplateParser(language, quasis.raw, exprs).eval({
53
+ tree = new TemplateParser(
54
+ language,
55
+ quasis.raw,
56
+ exprs.map((e) => buildNode(buildGapTag())),
57
+ ).eatProduction({
41
58
  language: language.name,
42
- type,
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
  },
50
72
  });
51
73
  };
52
74
 
53
- export const parse = (language, type, sourceText) => {
54
- return new TemplateParser(language, [sourceText], []).eval({
75
+ export const parse = (language, type, sourceText, expressions = []) => {
76
+ let source = Array.isArray(sourceText) ? sourceText : [sourceText];
77
+ return new TemplateParser(language, source, expressions).eatProduction({
55
78
  language: language.name,
56
79
  type,
57
80
  });
@@ -59,12 +82,19 @@ export const parse = (language, type, sourceText) => {
59
82
 
60
83
  export const str = buildTag(cstmll, 'String');
61
84
  export const num = buildTag(cstmll, 'Integer');
62
- export const cst = buildTag(cstmll, 'Node');
85
+ export const cst = buildTag(cstmll, 'Document');
86
+ export const t_ = buildTag(cstmll, 'Tag');
63
87
  export const cstml = cst;
64
- export const spam_ = buildTag(spamex, 'Matcher');
88
+ export const spam_ = buildTag(spamex, 'PropertyMatcher');
65
89
  export const re_ = buildTag(regex, 'Pattern');
66
90
  export const i = buildTag(instruction, 'Call');
67
91
 
92
+ export const t = new Proxy(t_, {
93
+ apply(tag, _, args) {
94
+ return reifyExpression(tag(...args));
95
+ },
96
+ });
97
+
68
98
  export const spam = new Proxy(spam_, {
69
99
  apply(tag, _, args) {
70
100
  return buildEmbeddedMatcher(tag(...args));
@@ -1,9 +1,8 @@
1
- import * as sym from '@bablr/agast-vm-helpers/symbols';
2
- import * as JSON from './json.js';
3
- import { isArray } from 'iter-tools-es';
1
+ import JSON from './json.js';
2
+ import { get } from '@bablr/agast-helpers/tree';
4
3
 
5
4
  const _ = /\s+/y;
6
- const PN = 'Punctuator';
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
- sym.node,
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
- 'Node',
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('Node', { path: 'tree' }, { fragment: true });
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,53 +88,32 @@ 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
- //@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
-
99
- // @Node
100
- Node(p, props) {
101
- let open = p.eatProduction('OpenNodeTag', { path: 'open' }, 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.properties.flags?.token) {
106
- p.eatProduction('NodeChild', { path: 'children[]' }, { token: true });
107
- p.eatMatchTrivia(_);
108
- } else if (!open.properties.selfClosingTagToken) {
109
- let lastIndex = p.idx;
110
- while (!(p.match('</') || p.done)) {
111
- p.eatProduction('NodeChild', { path: 'children[]' });
108
+ if (open.value.attributes.selfClosing) {
109
+ let token = !!get(['flags', 'token'], open);
110
+
111
+ while (p.atExpression || !(p.match(/<\/[^/]/y) || p.done)) {
112
+ p.eatProduction('NodeChild', { path: 'children[]' }, { token });
112
113
  p.eatMatchTrivia(_);
113
- if (p.idx === lastIndex) break;
114
- lastIndex = p.idx;
115
114
  }
116
- }
117
115
 
118
- if (!open.properties.selfClosingTagToken) {
119
- p.eatProduction('CloseNodeTag', { path: 'close' });
116
+ p.eatProduction('CloseNodeTag', { path: 'closeTag', noInterpolate: true });
120
117
  }
121
118
  }
122
119
 
@@ -129,22 +126,23 @@ export const grammar = class CSTMLMiniparserGrammar {
129
126
 
130
127
  if (token) {
131
128
  if (p.match(/<\*?@/y)) {
132
- p.eatProduction('Node');
129
+ p.eatProduction('Property');
133
130
  } else {
134
131
  p.eatProduction('LiteralTag');
135
132
  }
136
133
  } else {
137
- if (p.match(/[:<a-zA-Z`\\\u{80}-\u{10ffff}.]|[.#@]/uy)) {
134
+ if (p.match(/[:<a-zA-Z`\\\u{80}-\u{10ffff}.]|[.#@_]/uy) || p.atExpression) {
138
135
  p.eatProduction('Property');
139
136
  } else if (p.match(/['"]/y)) {
140
- p.eatProduction('LiteralTag');
137
+ p.eatProduction('Property');
138
+ } else {
139
+ p.fail();
141
140
  }
142
141
  }
143
142
  }
144
143
 
145
- // @Node
146
144
  AttributeDefinition(p) {
147
- p.eat('{', PN, { path: 'openToken', balanced: '}' });
145
+ p.eat('{', PN, { path: 'openToken' });
148
146
  p.eatMatchTrivia(_);
149
147
  p.eatProduction('IdentifierPath', { path: 'key' });
150
148
  p.eatMatchTrivia(_);
@@ -152,129 +150,184 @@ export const grammar = class CSTMLMiniparserGrammar {
152
150
  p.eatMatchTrivia(_);
153
151
  p.eatProduction('JSON:Expression', { path: 'value' });
154
152
  p.eatMatchTrivia(_);
155
- p.eat('}', PN, { path: 'closeToken', balancer: true });
153
+ p.eat('}', PN, { path: 'closeToken' });
156
154
  }
157
155
 
158
- // @Node
159
156
  Property(p) {
160
- if (p.match(/[a-zA-Z`\\\u{80}-\u{10ffff}.]|[.#@]/uy)) {
161
- p.eatProduction('ReferenceTag', { path: 'reference' });
157
+ if (p.match(/[a-zA-Z`\\\u{80}-\u{10ffff}.#@_]/uy)) {
158
+ p.eatProduction('ReferenceTag', { path: 'referenceTag' });
162
159
  }
163
160
  p.eatMatchTrivia(_);
164
- if (p.match(':')) {
165
- p.eatProduction('BindingTag', { path: 'binding' });
166
- p.eatMatchTrivia(_);
167
- }
168
- p.eatProduction('PropertyValue', { path: 'value' });
161
+ p.eatProduction('Expression', {
162
+ path: 'value',
163
+ });
169
164
  }
170
165
 
171
- PropertyValue(p) {
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) {
172
175
  if (p.match('null')) {
173
- p.eatProduction('NullTag');
174
- } else if (p.match(/\[\]|undefined/y)) {
175
- p.eatProduction('InitializerTag');
176
+ p.eatProduction('NullNode');
176
177
  } else if (p.match('<//>')) {
177
- p.eatProduction('GapTag');
178
+ p.eatProduction('GapNode');
179
+ } else if (p.match('</>') || p.match('<!')) {
180
+ p.fail();
178
181
  } else {
179
- p.eatProduction('Node');
182
+ p.eatProduction('TreeNode', { propertyValue: true });
180
183
  }
181
184
  }
182
185
 
183
- // @Node
184
- NodeFlags(p) {
185
- p.eatMatch('*', PN, { path: 'tokenToken' });
186
- p.eatMatch('$', PN, { path: 'hasGapToken' });
187
- p.eatMatch('_', PN, { path: 'fragmentToken' });
188
- p.eatMatch('_', PN, { path: 'coverFragmentToken' });
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 } };
189
191
  }
190
192
 
191
- // @Node
192
- OpenNodeTag(p, { fragment } = {}) {
193
- p.eat('<', PN, { path: 'openToken', startSpan: 'Tag', balanced: '>' });
193
+ OpenNodeTag(p) {
194
+ if (p.match(/['"]/y)) {
195
+ p.eatProduction('NodeFlags', { path: 'flags' }, { token: true });
196
+ p.eatProduction('JSON:String', { path: 'literalValue' });
197
+ return;
198
+ }
199
+
200
+ p.eat('<', PN, { path: 'openToken' });
194
201
 
195
- let flags = null;
196
202
  if (!p.atExpression) {
197
- flags = p.eatProduction('NodeFlags', { path: 'flags' });
203
+ p.eatProduction('NodeFlags', { path: 'flags' });
198
204
  }
199
205
 
200
206
  let sp = null;
201
207
 
202
- if (fragment && !flags.properties.fragmentToken) throw new Error();
208
+ let type;
209
+ if ((type = p.match(/__|_/y))) {
210
+ p.eat(type, null, { path: 'type' });
211
+ }
203
212
 
204
- if (!flags.properties.fragmentToken && !p.match(/./sy)) {
213
+ if (!type && !p.match(/./sy)) {
205
214
  throw new Error();
206
215
  }
207
216
 
208
- if (!flags.properties.fragmentToken) {
209
- p.eatProduction('Identifier', { path: 'type' });
210
-
211
- sp = p.eatMatchTrivia(_);
217
+ if (type !== '__' && p.match(/[a-zA-Z`u{80}-\u{10ffff}]/uy)) {
218
+ p.eatProduction('Identifier', { path: 'name' });
219
+ }
212
220
 
213
- let iv;
221
+ sp = p.eatMatchTrivia(_);
214
222
 
223
+ if (!type) {
215
224
  if (sp && (p.match(/['"]/y) || p.atExpression)) {
216
- iv = p.eatProduction('JSON:String', { path: 'intrinsicValue' });
225
+ p.eatProduction('JSON:String', { path: 'literalValue' });
217
226
 
218
227
  sp = p.eatMatchTrivia(_);
219
228
  }
220
229
 
221
- if (!flags.properties.tokenToken && iv) {
222
- throw new Error();
223
- }
224
-
225
230
  if (p.match('{') || p.atExpression) {
226
- p.eatProduction('JSON:Object');
231
+ p.eatProduction('JSON:Object', { path: 'attributes' });
227
232
  sp = p.eatMatchTrivia(_);
228
233
  }
229
234
 
230
235
  p.eatMatchTrivia(_);
231
236
  }
232
- p.eatMatch('/', PN, { path: 'selfClosingTagToken' });
233
- p.eat('>', PN, { path: 'closeToken', endSpan: 'Tag', balancer: true });
237
+ let sc = p.eatMatch('/', PN, { path: 'selfClosingToken' });
238
+ p.eat('>', PN, { path: 'closeToken' });
239
+
240
+ const selfClosing = !sc && (p.path.depth > 0 || p.span.type !== 'Bare');
241
+
242
+ return { attrs: { selfClosing } };
234
243
  }
235
244
 
236
- // @Node
237
245
  CloseNodeTag(p) {
238
- p.eat('</', PN, { path: 'openToken', startSpan: 'Tag', balanced: '>' });
239
- p.eat('>', PN, { path: 'closeToken', endSpan: 'Tag', balancer: true });
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' });
240
274
  }
241
275
 
242
- // @Node
243
276
  BindingTag(p) {
244
- p.eat(':', PN, { path: 'openToken', startSpan: 'Tag', balanced: ':' });
245
- if (!p.match(':')) {
246
- p.eatProduction('IdentifierPath');
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;
247
288
  }
248
- p.eat(':', PN, { path: 'closeToken', endSpan: 'Tag', balancer: true });
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' });
298
+ }
299
+ p.eatMatchTrivia(_);
249
300
  }
250
301
 
251
302
  IdentifierPath(p) {
252
- p.eatProduction('Identifier', { path: 'segments[]' });
253
- while (p.match('.')) {
254
- p.eat('.', PN, { path: 'separatorTokens[]' });
303
+ let first = true;
304
+ while (first || p.match('.')) {
305
+ if (!first) {
306
+ p.eat('.', PN, { path: '#separatorTokens' });
307
+ }
308
+
255
309
  p.eatProduction('Identifier', { path: 'segments[]' });
310
+ first = false;
256
311
  }
257
312
  }
258
313
 
259
- // @Node
260
314
  Identifier(p) {
261
315
  let res, q;
262
316
  q = p.match('`');
263
- if (q) p.eat('`', PN, { path: 'openToken', balanced: '`' });
317
+ if (q) p.eat('`', PN, { path: 'openToken' });
264
318
 
265
- p.eatProduction('IdentifierContent', { path: 'content', span: 'Identifier' }, { quoted: !!q });
319
+ p.eatProduction('IdentifierContent', { path: 'content' }, { quoted: !!q });
266
320
 
267
- if (q) p.eat('`', PN, { path: 'closeToken', balancer: true });
321
+ if (q) p.eat('`', PN, { path: 'closeToken' });
268
322
  }
269
323
 
270
- // @Node
271
324
  IdentifierContent(p, props) {
272
325
  let { quoted = false } = props || {};
273
326
 
274
327
  let lit, esc;
275
328
  do {
276
329
  if ((esc = p.match('\\'))) {
277
- p.eatMatchEscape(/\\(u(\{[0-9a-fA-F]\}|\d{4}))/y);
330
+ p.eatEscape(/\\(u(\{[0-9a-fA-F]\}|\d{4}))/y);
278
331
  } else {
279
332
  if (!quoted) {
280
333
  lit = p.eatMatchLiteral(/[a-zA-Z\u{80}-\u{10ffff}][a-zA-Z0-9_\u{80}-\u{10ffff}-]*/uy);
@@ -285,35 +338,61 @@ export const grammar = class CSTMLMiniparserGrammar {
285
338
  } while (lit || esc);
286
339
  }
287
340
 
288
- // @Cover
289
341
  Tag(p) {
290
- if (p.match(/['"]/y)) {
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)) {
291
362
  p.eatProduction('LiteralTag');
292
363
  } else {
293
364
  throw new Error();
294
365
  }
366
+ p.eatMatchTrivia(_);
295
367
  }
296
368
 
297
- // @Node
298
369
  ReferenceTag(p) {
299
- let name;
300
- if ((name = p.match(/[.#@]/y))) {
301
- p.eat(name, PN, { path: 'type' });
302
- } else {
370
+ let type;
371
+ if ((type = p.match(/\.\.|[.#@_]/y))) {
372
+ p.eat(type, PN, { path: 'type' });
373
+ }
374
+
375
+ if (!type || type === '#') {
303
376
  p.eatProduction('Identifier', { path: 'name' });
304
377
  }
305
378
  p.eatMatchTrivia(_);
306
379
 
307
- if (p.match(/[+$]/y)) {
308
- p.eatProduction('ReferenceFlags', { path: 'flags' });
309
- p.eatMatchTrivia(_);
310
- }
380
+ p.eatProduction('ReferenceFlags', { path: 'flags' });
381
+ p.eatMatchTrivia(_);
311
382
  p.eat(':', PN, { path: 'mapToken' });
312
383
  }
313
384
 
314
- // @Node
315
385
  ReferenceFlags(p) {
386
+ p.eatMatch('[]', PN, { path: 'arrayToken' });
316
387
  p.eatMatch('+', PN, { path: 'expressionToken' });
317
- p.eatMatch('$', PN, { path: 'hasGapToken' });
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' });
318
395
  }
319
396
  };
397
+
398
+ export default { name, canonicalURL, dependencies, covers, grammar };