@bablr/boot 0.9.0 → 0.11.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/index.js +45 -15
- package/lib/languages/cstml.js +196 -117
- package/lib/languages/instruction.js +32 -22
- package/lib/languages/json.js +22 -30
- package/lib/languages/regex.js +6 -32
- package/lib/languages/spamex.js +89 -92
- package/lib/match.js +19 -18
- package/lib/miniparser.js +143 -114
- package/lib/path.js +5 -36
- package/package.json +8 -5
package/lib/miniparser.js
CHANGED
|
@@ -4,25 +4,33 @@ import isString from 'iter-tools-es/methods/is-string';
|
|
|
4
4
|
import isObject from 'iter-tools-es/methods/is-object';
|
|
5
5
|
import find from 'iter-tools-es/methods/find';
|
|
6
6
|
import every from 'iter-tools-es/methods/every';
|
|
7
|
-
import * as sym from '@bablr/agast-vm-helpers/symbols';
|
|
8
7
|
import { Match } from './match.js';
|
|
9
8
|
import { isRegex, isArray, getPrototypeOf } from './utils.js';
|
|
10
9
|
import { ReferenceTag, LiteralTag } from '@bablr/agast-helpers/symbols';
|
|
11
10
|
import {
|
|
12
11
|
buildCloseNodeTag,
|
|
13
12
|
buildLiteralTag,
|
|
13
|
+
buildNullTag,
|
|
14
14
|
buildOpenNodeTag,
|
|
15
15
|
buildReferenceTag,
|
|
16
|
+
buildShiftTag,
|
|
16
17
|
nodeFlags,
|
|
17
18
|
} from '@bablr/agast-helpers/builders';
|
|
18
|
-
import {
|
|
19
|
-
import * as
|
|
20
|
-
import {
|
|
19
|
+
import { buildToken } from '@bablr/agast-helpers/tree';
|
|
20
|
+
import * as Tags from '@bablr/agast-helpers/tags';
|
|
21
|
+
import {
|
|
22
|
+
buildNode,
|
|
23
|
+
buildNullNode,
|
|
24
|
+
buildPathSegment,
|
|
25
|
+
get,
|
|
26
|
+
getTags,
|
|
27
|
+
Path,
|
|
28
|
+
} from '@bablr/agast-helpers/path';
|
|
21
29
|
import { parseReference } from '@bablr/agast-helpers/shorthand';
|
|
22
30
|
|
|
23
|
-
|
|
31
|
+
let Escape = Symbol.for('Escape');
|
|
24
32
|
|
|
25
|
-
|
|
33
|
+
let getProduction = (grammar, type) => {
|
|
26
34
|
return getPrototypeOf(grammar)[type];
|
|
27
35
|
};
|
|
28
36
|
|
|
@@ -82,11 +90,13 @@ export class TemplateParser {
|
|
|
82
90
|
}
|
|
83
91
|
|
|
84
92
|
get matchIsNode() {
|
|
85
|
-
return
|
|
93
|
+
return (
|
|
94
|
+
this.language.covers.get(Symbol.for('@bablr/node')).has(this.m.name) && !this.matchIsCover
|
|
95
|
+
);
|
|
86
96
|
}
|
|
87
97
|
|
|
88
98
|
get matchIsCover() {
|
|
89
|
-
return this.language.covers.has(this.m.
|
|
99
|
+
return this.language.covers.has(this.m.name);
|
|
90
100
|
}
|
|
91
101
|
|
|
92
102
|
get matchIsFragment() {
|
|
@@ -102,27 +112,27 @@ export class TemplateParser {
|
|
|
102
112
|
}
|
|
103
113
|
|
|
104
114
|
get slicedQuasi() {
|
|
105
|
-
|
|
115
|
+
let { idx, quasi } = this;
|
|
106
116
|
return quasi.slice(idx);
|
|
107
117
|
}
|
|
108
118
|
|
|
109
119
|
get guardedSlicedQuasi() {
|
|
110
|
-
|
|
111
|
-
|
|
120
|
+
let { span, slicedQuasi } = this;
|
|
121
|
+
let { guard } = span;
|
|
112
122
|
|
|
113
123
|
if (!guard) return slicedQuasi;
|
|
114
124
|
|
|
115
|
-
|
|
116
|
-
|
|
125
|
+
let pat = new RegExp(escapeRegex(guard), 'y');
|
|
126
|
+
let res = pat.exec(slicedQuasi);
|
|
117
127
|
|
|
118
128
|
return res ? slicedQuasi.slice(0, pat.lastIndex - res[0].length) : slicedQuasi;
|
|
119
129
|
}
|
|
120
130
|
|
|
121
131
|
matchSticky(pattern, attrs) {
|
|
122
|
-
|
|
123
|
-
|
|
132
|
+
let { slicedQuasi, guardedSlicedQuasi } = this;
|
|
133
|
+
let { balancer } = attrs;
|
|
124
134
|
|
|
125
|
-
|
|
135
|
+
let source = balancer ? slicedQuasi : guardedSlicedQuasi;
|
|
126
136
|
|
|
127
137
|
if (isString(pattern)) {
|
|
128
138
|
return source.startsWith(pattern) ? pattern : null;
|
|
@@ -130,7 +140,7 @@ export class TemplateParser {
|
|
|
130
140
|
if (!pattern.sticky) throw new Error('be sticky!');
|
|
131
141
|
pattern.lastIndex = 0;
|
|
132
142
|
|
|
133
|
-
|
|
143
|
+
let result = pattern.exec(source);
|
|
134
144
|
|
|
135
145
|
return result ? result[0] : null;
|
|
136
146
|
} else {
|
|
@@ -138,10 +148,19 @@ export class TemplateParser {
|
|
|
138
148
|
}
|
|
139
149
|
}
|
|
140
150
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
151
|
+
eatProduction(_id, attrs = {}, props = {}, shift_ = null) {
|
|
152
|
+
if (_id === null) {
|
|
153
|
+
let path_ = parseReference(attrs.path);
|
|
154
|
+
|
|
155
|
+
this.path.node = Path.from(this.node).advance(path_).advance(buildNullNode()).node;
|
|
156
|
+
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
let id = isObject(_id) ? _id : this.buildId(_id);
|
|
160
|
+
|
|
161
|
+
let parentMatch = this.m;
|
|
162
|
+
let parentPath = this.path?.node ? this.path : this.path?.parent;
|
|
163
|
+
let { name } = id;
|
|
145
164
|
|
|
146
165
|
if (parentMatch && this.matchIsNode) {
|
|
147
166
|
if (this.matchIsCover && Object.keys(attrs).length) {
|
|
@@ -155,39 +174,36 @@ export class TemplateParser {
|
|
|
155
174
|
this.m = Match.from(this.rootLanguage, id, attrs);
|
|
156
175
|
}
|
|
157
176
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
177
|
+
let { covers } = this.language;
|
|
178
|
+
let isNode = this.matchIsNode;
|
|
179
|
+
let isCover = this.matchIsCover;
|
|
180
|
+
let isEmbedded = this.language !== this.m.parent?.resolvedLanguage;
|
|
181
|
+
let { path, grammar } = this;
|
|
163
182
|
|
|
164
|
-
if (!
|
|
183
|
+
if (!name) throw new Error('eval requires a type');
|
|
165
184
|
|
|
166
185
|
if (parentPath?.node && this.atExpression && !attrs.noInterpolate && (isNode || isCover)) {
|
|
167
|
-
|
|
186
|
+
let { quasisDone } = this;
|
|
168
187
|
|
|
169
188
|
if (quasisDone) throw new Error('there must be more quasis than expressions');
|
|
170
189
|
|
|
171
|
-
|
|
190
|
+
let result = this.expression;
|
|
172
191
|
|
|
173
192
|
this.expressionIdx++;
|
|
174
193
|
this.quasiIdx++;
|
|
175
194
|
this.idx = 0;
|
|
176
195
|
|
|
177
|
-
if (parentPath?.node
|
|
178
|
-
|
|
179
|
-
const path = parseReference(this.m.attrs.path);
|
|
196
|
+
if (!parentPath?.node || isNode || covers.has(name)) {
|
|
197
|
+
let path = parseReference(this.m.attrs.path);
|
|
180
198
|
|
|
181
199
|
if (isArray(result)) {
|
|
182
|
-
for (
|
|
183
|
-
node
|
|
184
|
-
|
|
185
|
-
add(node, path, value);
|
|
200
|
+
for (let value of result) {
|
|
201
|
+
parentPath.node = Path.from(parentPath.node).advance(path).advance(value).node;
|
|
186
202
|
}
|
|
187
203
|
} else {
|
|
188
|
-
node
|
|
189
|
-
|
|
190
|
-
|
|
204
|
+
parentPath.node = Path.from(parentPath.node)
|
|
205
|
+
.advance(path)
|
|
206
|
+
.advance(result ? result : buildNullTag()).node;
|
|
191
207
|
}
|
|
192
208
|
}
|
|
193
209
|
} else {
|
|
@@ -195,42 +211,44 @@ export class TemplateParser {
|
|
|
195
211
|
this.spans.push({ type: 'Bare', guard: null });
|
|
196
212
|
}
|
|
197
213
|
|
|
198
|
-
if (!getProduction(grammar,
|
|
199
|
-
throw new Error(`Unknown production {type: ${
|
|
214
|
+
if (!getProduction(grammar, name)) {
|
|
215
|
+
throw new Error(`Unknown production {type: ${name}}`);
|
|
200
216
|
}
|
|
201
217
|
|
|
202
|
-
if (isNode) {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
}
|
|
218
|
+
// if (isNode) {
|
|
219
|
+
// let { node } = this.path;
|
|
220
|
+
// this.path.node = Path.from(node).advance(buildOpenNodeTag(nodeFlags, node.type)).node;
|
|
221
|
+
// }
|
|
206
222
|
|
|
207
|
-
|
|
223
|
+
let result = getPrototypeOf(grammar)[name].call(grammar, this, props);
|
|
208
224
|
|
|
209
225
|
if (isEmbedded) {
|
|
210
226
|
this.spans.pop();
|
|
211
227
|
}
|
|
212
228
|
|
|
213
|
-
if (isNode) {
|
|
214
|
-
const { node } = this.path;
|
|
229
|
+
if (isNode || !parentPath) {
|
|
215
230
|
if (result?.attrs) {
|
|
216
|
-
node
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
231
|
+
this.path.node = Path.from(this.node).replaceWith(
|
|
232
|
+
buildNode(
|
|
233
|
+
Tags.replaceAt(
|
|
234
|
+
0,
|
|
235
|
+
this.path.node.value.tags,
|
|
236
|
+
buildOpenNodeTag(nodeFlags, this.path.name, isCover ? '_' : null, result.attrs),
|
|
237
|
+
),
|
|
238
|
+
),
|
|
239
|
+
).node;
|
|
222
240
|
}
|
|
223
241
|
|
|
224
|
-
node
|
|
242
|
+
this.path.node = Path.from(this.node).advance(buildCloseNodeTag()).node;
|
|
225
243
|
|
|
226
|
-
if (parentPath?.node && !covers.has(
|
|
227
|
-
|
|
244
|
+
if (parentPath?.node && !covers.has(name)) {
|
|
245
|
+
let path = this.m.attrs.path
|
|
246
|
+
? parseReference(this.m.attrs.path)
|
|
247
|
+
: buildReferenceTag(parentPath.node.value.type === Symbol.for('_') ? '_' : '.');
|
|
228
248
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
shift(parentPath.node, path, node);
|
|
233
|
-
}
|
|
249
|
+
parentPath.node = Path.from(parentPath.node)
|
|
250
|
+
.advance(shift_ == null ? path : buildShiftTag())
|
|
251
|
+
.advance(this.node).node;
|
|
234
252
|
}
|
|
235
253
|
}
|
|
236
254
|
|
|
@@ -242,11 +260,11 @@ export class TemplateParser {
|
|
|
242
260
|
this.m = this.m.parent;
|
|
243
261
|
|
|
244
262
|
if (this.path?.node) {
|
|
245
|
-
|
|
263
|
+
let isTag = (child) => [LiteralTag, Escape].includes(child.type);
|
|
246
264
|
|
|
247
|
-
|
|
265
|
+
let tags = getTags(this.path.node);
|
|
248
266
|
|
|
249
|
-
if (find(isTag,
|
|
267
|
+
if (find(isTag, Tags.traverse(tags)) && every(isTag, Tags.traverse(tags))) {
|
|
250
268
|
throw new Error('strings must be wrapped in nodes');
|
|
251
269
|
}
|
|
252
270
|
}
|
|
@@ -254,7 +272,7 @@ export class TemplateParser {
|
|
|
254
272
|
}
|
|
255
273
|
|
|
256
274
|
updateSpans(attrs) {
|
|
257
|
-
|
|
275
|
+
let { startSpan, endSpan, balanced, balancer } = attrs;
|
|
258
276
|
if (endSpan || balancer) {
|
|
259
277
|
if (!this.span.guard) {
|
|
260
278
|
throw new Error('Only balanced spans can be closed with endSpan');
|
|
@@ -262,51 +280,50 @@ export class TemplateParser {
|
|
|
262
280
|
this.popSpan();
|
|
263
281
|
}
|
|
264
282
|
if (startSpan || balanced) {
|
|
265
|
-
|
|
283
|
+
let type = startSpan || this.span.type;
|
|
266
284
|
this.pushSpan({ type, guard: balanced });
|
|
267
285
|
}
|
|
268
286
|
}
|
|
269
287
|
|
|
270
288
|
buildId(id) {
|
|
271
|
-
let
|
|
289
|
+
let name;
|
|
272
290
|
let language = this.language.name;
|
|
273
291
|
|
|
274
292
|
if (id.includes(':')) {
|
|
275
|
-
({ 0: language, 1:
|
|
293
|
+
({ 0: language, 1: name } = id.split(':'));
|
|
276
294
|
} else {
|
|
277
|
-
|
|
295
|
+
name = id;
|
|
278
296
|
}
|
|
279
297
|
|
|
280
|
-
return {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
return this.eval(this.buildId(id), attrs, props);
|
|
298
|
+
return {
|
|
299
|
+
name,
|
|
300
|
+
language,
|
|
301
|
+
};
|
|
285
302
|
}
|
|
286
303
|
|
|
287
|
-
eatHeldProduction(
|
|
304
|
+
eatHeldProduction(name, attrs) {
|
|
288
305
|
if (!this.held) {
|
|
289
306
|
throw new Error();
|
|
290
307
|
}
|
|
291
308
|
|
|
292
|
-
|
|
309
|
+
let { held, node } = this;
|
|
293
310
|
|
|
294
311
|
this.held = null;
|
|
295
312
|
|
|
296
|
-
|
|
313
|
+
let path = parseReference(attrs.path);
|
|
297
314
|
|
|
298
|
-
|
|
315
|
+
this.path.node = Path.from(node).advance(path).advance(held).node;
|
|
299
316
|
|
|
300
317
|
return held;
|
|
301
318
|
}
|
|
302
319
|
|
|
303
320
|
shiftProduction(id, attrs = {}, props = {}) {
|
|
304
|
-
|
|
321
|
+
let { node } = this;
|
|
305
322
|
// don't push a new path onto the stack
|
|
306
323
|
|
|
307
324
|
// get the most recently produced node and detach it from its parent
|
|
308
325
|
|
|
309
|
-
|
|
326
|
+
let ref = Tags.getAt(-1, getTags(node)).value.tags[0];
|
|
310
327
|
|
|
311
328
|
if (!ref.value.flags.expression) throw new Error();
|
|
312
329
|
|
|
@@ -316,22 +333,20 @@ export class TemplateParser {
|
|
|
316
333
|
|
|
317
334
|
this.held = get(buildPathSegment(ref.value.name, -1), node);
|
|
318
335
|
|
|
319
|
-
let
|
|
320
|
-
|
|
321
|
-
const shifted = this.eval(id_, attrs, props, 1);
|
|
336
|
+
let shifted = this.eatProduction(id, attrs, props, 1);
|
|
322
337
|
|
|
323
338
|
// shift(node, ref, shifted);
|
|
324
339
|
|
|
325
340
|
return shifted;
|
|
326
341
|
}
|
|
327
342
|
|
|
328
|
-
eat(pattern,
|
|
329
|
-
if (!isString(
|
|
343
|
+
eat(pattern, name, attrs) {
|
|
344
|
+
if (name && !isString(name)) throw new Error('bad name');
|
|
330
345
|
if (!isObject(attrs) || !attrs.path) throw new Error('a node must have a path');
|
|
331
346
|
|
|
332
|
-
|
|
347
|
+
let { path, ..._attrs } = attrs;
|
|
333
348
|
|
|
334
|
-
|
|
349
|
+
let result = this.matchSticky(pattern, attrs, this);
|
|
335
350
|
|
|
336
351
|
if (!result) this.fail();
|
|
337
352
|
|
|
@@ -339,9 +354,11 @@ export class TemplateParser {
|
|
|
339
354
|
|
|
340
355
|
this.updateSpans(attrs);
|
|
341
356
|
|
|
342
|
-
|
|
357
|
+
let path_ = parseReference(attrs.path);
|
|
343
358
|
|
|
344
|
-
|
|
359
|
+
this.path.node = Path.from(this.node)
|
|
360
|
+
.advance(path_)
|
|
361
|
+
.advance(buildToken(name, result, _attrs)).node;
|
|
345
362
|
|
|
346
363
|
return result;
|
|
347
364
|
}
|
|
@@ -351,99 +368,111 @@ export class TemplateParser {
|
|
|
351
368
|
return this.matchSticky(pattern, attrs, this);
|
|
352
369
|
}
|
|
353
370
|
|
|
354
|
-
eatMatch(pattern,
|
|
355
|
-
if (!isString(
|
|
371
|
+
eatMatch(pattern, name, attrs) {
|
|
372
|
+
if (name && !isString(name)) throw new Error('bad name');
|
|
356
373
|
if (!isObject(attrs) || !attrs.path) throw new Error('a node must have a path');
|
|
357
374
|
|
|
358
|
-
|
|
375
|
+
let result = this.matchSticky(pattern, attrs, this);
|
|
359
376
|
|
|
360
377
|
if (result) {
|
|
361
378
|
this.updateSpans(attrs);
|
|
362
379
|
|
|
363
380
|
this.idx += result.length;
|
|
364
381
|
|
|
365
|
-
|
|
382
|
+
let { path, ..._attrs } = attrs;
|
|
383
|
+
|
|
384
|
+
let path_ = parseReference(path);
|
|
366
385
|
|
|
367
|
-
|
|
386
|
+
this.path.node = Path.from(this.node)
|
|
387
|
+
.advance(path_)
|
|
388
|
+
.advance(buildToken(name, result, _attrs)).node;
|
|
368
389
|
}
|
|
369
390
|
return result;
|
|
370
391
|
}
|
|
371
392
|
|
|
372
393
|
eatTrivia(pattern) {
|
|
373
|
-
|
|
394
|
+
let result = this.matchSticky(pattern, {}, this);
|
|
374
395
|
|
|
375
396
|
if (!result) this.fail();
|
|
376
397
|
|
|
377
398
|
this.idx += result.length;
|
|
378
399
|
|
|
379
|
-
|
|
400
|
+
this.path.node = Path.from(this.node)
|
|
401
|
+
.advance(buildReferenceTag('#'))
|
|
402
|
+
.advance(buildToken('Space', result)).node;
|
|
380
403
|
|
|
381
404
|
return result;
|
|
382
405
|
}
|
|
383
406
|
|
|
384
407
|
eatMatchTrivia(pattern) {
|
|
385
|
-
|
|
408
|
+
let result = this.matchSticky(pattern, {}, this);
|
|
386
409
|
|
|
387
410
|
if (result) {
|
|
388
411
|
this.idx += result.length;
|
|
389
412
|
|
|
390
|
-
|
|
413
|
+
this.path.node = Path.from(this.node)
|
|
414
|
+
.advance(buildReferenceTag('#'))
|
|
415
|
+
.advance(buildToken('Space', result)).node;
|
|
391
416
|
}
|
|
392
417
|
|
|
393
418
|
return result;
|
|
394
419
|
}
|
|
395
420
|
|
|
396
421
|
eatEscape(pattern) {
|
|
397
|
-
|
|
422
|
+
let result = this.matchSticky(pattern, {}, this);
|
|
398
423
|
|
|
399
424
|
if (!result) this.fail();
|
|
400
425
|
|
|
401
426
|
this.idx += result.length;
|
|
402
427
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
428
|
+
let raw = result;
|
|
429
|
+
let cooked = this.language.cookEscape(result, this.span);
|
|
430
|
+
let attributes = { cooked };
|
|
406
431
|
|
|
407
|
-
|
|
432
|
+
this.path.node = Path.from(this.node)
|
|
433
|
+
.advance(buildReferenceTag('@'))
|
|
434
|
+
.advance(buildToken('Escape', raw, attributes)).node;
|
|
408
435
|
|
|
409
436
|
return result;
|
|
410
437
|
}
|
|
411
438
|
|
|
412
439
|
eatMatchEscape(pattern) {
|
|
413
|
-
|
|
440
|
+
let result = this.matchSticky(pattern, {}, this);
|
|
414
441
|
|
|
415
442
|
if (result) {
|
|
416
443
|
this.idx += result.length;
|
|
417
444
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
445
|
+
let raw = result;
|
|
446
|
+
let cooked = this.language.cookEscape(result, this.span);
|
|
447
|
+
let attributes = { cooked };
|
|
421
448
|
|
|
422
|
-
|
|
449
|
+
this.path.node = Path.from(this.node)
|
|
450
|
+
.advance(buildReferenceTag('@'))
|
|
451
|
+
.advance(buildToken('Escape', raw, attributes)).node;
|
|
423
452
|
}
|
|
424
453
|
|
|
425
454
|
return result;
|
|
426
455
|
}
|
|
427
456
|
|
|
428
457
|
eatLiteral(pattern) {
|
|
429
|
-
|
|
458
|
+
let result = this.matchSticky(pattern, {}, this);
|
|
430
459
|
|
|
431
460
|
if (!result) this.fail();
|
|
432
461
|
|
|
433
462
|
this.idx += result.length;
|
|
434
463
|
|
|
435
|
-
this.node
|
|
464
|
+
this.path.node = buildNode(Tags.push(this.node.value.tags, buildLiteralTag(result)));
|
|
436
465
|
|
|
437
466
|
return result;
|
|
438
467
|
}
|
|
439
468
|
|
|
440
469
|
eatMatchLiteral(pattern) {
|
|
441
|
-
|
|
470
|
+
let result = this.matchSticky(pattern, {}, this);
|
|
442
471
|
|
|
443
472
|
if (result) {
|
|
444
473
|
this.idx += result.length;
|
|
445
474
|
|
|
446
|
-
this.node
|
|
475
|
+
this.path.node = buildNode(Tags.push(this.node.value.tags, buildLiteralTag(result)));
|
|
447
476
|
}
|
|
448
477
|
|
|
449
478
|
return result;
|
|
@@ -466,6 +495,6 @@ export class TemplateParser {
|
|
|
466
495
|
}
|
|
467
496
|
|
|
468
497
|
fail() {
|
|
469
|
-
throw new Error(`miniparser: parsing \`${this.
|
|
498
|
+
throw new Error(`miniparser: parsing \`${this.guardedSlicedQuasi}\` failed`);
|
|
470
499
|
}
|
|
471
500
|
}
|
package/lib/path.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
const { hasOwn } = Object;
|
|
2
|
-
const { isArray } = Array;
|
|
3
|
-
|
|
4
1
|
export class Path {
|
|
5
2
|
constructor(id, attributes, parent = null) {
|
|
6
3
|
this.id = id;
|
|
7
4
|
this.attributes = attributes;
|
|
8
5
|
this.parent = parent;
|
|
6
|
+
this.depth = parent ? parent.depth + 1 : 0;
|
|
9
7
|
|
|
10
8
|
this.node = null;
|
|
11
9
|
}
|
|
@@ -26,6 +24,10 @@ export class Path {
|
|
|
26
24
|
return this.id.type;
|
|
27
25
|
}
|
|
28
26
|
|
|
27
|
+
get name() {
|
|
28
|
+
return this.id.name;
|
|
29
|
+
}
|
|
30
|
+
|
|
29
31
|
generate(id, attrs) {
|
|
30
32
|
return new Path(id, attrs, this);
|
|
31
33
|
}
|
|
@@ -34,36 +36,3 @@ export class Path {
|
|
|
34
36
|
return new Path(id, attrs);
|
|
35
37
|
}
|
|
36
38
|
}
|
|
37
|
-
|
|
38
|
-
export class PathResolver {
|
|
39
|
-
constructor(node) {
|
|
40
|
-
this.node = node;
|
|
41
|
-
this.counters = {};
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
get(path) {
|
|
45
|
-
const { node, counters } = this;
|
|
46
|
-
|
|
47
|
-
const { isArray: pathIsArray, name } = path;
|
|
48
|
-
|
|
49
|
-
if (!hasOwn(node.properties, name)) {
|
|
50
|
-
throw new Error(`cannot resolve {path: ${name}}`);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
let value = node.properties[name];
|
|
54
|
-
|
|
55
|
-
if (pathIsArray) {
|
|
56
|
-
if (!isArray(value)) {
|
|
57
|
-
throw new Error(`cannot resolve {path: ${name}}: not an array`);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const counter = counters[name] ?? 0;
|
|
61
|
-
|
|
62
|
-
counters[name] = counter + 1;
|
|
63
|
-
|
|
64
|
-
value = value[counter];
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return value;
|
|
68
|
-
}
|
|
69
|
-
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bablr/boot",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Compile-time tools for bootstrapping BABLR VM",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=12.0.0"
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
],
|
|
21
21
|
"sideEffects": false,
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@bablr/agast-helpers": "0.
|
|
24
|
-
"@bablr/agast-vm-helpers": "0.
|
|
25
|
-
"@iter-tools/imm-stack": "1.
|
|
23
|
+
"@bablr/agast-helpers": "0.10.0",
|
|
24
|
+
"@bablr/agast-vm-helpers": "0.10.0",
|
|
25
|
+
"@iter-tools/imm-stack": "1.2.0",
|
|
26
26
|
"escape-string-regexp": "5.0.0",
|
|
27
27
|
"iter-tools-es": "^7.0.2"
|
|
28
28
|
},
|
|
@@ -40,7 +40,10 @@
|
|
|
40
40
|
"expect": "^29.6.2",
|
|
41
41
|
"prettier": "^2.0.5"
|
|
42
42
|
},
|
|
43
|
-
"repository":
|
|
43
|
+
"repository": {
|
|
44
|
+
"type": "git",
|
|
45
|
+
"url": "git+ssh://git@github.com/bablr-lang/boot.git"
|
|
46
|
+
},
|
|
44
47
|
"homepage": "https://github.com/bablr-lang/boot",
|
|
45
48
|
"author": "Conrad Buck <conartist6@gmail.com>",
|
|
46
49
|
"license": "MIT"
|