@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/builders.js +156 -202
- package/lib/decorators.js +0 -3
- package/lib/enhancers.js +3 -6
- package/lib/grammar.js +17 -35
- package/lib/index.js +0 -1
- package/lib/object.js +14 -10
- package/lib/productions.js +8 -6
- package/lib/productions.macro.js +7 -6
- package/lib/source.js +1 -1
- package/lib/tree.js +1 -3
- package/lib/trivia.js +208 -24
- package/package.json +7 -8
- package/lib/stream.js +0 -86
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
|
|
242
|
-
return __buildCall('
|
|
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
|
},
|
package/lib/productions.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* @macrome
|
|
2
2
|
* @generatedby @bablr/macrome-generator-bablr
|
|
3
|
-
* @generatedfrom ./productions.macro.js#
|
|
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.
|
|
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;
|
package/lib/productions.macro.js
CHANGED
|
@@ -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
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
|
|
4
|
-
import {
|
|
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* (
|
|
22
|
-
const co = new Coroutine(production(
|
|
23
|
-
const { ctx, s, isCovered, isCover, flags } =
|
|
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
|
|
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
|
-
|
|
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 {
|
|
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 ||
|
|
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 (
|
|
105
|
-
let
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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 (!
|
|
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
|
|
137
|
-
|
|
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
|
-
['
|
|
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
|
-
|
|
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.
|
|
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.
|
|
34
|
-
"@bablr/strategy_enhancer-debug-log": "0.
|
|
35
|
-
"@bablr/agast-helpers": "0.
|
|
36
|
-
"@bablr/agast-vm-helpers": "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/
|
|
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",
|