@bablr/boot 0.5.0 → 0.6.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 -0
- package/lib/index.js +25 -7
- package/lib/languages/cstml.js +23 -14
- package/lib/languages/regex.js +1 -1
- package/lib/miniparser.js +13 -2
- package/lib/print.js +0 -6
- package/package.json +2 -2
- package/shorthand.macro.js +7 -16
package/lib/builders.js
CHANGED
|
@@ -2,8 +2,11 @@ const sym = require('@bablr/boot-helpers/symbols');
|
|
|
2
2
|
const { freeze, getPrototypeOf } = Object;
|
|
3
3
|
const { isArray } = Array;
|
|
4
4
|
const {
|
|
5
|
+
DoctypeTag,
|
|
5
6
|
OpenNodeTag,
|
|
6
7
|
CloseNodeTag,
|
|
8
|
+
OpenFragmentTag,
|
|
9
|
+
CloseFragmentTag,
|
|
7
10
|
ReferenceTag,
|
|
8
11
|
GapTag,
|
|
9
12
|
LiteralTag,
|
|
@@ -66,6 +69,13 @@ const interpolateString = (value) => {
|
|
|
66
69
|
return buildNode('String', 'Content', children);
|
|
67
70
|
};
|
|
68
71
|
|
|
72
|
+
const buildDoctypeTag = (attributes) => {
|
|
73
|
+
return freeze({
|
|
74
|
+
type: DoctypeTag,
|
|
75
|
+
value: freeze({ doctype: 'cstml', version: 0, attributes }),
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
|
|
69
79
|
const buildReferenceTag = (name, isArray) => {
|
|
70
80
|
return freeze({ type: ReferenceTag, value: freeze({ name, isArray }) });
|
|
71
81
|
};
|
|
@@ -82,6 +92,19 @@ const buildNodeCloseTag = (type) => {
|
|
|
82
92
|
return freeze({ type: CloseNodeTag, value: freeze({ type }) });
|
|
83
93
|
};
|
|
84
94
|
|
|
95
|
+
const buildFragmentOpenTag = (flags = {}) => {
|
|
96
|
+
return freeze({
|
|
97
|
+
type: OpenFragmentTag,
|
|
98
|
+
value: freeze({
|
|
99
|
+
flags: freeze(flags),
|
|
100
|
+
}),
|
|
101
|
+
});
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const buildFragmentCloseTag = (type = null, language = null) => {
|
|
105
|
+
return freeze({ type: CloseFragmentTag, value: freeze({ language, type }) });
|
|
106
|
+
};
|
|
107
|
+
|
|
85
108
|
const buildLiteralTag = (value) => {
|
|
86
109
|
return freeze({ type: LiteralTag, value });
|
|
87
110
|
};
|
|
@@ -421,10 +444,13 @@ module.exports = {
|
|
|
421
444
|
buildSpace,
|
|
422
445
|
buildIdentifier,
|
|
423
446
|
buildAttribute,
|
|
447
|
+
buildDoctypeTag,
|
|
424
448
|
buildReferenceTag,
|
|
425
449
|
buildGapTag,
|
|
426
450
|
buildNodeOpenTag,
|
|
427
451
|
buildNodeCloseTag,
|
|
452
|
+
buildFragmentOpenTag,
|
|
453
|
+
buildFragmentCloseTag,
|
|
428
454
|
buildLiteralTag,
|
|
429
455
|
buildNode,
|
|
430
456
|
buildSyntacticNode,
|
|
@@ -432,6 +458,8 @@ module.exports = {
|
|
|
432
458
|
buildSyntacticEscapeNode,
|
|
433
459
|
buildTriviaNode,
|
|
434
460
|
buildGapNode,
|
|
461
|
+
nodeFlags,
|
|
462
|
+
|
|
435
463
|
ref,
|
|
436
464
|
lit,
|
|
437
465
|
gap,
|
package/lib/index.js
CHANGED
|
@@ -5,11 +5,16 @@ const regex = require('./languages/regex.js');
|
|
|
5
5
|
const instruction = require('./languages/instruction.js');
|
|
6
6
|
const {
|
|
7
7
|
buildLiteralTag,
|
|
8
|
+
buildDoctypeTag,
|
|
8
9
|
buildNodeOpenTag,
|
|
9
10
|
buildNodeCloseTag,
|
|
11
|
+
buildFragmentOpenTag,
|
|
12
|
+
buildFragmentCloseTag,
|
|
10
13
|
buildTriviaNode,
|
|
11
14
|
buildGapNode,
|
|
12
15
|
buildSyntacticEscapeNode,
|
|
16
|
+
nodeFlags,
|
|
17
|
+
buildReferenceTag,
|
|
13
18
|
} = require('./builders.js');
|
|
14
19
|
const { TemplateParser } = require('./miniparser.js');
|
|
15
20
|
const { Resolver } = require('./print.js');
|
|
@@ -62,7 +67,7 @@ const add = (obj, path, value) => {
|
|
|
62
67
|
|
|
63
68
|
const buildTag = (language, defaultType) => {
|
|
64
69
|
const defaultTag = (quasis, ...exprs) => {
|
|
65
|
-
return
|
|
70
|
+
return getAgASTTree(
|
|
66
71
|
language,
|
|
67
72
|
new TemplateParser(language, quasis.raw, exprs).eval({
|
|
68
73
|
language: language.name,
|
|
@@ -78,7 +83,7 @@ const buildTag = (language, defaultType) => {
|
|
|
78
83
|
|
|
79
84
|
get(_, type) {
|
|
80
85
|
return (quasis, ...exprs) => {
|
|
81
|
-
return
|
|
86
|
+
return getAgASTTree(
|
|
82
87
|
language,
|
|
83
88
|
new TemplateParser(language, quasis.raw, exprs).eval({
|
|
84
89
|
language: language.name,
|
|
@@ -97,6 +102,23 @@ const parse = (language, type, sourceText) => {
|
|
|
97
102
|
});
|
|
98
103
|
};
|
|
99
104
|
|
|
105
|
+
const getAgASTTree = (language, miniNode) => {
|
|
106
|
+
const attributes = { 'bablr-language': language.canonicalURL };
|
|
107
|
+
return {
|
|
108
|
+
flags: nodeFlags,
|
|
109
|
+
language: language.canonicalURL,
|
|
110
|
+
type: null,
|
|
111
|
+
children: [
|
|
112
|
+
buildDoctypeTag(attributes),
|
|
113
|
+
buildFragmentOpenTag(nodeFlags, null, null, null),
|
|
114
|
+
buildReferenceTag('.'),
|
|
115
|
+
buildFragmentCloseTag(),
|
|
116
|
+
],
|
|
117
|
+
properties: { ['.']: getAgASTValue(language, miniNode) },
|
|
118
|
+
attributes,
|
|
119
|
+
};
|
|
120
|
+
};
|
|
121
|
+
|
|
100
122
|
const getAgASTValue = (language, miniNode) => {
|
|
101
123
|
if (!miniNode) return miniNode;
|
|
102
124
|
|
|
@@ -109,7 +131,7 @@ const getAgASTValue = (language, miniNode) => {
|
|
|
109
131
|
escape: !!miniNode.flags?.escape,
|
|
110
132
|
trivia: !!miniNode.flags?.trivia,
|
|
111
133
|
token: false,
|
|
112
|
-
|
|
134
|
+
hasGap: false,
|
|
113
135
|
};
|
|
114
136
|
const properties = {};
|
|
115
137
|
let children = [];
|
|
@@ -136,10 +158,6 @@ const getAgASTValue = (language, miniNode) => {
|
|
|
136
158
|
flags.token = true;
|
|
137
159
|
}
|
|
138
160
|
|
|
139
|
-
if (type === 'Punctuator' || type === 'Keyword') {
|
|
140
|
-
flags.intrinsic = true;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
161
|
children = btree.push(
|
|
144
162
|
children,
|
|
145
163
|
buildNodeOpenTag(flags, resolvedLanguage.canonicalURL, type, attributes),
|
package/lib/languages/cstml.js
CHANGED
|
@@ -7,7 +7,6 @@ const _ = /\s+/y;
|
|
|
7
7
|
const PN = 'Punctuator';
|
|
8
8
|
const ID = 'Identifier';
|
|
9
9
|
const KW = 'Keyword';
|
|
10
|
-
const LIT = 'Literal';
|
|
11
10
|
|
|
12
11
|
const name = 'CSTML';
|
|
13
12
|
|
|
@@ -105,7 +104,7 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
105
104
|
|
|
106
105
|
let sp = p.eatMatchTrivia(_);
|
|
107
106
|
|
|
108
|
-
if ((sp && p.match(
|
|
107
|
+
if ((sp && p.match(/!?[a-zA-Z]/y)) || p.atExpression) {
|
|
109
108
|
p.eatProduction('Attributes');
|
|
110
109
|
sp = p.eatMatchTrivia(_);
|
|
111
110
|
}
|
|
@@ -156,7 +155,7 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
156
155
|
} else {
|
|
157
156
|
if (p.match(/<\*?#/y)) {
|
|
158
157
|
p.eatProduction('Node');
|
|
159
|
-
} else if (p.match(/[a-zA-Z]
|
|
158
|
+
} else if (p.match(/[a-zA-Z]|\./y)) {
|
|
160
159
|
p.eatProduction('Property');
|
|
161
160
|
} else if (p.match(/['"]/y)) {
|
|
162
161
|
p.eatProduction('LiteralTag');
|
|
@@ -184,10 +183,10 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
184
183
|
// @Node
|
|
185
184
|
Flags(p) {
|
|
186
185
|
let tr = p.eatMatch('#', PN, { path: 'triviaToken' });
|
|
187
|
-
p.eatMatch('~', PN, { path: 'intrinsicToken' });
|
|
188
186
|
p.eatMatch('*', PN, { path: 'tokenToken' });
|
|
189
187
|
let esc = p.eatMatch('@', PN, { path: 'escapeToken' });
|
|
190
188
|
let exp = p.eatMatch('+', PN, { path: 'expressionToken' });
|
|
189
|
+
p.eatMatch('$', PN, { path: 'hasGapToken' });
|
|
191
190
|
|
|
192
191
|
if ((tr && esc) || (exp && (tr || esc))) throw new Error();
|
|
193
192
|
}
|
|
@@ -210,12 +209,18 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
210
209
|
|
|
211
210
|
let sp = p.eatMatchTrivia(_);
|
|
212
211
|
|
|
213
|
-
|
|
214
|
-
|
|
212
|
+
let iv;
|
|
213
|
+
|
|
214
|
+
if (sp && (p.match(/['"]/y) || p.atExpression)) {
|
|
215
|
+
iv = p.eatProduction('String', { path: 'intrinsicValue' });
|
|
215
216
|
|
|
216
217
|
sp = p.eatMatchTrivia(_);
|
|
217
218
|
}
|
|
218
219
|
|
|
220
|
+
if (!flags.properties.tokenToken && iv) {
|
|
221
|
+
throw new Error();
|
|
222
|
+
}
|
|
223
|
+
|
|
219
224
|
if ((sp && p.match(/[a-zA-Z]+/y)) || p.atExpression) {
|
|
220
225
|
p.eatProduction('Attributes');
|
|
221
226
|
sp = p.eatMatchTrivia(_);
|
|
@@ -235,13 +240,13 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
235
240
|
// @Fragment
|
|
236
241
|
Attributes(p) {
|
|
237
242
|
let sp = true;
|
|
238
|
-
while (sp && (p.match(
|
|
243
|
+
while (sp && (p.match(/!?[a-zA-Z]/y) || p.atExpression)) {
|
|
239
244
|
if (p.atExpression) {
|
|
240
245
|
p.eatProduction('Attributes'); // ??
|
|
241
246
|
} else {
|
|
242
247
|
p.eatProduction('Attribute', { path: 'attributes[]' });
|
|
243
248
|
}
|
|
244
|
-
if (p.match(/\s
|
|
249
|
+
if (p.match(/\s+!?[a-zA-Z]/y) || (p.match(/\s+$/y) && !p.quasisDone)) {
|
|
245
250
|
sp = p.eatMatchTrivia(_);
|
|
246
251
|
} else {
|
|
247
252
|
sp = false;
|
|
@@ -251,7 +256,7 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
251
256
|
|
|
252
257
|
// @Cover
|
|
253
258
|
Attribute(p) {
|
|
254
|
-
if (p.match(/[a-zA-Z][
|
|
259
|
+
if (p.match(/[a-zA-Z][a-zA-Z-_]*\s*=/y)) {
|
|
255
260
|
p.eatProduction('MappingAttribute');
|
|
256
261
|
} else {
|
|
257
262
|
p.eatProduction('BooleanAttribute');
|
|
@@ -260,13 +265,13 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
260
265
|
|
|
261
266
|
// @Node
|
|
262
267
|
BooleanAttribute(p) {
|
|
263
|
-
p.
|
|
264
|
-
p.eat(/[a-zA-Z]
|
|
268
|
+
p.eatMatch('!', KW, { path: 'negateToken' });
|
|
269
|
+
p.eat(/[a-zA-Z][a-zA-Z-_]*/y, ID, { path: 'key' });
|
|
265
270
|
}
|
|
266
271
|
|
|
267
272
|
// @Node
|
|
268
273
|
MappingAttribute(p) {
|
|
269
|
-
p.eat(/[a-zA-Z]
|
|
274
|
+
p.eat(/[a-zA-Z][a-zA-Z-_]*/y, ID, { path: 'key' });
|
|
270
275
|
p.eatMatchTrivia(_);
|
|
271
276
|
p.eat('=', PN, { path: 'mapToken' });
|
|
272
277
|
p.eatMatchTrivia(_);
|
|
@@ -283,7 +288,7 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
283
288
|
}
|
|
284
289
|
|
|
285
290
|
TagType(p) {
|
|
286
|
-
if (p.match(/[
|
|
291
|
+
if (p.match(/[a-zA-Z\.]+:/y)) {
|
|
287
292
|
p.eatProduction('LanguageReference', { path: 'language' });
|
|
288
293
|
p.eat(':', PN, { path: 'namespaceSeparatorToken' });
|
|
289
294
|
p.eatProduction('Identifier', { path: 'type' });
|
|
@@ -324,7 +329,11 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
324
329
|
|
|
325
330
|
// @Node
|
|
326
331
|
ReferenceTag(p) {
|
|
327
|
-
p.
|
|
332
|
+
if (p.match('.')) {
|
|
333
|
+
p.eat('.', PN, { path: 'name' });
|
|
334
|
+
} else {
|
|
335
|
+
p.eatProduction('Identifier', { path: 'name' });
|
|
336
|
+
}
|
|
328
337
|
p.eatMatchTrivia(_);
|
|
329
338
|
p.eatMatch('[]', PN, { path: 'arrayToken' });
|
|
330
339
|
p.eatMatchTrivia(_);
|
package/lib/languages/regex.js
CHANGED
package/lib/miniparser.js
CHANGED
|
@@ -178,9 +178,19 @@ class TemplateParser {
|
|
|
178
178
|
const { properties, children } = parentPath.node;
|
|
179
179
|
const path = parsePath(this.m.attrs.path);
|
|
180
180
|
|
|
181
|
-
|
|
181
|
+
if (isArray(result)) {
|
|
182
|
+
for (const value of result) {
|
|
183
|
+
children.push(ref(path));
|
|
182
184
|
|
|
183
|
-
|
|
185
|
+
// TODO interpolate separators!
|
|
186
|
+
|
|
187
|
+
set(properties, path, value);
|
|
188
|
+
}
|
|
189
|
+
} else {
|
|
190
|
+
children.push(ref(path));
|
|
191
|
+
|
|
192
|
+
set(properties, path, result);
|
|
193
|
+
}
|
|
184
194
|
}
|
|
185
195
|
} else {
|
|
186
196
|
if (isEmbedded) {
|
|
@@ -198,6 +208,7 @@ class TemplateParser {
|
|
|
198
208
|
if (result?.attrs) {
|
|
199
209
|
node.attributes = result.attrs;
|
|
200
210
|
}
|
|
211
|
+
|
|
201
212
|
if (parentPath?.node && !covers.has(type)) {
|
|
202
213
|
const path = parsePath(this.m.attrs.path);
|
|
203
214
|
|
package/lib/print.js
CHANGED
|
@@ -161,17 +161,11 @@ class Resolver {
|
|
|
161
161
|
}
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
-
const buildDoctypeTag = () => {
|
|
165
|
-
return freeze({ type: DoctypeTag, value: { doctype: 'cstml', version: 0 } });
|
|
166
|
-
};
|
|
167
|
-
|
|
168
164
|
function* streamFromTree(rootNode) {
|
|
169
165
|
if (!rootNode || rootNode.type === GapTag) {
|
|
170
166
|
return rootNode;
|
|
171
167
|
}
|
|
172
168
|
|
|
173
|
-
yield buildDoctypeTag(rootNode.attributes);
|
|
174
|
-
|
|
175
169
|
let stack = emptyStack.push(rootNode);
|
|
176
170
|
const resolver = new Resolver();
|
|
177
171
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bablr/boot",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Compile-time tools for bootstrapping BABLR VM",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=12.0.0"
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"@babel/helper-module-imports": "^7.22.15",
|
|
23
23
|
"@babel/template": "^7.22.15",
|
|
24
24
|
"@babel/types": "7.23.0",
|
|
25
|
-
"@bablr/boot-helpers": "0.3.
|
|
25
|
+
"@bablr/boot-helpers": "0.3.1",
|
|
26
26
|
"@iter-tools/imm-stack": "1.1.0",
|
|
27
27
|
"escape-string-regexp": "4.0.0",
|
|
28
28
|
"iter-tools": "^7.5.3",
|
package/shorthand.macro.js
CHANGED
|
@@ -96,9 +96,7 @@ const generateBabelNodeChild = (child, exprs, bindings) => {
|
|
|
96
96
|
};
|
|
97
97
|
|
|
98
98
|
const getAgastNodeType = (flags) => {
|
|
99
|
-
if (flags.
|
|
100
|
-
return 's_i_node';
|
|
101
|
-
} else if (flags.token && flags.trivia) {
|
|
99
|
+
if (flags.token && flags.trivia) {
|
|
102
100
|
return 's_t_node';
|
|
103
101
|
} else if (flags.token && flags.escape) {
|
|
104
102
|
return 's_e_node';
|
|
@@ -140,7 +138,7 @@ const generateBabelNode = (node, exprs, bindings) => {
|
|
|
140
138
|
} else {
|
|
141
139
|
// gap
|
|
142
140
|
const expr = exprs.pop();
|
|
143
|
-
const { interpolateArray,
|
|
141
|
+
const { interpolateArray, interpolateFragmentChildren, interpolateString } = bindings;
|
|
144
142
|
|
|
145
143
|
if (pathIsArray) {
|
|
146
144
|
add(
|
|
@@ -155,17 +153,10 @@ const generateBabelNode = (node, exprs, bindings) => {
|
|
|
155
153
|
children_ = btree.push(
|
|
156
154
|
children_,
|
|
157
155
|
t.spreadElement(
|
|
158
|
-
expression('%%
|
|
159
|
-
|
|
156
|
+
expression('%%interpolateFragmentChildren%%(%%expr%%, %%ref%%)')({
|
|
157
|
+
interpolateFragmentChildren,
|
|
160
158
|
expr,
|
|
161
159
|
ref: expression(`%%t%%.ref\`${printRef(child.value)}\``)({ t: bindings.t }),
|
|
162
|
-
|
|
163
|
-
// Really really awful unsafe-as-heck hack, to be removed ASAP
|
|
164
|
-
// Fixing this requires having interpolation happen during parsing
|
|
165
|
-
// That way the grammar can deal with the separators!
|
|
166
|
-
sep: expression(
|
|
167
|
-
"%%t%%.embedded(%%t%%.t_node(%%l%%.Comment, null, [%%t%%.embedded(%%t%%.t_node('Space', 'Space', [%%t%%.lit(' ')]))]))",
|
|
168
|
-
)({ t: bindings.t, l: bindings.l }),
|
|
169
160
|
}),
|
|
170
161
|
),
|
|
171
162
|
);
|
|
@@ -306,10 +297,10 @@ const shorthandMacro = ({ references }) => {
|
|
|
306
297
|
);
|
|
307
298
|
}
|
|
308
299
|
|
|
309
|
-
if (!bindings.
|
|
310
|
-
bindings.
|
|
300
|
+
if (!bindings.interpolateFragmentChildren) {
|
|
301
|
+
bindings.interpolateFragmentChildren = addNamed(
|
|
311
302
|
getTopScope(ref.scope).path,
|
|
312
|
-
'
|
|
303
|
+
'interpolateFragmentChildren',
|
|
313
304
|
'@bablr/agast-helpers/template',
|
|
314
305
|
);
|
|
315
306
|
}
|