@bablr/boot 0.10.0 → 0.11.1

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,21 +42,30 @@ 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
  },
@@ -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).eval({
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, 'Node');
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, 'Matcher');
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));
@@ -1,9 +1,8 @@
1
- import * as sym from '@bablr/agast-vm-helpers/symbols';
2
- import * as JSON from './json.js';
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 = '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' }, { forceFragment: 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,39 +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' });
103
+ TreeNode(p, props) {
104
+ if (p.match(/['"]/y)) {
105
+ do {
106
+ p.eatProduction('LiteralTag', { path: 'children[]' });
107
+ p.eatMatchTrivia(_);
108
+ } while (p.match(/['"]/y));
109
+ return;
95
110
  }
96
- return { attrs: { isArray } };
97
- }
98
111
 
99
- // @Node
100
- Node(p, props) {
101
- let open = p.eatProduction('OpenNodeTag', { path: 'open', noInterpolate: true }, props);
112
+ let open = p.eatProduction('OpenNodeTag', { path: 'openTag', noInterpolate: true }, props);
102
113
 
103
114
  p.eatMatchTrivia(_);
104
115
 
105
- if (open.attributes.balanced) {
116
+ if (open.value.attributes.selfClosing) {
106
117
  let token = !!get(['flags', 'token'], open);
107
118
 
108
119
  while (p.atExpression || !(p.match(/<\/[^/]/y) || p.done)) {
@@ -110,7 +121,7 @@ export const grammar = class CSTMLMiniparserGrammar {
110
121
  p.eatMatchTrivia(_);
111
122
  }
112
123
 
113
- p.eatProduction('CloseNodeTag', { path: 'close', noInterpolate: true });
124
+ p.eatProduction('CloseNodeTag', { path: 'closeTag', noInterpolate: true });
114
125
  }
115
126
  }
116
127
 
@@ -138,9 +149,8 @@ export const grammar = class CSTMLMiniparserGrammar {
138
149
  }
139
150
  }
140
151
 
141
- // @Node
142
152
  AttributeDefinition(p) {
143
- p.eat('{', PN, { path: 'openToken', balanced: '}' });
153
+ p.eat('{', PN, { path: 'openToken' });
144
154
  p.eatMatchTrivia(_);
145
155
  p.eatProduction('IdentifierPath', { path: 'key' });
146
156
  p.eatMatchTrivia(_);
@@ -148,88 +158,73 @@ export const grammar = class CSTMLMiniparserGrammar {
148
158
  p.eatMatchTrivia(_);
149
159
  p.eatProduction('JSON:Expression', { path: 'value' });
150
160
  p.eatMatchTrivia(_);
151
- p.eat('}', PN, { path: 'closeToken', balancer: true });
161
+ p.eat('}', PN, { path: 'closeToken' });
152
162
  }
153
163
 
154
- // @Node
155
164
  Property(p) {
156
- let ref = null;
157
- if (p.match(/[a-zA-Z`\\\u{80}-\u{10ffff}.]|[.#@_]/uy)) {
158
- ref = p.eatProduction('ReferenceTag', { path: 'reference' });
165
+ if (p.match(/[a-zA-Z`\\\u{80}-\u{10ffff}.#@_]/uy)) {
166
+ p.eatProduction('ReferenceTag', { path: 'referenceTag' });
159
167
  }
160
168
  p.eatMatchTrivia(_);
161
- if (p.match(':')) {
162
- p.eatProduction('BindingTag', { path: 'binding' });
163
- p.eatMatchTrivia(_);
164
- }
165
- let refType = ref && get('type', ref);
166
- p.eatProduction('PropertyValue', {
169
+ p.eatProduction('Expression', {
167
170
  path: 'value',
168
- allowFragment: refType && sourceTextFor(refType) === '_',
169
171
  });
170
172
  }
171
173
 
172
- PropertyValue(p, { allowFragment }) {
174
+ NullNode(p) {
175
+ p.eatProduction('NullTag', { path: 'sigilTag' });
176
+ }
177
+
178
+ GapNode(p) {
179
+ p.eatProduction('GapTag', { path: 'sigilTag' });
180
+ }
181
+
182
+ Node(p) {
173
183
  if (p.match('null')) {
174
- p.eatProduction('NullTag');
175
- } else if (p.match(/\[\]|undefined/y)) {
176
- p.eatProduction('InitializerTag');
184
+ p.eatProduction('NullNode');
177
185
  } else if (p.match('<//>')) {
178
- p.eatProduction('GapTag');
186
+ p.eatProduction('GapNode');
187
+ } else if (p.match('</>') || p.match('<!')) {
188
+ p.fail();
179
189
  } else {
180
- p.eatProduction('Node', { allowFragment, propertyValue: true });
190
+ p.eatProduction('TreeNode', { propertyValue: true });
181
191
  }
182
192
  }
183
193
 
184
- // @Node
185
- NodeFlags(p) {
186
- p.eatMatch('*', PN, { path: 'tokenToken' });
187
- p.eatMatch('$', PN, { path: 'hasGapToken' });
188
- p.eatMatch('_', PN, { path: 'fragmentToken' });
189
- p.eatMatch('_', PN, { path: 'multiFragmentToken' });
190
- }
194
+ NodeFlags(p, props) {
195
+ let token = !!(p.eatMatch('*', PN, { path: 'tokenToken' }) || props.token);
196
+ let hasGap = !!p.eatMatch('$', PN, { path: 'hasGapToken' });
191
197
 
192
- // @Node
193
- OpenNodeTag(p, { forceFragment = false, allowFragment = true, propertyValue = false } = {}) {
194
- if (p.match(/['"]/y)) {
195
- p.eatProduction('JSON:String', { path: 'literalValue' });
196
- return;
197
- }
198
+ return { attrs: { token, hasGap } };
199
+ }
198
200
 
199
- p.eat('<', PN, { path: 'openToken', startSpan: 'Tag', balanced: '>' });
201
+ OpenNodeTag(p) {
202
+ p.eat('<', PN, { path: 'openToken' });
200
203
 
201
- let flags = null;
202
204
  if (!p.atExpression) {
203
- flags = p.eatProduction('NodeFlags', { path: 'flags' });
205
+ p.eatProduction('NodeFlags', { path: 'flags' });
204
206
  }
205
207
 
206
208
  let sp = null;
207
209
 
208
- let fragmentFlag = get('fragmentToken', flags);
209
- let multiFragmentFlag = get('multiFragmentFlag', flags);
210
- let tokenFlag = get('tokenToken', flags);
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();
210
+ let type;
211
+ if ((type = p.match(/__|_/y))) {
212
+ p.eat(type, null, { path: 'type' });
218
213
  }
219
214
 
220
- if (fragmentFlag && !allowFragment) {
215
+ if (!type && !p.match(/./sy)) {
221
216
  throw new Error();
222
217
  }
223
218
 
224
- if (!fragmentFlag) {
225
- p.eatProduction('Identifier', { path: 'type' });
226
-
227
- sp = p.eatMatchTrivia(_);
219
+ if (type !== '__' && p.match(/[a-zA-Z`u{80}-\u{10ffff}]/uy)) {
220
+ p.eatProduction('Identifier', { path: 'name' });
221
+ }
228
222
 
229
- let iv;
223
+ sp = p.eatMatchTrivia(_);
230
224
 
225
+ if (!type) {
231
226
  if (sp && (p.match(/['"]/y) || p.atExpression)) {
232
- iv = p.eatProduction('JSON:String', { path: 'literalValue' });
227
+ p.eatProduction('JSON:String', { path: 'literalValue' });
233
228
 
234
229
  sp = p.eatMatchTrivia(_);
235
230
  }
@@ -242,48 +237,92 @@ export const grammar = class CSTMLMiniparserGrammar {
242
237
  p.eatMatchTrivia(_);
243
238
  }
244
239
  let sc = p.eatMatch('/', PN, { path: 'selfClosingToken' });
245
- p.eat('>', PN, { path: 'closeToken', endSpan: 'Tag', balancer: true });
240
+ p.eat('>', PN, { path: 'closeToken' });
246
241
 
247
- const balanced = !sc && (p.path.depth > 0 || p.span.type !== 'Bare');
242
+ const selfClosing = !sc && (p.path.depth > 0 || p.span.type !== 'Bare');
248
243
 
249
- return { attrs: { balanced } };
244
+ return { attrs: { selfClosing } };
250
245
  }
251
246
 
252
- // @Node
253
247
  CloseNodeTag(p) {
254
- p.eat('</', PN, { path: 'openToken', startSpan: 'Tag', balanced: '>' });
255
- p.eat('>', PN, { path: 'closeToken', endSpan: 'Tag', balancer: true });
248
+ p.eat('</', PN, { path: 'openToken' });
249
+ p.eat('>', PN, { path: 'closeToken' });
250
+ }
251
+
252
+ Expression(p) {
253
+ p.eatProduction('BoundNode');
254
+
255
+ p.eatMatchTrivia('_');
256
+
257
+ if (p.match('^^^')) {
258
+ return { shift: 'ShiftExpression' };
259
+ }
260
+ }
261
+
262
+ BoundNode(p) {
263
+ while (p.match(':')) {
264
+ p.eatProduction('BindingTag', { path: 'bindingTags' });
265
+ p.eatMatchTrivia(_);
266
+ }
267
+ p.eatProduction('Node', { path: 'node' });
268
+ }
269
+
270
+ ShiftExpression(p) {
271
+ p.eatProduction('BoundNode', { path: 'original' });
272
+ p.eatMatchTrivia(_);
273
+ p.eatProduction('ShiftTag', { path: 'sigilTag' });
274
+ p.eatMatchTrivia(_);
275
+ p.eatProduction('TreeNode', { path: 'value' });
256
276
  }
257
277
 
258
- // @Node
259
278
  BindingTag(p) {
260
- p.eat(':', PN, { path: 'openToken', startSpan: 'Tag', balanced: ':' });
261
- if (!p.match(':')) {
262
- p.eatProduction('IdentifierPath');
279
+ p.eat(':', PN, { path: 'openToken' });
280
+
281
+ p.eatMatchTrivia(_);
282
+ let first = true;
283
+ while (!p.match(':') && (first || p.match('/'))) {
284
+ if (!first) {
285
+ p.eat('/', PN, { path: '#separatorTokens' });
286
+ }
287
+ p.eatProduction('BindingSegment', { path: 'segments[]' });
288
+ p.eatMatchTrivia(_);
289
+ first = false;
263
290
  }
264
- p.eat(':', PN, { path: 'closeToken', endSpan: 'Tag', balancer: true });
291
+ p.eat(':', PN, { path: 'closeToken' });
292
+ }
293
+
294
+ BindingSegment(p) {
295
+ p.eatMatchTrivia(_);
296
+ if (p.match('..')) {
297
+ p.eat('..', PN, { path: 'path' });
298
+ } else {
299
+ p.eatProduction('Identifier', { path: 'path' });
300
+ }
301
+ p.eatMatchTrivia(_);
265
302
  }
266
303
 
267
304
  IdentifierPath(p) {
268
- p.eatProduction('Identifier', { path: 'segments[]' });
269
- while (p.match('.')) {
270
- p.eat('.', PN, { path: 'separatorTokens[]' });
305
+ let first = true;
306
+ while (first || p.match('.')) {
307
+ if (!first) {
308
+ p.eat('.', PN, { path: '#separatorTokens' });
309
+ }
310
+
271
311
  p.eatProduction('Identifier', { path: 'segments[]' });
312
+ first = false;
272
313
  }
273
314
  }
274
315
 
275
- // @Node
276
316
  Identifier(p) {
277
317
  let res, q;
278
318
  q = p.match('`');
279
- if (q) p.eat('`', PN, { path: 'openToken', balanced: '`' });
319
+ if (q) p.eat('`', PN, { path: 'openToken' });
280
320
 
281
- p.eatProduction('IdentifierContent', { path: 'content', span: 'Identifier' }, { quoted: !!q });
321
+ p.eatProduction('IdentifierContent', { path: 'content' }, { quoted: !!q });
282
322
 
283
- if (q) p.eat('`', PN, { path: 'closeToken', balancer: true });
323
+ if (q) p.eat('`', PN, { path: 'closeToken' });
284
324
  }
285
325
 
286
- // @Node
287
326
  IdentifierContent(p, props) {
288
327
  let { quoted = false } = props || {};
289
328
 
@@ -301,19 +340,37 @@ export const grammar = class CSTMLMiniparserGrammar {
301
340
  } while (lit || esc);
302
341
  }
303
342
 
304
- // @Cover
305
343
  Tag(p) {
306
- if (p.match(/['"]/y)) {
344
+ p.eatMatchTrivia(_);
345
+ if (p.match('{')) {
346
+ p.eatProduction('AttributeDefinition');
347
+ } else if (p.match('null')) {
348
+ p.eatProduction('NullTag');
349
+ } else if (p.match(/[.#@_a-zA-Z\u0060\u{80}-\u{10ffff}]/uy)) {
350
+ p.eatProduction('ReferenceTag');
351
+ } else if (p.match(':')) {
352
+ p.eatProduction('BindingTag');
353
+ } else if (p.match('<!')) {
354
+ p.eatProduction('DoctypeTag');
355
+ } else if (p.match('<//>')) {
356
+ p.eatProduction('GapTag');
357
+ } else if (p.match('^^^')) {
358
+ p.eatProduction('ShiftTag');
359
+ } else if (p.match('</')) {
360
+ p.eatProduction('CloseNodeTag');
361
+ } else if (p.match('<')) {
362
+ p.eatProduction('OpenNodeTag');
363
+ } else if (p.match(/['"]/y)) {
307
364
  p.eatProduction('LiteralTag');
308
365
  } else {
309
366
  throw new Error();
310
367
  }
368
+ p.eatMatchTrivia(_);
311
369
  }
312
370
 
313
- // @Node
314
371
  ReferenceTag(p) {
315
372
  let type;
316
- if ((type = p.match(/[.#@_]/y))) {
373
+ if ((type = p.match(/\.\.|[.#@_]/y))) {
317
374
  p.eat(type, PN, { path: 'type' });
318
375
  }
319
376
 
@@ -322,16 +379,22 @@ export const grammar = class CSTMLMiniparserGrammar {
322
379
  }
323
380
  p.eatMatchTrivia(_);
324
381
 
325
- if (p.match(/[+$]/y)) {
326
- p.eatProduction('ReferenceFlags', { path: 'flags' });
327
- p.eatMatchTrivia(_);
328
- }
382
+ p.eatProduction('ReferenceFlags', { path: 'flags' });
383
+ p.eatMatchTrivia(_);
329
384
  p.eat(':', PN, { path: 'mapToken' });
330
385
  }
331
386
 
332
- // @Node
333
387
  ReferenceFlags(p) {
388
+ p.eatMatch('[]', PN, { path: 'arrayToken' });
334
389
  p.eatMatch('+', PN, { path: 'expressionToken' });
335
- p.eatMatch('$', PN, { path: 'hasGapToken' });
390
+ let i = p.eatMatch('*', PN, { path: 'intrinsicToken' });
391
+ let g = p.eatMatch('$', PN, { path: 'hasGapToken' });
392
+ if (i && g) p.fail();
393
+ }
394
+
395
+ ShiftTag(p) {
396
+ p.eat('^^^', PN, { path: 'sigilToken' });
336
397
  }
337
398
  };
399
+
400
+ export default { name, canonicalURL, dependencies, covers, grammar };