@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 +28 -6
- package/lib/decorators.js +15 -3
- package/lib/grammar.js +15 -5
- package/lib/object.js +1 -0
- package/lib/productions.js +34 -15
- package/lib/productions.macro.js +30 -19
- package/lib/symbols.js +1 -1
- package/lib/trivia.js +152 -33
- package/package.json +6 -6
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(
|
|
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(
|
|
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-
|
|
384
|
+
if (!/^[a-zA-Z_]+$/.test(name)) throw new Error();
|
|
378
385
|
|
|
379
|
-
|
|
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
|
|
70
|
+
export const UndefinedAttributes = (attributes) => (desc, context) => {
|
|
59
71
|
context.addInitializer(function () {
|
|
60
|
-
this.
|
|
61
|
-
this.
|
|
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/
|
|
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
|
-
|
|
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
|
|
240
|
-
return __buildCall('
|
|
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 {
|
package/lib/productions.js
CHANGED
|
@@ -1,33 +1,34 @@
|
|
|
1
1
|
/* @macrome
|
|
2
2
|
* @generatedby @bablr/macrome-generator-bablr
|
|
3
|
-
* @generatedfrom ./productions.macro.js#
|
|
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 {
|
|
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
|
|
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
|
-
|
|
15
|
+
props
|
|
15
16
|
}) {
|
|
16
17
|
const {
|
|
17
18
|
element,
|
|
18
19
|
separator,
|
|
19
20
|
allowHoles = false,
|
|
20
21
|
allowTrailingSeparator = true
|
|
21
|
-
} =
|
|
22
|
-
if (!['#', '@'].includes(getCooked(getEmbeddedMatcher(separator).properties.refMatcher
|
|
23
|
-
yield eat(buildEmbeddedMatcher(buildPropertyMatcher(getEmbeddedMatcher(separator).properties.refMatcher
|
|
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
|
|
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
|
-
|
|
42
|
+
props: {
|
|
43
|
+
value: alternatives
|
|
44
|
+
}
|
|
42
45
|
}) {
|
|
43
46
|
for (const alternative of alternatives) {
|
|
44
|
-
if (alternative
|
|
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
|
-
|
|
57
|
+
props: {
|
|
58
|
+
value: matchers
|
|
59
|
+
}
|
|
53
60
|
}) {
|
|
54
61
|
for (const matcher of matchers) {
|
|
55
|
-
|
|
62
|
+
if (Array.isArray(matcher)) {
|
|
63
|
+
yield eat(...matcher);
|
|
64
|
+
} else {
|
|
65
|
+
yield eat(matcher);
|
|
66
|
+
}
|
|
56
67
|
}
|
|
57
68
|
}
|
|
58
|
-
export function*
|
|
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 =
|
|
82
|
+
export const Keyword = Literal;
|
|
83
|
+
export const Punctuator = Literal;
|
package/lib/productions.macro.js
CHANGED
|
@@ -1,27 +1,26 @@
|
|
|
1
1
|
import { spam as m } from '@bablr/boot';
|
|
2
|
-
import {
|
|
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
|
|
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({
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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*
|
|
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
|
|
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
|
-
|
|
19
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
42
|
+
['ArrayNodeMatcher', 'NullNodeMatcher'].includes(
|
|
43
|
+
matcher.value.properties.nodeMatcher.node.type.description,
|
|
44
|
+
)
|
|
45
45
|
) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
-
|
|
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.
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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.
|
|
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.
|
|
34
|
-
"@bablr/strategy_enhancer-debug-log": "0.
|
|
35
|
-
"@bablr/agast-helpers": "0.
|
|
36
|
-
"@bablr/agast-vm-helpers": "0.
|
|
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.
|
|
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",
|