@bablr/helpers 0.21.4 → 0.22.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/builders.js CHANGED
@@ -7,6 +7,7 @@ import {
7
7
  } from '@bablr/agast-helpers/tree';
8
8
  import { buildLiteralTag as agastBuildLiteralTag } from '@bablr/agast-helpers/builders';
9
9
  import * as t from '@bablr/agast-helpers/shorthand';
10
+ import * as sumtree from '@bablr/agast-helpers/sumtree';
10
11
  import * as l from '@bablr/agast-vm-helpers/languages';
11
12
  import { concat } from '@bablr/agast-vm-helpers/iterable';
12
13
 
@@ -145,7 +146,13 @@ export const buildOpenNodeMatcher = (flags, language, type, intrinsicValue, attr
145
146
  yield t.ref`languageSeparator`;
146
147
  yield gap(language_ && type ? buildToken(l.CSTML, 'Punctuator', ':') : buildNullNode());
147
148
  yield t.ref`type`;
148
- yield gap(typeof type === 'string' ? buildIdentifier(type) : type);
149
+ yield gap(
150
+ typeof type === 'string'
151
+ ? ['.', '#', '@'].includes(type)
152
+ ? buildKeyword(type)
153
+ : buildIdentifier(type)
154
+ : type,
155
+ );
149
156
 
150
157
  yield* when(intrinsicValue, [t.ref`#`, ...buildSpace().children]);
151
158
 
@@ -185,7 +192,7 @@ export const buildReferenceMatcher = (name, isArray, flags) => {
185
192
  (function* () {
186
193
  yield t.nodeOpen(t.nodeFlags, l.Spamex, 'ReferenceMatcher');
187
194
  yield t.ref`name`;
188
- yield gap(buildToken(l.CSTML, 'Identifier', name));
195
+ yield gap(['#', '@', '.'].includes(name) ? buildKeyword(name) : buildIdentifier(name));
189
196
  yield* (function* () {
190
197
  if (isArray) {
191
198
  yield t.ref`openIndexToken`;
@@ -199,7 +206,7 @@ export const buildReferenceMatcher = (name, isArray, flags) => {
199
206
  yield t.ref`sigilToken`;
200
207
  yield gap(buildToken(l.CSTML, 'Punctuator', ':'));
201
208
  yield t.ref`#`;
202
- yield* buildSpace().children;
209
+ yield* sumtree.traverse(buildSpace().children);
203
210
  yield t.nodeClose();
204
211
  })(),
205
212
  { expressions },
@@ -218,7 +225,7 @@ export const buildFragmentMatcher = (flags) => {
218
225
  yield t.ref`flags`;
219
226
  yield gap(flags);
220
227
  yield t.ref`#`;
221
- yield* buildSpace().children;
228
+ yield* sumtree.traverse(buildSpace().children);
222
229
  yield t.ref`closeToken`;
223
230
  yield gap(buildToken(l.CSTML, 'Punctuator', '/>'));
224
231
  yield t.nodeClose();
@@ -374,9 +381,24 @@ export const buildSpace = () => {
374
381
  };
375
382
 
376
383
  export const buildIdentifier = (name) => {
377
- if (!/^[a-zA-Z]+$/.test(name)) throw new Error();
384
+ if (!/^[a-zA-Z_]+$/.test(name)) throw new Error();
378
385
 
379
- return buildToken(l.Instruction, 'Identifier', name);
386
+ const expressions = [];
387
+ const gap = buildFilledGapFunction(expressions);
388
+
389
+ return treeFromStream(
390
+ [
391
+ t.nodeOpen(t.nodeFlags, l.CSTML, 'Identifier'),
392
+ t.ref`content`,
393
+ gap(buildIdentifierContent(name)),
394
+ t.nodeClose(),
395
+ ],
396
+ { expressions },
397
+ );
398
+ };
399
+
400
+ export const buildIdentifierContent = (value) => {
401
+ return buildToken(l.CSTML, 'IdentifierContent', value);
380
402
  };
381
403
 
382
404
  export const buildKeyword = (name) => {
package/lib/decorators.js CHANGED
@@ -13,6 +13,18 @@ export const AllowEmpty = (desc, context) => {
13
13
  });
14
14
  };
15
15
 
16
+ export const Literal = (desc, context) => {
17
+ context.addInitializer(function () {
18
+ let literals = this.literals;
19
+
20
+ if (!literals) {
21
+ literals = this.literals = new Set();
22
+ }
23
+
24
+ literals.add(context.name);
25
+ });
26
+ };
27
+
16
28
  export const CoveredBy = (type) => {
17
29
  return (desc, context) => {
18
30
  if (!/^[a-zA-Z]+$/.test(printType(type))) throw new Error();
@@ -55,9 +67,9 @@ export const Attributes = (attributes) => (desc, context) => {
55
67
  });
56
68
  };
57
69
 
58
- export const UnboundAttributes = (attributes) => (desc, context) => {
70
+ export const UndefinedAttributes = (attributes) => (desc, context) => {
59
71
  context.addInitializer(function () {
60
- this.unboundAttributes = this.unboundAttributes || new Map();
61
- this.unboundAttributes.set(context.name, attributes);
72
+ this.undefinedAttributes = this.undefinedAttributes || new Map();
73
+ this.undefinedAttributes.set(context.name, attributes);
62
74
  });
63
75
  };
package/lib/grammar.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import every from 'iter-tools-es/methods/every';
2
2
  import isString from 'iter-tools-es/methods/is-string';
3
- import { getOwnPropertySymbols, getPrototypeOf, objectEntries } from './object.js';
3
+ import { getOwnPropertySymbols, getPrototypeOf, objectEntries, objectValues } from './object.js';
4
4
  import { OpenNodeTag, CloseNodeTag, NullTag } from './symbols.js';
5
5
  import { buildExpression } from './builders.js';
6
- import { buildEmbeddedObject } from '@bablr/agast-helpers/tree';
6
+ import { buildEmbeddedObject } from '@bablr/agast-vm-helpers/builders';
7
7
 
8
8
  export * from './decorators.js';
9
9
 
@@ -92,7 +92,17 @@ export const unresolveLanguage = (context, baseLanguage, absoluteLanguage) => {
92
92
  }
93
93
  }
94
94
 
95
- throw new Error('Cannot currently unresolve nested deps');
95
+ // TODO wow I am lazy I literally just hardcoded this to depth two yep
96
+ // I really want to do a BFS with handling for dep cycles
97
+ for (const lang of objectValues(baseLanguage.dependencies)) {
98
+ for (const { 0: key, 1: value } of objectEntries(lang.dependencies)) {
99
+ if (value.canonicalURL === absoluteLanguage) {
100
+ return [key];
101
+ }
102
+ }
103
+ }
104
+
105
+ throw new Error('Cannot currently unresolve more deeply nested deps');
96
106
  };
97
107
 
98
108
  export const explodeSubtypes = (aliases, exploded, types) => {
@@ -236,8 +246,8 @@ export const fail = () => {
236
246
  return __buildCall('fail');
237
247
  };
238
248
 
239
- export const bindAttribute = (key, value) => {
240
- return __buildCall('bindAttribute', key, value);
249
+ export const defineAttribute = (key, value) => {
250
+ return __buildCall('defineAttribute', key, value);
241
251
  };
242
252
 
243
253
  export const write = (value) => {
package/lib/object.js CHANGED
@@ -10,6 +10,7 @@ export const isString = (obj) => typeof obj === 'string';
10
10
  export const isRegex = (obj) => obj instanceof RegExp;
11
11
  export const isPattern = (obj) => isString(obj) || isRegex(obj);
12
12
  export const isType = (obj) => isSymbol(obj) || isString(obj);
13
+ export const isPlainObject = (val) => val && getPrototypeOf(val) === Object.prototype;
13
14
 
14
15
  export const objectKeys = (obj) => {
15
16
  return {
@@ -1,33 +1,34 @@
1
1
  /* @macrome
2
2
  * @generatedby @bablr/macrome-generator-bablr
3
- * @generatedfrom ./productions.macro.js#b39a819f59f161409dfbc86e5266dade96b58b55
3
+ * @generatedfrom ./productions.macro.js#1fc6c6c7f7c9fc7c43a69d9729301c75581c11ea
4
4
  * This file is autogenerated. Please do not edit it directly.
5
5
  * When editing run `npx macrome watch` then change the file this is generated from.
6
6
  */
7
7
  import { spam as m } from '@bablr/boot';
8
- import { buildEmbeddedMatcher, getCooked } from '@bablr/agast-helpers/tree';
8
+ import { getCooked } from '@bablr/agast-helpers/tree';
9
9
  import { eat, eatMatch } from './grammar.js';
10
10
  import { EmbeddedMatcher } from './symbols.js';
11
- import { getEmbeddedMatcher, getEmbeddedObject } from '@bablr/agast-vm-helpers/deembed';
11
+ import { getEmbeddedMatcher } from '@bablr/agast-vm-helpers/deembed';
12
12
  import { buildPropertyMatcher } from './builders.js';
13
+ import { buildEmbeddedMatcher } from '@bablr/agast-vm-helpers/builders';
13
14
  export function* List({
14
- value: props
15
+ props
15
16
  }) {
16
17
  const {
17
18
  element,
18
19
  separator,
19
20
  allowHoles = false,
20
21
  allowTrailingSeparator = true
21
- } = getEmbeddedObject(props);
22
- if (!['#', '@'].includes(getCooked(getEmbeddedMatcher(separator).properties.refMatcher.node.properties.name.node))) {
23
- yield eat(buildEmbeddedMatcher(buildPropertyMatcher(getEmbeddedMatcher(separator).properties.refMatcher.node, m.ArrayNodeMatcher`[]`)));
22
+ } = props;
23
+ if (!['#', '@'].includes(getCooked(getEmbeddedMatcher(separator).properties.refMatcher?.node.properties.name.node.properties.content.node))) {
24
+ yield eat(buildEmbeddedMatcher(buildPropertyMatcher(getEmbeddedMatcher(separator).properties.refMatcher?.node, m.ArrayNodeMatcher`[]`)));
24
25
  }
25
- yield eat(buildEmbeddedMatcher(buildPropertyMatcher(getEmbeddedMatcher(element).properties.refMatcher.node, m.ArrayNodeMatcher`[]`)));
26
+ yield eat(buildEmbeddedMatcher(buildPropertyMatcher(getEmbeddedMatcher(Array.isArray(element) ? element[0] : element).properties.refMatcher?.node, m.ArrayNodeMatcher`[]`)));
26
27
  let sep,
27
28
  it,
28
29
  anySep = false;
29
30
  for (;;) {
30
- it = yield eatMatch(element);
31
+ it = yield eatMatch(...(Array.isArray(element) ? element : [element]));
31
32
  if (it || allowTrailingSeparator) {
32
33
  sep = yield eatMatch(separator);
33
34
  anySep ||= sep;
@@ -38,10 +39,14 @@ export function* List({
38
39
  }
39
40
  }
40
41
  export function* Any({
41
- value: alternatives
42
+ props: {
43
+ value: alternatives
44
+ }
42
45
  }) {
43
46
  for (const alternative of alternatives) {
44
- if (alternative.type === EmbeddedMatcher) {
47
+ if (Array.isArray(alternative)) {
48
+ if (yield eatMatch(...alternative)) break;
49
+ } else if (alternative.type === EmbeddedMatcher) {
45
50
  if (yield eatMatch(alternative)) break;
46
51
  } else {
47
52
  throw new Error();
@@ -49,16 +54,30 @@ export function* Any({
49
54
  }
50
55
  }
51
56
  export function* All({
52
- value: matchers
57
+ props: {
58
+ value: matchers
59
+ }
53
60
  }) {
54
61
  for (const matcher of matchers) {
55
- yield eat(matcher);
62
+ if (Array.isArray(matcher)) {
63
+ yield eat(...matcher);
64
+ } else {
65
+ yield eat(matcher);
66
+ }
56
67
  }
57
68
  }
58
- export function* Punctuator({
69
+ export function* Optional({
70
+ props: {
71
+ value: matcher
72
+ }
73
+ }) {
74
+ yield eatMatch(matcher);
75
+ }
76
+ export function* Literal({
59
77
  intrinsicValue
60
78
  }) {
61
79
  if (!intrinsicValue) throw new Error('Intrinsic productions must have value');
62
80
  yield eat(intrinsicValue);
63
81
  }
64
- export const Keyword = Punctuator;
82
+ export const Keyword = Literal;
83
+ export const Punctuator = Literal;
@@ -1,27 +1,26 @@
1
1
  import { spam as m } from '@bablr/boot';
2
- import { buildEmbeddedMatcher, getCooked } from '@bablr/agast-helpers/tree';
2
+ import { getCooked } from '@bablr/agast-helpers/tree';
3
3
  import { eat, eatMatch } from './grammar.js';
4
4
  import { EmbeddedMatcher } from './symbols.js';
5
- import { getEmbeddedMatcher, getEmbeddedObject } from '@bablr/agast-vm-helpers/deembed';
5
+ import { getEmbeddedMatcher } from '@bablr/agast-vm-helpers/deembed';
6
6
  import { buildPropertyMatcher } from './builders.js';
7
+ import { buildEmbeddedMatcher } from '@bablr/agast-vm-helpers/builders';
7
8
 
8
- export function* List({ value: props }) {
9
- const {
10
- element,
11
- separator,
12
- allowHoles = false,
13
- allowTrailingSeparator = true,
14
- } = getEmbeddedObject(props);
9
+ export function* List({ props }) {
10
+ const { element, separator, allowHoles = false, allowTrailingSeparator = true } = props;
15
11
 
16
12
  if (
17
13
  !['#', '@'].includes(
18
- getCooked(getEmbeddedMatcher(separator).properties.refMatcher.node.properties.name.node),
14
+ getCooked(
15
+ getEmbeddedMatcher(separator).properties.refMatcher?.node.properties.name.node.properties
16
+ .content.node,
17
+ ),
19
18
  )
20
19
  ) {
21
20
  yield eat(
22
21
  buildEmbeddedMatcher(
23
22
  buildPropertyMatcher(
24
- getEmbeddedMatcher(separator).properties.refMatcher.node,
23
+ getEmbeddedMatcher(separator).properties.refMatcher?.node,
25
24
  m.ArrayNodeMatcher`[]`,
26
25
  ),
27
26
  ),
@@ -31,7 +30,8 @@ export function* List({ value: props }) {
31
30
  yield eat(
32
31
  buildEmbeddedMatcher(
33
32
  buildPropertyMatcher(
34
- getEmbeddedMatcher(element).properties.refMatcher.node,
33
+ getEmbeddedMatcher(Array.isArray(element) ? element[0] : element).properties.refMatcher
34
+ ?.node,
35
35
  m.ArrayNodeMatcher`[]`,
36
36
  ),
37
37
  ),
@@ -41,7 +41,7 @@ export function* List({ value: props }) {
41
41
  it,
42
42
  anySep = false;
43
43
  for (;;) {
44
- it = yield eatMatch(element);
44
+ it = yield eatMatch(...(Array.isArray(element) ? element : [element]));
45
45
  if (it || allowTrailingSeparator) {
46
46
  sep = yield eatMatch(separator);
47
47
  anySep ||= sep;
@@ -52,9 +52,11 @@ export function* List({ value: props }) {
52
52
  }
53
53
  }
54
54
 
55
- export function* Any({ value: alternatives }) {
55
+ export function* Any({ props: { value: alternatives } }) {
56
56
  for (const alternative of alternatives) {
57
- if (alternative.type === EmbeddedMatcher) {
57
+ if (Array.isArray(alternative)) {
58
+ if (yield eatMatch(...alternative)) break;
59
+ } else if (alternative.type === EmbeddedMatcher) {
58
60
  if (yield eatMatch(alternative)) break;
59
61
  } else {
60
62
  throw new Error();
@@ -62,16 +64,25 @@ export function* Any({ value: alternatives }) {
62
64
  }
63
65
  }
64
66
 
65
- export function* All({ value: matchers }) {
67
+ export function* All({ props: { value: matchers } }) {
66
68
  for (const matcher of matchers) {
67
- yield eat(matcher);
69
+ if (Array.isArray(matcher)) {
70
+ yield eat(...matcher);
71
+ } else {
72
+ yield eat(matcher);
73
+ }
68
74
  }
69
75
  }
70
76
 
71
- export function* Punctuator({ intrinsicValue }) {
77
+ export function* Optional({ props: { value: matcher } }) {
78
+ yield eatMatch(matcher);
79
+ }
80
+
81
+ export function* Literal({ intrinsicValue }) {
72
82
  if (!intrinsicValue) throw new Error('Intrinsic productions must have value');
73
83
 
74
84
  yield eat(intrinsicValue);
75
85
  }
86
+ export const Keyword = Literal;
76
87
 
77
- export const Keyword = Punctuator;
88
+ export const Punctuator = Literal;
package/lib/symbols.js CHANGED
@@ -1 +1 @@
1
- export * from '@bablr/agast-helpers/symbols';
1
+ export * from '@bablr/agast-vm-helpers/symbols';
package/lib/trivia.js CHANGED
@@ -1,28 +1,26 @@
1
+ import { spam as m } from '@bablr/boot';
1
2
  import { Coroutine } from '@bablr/coroutine';
3
+ import { eat, eatMatch, mapProductions, o, resolveLanguage } from './grammar.js';
4
+ import { EmbeddedMatcher, EmbeddedRegex, EmbeddedNode } from './symbols.js';
5
+ import { buildIdentifier, buildString } from './builders.js';
6
+ import { buildCall, buildEmbeddedInstruction } from '@bablr/agast-vm-helpers/builders';
7
+ import { getEmbeddedInstruction } from '@bablr/agast-vm-helpers/deembed';
2
8
  import { reifyExpression } from '@bablr/agast-vm-helpers';
3
- import { mapProductions } from './grammar.js';
4
- import { OpenNodeTag, CloseNodeTag, ReferenceTag, EmbeddedMatcher } from './symbols.js';
5
- import { getEmbeddedMatcher } from '@bablr/agast-vm-helpers/deembed';
6
- import { getCooked, isFragmentNode } from '@bablr/agast-helpers/tree';
7
-
8
- const lookbehind = (context, s) => {
9
- let token = s.resultPath;
10
- while (token && [OpenNodeTag, CloseNodeTag, ReferenceTag].includes(token.type)) {
11
- const prevToken = context.getPreviousTagPath(token);
12
- if (!prevToken) break;
13
- token = prevToken;
14
- }
15
- return token;
16
- };
17
9
 
18
- // eslint-disable-next-line no-undef
19
- const matchedResults = new WeakSet();
10
+ export const triviaEnhancer = (
11
+ { triviaIsAllowed, triviaIsRequired = () => false, triviaMatcher },
12
+ grammar,
13
+ ) => {
14
+ let Wrapper_ = 'Wrapper';
15
+ let Literal_ = 'Literal';
16
+
17
+ while (grammar.prototype[Wrapper_]) Wrapper_ += '_';
18
+ while (grammar.prototype[Literal_]) Literal_ += '_';
20
19
 
21
- export const triviaEnhancer = ({ triviaIsAllowed, eatMatchTrivia }, grammar) => {
22
- return mapProductions((production) => {
20
+ const resultGrammar = mapProductions((production) => {
23
21
  return function* (props) {
24
22
  const co = new Coroutine(production(props));
25
- const { s, ctx } = props;
23
+ const { ctx, s, isCovered, isCover, flags } = props;
26
24
 
27
25
  co.advance();
28
26
 
@@ -38,20 +36,87 @@ export const triviaEnhancer = ({ triviaIsAllowed, eatMatchTrivia }, grammar) =>
38
36
  case 'match':
39
37
  case 'guard': {
40
38
  const { 0: matcher, 1: props, 2: options } = args;
39
+
41
40
  if (
42
- matcher &&
43
41
  matcher.type === EmbeddedMatcher &&
44
- getCooked(matcher.value.properties.refMatcher?.node.properties.name.node) !== '#'
42
+ ['ArrayNodeMatcher', 'NullNodeMatcher'].includes(
43
+ matcher.value.properties.nodeMatcher.node.type.description,
44
+ )
45
45
  ) {
46
- const previous = lookbehind(ctx, s);
47
- if (triviaIsAllowed(s) && (!previous || !matchedResults.has(previous))) {
48
- matchedResults.add(previous);
49
- yield* eatMatchTrivia();
50
- matchedResults.add(s.resultPath);
46
+ returnValue = yield instr;
47
+ break;
48
+ }
49
+
50
+ if (
51
+ matcher.type === EmbeddedRegex ||
52
+ typeof matcher === 'string' ||
53
+ (matcher.type === EmbeddedNode && matcher.value.flags.token)
54
+ ) {
55
+ if (triviaIsAllowed(s) && !flags.token) {
56
+ let isString = typeof matcher === 'string';
57
+ let wrappedMatcher = m`value: <*Literal ${
58
+ isString ? buildString(matcher) : matcher.value
59
+ } />`;
60
+
61
+ let tmi = buildEmbeddedInstruction(
62
+ triviaIsRequired() ? eat(triviaMatcher) : eatMatch(triviaMatcher),
63
+ );
64
+
65
+ let result = yield buildCall(verb, m`<_${buildIdentifier(Wrapper_)} />`, [
66
+ tmi,
67
+ buildEmbeddedInstruction(eat(wrappedMatcher, props, options)),
68
+ ]);
69
+
70
+ returnValue = result?.get('value');
71
+ } else {
72
+ returnValue = yield instr;
51
73
  }
74
+ break;
52
75
  }
53
76
 
54
- returnValue = returnValue || (yield instr);
77
+ let { name } = reifyExpression(matcher.value.properties.refMatcher?.node) || {};
78
+ let realMatcher = reifyExpression(matcher.value.properties.nodeMatcher?.node);
79
+ let { flags: matcherFlags } = realMatcher;
80
+
81
+ let isNode = matcherFlags && !matcherFlags.fragment;
82
+ let isCoverBoundary = matcherFlags && (matcherFlags.cover || (isNode && !isCovered));
83
+ if (
84
+ matcher &&
85
+ (matcher.type !== EmbeddedMatcher || name !== '#') &&
86
+ !s.holding &&
87
+ !flags.token &&
88
+ isCoverBoundary
89
+ ) {
90
+ if (triviaIsAllowed(s)) {
91
+ let tmi = buildEmbeddedInstruction(
92
+ triviaIsRequired() ? eat(triviaMatcher) : eatMatch(triviaMatcher),
93
+ );
94
+
95
+ let result = yield buildCall(
96
+ verb,
97
+ m`<_${buildIdentifier(Wrapper_)} />`,
98
+ [tmi, buildEmbeddedInstruction(eat(matcher, props, options))],
99
+ o({ bind: options?.value.bind ?? false }),
100
+ );
101
+ let trivialResult = result;
102
+
103
+ if (result && !result.isNull) {
104
+ if (matcher.value.properties.refMatcher) {
105
+ let path = ctx
106
+ .sourceTextFor(matcher.value.properties.refMatcher.node)
107
+ .slice(0, -1);
108
+ result = result.get(path);
109
+ }
110
+
111
+ result = result && result.merge(trivialResult);
112
+ }
113
+ returnValue = result;
114
+ } else {
115
+ returnValue = yield instr;
116
+ }
117
+ } else {
118
+ returnValue = yield instr;
119
+ }
55
120
  break;
56
121
  }
57
122
 
@@ -63,12 +128,34 @@ export const triviaEnhancer = ({ triviaIsAllowed, eatMatchTrivia }, grammar) =>
63
128
  co.advance(returnValue);
64
129
  }
65
130
 
66
- if (!s.node?.flags.token && s.node.isFragmentNode) {
67
- const previous = lookbehind(ctx, s);
68
- if (triviaIsAllowed(s) && !matchedResults.has(previous)) {
69
- matchedResults.add(previous);
70
- yield* eatMatchTrivia();
71
- matchedResults.add(s.resultPath);
131
+ if (!s.depths.path && !flags.token && !(isCovered || isCover)) {
132
+ if (triviaIsAllowed(s)) {
133
+ yield eatMatch(triviaMatcher);
134
+ }
135
+ } else if (co.value) {
136
+ let realMatcher = reifyExpression(
137
+ co.value.arguments[0].value.properties.nodeMatcher.node,
138
+ );
139
+ let { flags: matcherFlags } = realMatcher;
140
+
141
+ let isNode = matcherFlags && !matcherFlags.fragment;
142
+
143
+ if (
144
+ !flags.token &&
145
+ isNode &&
146
+ !isCover &&
147
+ co.value &&
148
+ ['holdFor', 'holdForMatch'].includes(co.value.verb)
149
+ ) {
150
+ if (triviaIsAllowed(s)) {
151
+ let tmi = buildEmbeddedInstruction(
152
+ triviaIsRequired() ? eat(triviaMatcher) : eatMatch(triviaMatcher),
153
+ );
154
+ return buildCall(co.value.verb, m`<_${buildIdentifier(Wrapper_)} />`, [
155
+ tmi,
156
+ buildEmbeddedInstruction(eat(co.value.arguments[0], co.value.arguments[1])),
157
+ ]);
158
+ }
72
159
  }
73
160
  }
74
161
 
@@ -79,4 +166,36 @@ export const triviaEnhancer = ({ triviaIsAllowed, eatMatchTrivia }, grammar) =>
79
166
  }
80
167
  };
81
168
  }, grammar);
169
+
170
+ return class extends resultGrammar {
171
+ constructor() {
172
+ super();
173
+
174
+ if (!this.emptyables) {
175
+ this.emptyables = new Set();
176
+ }
177
+
178
+ if (!this.covers) {
179
+ this.covers = new Map();
180
+ }
181
+
182
+ if (!this.covers.get(Symbol.for('@bablr/node'))) {
183
+ this.covers.set(Symbol.for('@bablr/node'), new Set());
184
+ }
185
+
186
+ this.covers.get(Symbol.for('@bablr/node')).add(Literal_);
187
+
188
+ this.emptyables.add(Wrapper_);
189
+ }
190
+
191
+ *[Wrapper_]({ props: { value: wrapped } }) {
192
+ for (const instr of wrapped) {
193
+ yield getEmbeddedInstruction(instr);
194
+ }
195
+ }
196
+
197
+ *[Literal_]({ intrinsicValue }) {
198
+ yield eat(intrinsicValue);
199
+ }
200
+ };
82
201
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bablr/helpers",
3
3
  "description": "Command helpers for use in writing BABLR grammars",
4
- "version": "0.21.4",
4
+ "version": "0.22.0",
5
5
  "author": "Conrad Buck<conartist6@gmail.com>",
6
6
  "type": "module",
7
7
  "files": [
@@ -30,16 +30,16 @@
30
30
  "clean": "macrome clean"
31
31
  },
32
32
  "dependencies": {
33
- "@bablr/language_enhancer-debug-log": "0.8.1",
34
- "@bablr/strategy_enhancer-debug-log": "0.7.2",
35
- "@bablr/agast-helpers": "0.6.1",
36
- "@bablr/agast-vm-helpers": "0.6.1",
33
+ "@bablr/language_enhancer-debug-log": "0.9.0",
34
+ "@bablr/strategy_enhancer-debug-log": "0.8.0",
35
+ "@bablr/agast-helpers": "0.7.0",
36
+ "@bablr/agast-vm-helpers": "0.7.0",
37
37
  "@bablr/coroutine": "0.1.0",
38
38
  "@iter-tools/imm-stack": "1.1.0",
39
39
  "iter-tools-es": "^7.5.3"
40
40
  },
41
41
  "devDependencies": {
42
- "@bablr/boot": "0.7.2",
42
+ "@bablr/boot": "0.8.0",
43
43
  "@bablr/eslint-config-base": "github:bablr-lang/eslint-config-base#d834ccc52795d6c3b96ecc6c419960fceed221a6",
44
44
  "@bablr/macrome": "0.1.3",
45
45
  "@bablr/macrome-generator-bablr": "0.3.2",