@bablr/helpers 0.22.1 → 0.24.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 +261 -201
- 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 +13 -11
- package/lib/productions.macro.js +13 -17
- package/lib/source.js +1 -1
- package/lib/tree.js +1 -3
- package/lib/trivia.js +213 -33
- package/package.json +8 -9
- 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,13 +1,13 @@
|
|
|
1
1
|
/* @macrome
|
|
2
2
|
* @generatedby @bablr/macrome-generator-bablr
|
|
3
|
-
* @generatedfrom ./productions.macro.js#
|
|
3
|
+
* @generatedfrom ./productions.macro.js#a661312b1d84c6cc48eac8794f36c3b607a57892
|
|
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 { getCooked } from '@bablr/agast-helpers/tree';
|
|
8
|
+
import { get, getCooked } from '@bablr/agast-helpers/tree';
|
|
9
9
|
import { eat, eatMatch } from './grammar.js';
|
|
10
|
-
import {
|
|
10
|
+
import { Matcher } from './symbols.js';
|
|
11
11
|
import { getEmbeddedMatcher } from '@bablr/agast-vm-helpers/deembed';
|
|
12
12
|
import { buildPropertyMatcher } from './builders.js';
|
|
13
13
|
import { buildEmbeddedMatcher } from '@bablr/agast-vm-helpers/builders';
|
|
@@ -20,10 +20,10 @@ export function* List({
|
|
|
20
20
|
allowHoles = false,
|
|
21
21
|
allowTrailingSeparator = true
|
|
22
22
|
} = props;
|
|
23
|
-
if (
|
|
24
|
-
yield eat(buildEmbeddedMatcher(buildPropertyMatcher(getEmbeddedMatcher(separator)
|
|
23
|
+
if (getCooked(get(['refMatcher', 'name', 'content'], getEmbeddedMatcher(separator)))) {
|
|
24
|
+
yield eat(buildEmbeddedMatcher(buildPropertyMatcher(get('refMatcher', getEmbeddedMatcher(separator)), null, m.ArrayNodeMatcher`[]`)));
|
|
25
25
|
}
|
|
26
|
-
yield eat(buildEmbeddedMatcher(buildPropertyMatcher(getEmbeddedMatcher(Array.isArray(element) ? element[0] : element)
|
|
26
|
+
yield eat(buildEmbeddedMatcher(buildPropertyMatcher(get('refMatcher', getEmbeddedMatcher(Array.isArray(element) ? element[0] : element)), null, m.ArrayNodeMatcher`[]`)));
|
|
27
27
|
let sep,
|
|
28
28
|
it,
|
|
29
29
|
anySep = false;
|
|
@@ -46,7 +46,7 @@ export function* Any({
|
|
|
46
46
|
for (const alternative of alternatives) {
|
|
47
47
|
if (Array.isArray(alternative)) {
|
|
48
48
|
if (yield eatMatch(...alternative)) break;
|
|
49
|
-
} else if (alternative.type ===
|
|
49
|
+
} else if (alternative.type === Matcher) {
|
|
50
50
|
if (yield eatMatch(alternative)) break;
|
|
51
51
|
} else {
|
|
52
52
|
throw new Error();
|
|
@@ -74,10 +74,12 @@ export function* Optional({
|
|
|
74
74
|
yield eatMatch(matcher);
|
|
75
75
|
}
|
|
76
76
|
export function* Literal({
|
|
77
|
-
|
|
77
|
+
ctx,
|
|
78
|
+
literalValue
|
|
78
79
|
}) {
|
|
79
|
-
if (!
|
|
80
|
-
yield eat(
|
|
80
|
+
if (!literalValue) throw new Error('Intrinsic productions must have value');
|
|
81
|
+
yield eat(ctx.sourceTextFor(literalValue.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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { spam as m } from '@bablr/boot';
|
|
2
|
-
import { getCooked } from '@bablr/agast-helpers/tree';
|
|
2
|
+
import { get, getCooked } from '@bablr/agast-helpers/tree';
|
|
3
3
|
import { eat, eatMatch } from './grammar.js';
|
|
4
|
-
import {
|
|
4
|
+
import { Matcher } from './symbols.js';
|
|
5
5
|
import { getEmbeddedMatcher } from '@bablr/agast-vm-helpers/deembed';
|
|
6
6
|
import { buildPropertyMatcher } from './builders.js';
|
|
7
7
|
import { buildEmbeddedMatcher } from '@bablr/agast-vm-helpers/builders';
|
|
@@ -9,18 +9,12 @@ import { buildEmbeddedMatcher } from '@bablr/agast-vm-helpers/builders';
|
|
|
9
9
|
export function* List({ props }) {
|
|
10
10
|
const { element, separator, allowHoles = false, allowTrailingSeparator = true } = props;
|
|
11
11
|
|
|
12
|
-
if (
|
|
13
|
-
!['#', '@'].includes(
|
|
14
|
-
getCooked(
|
|
15
|
-
getEmbeddedMatcher(separator).properties.refMatcher?.node.properties.name.node.properties
|
|
16
|
-
.content.node,
|
|
17
|
-
),
|
|
18
|
-
)
|
|
19
|
-
) {
|
|
12
|
+
if (getCooked(get(['refMatcher', 'name', 'content'], getEmbeddedMatcher(separator)))) {
|
|
20
13
|
yield eat(
|
|
21
14
|
buildEmbeddedMatcher(
|
|
22
15
|
buildPropertyMatcher(
|
|
23
|
-
getEmbeddedMatcher(separator)
|
|
16
|
+
get('refMatcher', getEmbeddedMatcher(separator)),
|
|
17
|
+
null,
|
|
24
18
|
m.ArrayNodeMatcher`[]`,
|
|
25
19
|
),
|
|
26
20
|
),
|
|
@@ -30,8 +24,8 @@ export function* List({ props }) {
|
|
|
30
24
|
yield eat(
|
|
31
25
|
buildEmbeddedMatcher(
|
|
32
26
|
buildPropertyMatcher(
|
|
33
|
-
getEmbeddedMatcher(Array.isArray(element) ? element[0] : element)
|
|
34
|
-
|
|
27
|
+
get('refMatcher', getEmbeddedMatcher(Array.isArray(element) ? element[0] : element)),
|
|
28
|
+
null,
|
|
35
29
|
m.ArrayNodeMatcher`[]`,
|
|
36
30
|
),
|
|
37
31
|
),
|
|
@@ -56,7 +50,7 @@ export function* Any({ props: { value: alternatives } }) {
|
|
|
56
50
|
for (const alternative of alternatives) {
|
|
57
51
|
if (Array.isArray(alternative)) {
|
|
58
52
|
if (yield eatMatch(...alternative)) break;
|
|
59
|
-
} else if (alternative.type ===
|
|
53
|
+
} else if (alternative.type === Matcher) {
|
|
60
54
|
if (yield eatMatch(alternative)) break;
|
|
61
55
|
} else {
|
|
62
56
|
throw new Error();
|
|
@@ -78,11 +72,13 @@ export function* Optional({ props: { value: matcher } }) {
|
|
|
78
72
|
yield eatMatch(matcher);
|
|
79
73
|
}
|
|
80
74
|
|
|
81
|
-
export function* Literal({
|
|
82
|
-
if (!
|
|
75
|
+
export function* Literal({ ctx, literalValue }) {
|
|
76
|
+
if (!literalValue) throw new Error('Intrinsic productions must have value');
|
|
83
77
|
|
|
84
|
-
yield eat(
|
|
78
|
+
yield eat(ctx.sourceTextFor(literalValue.value));
|
|
85
79
|
}
|
|
86
80
|
export const Keyword = Literal;
|
|
87
81
|
|
|
88
82
|
export const Punctuator = Literal;
|
|
83
|
+
|
|
84
|
+
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,139 @@
|
|
|
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
|
+
Matcher,
|
|
7
|
+
Regex,
|
|
8
|
+
Node,
|
|
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 { get, 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 === Matcher &&
|
|
64
|
+
getCooked(get(['refMatcher', 'type', 'value'], matcher.value)) !== '#'
|
|
65
|
+
) {
|
|
66
|
+
const previous = lookbehind(ctx, s);
|
|
67
|
+
if (triviaIsAllowed(s) && (!previous || !matchedResults.has(previous))) {
|
|
68
|
+
matchedResults.add(previous);
|
|
69
|
+
yield eatMatch(triviaMatcher);
|
|
70
|
+
matchedResults.add(s.resultPath);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
returnValue = returnValue || (yield instr);
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
default:
|
|
79
|
+
returnValue = yield instr;
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
co.advance(returnValue);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (co.value) {
|
|
87
|
+
let realMatcher = reifyExpression(get('nodeMatcher', co.value.arguments[0].value));
|
|
88
|
+
let { flags: matcherFlags } = realMatcher;
|
|
89
|
+
|
|
90
|
+
let isNode = matcherFlags && !matcherFlags.fragment;
|
|
91
|
+
|
|
92
|
+
if (
|
|
93
|
+
!flags.token &&
|
|
94
|
+
isNode &&
|
|
95
|
+
!isCover &&
|
|
96
|
+
(!s.depths.path || (co.value && ['shift', 'shiftMatch'].includes(co.value.verb)))
|
|
97
|
+
) {
|
|
98
|
+
if (triviaIsAllowed(s)) {
|
|
99
|
+
yield eatMatch(triviaMatcher);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return co.value;
|
|
104
|
+
} else {
|
|
105
|
+
if (!s.depths.path && !flags.token && !isCovered) {
|
|
106
|
+
if (triviaIsAllowed(s)) {
|
|
107
|
+
yield eatMatch(triviaMatcher);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
} catch (e) {
|
|
112
|
+
co.throw(e);
|
|
113
|
+
throw e;
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
}, grammar);
|
|
117
|
+
|
|
118
|
+
return class extends resultGrammar {
|
|
119
|
+
*[Wrapper_]({ value: wrapped }) {
|
|
120
|
+
for (const instr of wrapped) {
|
|
121
|
+
yield getEmbeddedInstruction(instr);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
*[Literal_]({ value: matcher }) {
|
|
126
|
+
yield eat(matcher);
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
};
|
|
9
130
|
|
|
10
131
|
export const triviaEnhancer = (
|
|
11
132
|
{ triviaIsAllowed, triviaIsRequired = () => false, triviaMatcher },
|
|
12
133
|
grammar,
|
|
13
134
|
) => {
|
|
135
|
+
if (!triviaMatcher) throw new Error();
|
|
136
|
+
|
|
14
137
|
let Wrapper_ = 'Wrapper';
|
|
15
138
|
let Literal_ = 'Literal';
|
|
16
139
|
|
|
@@ -18,9 +141,9 @@ export const triviaEnhancer = (
|
|
|
18
141
|
while (grammar.prototype[Literal_]) Literal_ += '_';
|
|
19
142
|
|
|
20
143
|
const resultGrammar = mapProductions((production) => {
|
|
21
|
-
return function* (
|
|
22
|
-
const co = new Coroutine(production(
|
|
23
|
-
const { ctx, s, isCovered, isCover, flags } =
|
|
144
|
+
return function* (args) {
|
|
145
|
+
const co = new Coroutine(production(args));
|
|
146
|
+
const { ctx, s, isCovered, isCover, isCoverBoundary, flags, mergedReference } = args;
|
|
24
147
|
|
|
25
148
|
co.advance();
|
|
26
149
|
|
|
@@ -38,9 +161,9 @@ export const triviaEnhancer = (
|
|
|
38
161
|
const { 0: matcher, 1: props, 2: options } = args;
|
|
39
162
|
|
|
40
163
|
if (
|
|
41
|
-
matcher.type ===
|
|
164
|
+
matcher.type === Matcher &&
|
|
42
165
|
['ArrayNodeMatcher', 'NullNodeMatcher'].includes(
|
|
43
|
-
matcher.value.
|
|
166
|
+
get('nodeMatcher', matcher.value).type.description,
|
|
44
167
|
)
|
|
45
168
|
) {
|
|
46
169
|
returnValue = yield instr;
|
|
@@ -48,64 +171,90 @@ export const triviaEnhancer = (
|
|
|
48
171
|
}
|
|
49
172
|
|
|
50
173
|
if (
|
|
51
|
-
matcher.type ===
|
|
174
|
+
matcher.type === Regex ||
|
|
52
175
|
typeof matcher === 'string' ||
|
|
53
|
-
(matcher.type ===
|
|
176
|
+
(matcher.type === Node && matcher.value.flags.token)
|
|
54
177
|
) {
|
|
55
178
|
if (triviaIsAllowed(s) && !flags.token) {
|
|
56
179
|
let isString = typeof matcher === 'string';
|
|
57
|
-
let wrappedMatcher = m
|
|
180
|
+
let wrappedMatcher = m`#: <*Literal ${
|
|
58
181
|
isString ? buildString(matcher) : matcher.value
|
|
59
182
|
} />`;
|
|
60
183
|
|
|
61
|
-
let tmi = buildEmbeddedInstruction(
|
|
62
|
-
triviaIsRequired() ? eat(triviaMatcher) : eatMatch(triviaMatcher),
|
|
63
|
-
);
|
|
184
|
+
let tmi = buildEmbeddedInstruction(eatMatch(triviaMatcher));
|
|
64
185
|
|
|
65
|
-
let result = yield buildCall(verb, m`<
|
|
186
|
+
let result = yield buildCall(verb, m`<__${buildIdentifier(Wrapper_)} />`, [
|
|
66
187
|
tmi,
|
|
67
188
|
buildEmbeddedInstruction(eat(wrappedMatcher, props, options)),
|
|
68
189
|
]);
|
|
69
190
|
|
|
70
|
-
|
|
191
|
+
let prop = null;
|
|
192
|
+
|
|
193
|
+
if (result) {
|
|
194
|
+
for (let child of result.tagsInner) {
|
|
195
|
+
if (child.type === Property) prop = child.value;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
returnValue = prop?.node;
|
|
71
200
|
} else {
|
|
72
201
|
returnValue = yield instr;
|
|
73
202
|
}
|
|
74
203
|
break;
|
|
75
204
|
}
|
|
76
205
|
|
|
77
|
-
let {
|
|
78
|
-
let realMatcher = reifyExpression(matcher.value
|
|
206
|
+
let { type: refType } = reifyExpression(get('refMatcher', matcher.value)) || {};
|
|
207
|
+
let realMatcher = reifyExpression(get('nodeMatcher', matcher.value));
|
|
79
208
|
let { flags: matcherFlags } = realMatcher;
|
|
80
209
|
|
|
81
210
|
let isNode = matcherFlags && !matcherFlags.fragment;
|
|
82
211
|
let isCoverBoundary = matcherFlags && (matcherFlags.cover || (isNode && !isCovered));
|
|
83
212
|
if (
|
|
84
213
|
matcher &&
|
|
85
|
-
(matcher.type !==
|
|
214
|
+
(matcher.type !== Matcher || refType !== '#') &&
|
|
86
215
|
!s.holding &&
|
|
87
216
|
!flags.token &&
|
|
88
217
|
isCoverBoundary
|
|
89
218
|
) {
|
|
90
219
|
if (triviaIsAllowed(s)) {
|
|
220
|
+
let { nodeMatcher } = reifyExpression(matcher.value);
|
|
221
|
+
|
|
91
222
|
let tmi = buildEmbeddedInstruction(
|
|
92
|
-
triviaIsRequired() ? eat(triviaMatcher) : eatMatch(triviaMatcher),
|
|
223
|
+
triviaIsRequired(s, nodeMatcher) ? eat(triviaMatcher) : eatMatch(triviaMatcher),
|
|
93
224
|
);
|
|
94
225
|
|
|
95
226
|
let result = yield buildCall(
|
|
96
227
|
verb,
|
|
97
|
-
m`<
|
|
228
|
+
m`<__${buildIdentifier(Wrapper_)} />`,
|
|
98
229
|
[tmi, buildEmbeddedInstruction(eat(matcher, props, options))],
|
|
99
230
|
o({ bind: options?.value.bind ?? false }),
|
|
100
231
|
);
|
|
101
232
|
let trivialResult = result;
|
|
102
233
|
|
|
103
234
|
if (result && !result.isNull) {
|
|
104
|
-
if (
|
|
105
|
-
let
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
235
|
+
if (isNode || isCoverBoundary) {
|
|
236
|
+
let refMatcher = get('refMatcher', matcher.value);
|
|
237
|
+
|
|
238
|
+
let name, isArray;
|
|
239
|
+
|
|
240
|
+
if (!refMatcher) {
|
|
241
|
+
({ name, isArray } = mergedReference);
|
|
242
|
+
} else {
|
|
243
|
+
let name_ = get('name', refMatcher);
|
|
244
|
+
let openIndexToken = get('openIndexToken', refMatcher);
|
|
245
|
+
name = name_ && ctx.sourceTextFor(name_);
|
|
246
|
+
isArray = !!openIndexToken;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (name) {
|
|
250
|
+
let pathSpec = name;
|
|
251
|
+
|
|
252
|
+
if (isArray) {
|
|
253
|
+
pathSpec = buildPathSegment(name, -1);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
result = result.get([pathSpec]);
|
|
257
|
+
}
|
|
109
258
|
}
|
|
110
259
|
|
|
111
260
|
result = result && result.merge(trivialResult);
|
|
@@ -128,14 +277,13 @@ export const triviaEnhancer = (
|
|
|
128
277
|
co.advance(returnValue);
|
|
129
278
|
}
|
|
130
279
|
|
|
131
|
-
if (!
|
|
280
|
+
if (!flags.token && !(isCovered || isCover)) {
|
|
132
281
|
if (triviaIsAllowed(s)) {
|
|
133
282
|
yield eatMatch(triviaMatcher);
|
|
134
283
|
}
|
|
135
284
|
} else if (co.value) {
|
|
136
|
-
let
|
|
137
|
-
|
|
138
|
-
);
|
|
285
|
+
let matcher = co.value.arguments[0];
|
|
286
|
+
let realMatcher = reifyExpression(get('nodeMatcher', matcher.value));
|
|
139
287
|
let { flags: matcherFlags } = realMatcher;
|
|
140
288
|
|
|
141
289
|
let isNode = matcherFlags && !matcherFlags.fragment;
|
|
@@ -145,16 +293,48 @@ export const triviaEnhancer = (
|
|
|
145
293
|
isNode &&
|
|
146
294
|
!isCover &&
|
|
147
295
|
co.value &&
|
|
148
|
-
['
|
|
296
|
+
['shift', 'shiftMatch'].includes(co.value.verb)
|
|
149
297
|
) {
|
|
150
298
|
if (triviaIsAllowed(s)) {
|
|
151
299
|
let tmi = buildEmbeddedInstruction(
|
|
152
300
|
triviaIsRequired() ? eat(triviaMatcher) : eatMatch(triviaMatcher),
|
|
153
301
|
);
|
|
154
|
-
|
|
302
|
+
let result = yield buildCall(co.value.verb, m`<__${buildIdentifier(Wrapper_)} />`, [
|
|
155
303
|
tmi,
|
|
156
304
|
buildEmbeddedInstruction(eat(co.value.arguments[0], co.value.arguments[1])),
|
|
157
305
|
]);
|
|
306
|
+
|
|
307
|
+
let trivialResult = result;
|
|
308
|
+
|
|
309
|
+
if (result && !result.isNull) {
|
|
310
|
+
if (isNode || isCoverBoundary) {
|
|
311
|
+
let refMatcher = get('refMatcher', matcher.value);
|
|
312
|
+
|
|
313
|
+
let name, isArray;
|
|
314
|
+
|
|
315
|
+
if (!refMatcher) {
|
|
316
|
+
({ name, isArray } = mergedReference);
|
|
317
|
+
} else {
|
|
318
|
+
let name = get('name', refMatcher);
|
|
319
|
+
let openIndexToken = get('openIndexToken', refMatcher);
|
|
320
|
+
name = name && ctx.sourceTextFor(name);
|
|
321
|
+
isArray = !!openIndexToken;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
if (name) {
|
|
325
|
+
let pathSpec = name;
|
|
326
|
+
|
|
327
|
+
if (isArray) {
|
|
328
|
+
pathSpec = buildPathSegment(name, -1);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
result = result.get([pathSpec]);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
result = result && result.merge(trivialResult);
|
|
336
|
+
}
|
|
337
|
+
return result;
|
|
158
338
|
}
|
|
159
339
|
}
|
|
160
340
|
}
|
|
@@ -194,8 +374,8 @@ export const triviaEnhancer = (
|
|
|
194
374
|
}
|
|
195
375
|
}
|
|
196
376
|
|
|
197
|
-
*[Literal_]({
|
|
198
|
-
yield eat(
|
|
377
|
+
*[Literal_]({ literalValue }) {
|
|
378
|
+
yield eat(literalValue);
|
|
199
379
|
}
|
|
200
380
|
};
|
|
201
381
|
};
|