@bablr/helpers 0.20.6 → 0.21.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 +732 -500
- package/lib/decorators.js +2 -1
- package/lib/enhancers.js +4 -36
- package/lib/grammar.js +117 -11
- package/lib/productions.js +29 -92
- package/lib/productions.macro.js +46 -21
- package/lib/shorthand.js +1 -3
- package/lib/source.js +45 -3
- package/lib/stream.js +7 -9
- package/lib/trivia.js +19 -13
- package/package.json +7 -4
package/lib/builders.js
CHANGED
|
@@ -1,117 +1,130 @@
|
|
|
1
1
|
// import { i } from '@bablr/boot/shorthand.macro';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { interpolateFragment, buildFilledGapFunction } from '@bablr/agast-helpers/template';
|
|
3
|
+
import {
|
|
4
|
+
buildNullNode,
|
|
5
|
+
isNull,
|
|
6
|
+
treeFromStreamSync as treeFromStream,
|
|
7
|
+
} from '@bablr/agast-helpers/tree';
|
|
4
8
|
import { buildLiteralTag as agastBuildLiteralTag } from '@bablr/agast-helpers/builders';
|
|
5
9
|
import * as t from '@bablr/agast-helpers/shorthand';
|
|
6
|
-
import * as btree from '@bablr/agast-helpers/btree';
|
|
7
10
|
import * as l from '@bablr/agast-vm-helpers/languages';
|
|
11
|
+
import { concat } from '@bablr/agast-vm-helpers/iterable';
|
|
8
12
|
|
|
9
|
-
const { getPrototypeOf, freeze } = Object;
|
|
13
|
+
const { getPrototypeOf, freeze, hasOwn } = Object;
|
|
10
14
|
const { isArray } = Array;
|
|
11
15
|
|
|
12
16
|
const when = (condition, value) => (condition ? value : { *[Symbol.iterator]() {} });
|
|
13
17
|
|
|
14
18
|
const isString = (val) => typeof val === 'string';
|
|
15
|
-
const isBoolean = (val) => typeof val === 'boolean';
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
[t.ref`name`],
|
|
45
|
-
when(isArray, [t.ref`arrayOperatorToken`]),
|
|
46
|
-
when(hasGap, [t.ref`hasGapToken`]),
|
|
47
|
-
[t.ref`sigilToken`],
|
|
48
|
-
),
|
|
49
|
-
),
|
|
50
|
-
{
|
|
51
|
-
name: buildIdentifier(name),
|
|
52
|
-
arrayOperatorToken: isArray ? t.s_node(l.CSTML, 'Punctuator', '[]') : t.null_node(),
|
|
53
|
-
hasGapToken: hasGap ? t.s_node(l.CSTML, 'Punctuator', '$') : t.null_node(),
|
|
54
|
-
sigilToken: t.s_node(l.CSTML, 'Punctuator', ':'),
|
|
55
|
-
},
|
|
20
|
+
export const buildReferenceTag = (
|
|
21
|
+
name,
|
|
22
|
+
isArray = false,
|
|
23
|
+
flags = t.referenceFlags,
|
|
24
|
+
index = null,
|
|
25
|
+
) => {
|
|
26
|
+
let expressions = [];
|
|
27
|
+
const gap = buildFilledGapFunction(expressions);
|
|
28
|
+
|
|
29
|
+
return treeFromStream(
|
|
30
|
+
[
|
|
31
|
+
t.nodeOpen(t.nodeFlags, l.CSTML, 'ReferenceTag'),
|
|
32
|
+
t.ref`name`,
|
|
33
|
+
gap(name ? buildIdentifier(name) : buildNullNode()),
|
|
34
|
+
t.ref`openIndexToken`,
|
|
35
|
+
gap(isArray ? buildToken(l.CSTML, 'Punctuator', '[') : buildNullNode()),
|
|
36
|
+
t.ref`index`,
|
|
37
|
+
gap(index || buildNullNode()),
|
|
38
|
+
t.ref`closeIndexToken`,
|
|
39
|
+
gap(isArray ? buildToken(l.CSTML, 'Punctuator', ']') : buildNullNode()),
|
|
40
|
+
t.ref`flags`,
|
|
41
|
+
gap(flags ? buildReferenceFlags(flags) : buildNullNode()),
|
|
42
|
+
t.ref`sigilToken`,
|
|
43
|
+
gap(buildToken(l.CSTML, 'Punctuator', ':')),
|
|
44
|
+
t.nodeClose(),
|
|
45
|
+
],
|
|
46
|
+
{ expressions },
|
|
56
47
|
);
|
|
57
48
|
};
|
|
58
49
|
|
|
59
50
|
export const buildGapTag = () => {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
51
|
+
let expressions = [];
|
|
52
|
+
const gap = buildFilledGapFunction(expressions);
|
|
53
|
+
|
|
54
|
+
return treeFromStream(
|
|
55
|
+
[
|
|
56
|
+
t.nodeOpen(t.nodeFlags, l.CSTML, 'ShiftTag'),
|
|
57
|
+
t.ref`sigilToken`,
|
|
58
|
+
gap(buildToken(l.CSTML, 'Punctuator', '<//>')),
|
|
59
|
+
t.nodeClose(),
|
|
60
|
+
],
|
|
61
|
+
{ expressions },
|
|
62
|
+
);
|
|
63
63
|
};
|
|
64
64
|
|
|
65
65
|
export const buildShiftTag = () => {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
let expressions = [];
|
|
67
|
+
const gap = buildFilledGapFunction(expressions);
|
|
68
|
+
|
|
69
|
+
return treeFromStream(
|
|
70
|
+
[
|
|
71
|
+
t.nodeOpen(t.nodeFlags, l.CSTML, 'ShiftTag'),
|
|
72
|
+
t.ref`sigilToken`,
|
|
73
|
+
gap(buildToken(l.CSTML, 'Punctuator', '^^^')),
|
|
74
|
+
t.nodeClose(),
|
|
75
|
+
],
|
|
76
|
+
{ expressions },
|
|
77
|
+
);
|
|
69
78
|
};
|
|
70
79
|
|
|
71
|
-
export const
|
|
72
|
-
const {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
80
|
+
export const buildReferenceFlags = (flags = t.referenceFlags) => {
|
|
81
|
+
const { expression = null, hasGap = null } = flags;
|
|
82
|
+
let expressions = [];
|
|
83
|
+
const gap = buildFilledGapFunction(expressions);
|
|
84
|
+
|
|
85
|
+
return treeFromStream(
|
|
86
|
+
[
|
|
87
|
+
t.nodeOpen(t.nodeFlags, l.CSTML, 'ReferenceFlags'),
|
|
88
|
+
t.ref`expressionToken`,
|
|
89
|
+
gap(expression ? buildToken(l.CSTML, 'Punctuator', '+') : buildNullNode()),
|
|
90
|
+
t.ref`hasGapToken`,
|
|
91
|
+
gap(hasGap ? buildToken(l.CSTML, 'Punctuator', '$') : buildNullNode()),
|
|
92
|
+
t.nodeClose(),
|
|
93
|
+
],
|
|
94
|
+
{ expressions },
|
|
95
|
+
);
|
|
96
|
+
};
|
|
77
97
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
escapeToken: escape ? t.s_node(l.CSTML, 'Punctuator', '@') : t.null_node(),
|
|
94
|
-
expressionToken: expression ? t.s_node(l.CSTML, 'Punctuator', '+') : t.null_node(),
|
|
95
|
-
hasGapToken: hasGap ? t.s_node(l.CSTML, 'Punctuator', '$') : t.null_node(),
|
|
96
|
-
},
|
|
98
|
+
export const buildNodeFlags = (flags = t.nodeFlags) => {
|
|
99
|
+
const { token = null, hasGap = null } = flags;
|
|
100
|
+
let expressions = [];
|
|
101
|
+
const gap = buildFilledGapFunction(expressions);
|
|
102
|
+
|
|
103
|
+
return treeFromStream(
|
|
104
|
+
[
|
|
105
|
+
t.nodeOpen(t.nodeFlags, l.CSTML, 'NodeFlags'),
|
|
106
|
+
t.ref`triviaToken`,
|
|
107
|
+
gap(token ? buildToken(l.CSTML, 'Punctuator', '*') : buildNullNode()),
|
|
108
|
+
t.ref`hasGapToken`,
|
|
109
|
+
gap(hasGap ? buildToken(l.CSTML, 'Punctuator', '$') : buildNullNode()),
|
|
110
|
+
t.nodeClose(),
|
|
111
|
+
],
|
|
112
|
+
{ expressions },
|
|
97
113
|
);
|
|
98
114
|
};
|
|
99
115
|
|
|
100
|
-
export const buildSpamMatcher = (type = null, value = null, attributes =
|
|
101
|
-
return
|
|
116
|
+
export const buildSpamMatcher = (type = null, value = null, attributes = null) => {
|
|
117
|
+
return buildOpenNodeMatcher(t.nodeFlags, null, type, value, attributes);
|
|
102
118
|
};
|
|
103
119
|
|
|
104
|
-
export const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
type,
|
|
108
|
-
intrinsicValue,
|
|
109
|
-
attributes = {},
|
|
110
|
-
) => {
|
|
111
|
-
const attributes_ = buildAttributes(attributes);
|
|
120
|
+
export const buildOpenNodeMatcher = (flags, language, type, intrinsicValue, attributes = null) => {
|
|
121
|
+
const expressions = [];
|
|
122
|
+
const gap = buildFilledGapFunction(expressions);
|
|
112
123
|
|
|
113
124
|
let language_;
|
|
114
125
|
|
|
126
|
+
if (!type) throw new Error();
|
|
127
|
+
|
|
115
128
|
if (isString(language)) {
|
|
116
129
|
language_ = language;
|
|
117
130
|
} else {
|
|
@@ -120,115 +133,195 @@ export const buildFullyQualifiedSpamMatcher = (
|
|
|
120
133
|
language_ = lArr.length === 0 ? null : lArr;
|
|
121
134
|
}
|
|
122
135
|
|
|
123
|
-
return
|
|
124
|
-
|
|
125
|
-
l.Spamex,
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
136
|
+
return treeFromStream(
|
|
137
|
+
(function* () {
|
|
138
|
+
yield t.nodeOpen(t.nodeFlags, l.Spamex, 'OpenNodeMatcher');
|
|
139
|
+
yield t.ref`openToken`;
|
|
140
|
+
yield gap(buildToken(l.CSTML, 'Punctuator', '<'));
|
|
141
|
+
yield t.ref`flags`;
|
|
142
|
+
yield gap(buildNodeFlags(flags));
|
|
143
|
+
yield t.ref`language`;
|
|
144
|
+
yield gap(language_ ? buildLanguage(language_) : buildNullNode());
|
|
145
|
+
yield t.ref`languageSeparator`;
|
|
146
|
+
yield gap(language_ && type ? buildToken(l.CSTML, 'Punctuator', ':') : buildNullNode());
|
|
147
|
+
yield t.ref`type`;
|
|
148
|
+
yield gap(typeof type === 'string' ? buildIdentifier(type) : type);
|
|
149
|
+
|
|
150
|
+
yield* when(intrinsicValue, [t.ref`#`, ...buildSpace().children]);
|
|
151
|
+
|
|
152
|
+
yield t.ref`intrinsicValue`;
|
|
153
|
+
yield gap(intrinsicValue ? buildString(intrinsicValue) : buildNullNode());
|
|
154
|
+
|
|
155
|
+
yield* when(attributes?.properties['.'].length, [t.ref`#`, ...buildSpace().children]);
|
|
156
|
+
if (attributes?.properties['.'].length) {
|
|
157
|
+
yield* interpolateFragment(attributes, t.ref`attributes[]`, expressions);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
yield t.ref`selfClosingTagToken`;
|
|
161
|
+
yield gap(buildToken(l.CSTML, 'Punctuator', '/'));
|
|
162
|
+
yield t.ref`closeToken`;
|
|
163
|
+
yield gap(buildToken(l.CSTML, 'Punctuator', '>'));
|
|
164
|
+
yield t.nodeClose();
|
|
165
|
+
})(),
|
|
166
|
+
{ expressions },
|
|
167
|
+
);
|
|
152
168
|
};
|
|
153
169
|
|
|
154
|
-
export const
|
|
155
|
-
const
|
|
170
|
+
export const buildBasicNodeMatcher = (open) => {
|
|
171
|
+
const expressions = [];
|
|
172
|
+
const gap = buildFilledGapFunction(expressions);
|
|
173
|
+
|
|
174
|
+
return treeFromStream(
|
|
175
|
+
[t.nodeOpen(t.nodeFlags, l.Spamex, 'BasicNodeMatcher'), t.ref`open`, gap(open), t.nodeClose()],
|
|
176
|
+
{ expressions },
|
|
177
|
+
);
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
export const buildReferenceMatcher = (name, isArray, flags) => {
|
|
181
|
+
const expressions = [];
|
|
182
|
+
const gap = buildFilledGapFunction(expressions);
|
|
183
|
+
|
|
184
|
+
return treeFromStream(
|
|
185
|
+
(function* () {
|
|
186
|
+
yield t.nodeOpen(t.nodeFlags, l.Spamex, 'ReferenceMatcher');
|
|
187
|
+
yield t.ref`name`;
|
|
188
|
+
yield gap(buildToken(l.CSTML, 'Identifier', name));
|
|
189
|
+
yield* (function* () {
|
|
190
|
+
if (isArray) {
|
|
191
|
+
yield t.ref`openIndexToken`;
|
|
192
|
+
yield gap(buildToken(l.CSTML, 'Punctuator', '['));
|
|
193
|
+
yield t.ref`closeIndexToken`;
|
|
194
|
+
yield gap(buildToken(l.CSTML, 'Punctuator', ']'));
|
|
195
|
+
}
|
|
196
|
+
})();
|
|
197
|
+
yield t.ref`flags`;
|
|
198
|
+
yield gap(flags);
|
|
199
|
+
yield t.ref`sigilToken`;
|
|
200
|
+
yield gap(buildToken(l.CSTML, 'Punctuator', ':'));
|
|
201
|
+
yield t.ref`#`;
|
|
202
|
+
yield* buildSpace().children;
|
|
203
|
+
yield t.nodeClose();
|
|
204
|
+
})(),
|
|
205
|
+
{ expressions },
|
|
206
|
+
);
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
export const buildFragmentMatcher = (flags) => {
|
|
210
|
+
const expressions = [];
|
|
211
|
+
const gap = buildFilledGapFunction(expressions);
|
|
212
|
+
|
|
213
|
+
return treeFromStream(
|
|
214
|
+
(function* () {
|
|
215
|
+
yield t.nodeOpen(t.nodeFlags, l.Spamex, 'FragmentMatcher');
|
|
216
|
+
yield t.ref`openToken`;
|
|
217
|
+
yield gap(buildToken(l.CSTML, 'Punctuator', '<'));
|
|
218
|
+
yield t.ref`flags`;
|
|
219
|
+
yield gap(flags);
|
|
220
|
+
yield t.ref`#`;
|
|
221
|
+
yield* buildSpace().children;
|
|
222
|
+
yield t.ref`closeToken`;
|
|
223
|
+
yield gap(buildToken(l.CSTML, 'Punctuator', '/>'));
|
|
224
|
+
yield t.nodeClose();
|
|
225
|
+
})(),
|
|
226
|
+
{ expressions },
|
|
227
|
+
);
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
export const buildToken = (language, type, value, attributes = {}) => {
|
|
231
|
+
return treeFromStream([
|
|
232
|
+
t.nodeOpen(t.tokenFlags, language, type, attributes),
|
|
233
|
+
t.lit(value),
|
|
234
|
+
t.nodeClose(),
|
|
235
|
+
]);
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
export const buildPunctuator = (language, value, attributes = {}) => {
|
|
239
|
+
return buildToken(language, 'Punctuator', value, attributes);
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
export const buildOpenNodeTag = (flags, language, type = null, attributes) => {
|
|
243
|
+
const expressions = [];
|
|
244
|
+
const gap = buildFilledGapFunction(expressions);
|
|
156
245
|
|
|
157
246
|
let language_ = !language || language.length === 0 ? null : language;
|
|
158
247
|
|
|
159
|
-
return
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
)
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
type: type ? buildIdentifier(type) : t.null_node(),
|
|
178
|
-
attributes: attributes_.properties['.'],
|
|
179
|
-
closeToken: t.s_node(l.CSTML, 'Punctuator', '>'),
|
|
180
|
-
},
|
|
248
|
+
return treeFromStream(
|
|
249
|
+
(function* () {
|
|
250
|
+
yield t.ref`openToken`;
|
|
251
|
+
yield gap(buildPunctuator(l.CSTML, '<'));
|
|
252
|
+
yield t.ref`flags`;
|
|
253
|
+
yield gap(buildNodeFlags(flags));
|
|
254
|
+
yield t.ref`language`;
|
|
255
|
+
yield gap(language_ && type ? buildLanguage(language_) : buildNullNode());
|
|
256
|
+
yield t.ref`languageSeparator`;
|
|
257
|
+
yield gap(language_ && type ? buildPunctuator(l.CSTML, ':') : buildNullNode());
|
|
258
|
+
yield t.ref`type`;
|
|
259
|
+
yield gap(type ? buildIdentifier(type) : buildNullNode());
|
|
260
|
+
yield* when(attributes.properties['.'].length, [t.ref`#`, gap(buildSpace())]);
|
|
261
|
+
yield* interpolateFragment(attributes, t.ref`attributes[]`, expressions);
|
|
262
|
+
yield t.ref`closeToken`;
|
|
263
|
+
yield gap(buildPunctuator(l.CSTML, '>'));
|
|
264
|
+
})(),
|
|
265
|
+
{ expressions },
|
|
181
266
|
);
|
|
182
267
|
};
|
|
183
268
|
|
|
184
269
|
export const buildDoctypeTag = (attributes) => {
|
|
185
|
-
const
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
)
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
270
|
+
const expressions = [];
|
|
271
|
+
const gap = buildFilledGapFunction(expressions);
|
|
272
|
+
|
|
273
|
+
return treeFromStream(
|
|
274
|
+
(function* () {
|
|
275
|
+
yield t.nodeOpen(t.nodeFlags, l.CSTML, 'DoctypeTag');
|
|
276
|
+
yield t.ref`openToken`;
|
|
277
|
+
yield gap(buildPunctuator(l.CSTML, 'Punctuator', '<!'));
|
|
278
|
+
yield t.ref`version`;
|
|
279
|
+
yield gap(buildToken(l.CSTML, 'PositiveInteger', '0'));
|
|
280
|
+
yield t.ref`versionSeparator`;
|
|
281
|
+
yield gap(buildPunctuator(l.CSTML, 'Punctuator', ':'));
|
|
282
|
+
yield t.ref`doctype`;
|
|
283
|
+
yield gap(buildKeyword(l.CSTML, 'cstml'));
|
|
284
|
+
yield t.nodeClose();
|
|
285
|
+
|
|
286
|
+
yield* when(attributes.properties['.'].length, [t.ref`#`, ...buildSpace().children]);
|
|
287
|
+
yield* interpolateFragment(attributes, t.ref`attributes[]`, expressions);
|
|
288
|
+
|
|
289
|
+
yield t.ref`closeToken`;
|
|
290
|
+
yield gap(buildToken(l.CSTML, 'Punctuator', '>'));
|
|
291
|
+
})(),
|
|
292
|
+
{ expressions },
|
|
206
293
|
);
|
|
207
294
|
};
|
|
208
295
|
|
|
209
296
|
export const buildIdentifierPath = (path) => {
|
|
210
297
|
const path_ = isString(path) ? [path] : [...path];
|
|
211
|
-
const
|
|
212
|
-
const
|
|
298
|
+
const expressions = [];
|
|
299
|
+
const gap = buildFilledGapFunction(expressions);
|
|
213
300
|
|
|
214
301
|
if (!path_.length) {
|
|
215
302
|
return null;
|
|
216
303
|
}
|
|
217
304
|
|
|
218
|
-
return
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
305
|
+
return treeFromStream(
|
|
306
|
+
(function* () {
|
|
307
|
+
yield t.nodeOpen(t.nodeFlags, l.CSTML, 'IdentifierPath');
|
|
308
|
+
yield t.ref`segments[]`;
|
|
309
|
+
yield t.arr();
|
|
310
|
+
yield t.ref`separatorTokens[]`;
|
|
311
|
+
yield t.arr();
|
|
312
|
+
|
|
313
|
+
yield* path_
|
|
314
|
+
.flatMap((name) => [
|
|
315
|
+
t.ref`segments[]`,
|
|
316
|
+
gap(buildIdentifier(name)),
|
|
317
|
+
t.ref`separatorTokens[]`,
|
|
318
|
+
gap(buildToken(l.CSTML, 'Punctuator', '.')),
|
|
319
|
+
])
|
|
320
|
+
.slice(0, -1);
|
|
321
|
+
|
|
322
|
+
yield t.nodeClose();
|
|
323
|
+
})(),
|
|
324
|
+
{ expressions },
|
|
232
325
|
);
|
|
233
326
|
};
|
|
234
327
|
|
|
@@ -238,31 +331,36 @@ export const buildLanguage = (language) => {
|
|
|
238
331
|
: buildIdentifierPath(language);
|
|
239
332
|
};
|
|
240
333
|
|
|
241
|
-
export const
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
},
|
|
334
|
+
export const buildCloseNodeTag = (type, language) => {
|
|
335
|
+
const expressions = [];
|
|
336
|
+
const gap = buildFilledGapFunction(expressions);
|
|
337
|
+
|
|
338
|
+
return treeFromStream(
|
|
339
|
+
[
|
|
340
|
+
t.nodeOpen(t.nodeFlags, l.CSTML, 'CloseNodeTag'),
|
|
341
|
+
t.ref`openToken`,
|
|
342
|
+
gap(buildToken(l.CSTML, 'Punctuator', '</')),
|
|
343
|
+
t.ref`language`,
|
|
344
|
+
t.gap(language ? buildLanguage(language) : buildNullNode()),
|
|
345
|
+
t.ref`languageSeparator`,
|
|
346
|
+
gap(language && type ? buildToken(l.CSTML, 'Punctuator', ':') : buildNullNode()),
|
|
347
|
+
t.ref`type`,
|
|
348
|
+
gap(type ? buildIdentifier(type) : buildNullNode()),
|
|
349
|
+
t.ref`closeToken`,
|
|
350
|
+
gap(buildToken(l.CSTML, 'Punctuator', '>')),
|
|
351
|
+
t.nodeClose(),
|
|
352
|
+
],
|
|
353
|
+
{ expressions },
|
|
261
354
|
);
|
|
262
355
|
};
|
|
263
356
|
|
|
264
357
|
export const buildLiteralTag = (value) => {
|
|
265
|
-
return
|
|
358
|
+
return treeFromStream([
|
|
359
|
+
t.nodeOpen(t.nodeFlags, l.Instruction, 'LiteralTag'),
|
|
360
|
+
t.ref`value`,
|
|
361
|
+
t.lit(value),
|
|
362
|
+
t.nodeClose(),
|
|
363
|
+
]);
|
|
266
364
|
};
|
|
267
365
|
|
|
268
366
|
export const buildTerminalProps = (matcher) => {
|
|
@@ -272,34 +370,54 @@ export const buildTerminalProps = (matcher) => {
|
|
|
272
370
|
};
|
|
273
371
|
|
|
274
372
|
export const buildSpace = () => {
|
|
275
|
-
return
|
|
373
|
+
return buildToken(l.Space, 'Space', ' ');
|
|
276
374
|
};
|
|
277
375
|
|
|
278
376
|
export const buildIdentifier = (name) => {
|
|
279
|
-
|
|
280
|
-
};
|
|
377
|
+
if (!/^[a-zA-Z]+$/.test(name)) throw new Error();
|
|
281
378
|
|
|
282
|
-
|
|
283
|
-
return t.s_node(l.Instruction, 'Identifier', name);
|
|
379
|
+
return buildToken(l.Instruction, 'Identifier', name);
|
|
284
380
|
};
|
|
285
381
|
|
|
286
|
-
export const
|
|
287
|
-
return
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
382
|
+
export const buildKeyword = (name) => {
|
|
383
|
+
return buildToken(l.Instruction, 'Keyword', name);
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
export const buildCall = (verb, args) => {
|
|
387
|
+
const expressions = [];
|
|
388
|
+
const gap = buildFilledGapFunction(expressions);
|
|
389
|
+
|
|
390
|
+
return treeFromStream(
|
|
391
|
+
[
|
|
392
|
+
t.nodeOpen(t.nodeFlags, l.Instruction, 'Call'),
|
|
393
|
+
t.ref`verb`,
|
|
394
|
+
gap(verb),
|
|
395
|
+
t.ref`arguments`,
|
|
396
|
+
gap(args),
|
|
397
|
+
t.nodeClose(),
|
|
398
|
+
],
|
|
399
|
+
{ expressions },
|
|
400
|
+
);
|
|
291
401
|
};
|
|
292
402
|
|
|
293
403
|
export const buildProperty = (key, value) => {
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
{
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
404
|
+
const expressions = [];
|
|
405
|
+
const gap = buildFilledGapFunction(expressions);
|
|
406
|
+
|
|
407
|
+
return treeFromStream(
|
|
408
|
+
(function* () {
|
|
409
|
+
yield t.nodeOpen(t.nodeFlags, l.Instruction, 'Property');
|
|
410
|
+
yield t.ref`key`;
|
|
411
|
+
yield gap(key);
|
|
412
|
+
yield t.ref`mapOperator`;
|
|
413
|
+
yield gap(buildToken(l.Instruction, 'Punctuator', ':'));
|
|
414
|
+
yield t.ref`#`;
|
|
415
|
+
yield gap(buildSpace());
|
|
416
|
+
yield t.ref`value`;
|
|
417
|
+
yield gap(value);
|
|
418
|
+
yield t.nodeClose();
|
|
419
|
+
})(),
|
|
420
|
+
{ expressions },
|
|
303
421
|
);
|
|
304
422
|
};
|
|
305
423
|
|
|
@@ -311,24 +429,23 @@ const escapables = {
|
|
|
311
429
|
};
|
|
312
430
|
|
|
313
431
|
export const buildDigit = (value) => {
|
|
314
|
-
return
|
|
432
|
+
return buildToken(l.CSTML, 'Digit', value);
|
|
315
433
|
};
|
|
316
434
|
|
|
317
435
|
export const buildInteger = (value, base = 10) => {
|
|
436
|
+
const expressions = [];
|
|
437
|
+
const gap = buildFilledGapFunction(expressions);
|
|
438
|
+
|
|
318
439
|
const digits = value.toString(base).split('');
|
|
319
440
|
|
|
320
|
-
return
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
[t.ref`digits[]`, t.arr()],
|
|
326
|
-
digits.map(() => t.ref`digits[]`),
|
|
327
|
-
),
|
|
441
|
+
return treeFromStream(
|
|
442
|
+
concat(
|
|
443
|
+
[t.nodeOpen(t.nodeFlags, l.CSTML, 'Integer'), t.ref`digits[]`, t.arr()],
|
|
444
|
+
digits.flatMap((digit) => [t.ref`digits[]`, gap(buildDigit(digit))]),
|
|
445
|
+
[t.nodeClose()],
|
|
328
446
|
),
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
},
|
|
447
|
+
|
|
448
|
+
{ expressions },
|
|
332
449
|
);
|
|
333
450
|
};
|
|
334
451
|
|
|
@@ -342,10 +459,20 @@ export const buildInfinity = (value) => {
|
|
|
342
459
|
throw new Error();
|
|
343
460
|
}
|
|
344
461
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
462
|
+
const expressions = [];
|
|
463
|
+
const gap = buildFilledGapFunction(expressions);
|
|
464
|
+
|
|
465
|
+
return treeFromStream(
|
|
466
|
+
[
|
|
467
|
+
t.nodeOpen(t.nodeFlags, l.CSTML, 'Infinity'),
|
|
468
|
+
t.ref`sign`,
|
|
469
|
+
gap(buildToken(l.CSTML, 'Punctuator', sign)),
|
|
470
|
+
t.ref`value`,
|
|
471
|
+
gap(buildToken(l.CSTML, 'Keyword', 'Infinity')),
|
|
472
|
+
t.nodeClose(),
|
|
473
|
+
],
|
|
474
|
+
{ expressions },
|
|
475
|
+
);
|
|
349
476
|
};
|
|
350
477
|
|
|
351
478
|
export const buildNumber = (value) => {
|
|
@@ -358,297 +485,390 @@ export const buildNumber = (value) => {
|
|
|
358
485
|
|
|
359
486
|
export const buildString = (value) => {
|
|
360
487
|
const pieces = isArray(value) ? value : [value];
|
|
361
|
-
const tags = [];
|
|
362
488
|
let lit = '';
|
|
363
489
|
|
|
364
490
|
if (pieces.length === 1 && pieces[0] === "'") {
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
491
|
+
const expressions = [];
|
|
492
|
+
const gap = buildFilledGapFunction(expressions);
|
|
493
|
+
return treeFromStream(
|
|
494
|
+
[
|
|
495
|
+
t.nodeOpen(t.nodeFlags, l.JSON, 'String'),
|
|
496
|
+
t.ref`openToken`,
|
|
497
|
+
gap(buildToken(l.JSON, 'Punctuator', '"')),
|
|
498
|
+
t.ref`content`,
|
|
499
|
+
gap(buildToken(l.JSON, 'StringContent', value)),
|
|
500
|
+
t.ref`closeToken`,
|
|
501
|
+
gap(buildToken(l.JSON, 'Punctuator', '"')),
|
|
502
|
+
t.nodeClose(),
|
|
503
|
+
],
|
|
504
|
+
{ expressions },
|
|
374
505
|
);
|
|
375
506
|
}
|
|
376
507
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
) {
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
508
|
+
const expressions = [];
|
|
509
|
+
const gap = buildFilledGapFunction(expressions);
|
|
510
|
+
|
|
511
|
+
return treeFromStream(
|
|
512
|
+
(function* () {
|
|
513
|
+
yield t.nodeOpen(t.nodeFlags, l.JSON, 'String');
|
|
514
|
+
yield t.ref`openToken`;
|
|
515
|
+
const tok = buildToken(l.JSON, 'Punctuator', "'");
|
|
516
|
+
yield gap(tok);
|
|
517
|
+
yield t.ref`content`;
|
|
518
|
+
yield t.nodeOpen(t.tokenFlags, l.JSON, 'StringContent');
|
|
519
|
+
|
|
520
|
+
for (const piece of pieces) {
|
|
521
|
+
if (isString(piece)) {
|
|
522
|
+
const value = piece;
|
|
523
|
+
|
|
524
|
+
for (const chr of value) {
|
|
525
|
+
if (
|
|
526
|
+
chr === '\\' ||
|
|
527
|
+
chr === "'" ||
|
|
528
|
+
chr === '\n' ||
|
|
529
|
+
chr === '\r' ||
|
|
530
|
+
chr === '\t' ||
|
|
531
|
+
chr === '\0' ||
|
|
532
|
+
chr.charCodeAt(0) < 32
|
|
533
|
+
) {
|
|
534
|
+
if (lit) {
|
|
535
|
+
yield agastBuildLiteralTag(lit);
|
|
536
|
+
lit = '';
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
let value;
|
|
540
|
+
|
|
541
|
+
if (escapables[chr]) {
|
|
542
|
+
const expressions = [];
|
|
543
|
+
const gap = buildFilledGapFunction(expressions);
|
|
544
|
+
|
|
545
|
+
value = treeFromStream(
|
|
546
|
+
[
|
|
547
|
+
t.nodeOpen(t.nodeFlags, l.JSON, 'EscapeCode'),
|
|
548
|
+
t.ref`sigilToken`,
|
|
549
|
+
gap(buildKeyword(escapables[chr])),
|
|
550
|
+
t.ref`digits[]`,
|
|
551
|
+
t.arr(),
|
|
552
|
+
t.nodeClose(),
|
|
553
|
+
],
|
|
554
|
+
{ expressions },
|
|
555
|
+
);
|
|
556
|
+
} else if (chr.charCodeAt(0) < 32) {
|
|
557
|
+
const hexDigits = chr.charCodeAt(0).toString(16).padStart(4, '0');
|
|
558
|
+
const expressions = [];
|
|
559
|
+
const gap = buildFilledGapFunction(expressions);
|
|
560
|
+
|
|
561
|
+
value = treeFromStream(
|
|
562
|
+
[
|
|
563
|
+
t.nodeOpen(t.nodeFlags, l.JSON, 'EscapeCode'),
|
|
564
|
+
t.ref`sigilToken`,
|
|
565
|
+
gap(buildKeyword('u')),
|
|
566
|
+
t.ref`digits[]`,
|
|
567
|
+
t.arr(),
|
|
568
|
+
[...hexDigits].flatMap((digit) => [t.ref`digits[]`, gap(buildDigit(digit))]),
|
|
569
|
+
t.nodeClose(),
|
|
570
|
+
],
|
|
571
|
+
{ expressions },
|
|
572
|
+
);
|
|
573
|
+
} else {
|
|
574
|
+
value = buildKeyword(chr);
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
yield t.ref`@`;
|
|
578
|
+
yield t.nodeOpen(t.nodeFlags, l.JSON, 'EscapeSequence', { cooked: chr });
|
|
579
|
+
yield t.ref`escape`;
|
|
580
|
+
yield gap(buildToken(l.JSON, 'Punctuator', '\\'));
|
|
581
|
+
yield t.ref`value`;
|
|
582
|
+
yield gap(value);
|
|
583
|
+
yield t.nodeClose();
|
|
584
|
+
} else {
|
|
585
|
+
lit += chr;
|
|
586
|
+
}
|
|
394
587
|
}
|
|
588
|
+
} else {
|
|
589
|
+
yield agastBuildLiteralTag(lit);
|
|
590
|
+
lit = '';
|
|
395
591
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
if (
|
|
399
|
-
|
|
400
|
-
sigilToken: buildKeyword(escapables[chr]),
|
|
401
|
-
digits: t.null_node(),
|
|
402
|
-
});
|
|
403
|
-
} else if (chr.charCodeAt(0) < 32) {
|
|
404
|
-
const hexDigits = chr.charCodeAt(0).toString(16).padStart(4, '0');
|
|
405
|
-
value = t.node(
|
|
406
|
-
l.CSTML,
|
|
407
|
-
'EscapeCode',
|
|
408
|
-
btree.fromValues(
|
|
409
|
-
concat(
|
|
410
|
-
[t.ref`sigilToken`, t.ref`digits[]`, t.arr()],
|
|
411
|
-
[...hexDigits].map((d) => t.ref`digits[]`),
|
|
412
|
-
),
|
|
413
|
-
),
|
|
414
|
-
{
|
|
415
|
-
sigilToken: buildKeyword('u'),
|
|
416
|
-
digits: [...hexDigits].map((digit) => buildDigit(digit)),
|
|
417
|
-
},
|
|
418
|
-
);
|
|
592
|
+
if (piece == null) {
|
|
593
|
+
throw new Error('not implemented');
|
|
594
|
+
} else if (isString(piece.type)) {
|
|
595
|
+
yield piece;
|
|
419
596
|
} else {
|
|
420
|
-
|
|
597
|
+
throw new Error();
|
|
421
598
|
}
|
|
422
|
-
|
|
423
|
-
tags.push(
|
|
424
|
-
t.buildEmbeddedNode(
|
|
425
|
-
t.e_node(
|
|
426
|
-
l.CSTML,
|
|
427
|
-
'EscapeSequence',
|
|
428
|
-
[t.ref`escape`, t.ref`value`],
|
|
429
|
-
{
|
|
430
|
-
escape: t.s_node(l.CSTML, 'Punctuator', '\\'),
|
|
431
|
-
value,
|
|
432
|
-
},
|
|
433
|
-
{ cooked: chr },
|
|
434
|
-
),
|
|
435
|
-
),
|
|
436
|
-
);
|
|
437
|
-
} else {
|
|
438
|
-
lit += chr;
|
|
439
599
|
}
|
|
440
600
|
}
|
|
441
|
-
} else {
|
|
442
|
-
tags.push(agastBuildLiteralTag(lit));
|
|
443
|
-
lit = '';
|
|
444
|
-
|
|
445
|
-
if (piece == null) {
|
|
446
|
-
throw new Error('not implemented');
|
|
447
|
-
} else if (isString(piece.type)) {
|
|
448
|
-
tags.push(piece);
|
|
449
|
-
} else {
|
|
450
|
-
throw new Error();
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
601
|
|
|
455
|
-
|
|
456
|
-
|
|
602
|
+
if (lit) yield agastBuildLiteralTag(lit);
|
|
603
|
+
lit = '';
|
|
457
604
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
content: interpolateString(tags),
|
|
465
|
-
closeToken: t.s_node(l.CSTML, 'Punctuator', "'"),
|
|
466
|
-
},
|
|
605
|
+
yield t.nodeClose();
|
|
606
|
+
yield t.ref`closeToken`;
|
|
607
|
+
yield gap(buildToken(l.JSON, 'Punctuator', "'"));
|
|
608
|
+
yield t.nodeClose();
|
|
609
|
+
})(),
|
|
610
|
+
{ expressions },
|
|
467
611
|
);
|
|
468
612
|
};
|
|
469
613
|
|
|
470
614
|
export const buildBoolean = (value) => {
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
615
|
+
const expressions = [];
|
|
616
|
+
const gap = buildFilledGapFunction(expressions);
|
|
617
|
+
|
|
618
|
+
return treeFromStream(
|
|
619
|
+
[
|
|
620
|
+
t.nodeOpen(t.nodeFlags, l.Instruction, 'Boolean'),
|
|
621
|
+
t.ref`sigilToken`,
|
|
622
|
+
gap(buildToken(l.Instruction, 'Keyword', value ? 'true' : 'false')),
|
|
623
|
+
t.nodeClose(),
|
|
624
|
+
],
|
|
625
|
+
{ expressions },
|
|
626
|
+
);
|
|
627
|
+
};
|
|
628
|
+
|
|
629
|
+
export const buildNull = () => {
|
|
630
|
+
const expressions = [];
|
|
631
|
+
const gap = buildFilledGapFunction(expressions);
|
|
632
|
+
|
|
633
|
+
return treeFromStream(
|
|
634
|
+
[
|
|
635
|
+
t.nodeOpen(t.nodeFlags, l.Instruction, 'Null'),
|
|
636
|
+
t.ref`sigilToken`,
|
|
637
|
+
gap(buildToken(l.Instruction, 'Keyword', 'null')),
|
|
638
|
+
t.nodeClose(),
|
|
639
|
+
],
|
|
640
|
+
{ expressions },
|
|
641
|
+
);
|
|
474
642
|
};
|
|
475
643
|
|
|
476
644
|
export const buildNullTag = () => {
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
645
|
+
const expressions = [];
|
|
646
|
+
const gap = buildFilledGapFunction(expressions);
|
|
647
|
+
|
|
648
|
+
return treeFromStream(
|
|
649
|
+
[
|
|
650
|
+
t.nodeOpen(t.nodeFlags, l.CSTML, 'NullTag'),
|
|
651
|
+
t.ref`sigilToken`,
|
|
652
|
+
gap(buildToken(l.CSTML, 'Keyword', 'null')),
|
|
653
|
+
t.nodeClose(),
|
|
654
|
+
],
|
|
655
|
+
{ expressions },
|
|
656
|
+
);
|
|
480
657
|
};
|
|
481
658
|
|
|
482
659
|
export const buildArray = (elements) => {
|
|
483
|
-
const
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
},
|
|
660
|
+
const expressions = [];
|
|
661
|
+
const gap = buildFilledGapFunction(expressions);
|
|
662
|
+
|
|
663
|
+
return treeFromStream(
|
|
664
|
+
(function* () {
|
|
665
|
+
yield t.nodeOpen(t.nodeFlags, l.Instruction, 'Array');
|
|
666
|
+
yield t.ref`openToken`;
|
|
667
|
+
yield gap(buildToken(l.Instruction, 'Punctuator', '['));
|
|
668
|
+
yield* interpolateFragment(elements, t.ref`elements[]`, expressions);
|
|
669
|
+
yield t.ref`closeToken`;
|
|
670
|
+
yield gap(buildToken(l.Instruction, 'Punctuator', ']'));
|
|
671
|
+
yield t.nodeClose();
|
|
672
|
+
})(),
|
|
673
|
+
{ expressions },
|
|
497
674
|
);
|
|
498
675
|
};
|
|
499
676
|
|
|
500
677
|
export const buildArrayElements = (values) => {
|
|
501
|
-
|
|
678
|
+
const expressions = [];
|
|
679
|
+
return treeFromStream(
|
|
680
|
+
(function* () {
|
|
681
|
+
yield t.doctype({ bablrLanguage: l.Instruction });
|
|
682
|
+
yield t.nodeOpen(t.nodeFlags);
|
|
683
|
+
yield* buildSpaceSeparatedList(values, t.ref`.[]`, expressions);
|
|
684
|
+
yield t.nodeClose();
|
|
685
|
+
})(),
|
|
686
|
+
{ expressions },
|
|
687
|
+
);
|
|
502
688
|
};
|
|
503
689
|
|
|
504
|
-
export
|
|
690
|
+
export function* buildSpaceSeparatedList(values, ref, expressions) {
|
|
691
|
+
const gap = buildFilledGapFunction(expressions);
|
|
505
692
|
|
|
506
|
-
|
|
507
|
-
const values_ = buildTupleValues(values);
|
|
508
|
-
return t.node(
|
|
509
|
-
l.Instruction,
|
|
510
|
-
'Tuple',
|
|
511
|
-
btree.fromValues(
|
|
512
|
-
concat([t.ref`openToken`], interpolateFragmentChildren(values_, t.ref`values[]`), [
|
|
513
|
-
t.ref`closeToken`,
|
|
514
|
-
]),
|
|
515
|
-
),
|
|
516
|
-
{
|
|
517
|
-
openToken: t.s_node(l.Instruction, 'Punctuator', '('),
|
|
518
|
-
values: values_.properties['.'],
|
|
519
|
-
closeToken: t.s_node(l.Instruction, 'Punctuator', ')'),
|
|
520
|
-
},
|
|
521
|
-
);
|
|
522
|
-
};
|
|
693
|
+
if (!ref.value.isArray) throw new Error();
|
|
523
694
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
)
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
}
|
|
695
|
+
yield freeze({ ...ref });
|
|
696
|
+
yield t.arr();
|
|
697
|
+
|
|
698
|
+
let first = true;
|
|
699
|
+
for (const value of values) {
|
|
700
|
+
if (!first) {
|
|
701
|
+
yield t.buildReferenceTag('#', false);
|
|
702
|
+
yield gap(buildSpace());
|
|
703
|
+
}
|
|
704
|
+
yield freeze({ ...ref });
|
|
705
|
+
yield gap(value || buildNullNode());
|
|
706
|
+
first = false;
|
|
707
|
+
}
|
|
708
|
+
}
|
|
537
709
|
|
|
538
710
|
export const buildObjectProperties = (properties) => {
|
|
539
|
-
|
|
540
|
-
|
|
711
|
+
const expressions = [];
|
|
712
|
+
|
|
713
|
+
return treeFromStream(
|
|
714
|
+
concat(
|
|
715
|
+
[t.doctype({ bablrLanguage: l.Instruction }), t.nodeOpen(t.nodeFlags)],
|
|
716
|
+
buildSpaceSeparatedList(properties, t.ref`properties[]`, expressions),
|
|
717
|
+
[t.nodeClose()],
|
|
718
|
+
),
|
|
719
|
+
{ expressions },
|
|
541
720
|
);
|
|
542
721
|
};
|
|
543
722
|
|
|
544
723
|
export const buildObject = (properties) => {
|
|
545
|
-
const
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
724
|
+
const expressions = [];
|
|
725
|
+
const gap = buildFilledGapFunction(expressions);
|
|
726
|
+
|
|
727
|
+
return treeFromStream(
|
|
728
|
+
(function* () {
|
|
729
|
+
yield t.nodeOpen(t.nodeFlags, l.Instruction, 'Object');
|
|
730
|
+
yield t.ref`openToken`;
|
|
731
|
+
yield gap(buildToken(l.Instruction, 'Punctuator', '{'));
|
|
732
|
+
|
|
733
|
+
yield* interpolateFragment(properties, t.ref`properties[]`, expressions);
|
|
734
|
+
|
|
735
|
+
yield t.ref`closeToken`;
|
|
736
|
+
yield gap(buildToken(l.Instruction, 'Punctuator', '}'));
|
|
737
|
+
yield t.nodeClose();
|
|
738
|
+
})(),
|
|
739
|
+
{ expressions },
|
|
560
740
|
);
|
|
561
741
|
};
|
|
562
742
|
|
|
563
|
-
export const
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
{
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
743
|
+
export const buildPattern = (alternatives, flags) => {
|
|
744
|
+
const expressions = [];
|
|
745
|
+
const gap = buildFilledGapFunction(expressions);
|
|
746
|
+
|
|
747
|
+
return treeFromStream(
|
|
748
|
+
(function* () {
|
|
749
|
+
yield t.nodeOpen(t.nodeFlags, l.Regex, 'Pattern');
|
|
750
|
+
yield t.ref`openToken`;
|
|
751
|
+
yield gap(buildToken(l.Regex, 'Punctuator', '/'));
|
|
752
|
+
|
|
753
|
+
yield* interpolateFragment(alternatives, t.ref`alternatives[]`, expressions);
|
|
754
|
+
|
|
755
|
+
yield t.ref`closeToken`;
|
|
756
|
+
yield gap(buildToken(l.Regex, 'Punctuator', '/'));
|
|
757
|
+
yield t.ref`flags`;
|
|
758
|
+
yield gap(flags || buildReferenceFlags());
|
|
759
|
+
yield t.nodeClose();
|
|
760
|
+
})(),
|
|
761
|
+
{ expressions },
|
|
573
762
|
);
|
|
574
763
|
};
|
|
575
764
|
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
765
|
+
const flagCharacters = {
|
|
766
|
+
global: 'g',
|
|
767
|
+
ignoreCase: 'i',
|
|
768
|
+
multiline: 'm',
|
|
769
|
+
dotAll: 's',
|
|
770
|
+
unicode: 'u',
|
|
771
|
+
sticky: 'y',
|
|
581
772
|
};
|
|
582
773
|
|
|
583
|
-
export const
|
|
584
|
-
|
|
585
|
-
|
|
774
|
+
export const buildRegexFlags = (flags = '') => {
|
|
775
|
+
let expressions = [];
|
|
776
|
+
const gap = buildFilledGapFunction(expressions);
|
|
586
777
|
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
separators: alternatives.properties.separators,
|
|
600
|
-
alternatives: alternatives.properties['.'],
|
|
601
|
-
closeToken: t.s_node(l.Regex, 'Punctuator', '/'),
|
|
602
|
-
flags: buildFlags(flags),
|
|
603
|
-
},
|
|
778
|
+
return treeFromStream(
|
|
779
|
+
(function* () {
|
|
780
|
+
yield t.nodeOpen(t.nodeFlags, l.Regex, 'Flags');
|
|
781
|
+
|
|
782
|
+
for (const { 0: name, 1: chr } of Object.entries(flagCharacters)) {
|
|
783
|
+
yield t.buildReferenceTag(name + 'Token');
|
|
784
|
+
|
|
785
|
+
yield gap(flags.includes(chr) ? buildToken(l.CSTML, 'Punctuator', chr) : buildNullNode());
|
|
786
|
+
}
|
|
787
|
+
yield t.nodeClose();
|
|
788
|
+
})(),
|
|
789
|
+
{ expressions },
|
|
604
790
|
);
|
|
605
791
|
};
|
|
606
792
|
|
|
607
793
|
export const buildAlternative = (elements) => {
|
|
608
|
-
const
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
elements
|
|
614
|
-
|
|
615
|
-
{ elements: elementsArray },
|
|
616
|
-
);
|
|
617
|
-
};
|
|
618
|
-
|
|
619
|
-
export const buildAlternatives = (alternatives = {}) => {
|
|
620
|
-
return t.frag(
|
|
621
|
-
btree.fromValues(
|
|
622
|
-
concat(
|
|
623
|
-
[t.ref`.[]`, t.arr(), t.ref`separators[]`, t.arr()],
|
|
624
|
-
buildSeparatedListChildren(alternatives, t.ref`.[]`, t.ref`separators[]`),
|
|
625
|
-
),
|
|
794
|
+
const expressions = [];
|
|
795
|
+
|
|
796
|
+
return treeFromStream(
|
|
797
|
+
concat(
|
|
798
|
+
[t.nodeOpen(t.nodeFlags, l.Regex, 'Alternative')],
|
|
799
|
+
interpolateFragment(elements, t.ref`elements[]+`, expressions),
|
|
800
|
+
[t.nodeClose()],
|
|
626
801
|
),
|
|
627
|
-
{
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
802
|
+
{ expressions },
|
|
803
|
+
);
|
|
804
|
+
};
|
|
805
|
+
|
|
806
|
+
export const buildAlternatives = (alternatives = []) => {
|
|
807
|
+
const expressions = [];
|
|
808
|
+
const gap = buildFilledGapFunction(expressions);
|
|
809
|
+
|
|
810
|
+
return treeFromStream(
|
|
811
|
+
(function* () {
|
|
812
|
+
yield t.doctype({ bablrLanguage: l.Regex });
|
|
813
|
+
yield t.nodeOpen(t.nodeFlags);
|
|
814
|
+
yield t.ref`.[]`;
|
|
815
|
+
yield t.arr();
|
|
816
|
+
yield t.ref`separatorTokens[]`;
|
|
817
|
+
yield t.arr();
|
|
818
|
+
|
|
819
|
+
yield* alternatives
|
|
820
|
+
.flatMap((alt) => [
|
|
821
|
+
t.ref`.[]`,
|
|
822
|
+
gap(alt),
|
|
823
|
+
t.ref`separatorTokens[]`,
|
|
824
|
+
gap(buildPunctuator(l.Regex, '|')),
|
|
825
|
+
])
|
|
826
|
+
.slice(0, -2);
|
|
827
|
+
|
|
828
|
+
yield t.nodeClose();
|
|
829
|
+
})(),
|
|
830
|
+
{ expressions },
|
|
831
|
+
);
|
|
832
|
+
};
|
|
833
|
+
|
|
834
|
+
export const buildRegexGap = () => {
|
|
835
|
+
const expressions = [];
|
|
836
|
+
const gap = buildFilledGapFunction(expressions);
|
|
837
|
+
|
|
838
|
+
return treeFromStream(
|
|
839
|
+
[
|
|
840
|
+
t.nodeOpen(t.nodeFlags, l.Regex, 'Gap'),
|
|
841
|
+
t.ref`escapeToken`,
|
|
842
|
+
gap(buildToken(l.Regex, 'Punctuator', '\\')),
|
|
843
|
+
t.ref`value`,
|
|
844
|
+
gap(buildToken(l.Regex, 'Keyword', 'g')),
|
|
845
|
+
t.nodeClose(),
|
|
846
|
+
],
|
|
847
|
+
{ expressions },
|
|
631
848
|
);
|
|
632
849
|
};
|
|
633
850
|
|
|
634
851
|
export const buildElements = (elements) => {
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
),
|
|
852
|
+
const expressions = [];
|
|
853
|
+
const gap = buildFilledGapFunction(expressions);
|
|
854
|
+
|
|
855
|
+
return treeFromStream(
|
|
856
|
+
concat(
|
|
857
|
+
[t.doctype({ bablrLanguage: l.Regex }), t.nodeOpen(t.nodeFlags), t.ref`.[]+`, t.arr()],
|
|
858
|
+
elements.flatMap((el) => [t.ref`.[]+`, gap(el)]),
|
|
859
|
+
[t.nodeClose()],
|
|
641
860
|
),
|
|
642
|
-
{
|
|
643
|
-
['.']: elements,
|
|
644
|
-
},
|
|
861
|
+
{ expressions },
|
|
645
862
|
);
|
|
646
863
|
};
|
|
647
864
|
|
|
648
865
|
export const buildExpression = (expr) => {
|
|
866
|
+
throw new Error('unimplemented');
|
|
867
|
+
|
|
649
868
|
if (isNull(expr)) return buildNullTag();
|
|
650
869
|
|
|
651
870
|
switch (typeof expr) {
|
|
871
|
+
case 'symbol':
|
|
652
872
|
case 'boolean':
|
|
653
873
|
return buildBoolean(expr);
|
|
654
874
|
case 'string':
|
|
@@ -658,12 +878,21 @@ export const buildExpression = (expr) => {
|
|
|
658
878
|
case 'object': {
|
|
659
879
|
switch (getPrototypeOf(expr)) {
|
|
660
880
|
case Array.prototype:
|
|
661
|
-
return buildArray(expr);
|
|
881
|
+
return buildArray(buildArrayElements(expr));
|
|
662
882
|
case Object.prototype:
|
|
663
|
-
if (
|
|
883
|
+
if (
|
|
884
|
+
hasOwn(expr, 'type') &&
|
|
885
|
+
hasOwn(expr, 'language') &&
|
|
886
|
+
hasOwn(expr, 'children') &&
|
|
887
|
+
hasOwn(expr, 'properties')
|
|
888
|
+
) {
|
|
664
889
|
return expr;
|
|
665
890
|
}
|
|
666
|
-
return buildObject(
|
|
891
|
+
return buildObject(
|
|
892
|
+
buildObjectProperties(
|
|
893
|
+
Object.entries(expr).map((e) => buildProperty(buildIdentifier(e[0]), e[1])),
|
|
894
|
+
),
|
|
895
|
+
);
|
|
667
896
|
default:
|
|
668
897
|
throw new Error();
|
|
669
898
|
}
|
|
@@ -673,49 +902,52 @@ export const buildExpression = (expr) => {
|
|
|
673
902
|
}
|
|
674
903
|
};
|
|
675
904
|
|
|
676
|
-
export const
|
|
677
|
-
const
|
|
678
|
-
|
|
905
|
+
export const buildTaggedString = (tag, content) => {
|
|
906
|
+
const expressions = [];
|
|
907
|
+
const gap = buildFilledGapFunction(expressions);
|
|
908
|
+
|
|
909
|
+
return treeFromStream(
|
|
910
|
+
[
|
|
911
|
+
t.buildOpenNodeTag(t.nodeFlags, l.Spamex, 'SpamexString'),
|
|
912
|
+
t.buildReferenceTag('sigilToken'),
|
|
913
|
+
gap(buildToken(l.Instruction, 'Keyword', tag)),
|
|
914
|
+
t.buildReferenceTag('openToken'),
|
|
915
|
+
gap(buildToken(l.Instruction, 'Punctuator', "'")),
|
|
916
|
+
t.buildReferenceTag('content'),
|
|
917
|
+
gap(content),
|
|
918
|
+
t.buildReferenceTag('closeToken'),
|
|
919
|
+
gap(buildToken(l.Instruction, 'Punctuator', "'")),
|
|
920
|
+
t.buildCloseNodeTag(),
|
|
921
|
+
],
|
|
922
|
+
{ expressions },
|
|
679
923
|
);
|
|
924
|
+
};
|
|
680
925
|
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
[t.ref`.[]`, t.arr()],
|
|
684
|
-
buildSeparatedListChildren(attributes_, t.ref`.[]`, t.embedded(buildSpace())),
|
|
685
|
-
),
|
|
686
|
-
{
|
|
687
|
-
['.']: attributes_,
|
|
688
|
-
},
|
|
689
|
-
);
|
|
926
|
+
export const buildSpamexString = (content) => {
|
|
927
|
+
return buildTaggedString('m', content);
|
|
690
928
|
};
|
|
691
929
|
|
|
692
|
-
export const
|
|
693
|
-
|
|
930
|
+
export const buildRegexString = (content) => {
|
|
931
|
+
return buildTaggedString('re', content);
|
|
932
|
+
};
|
|
694
933
|
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
),
|
|
710
|
-
),
|
|
711
|
-
{
|
|
712
|
-
openToken: t.s_node(l.CSTML, 'Punctuator', '<'),
|
|
713
|
-
language: buildLanguage(language_),
|
|
714
|
-
languageSeparator: language_ && type ? t.s_node(l.CSTML, 'Punctuator', ':') : t.null_node(),
|
|
715
|
-
flags: flags_,
|
|
716
|
-
type: buildIdentifier(type),
|
|
717
|
-
attributes: attributes.properties.attributes,
|
|
718
|
-
closeToken: t.s_node(l.CSTML, 'Punctuator', '>'),
|
|
719
|
-
},
|
|
934
|
+
export const buildPropertyMatcher = (refMatcher, nodeMatcher) => {
|
|
935
|
+
const expressions = [];
|
|
936
|
+
const gap = buildFilledGapFunction(expressions);
|
|
937
|
+
|
|
938
|
+
return treeFromStream(
|
|
939
|
+
[
|
|
940
|
+
t.nodeOpen(t.nodeFlags, l.Spamex, 'PropertyMatcher'),
|
|
941
|
+
t.ref`refMatcher`,
|
|
942
|
+
gap(refMatcher || buildNullNode()),
|
|
943
|
+
t.ref`nodeMatcher`,
|
|
944
|
+
gap(nodeMatcher),
|
|
945
|
+
t.nodeClose(),
|
|
946
|
+
],
|
|
947
|
+
{ expressions },
|
|
720
948
|
);
|
|
721
949
|
};
|
|
950
|
+
|
|
951
|
+
export const buildGapNodeMatcher = () => {
|
|
952
|
+
return buildToken(l.Spamex, 'GapNodeMatcher', '<//>');
|
|
953
|
+
};
|