@bablr/helpers 0.22.0 → 0.23.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/decorators.js CHANGED
@@ -1,4 +1,3 @@
1
- import { printType } from '@bablr/agast-helpers/print';
2
1
  import * as sym from './symbols.js';
3
2
 
4
3
  export const AllowEmpty = (desc, context) => {
@@ -27,8 +26,6 @@ export const Literal = (desc, context) => {
27
26
 
28
27
  export const CoveredBy = (type) => {
29
28
  return (desc, context) => {
30
- if (!/^[a-zA-Z]+$/.test(printType(type))) throw new Error();
31
-
32
29
  context.addInitializer(function () {
33
30
  let covers = this.covers;
34
31
 
package/lib/enhancers.js CHANGED
@@ -1,7 +1,4 @@
1
- import {
2
- enhanceStrategyBuilderWithDebugLogging as logStrategy,
3
- enhanceStrategyBuilderWithEmittedLogging as logEmitted,
4
- } from '@bablr/strategy_enhancer-debug-log';
1
+ import { enhanceStrategyBuilderWithDebugLogging as logStrategy } from '@bablr/strategy_enhancer-debug-log';
5
2
  import { enhanceProductionWithDebugLogging as createProductionLogger } from '@bablr/language_enhancer-debug-log';
6
3
  import { mapProductions } from './grammar.js';
7
4
 
@@ -40,8 +37,8 @@ export const compose = (functions) => {
40
37
 
41
38
  export const debugEnhancers = {
42
39
  // bablr: (strategy) => logStrategy(strategy, '<<< '),
43
- createBablrStrategy: (strategy) => (matcher, props) =>
44
- logStrategy(strategy(matcher, props), ' >>> '),
40
+ createBablrStrategy: (strategy) => (language, matcher, props) =>
41
+ logStrategy(strategy(language, matcher, props), ' >>> '),
45
42
  bablrProduction: createProductionLogger('>>> '),
46
43
  };
47
44
 
package/lib/grammar.js CHANGED
@@ -2,7 +2,6 @@ import every from 'iter-tools-es/methods/every';
2
2
  import isString from 'iter-tools-es/methods/is-string';
3
3
  import { getOwnPropertySymbols, getPrototypeOf, objectEntries, objectValues } from './object.js';
4
4
  import { OpenNodeTag, CloseNodeTag, NullTag } from './symbols.js';
5
- import { buildExpression } from './builders.js';
6
5
  import { buildEmbeddedObject } from '@bablr/agast-vm-helpers/builders';
7
6
 
8
7
  export * from './decorators.js';
@@ -17,6 +16,21 @@ export const notNull = (facade) => {
17
16
  return facade && (facade.type !== null || facade.openTag.type !== NullTag);
18
17
  };
19
18
 
19
+ export const mapOwnProductions = (fn, Grammar) => {
20
+ let { prototype } = Grammar;
21
+
22
+ class MappedGrammar extends Grammar {}
23
+
24
+ const mapped = MappedGrammar.prototype;
25
+
26
+ for (const key of [...getOwnPropertyNames(prototype), ...getOwnPropertySymbols(prototype)]) {
27
+ if (!hasOwn(mapped, key)) {
28
+ mapped[key] = fn(prototype[key], key);
29
+ }
30
+ }
31
+ return MappedGrammar;
32
+ };
33
+
20
34
  export const mapProductions = (fn, Grammar) => {
21
35
  let { prototype } = Grammar;
22
36
 
@@ -81,30 +95,6 @@ export const resolveLanguage = (context, language, path) => {
81
95
  return l;
82
96
  };
83
97
 
84
- export const unresolveLanguage = (context, baseLanguage, absoluteLanguage) => {
85
- if (absoluteLanguage == null || absoluteLanguage === baseLanguage.canonicalURL) {
86
- return null;
87
- }
88
-
89
- for (const { 0: key, 1: value } of objectEntries(baseLanguage.dependencies)) {
90
- if (value.canonicalURL === absoluteLanguage) {
91
- return [key];
92
- }
93
- }
94
-
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');
106
- };
107
-
108
98
  export const explodeSubtypes = (aliases, exploded, types) => {
109
99
  for (const type of types) {
110
100
  const explodedTypes = aliases.get(type);
@@ -206,14 +196,6 @@ export function* zipLanguages(tags, rootLanguage) {
206
196
  }
207
197
  }
208
198
 
209
- const safeShallowEmbed = (value) => {
210
- if (typeof value !== 'object') {
211
- return buildExpression(value);
212
- } else {
213
- return value;
214
- }
215
- };
216
-
217
199
  const __buildCall = (verb, ...args) => {
218
200
  while (args.length && args[args.length - 1] === undefined) {
219
201
  args.pop();
@@ -238,8 +220,8 @@ export const guard = (matcher, value, options) => {
238
220
  return __buildCall('guard', matcher, value, options);
239
221
  };
240
222
 
241
- export const holdForMatch = (matcher, value, options) => {
242
- return __buildCall('holdForMatch', matcher, value, options);
223
+ export const shiftMatch = (matcher, value, options) => {
224
+ return __buildCall('shiftMatch', matcher, value, options);
243
225
  };
244
226
 
245
227
  export const fail = () => {
package/lib/index.js CHANGED
@@ -6,7 +6,6 @@ export * as object from './object.js';
6
6
  export * as productions from './productions.js';
7
7
  export * as shorthand from './shorthand.js';
8
8
  export * as source from './source.js';
9
- export * as stream from './stream.js';
10
9
  export * as symbols from './symbols.js';
11
10
  export * as tree from './tree.js';
12
11
  export * as trivia from './trivia.js';
package/lib/object.js CHANGED
@@ -1,20 +1,22 @@
1
1
  import map from 'iter-tools-es/methods/map';
2
+ export {
3
+ isObject,
4
+ isArray,
5
+ isPlainObject,
6
+ isFunction,
7
+ isSymbol,
8
+ isString,
9
+ isType,
10
+ isRegex,
11
+ isPattern,
12
+ } from '@bablr/agast-helpers/object';
2
13
 
3
14
  export const { hasOwn, getOwnPropertySymbols, getPrototypeOf, fromEntries } = Object;
4
15
 
5
- export const isObject = (obj) => obj !== null && typeof obj === 'object';
6
- export const { isArray } = Array;
7
- export const isFunction = (obj) => typeof obj === 'function';
8
- export const isSymbol = (obj) => typeof obj === 'symbol';
9
- export const isString = (obj) => typeof obj === 'string';
10
- export const isRegex = (obj) => obj instanceof RegExp;
11
- export const isPattern = (obj) => isString(obj) || isRegex(obj);
12
- export const isType = (obj) => isSymbol(obj) || isString(obj);
13
- export const isPlainObject = (val) => val && getPrototypeOf(val) === Object.prototype;
14
-
15
16
  export const objectKeys = (obj) => {
16
17
  return {
17
18
  *[Symbol.iterator]() {
19
+ if (obj == null) return;
18
20
  for (let key in obj) if (hasOwn(obj, key)) yield key;
19
21
  yield* getOwnPropertySymbols(obj);
20
22
  },
@@ -24,6 +26,7 @@ export const objectKeys = (obj) => {
24
26
  export const objectValues = (obj) => {
25
27
  return {
26
28
  *[Symbol.iterator]() {
29
+ if (obj == null) return;
27
30
  for (let key in obj) if (hasOwn(obj, key)) yield obj[key];
28
31
  yield* map((sym) => obj[sym], getOwnPropertySymbols(obj));
29
32
  },
@@ -33,6 +36,7 @@ export const objectValues = (obj) => {
33
36
  export const objectEntries = (obj) => {
34
37
  return {
35
38
  *[Symbol.iterator]() {
39
+ if (obj == null) return;
36
40
  for (let key in obj) if (hasOwn(obj, key)) yield [key, obj[key]];
37
41
  yield* map((sym) => [sym, obj[sym]], getOwnPropertySymbols(obj));
38
42
  },
@@ -1,6 +1,6 @@
1
1
  /* @macrome
2
2
  * @generatedby @bablr/macrome-generator-bablr
3
- * @generatedfrom ./productions.macro.js#1fc6c6c7f7c9fc7c43a69d9729301c75581c11ea
3
+ * @generatedfrom ./productions.macro.js#b095c92e30507ebaab43cd0c2b1dcee55853950f
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
  */
@@ -20,10 +20,10 @@ export function* List({
20
20
  allowHoles = false,
21
21
  allowTrailingSeparator = true
22
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`[]`)));
23
+ if (!['#', '@'].includes(getCooked(getEmbeddedMatcher(separator).properties.refMatcher?.node.properties.type?.node))) {
24
+ yield eat(buildEmbeddedMatcher(buildPropertyMatcher(getEmbeddedMatcher(separator).properties.refMatcher?.node, null, m.ArrayNodeMatcher`[]`)));
25
25
  }
26
- yield eat(buildEmbeddedMatcher(buildPropertyMatcher(getEmbeddedMatcher(Array.isArray(element) ? element[0] : element).properties.refMatcher?.node, m.ArrayNodeMatcher`[]`)));
26
+ yield eat(buildEmbeddedMatcher(buildPropertyMatcher(getEmbeddedMatcher(Array.isArray(element) ? element[0] : element).properties.refMatcher?.node, null, m.ArrayNodeMatcher`[]`)));
27
27
  let sep,
28
28
  it,
29
29
  anySep = false;
@@ -74,10 +74,12 @@ export function* Optional({
74
74
  yield eatMatch(matcher);
75
75
  }
76
76
  export function* Literal({
77
+ ctx,
77
78
  intrinsicValue
78
79
  }) {
79
80
  if (!intrinsicValue) throw new Error('Intrinsic productions must have value');
80
- yield eat(intrinsicValue);
81
+ yield eat(ctx.sourceTextFor(intrinsicValue.value));
81
82
  }
82
83
  export const Keyword = Literal;
83
- export const Punctuator = Literal;
84
+ export const Punctuator = Literal;
85
+ export const Space = Literal;
@@ -11,16 +11,14 @@ export function* List({ props }) {
11
11
 
12
12
  if (
13
13
  !['#', '@'].includes(
14
- getCooked(
15
- getEmbeddedMatcher(separator).properties.refMatcher?.node.properties.name.node.properties
16
- .content.node,
17
- ),
14
+ getCooked(getEmbeddedMatcher(separator).properties.refMatcher?.node.properties.type?.node),
18
15
  )
19
16
  ) {
20
17
  yield eat(
21
18
  buildEmbeddedMatcher(
22
19
  buildPropertyMatcher(
23
20
  getEmbeddedMatcher(separator).properties.refMatcher?.node,
21
+ null,
24
22
  m.ArrayNodeMatcher`[]`,
25
23
  ),
26
24
  ),
@@ -32,6 +30,7 @@ export function* List({ props }) {
32
30
  buildPropertyMatcher(
33
31
  getEmbeddedMatcher(Array.isArray(element) ? element[0] : element).properties.refMatcher
34
32
  ?.node,
33
+ null,
35
34
  m.ArrayNodeMatcher`[]`,
36
35
  ),
37
36
  ),
@@ -78,11 +77,13 @@ export function* Optional({ props: { value: matcher } }) {
78
77
  yield eatMatch(matcher);
79
78
  }
80
79
 
81
- export function* Literal({ intrinsicValue }) {
80
+ export function* Literal({ ctx, intrinsicValue }) {
82
81
  if (!intrinsicValue) throw new Error('Intrinsic productions must have value');
83
82
 
84
- yield eat(intrinsicValue);
83
+ yield eat(ctx.sourceTextFor(intrinsicValue.value));
85
84
  }
86
85
  export const Keyword = Literal;
87
86
 
88
87
  export const Punctuator = Literal;
88
+
89
+ export const Space = Literal;
package/lib/source.js CHANGED
@@ -142,7 +142,7 @@ function* __sourceFromTokenStream(tags) {
142
142
  step = iter.next();
143
143
 
144
144
  if (step instanceof Promise) {
145
- yield step;
145
+ step = yield step;
146
146
  }
147
147
 
148
148
  if (step.done) break;
package/lib/tree.js CHANGED
@@ -1,8 +1,6 @@
1
1
  import { streamFromTree } from '@bablr/agast-helpers/tree';
2
-
3
- import { printPrettyCSTML as printPrettyCSTMLFromStream } from './stream.js';
2
+ import { printPrettyCSTML as printPrettyCSTMLFromStream } from '@bablr/agast-helpers/stream';
4
3
 
5
4
  export const printPrettyCSTML = (rootNode, options = {}) => {
6
- // i need a context-aware streamFromTree here to build a stream with linked Tags...?
7
5
  return printPrettyCSTMLFromStream(streamFromTree(rootNode), options);
8
6
  };
package/lib/trivia.js CHANGED
@@ -1,16 +1,144 @@
1
+ /* global WeakSet */
1
2
  import { spam as m } from '@bablr/boot';
2
3
  import { Coroutine } from '@bablr/coroutine';
3
- import { eat, eatMatch, mapProductions, o, resolveLanguage } from './grammar.js';
4
- import { EmbeddedMatcher, EmbeddedRegex, EmbeddedNode } from './symbols.js';
4
+ import { eat, eatMatch, mapOwnProductions, mapProductions, o } from './grammar.js';
5
+ import {
6
+ EmbeddedMatcher,
7
+ EmbeddedRegex,
8
+ EmbeddedNode,
9
+ OpenNodeTag,
10
+ CloseNodeTag,
11
+ ReferenceTag,
12
+ Property,
13
+ } from './symbols.js';
5
14
  import { buildIdentifier, buildString } from './builders.js';
6
15
  import { buildCall, buildEmbeddedInstruction } from '@bablr/agast-vm-helpers/builders';
7
16
  import { getEmbeddedInstruction } from '@bablr/agast-vm-helpers/deembed';
8
17
  import { reifyExpression } from '@bablr/agast-vm-helpers';
18
+ import { getCooked } from '@bablr/agast-helpers/tree';
19
+ import { buildPathSegment } from '@bablr/agast-helpers/path';
20
+
21
+ const lookbehind = (context, s) => {
22
+ let token = s.resultPath;
23
+ while (token && [OpenNodeTag, CloseNodeTag, ReferenceTag].includes(token.type)) {
24
+ const prevToken = context.getPreviousTagPath(token);
25
+ if (!prevToken) break;
26
+ token = prevToken;
27
+ }
28
+ return token;
29
+ };
30
+
31
+ const matchedResults = new WeakSet();
32
+
33
+ export const basicTriviaEnhancer = ({ triviaIsAllowed, triviaMatcher }, grammar) => {
34
+ let Wrapper_ = 'Wrapper';
35
+ let Literal_ = 'Literal';
36
+
37
+ while (grammar.prototype[Wrapper_]) Wrapper_ += '_';
38
+ while (grammar.prototype[Literal_]) Literal_ += '_';
39
+
40
+ const resultGrammar = mapOwnProductions((production) => {
41
+ return function* (props) {
42
+ const co = new Coroutine(production(props));
43
+ const { s, ctx, flags, isCover, isCovered } = props;
44
+
45
+ co.advance();
46
+
47
+ try {
48
+ while (!co.done) {
49
+ const instr = co.value;
50
+ const { verb, arguments: args = [] } = instr;
51
+ let returnValue = undefined;
52
+
53
+ switch (verb) {
54
+ case 'eat':
55
+ case 'eatMatch':
56
+ case 'match':
57
+ case 'guard': {
58
+ const { 0: matcher } = args;
59
+
60
+ if (
61
+ matcher &&
62
+ !isCovered &&
63
+ matcher.type === EmbeddedMatcher &&
64
+ getCooked(
65
+ matcher.value.properties.refMatcher?.node.properties.type?.node.properties.value
66
+ ?.node,
67
+ ) !== '#'
68
+ ) {
69
+ const previous = lookbehind(ctx, s);
70
+ if (triviaIsAllowed(s) && (!previous || !matchedResults.has(previous))) {
71
+ matchedResults.add(previous);
72
+ yield eatMatch(triviaMatcher);
73
+ matchedResults.add(s.resultPath);
74
+ }
75
+ }
76
+
77
+ returnValue = returnValue || (yield instr);
78
+ break;
79
+ }
80
+
81
+ default:
82
+ returnValue = yield instr;
83
+ break;
84
+ }
85
+
86
+ co.advance(returnValue);
87
+ }
88
+
89
+ if (co.value) {
90
+ let realMatcher = reifyExpression(
91
+ co.value.arguments[0].value.properties.nodeMatcher.node,
92
+ );
93
+ let { flags: matcherFlags } = realMatcher;
94
+
95
+ let isNode = matcherFlags && !matcherFlags.fragment;
96
+
97
+ if (
98
+ !flags.token &&
99
+ isNode &&
100
+ !isCover &&
101
+ (!s.depths.path || (co.value && ['shift', 'shiftMatch'].includes(co.value.verb)))
102
+ ) {
103
+ if (triviaIsAllowed(s)) {
104
+ yield eatMatch(triviaMatcher);
105
+ }
106
+ }
107
+
108
+ return co.value;
109
+ } else {
110
+ if (!s.depths.path && !flags.token && !(isCovered || isCover)) {
111
+ if (triviaIsAllowed(s)) {
112
+ yield eatMatch(triviaMatcher);
113
+ }
114
+ }
115
+ }
116
+ } catch (e) {
117
+ co.throw(e);
118
+ throw e;
119
+ }
120
+ };
121
+ }, grammar);
122
+
123
+ return class extends resultGrammar {
124
+ *[Wrapper_]({ value: wrapped }) {
125
+ for (const instr of wrapped) {
126
+ yield getEmbeddedInstruction(instr);
127
+ }
128
+ }
129
+
130
+ *[Literal_]({ value: matcher }) {
131
+ yield eat(matcher);
132
+ }
133
+ };
134
+ };
9
135
 
10
136
  export const triviaEnhancer = (
11
137
  { triviaIsAllowed, triviaIsRequired = () => false, triviaMatcher },
12
138
  grammar,
13
139
  ) => {
140
+ if (!triviaMatcher) throw new Error();
141
+
14
142
  let Wrapper_ = 'Wrapper';
15
143
  let Literal_ = 'Literal';
16
144
 
@@ -18,9 +146,9 @@ export const triviaEnhancer = (
18
146
  while (grammar.prototype[Literal_]) Literal_ += '_';
19
147
 
20
148
  const resultGrammar = mapProductions((production) => {
21
- return function* (props) {
22
- const co = new Coroutine(production(props));
23
- const { ctx, s, isCovered, isCover, flags } = props;
149
+ return function* (args) {
150
+ const co = new Coroutine(production(args));
151
+ const { ctx, s, isCovered, isCover, isCoverBoundary, flags, mergedReference } = args;
24
152
 
25
153
  co.advance();
26
154
 
@@ -54,27 +182,34 @@ export const triviaEnhancer = (
54
182
  ) {
55
183
  if (triviaIsAllowed(s) && !flags.token) {
56
184
  let isString = typeof matcher === 'string';
57
- let wrappedMatcher = m`value: <*Literal ${
185
+ let wrappedMatcher = m`#: <*Literal ${
58
186
  isString ? buildString(matcher) : matcher.value
59
187
  } />`;
60
188
 
61
- let tmi = buildEmbeddedInstruction(
62
- triviaIsRequired() ? eat(triviaMatcher) : eatMatch(triviaMatcher),
63
- );
189
+ let tmi = buildEmbeddedInstruction(eatMatch(triviaMatcher));
64
190
 
65
191
  let result = yield buildCall(verb, m`<_${buildIdentifier(Wrapper_)} />`, [
66
192
  tmi,
67
193
  buildEmbeddedInstruction(eat(wrappedMatcher, props, options)),
68
194
  ]);
69
195
 
70
- returnValue = result?.get('value');
196
+ let prop = null;
197
+
198
+ if (result) {
199
+ for (let child of result.children) {
200
+ if (child.type === Property) prop = child;
201
+ }
202
+ }
203
+
204
+ returnValue = prop?.value.node;
71
205
  } else {
72
206
  returnValue = yield instr;
73
207
  }
74
208
  break;
75
209
  }
76
210
 
77
- let { name } = reifyExpression(matcher.value.properties.refMatcher?.node) || {};
211
+ let { type: refType } =
212
+ reifyExpression(matcher.value.properties.refMatcher?.node) || {};
78
213
  let realMatcher = reifyExpression(matcher.value.properties.nodeMatcher?.node);
79
214
  let { flags: matcherFlags } = realMatcher;
80
215
 
@@ -82,14 +217,16 @@ export const triviaEnhancer = (
82
217
  let isCoverBoundary = matcherFlags && (matcherFlags.cover || (isNode && !isCovered));
83
218
  if (
84
219
  matcher &&
85
- (matcher.type !== EmbeddedMatcher || name !== '#') &&
220
+ (matcher.type !== EmbeddedMatcher || refType !== '#') &&
86
221
  !s.holding &&
87
222
  !flags.token &&
88
223
  isCoverBoundary
89
224
  ) {
90
225
  if (triviaIsAllowed(s)) {
226
+ let { nodeMatcher } = reifyExpression(matcher.value);
227
+
91
228
  let tmi = buildEmbeddedInstruction(
92
- triviaIsRequired() ? eat(triviaMatcher) : eatMatch(triviaMatcher),
229
+ triviaIsRequired(s, nodeMatcher) ? eat(triviaMatcher) : eatMatch(triviaMatcher),
93
230
  );
94
231
 
95
232
  let result = yield buildCall(
@@ -101,11 +238,28 @@ export const triviaEnhancer = (
101
238
  let trivialResult = result;
102
239
 
103
240
  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);
241
+ if (isNode || isCoverBoundary) {
242
+ let { refMatcher } = matcher.value.properties;
243
+
244
+ let name, isArray;
245
+
246
+ if (!refMatcher) {
247
+ ({ name, isArray } = mergedReference);
248
+ } else {
249
+ let { name: name_, openIndexToken } = refMatcher.node.properties;
250
+ name = name_ && ctx.sourceTextFor(name_.node);
251
+ isArray = !!openIndexToken;
252
+ }
253
+
254
+ if (name) {
255
+ let pathSpec = name;
256
+
257
+ if (isArray) {
258
+ pathSpec = buildPathSegment(name, -1);
259
+ }
260
+
261
+ result = result.get([pathSpec]);
262
+ }
109
263
  }
110
264
 
111
265
  result = result && result.merge(trivialResult);
@@ -128,14 +282,13 @@ export const triviaEnhancer = (
128
282
  co.advance(returnValue);
129
283
  }
130
284
 
131
- if (!s.depths.path && !flags.token && !(isCovered || isCover)) {
285
+ if (!flags.token && !(isCovered || isCover)) {
132
286
  if (triviaIsAllowed(s)) {
133
287
  yield eatMatch(triviaMatcher);
134
288
  }
135
289
  } else if (co.value) {
136
- let realMatcher = reifyExpression(
137
- co.value.arguments[0].value.properties.nodeMatcher.node,
138
- );
290
+ let matcher = co.value.arguments[0];
291
+ let realMatcher = reifyExpression(matcher.value.properties.nodeMatcher.node);
139
292
  let { flags: matcherFlags } = realMatcher;
140
293
 
141
294
  let isNode = matcherFlags && !matcherFlags.fragment;
@@ -145,16 +298,47 @@ export const triviaEnhancer = (
145
298
  isNode &&
146
299
  !isCover &&
147
300
  co.value &&
148
- ['holdFor', 'holdForMatch'].includes(co.value.verb)
301
+ ['shift', 'shiftMatch'].includes(co.value.verb)
149
302
  ) {
150
303
  if (triviaIsAllowed(s)) {
151
304
  let tmi = buildEmbeddedInstruction(
152
305
  triviaIsRequired() ? eat(triviaMatcher) : eatMatch(triviaMatcher),
153
306
  );
154
- return buildCall(co.value.verb, m`<_${buildIdentifier(Wrapper_)} />`, [
307
+ let result = yield buildCall(co.value.verb, m`<_${buildIdentifier(Wrapper_)} />`, [
155
308
  tmi,
156
309
  buildEmbeddedInstruction(eat(co.value.arguments[0], co.value.arguments[1])),
157
310
  ]);
311
+
312
+ let trivialResult = result;
313
+
314
+ if (result && !result.isNull) {
315
+ if (isNode || isCoverBoundary) {
316
+ let { refMatcher } = matcher.value.properties;
317
+
318
+ let name, isArray;
319
+
320
+ if (!refMatcher) {
321
+ ({ name, isArray } = mergedReference);
322
+ } else {
323
+ let { name, openIndexToken } = refMatcher.node.properties;
324
+ name = name && ctx.sourceTextFor(name.node);
325
+ isArray = !!openIndexToken;
326
+ }
327
+
328
+ if (name) {
329
+ let pathSpec = name;
330
+
331
+ if (isArray) {
332
+ pathSpec = buildPathSegment(name, -1);
333
+ }
334
+
335
+ result = result.get([pathSpec]);
336
+ }
337
+ }
338
+
339
+ result = result && result.merge(trivialResult);
340
+ }
341
+ return result;
158
342
  }
159
343
  }
160
344
  }
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.22.0",
4
+ "version": "0.23.0",
5
5
  "author": "Conrad Buck<conartist6@gmail.com>",
6
6
  "type": "module",
7
7
  "files": [
@@ -17,7 +17,6 @@
17
17
  "./productions": "./lib/productions.js",
18
18
  "./shorthand": "./lib/shorthand.js",
19
19
  "./source": "./lib/source.js",
20
- "./stream": "./lib/stream.js",
21
20
  "./symbols": "./lib/symbols.js",
22
21
  "./tree": "./lib/tree.js",
23
22
  "./trivia": "./lib/trivia.js",
@@ -30,17 +29,17 @@
30
29
  "clean": "macrome clean"
31
30
  },
32
31
  "dependencies": {
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",
32
+ "@bablr/language_enhancer-debug-log": "0.10.0",
33
+ "@bablr/strategy_enhancer-debug-log": "0.9.0",
34
+ "@bablr/agast-helpers": "0.8.0",
35
+ "@bablr/agast-vm-helpers": "0.8.0",
36
+ "@bablr/boot": "0.9.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.8.0",
43
- "@bablr/eslint-config-base": "github:bablr-lang/eslint-config-base#d834ccc52795d6c3b96ecc6c419960fceed221a6",
42
+ "@bablr/eslint-config-base": "github:bablr-lang/eslint-config-base#c97bfa4b3663f8378e9b3e42bb5a41e685406cf9",
44
43
  "@bablr/macrome": "0.1.3",
45
44
  "@bablr/macrome-generator-bablr": "0.3.2",
46
45
  "enhanced-resolve": "^5.12.0",