parseman 0.5.0 → 0.6.1
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/README.md +19 -15
- package/dist/combinators/choice.d.ts.map +1 -1
- package/dist/combinators/completions.d.ts +1 -1
- package/dist/combinators/completions.d.ts.map +1 -1
- package/dist/combinators/grammar.d.ts.map +1 -1
- package/dist/combinators/keywords.d.ts +22 -0
- package/dist/combinators/keywords.d.ts.map +1 -1
- package/dist/combinators/literal.d.ts.map +1 -1
- package/dist/combinators/map.d.ts +8 -2
- package/dist/combinators/map.d.ts.map +1 -1
- package/dist/combinators/node.d.ts +10 -11
- package/dist/combinators/node.d.ts.map +1 -1
- package/dist/combinators/not.d.ts +3 -3
- package/dist/combinators/not.d.ts.map +1 -1
- package/dist/combinators/recover.d.ts +2 -2
- package/dist/combinators/recover.d.ts.map +1 -1
- package/dist/combinators/regex.d.ts.map +1 -1
- package/dist/combinators/repeat.d.ts +4 -4
- package/dist/combinators/repeat.d.ts.map +1 -1
- package/dist/combinators/scanTo.d.ts.map +1 -1
- package/dist/combinators/sequence.d.ts.map +1 -1
- package/dist/combinators/trivia-skip.d.ts +16 -10
- package/dist/combinators/trivia-skip.d.ts.map +1 -1
- package/dist/combinators/withCtx.d.ts +2 -2
- package/dist/combinators/withCtx.d.ts.map +1 -1
- package/dist/compiler/codegen.d.ts +4 -2
- package/dist/compiler/codegen.d.ts.map +1 -1
- package/dist/compiler/inline-build.d.ts +11 -0
- package/dist/compiler/inline-build.d.ts.map +1 -0
- package/dist/compiler/inline-callback.d.ts +12 -0
- package/dist/compiler/inline-callback.d.ts.map +1 -0
- package/dist/compiler/trivia-fast-path.d.ts +24 -0
- package/dist/compiler/trivia-fast-path.d.ts.map +1 -0
- package/dist/cst/capture-buffer.d.ts +46 -0
- package/dist/cst/capture-buffer.d.ts.map +1 -0
- package/dist/cst/trivia-entries.d.ts +20 -0
- package/dist/cst/trivia-entries.d.ts.map +1 -0
- package/dist/cst/trivia-index.d.ts +11 -11
- package/dist/cst/trivia-index.d.ts.map +1 -1
- package/dist/cst/trivia-kinds.d.ts +47 -0
- package/dist/cst/trivia-kinds.d.ts.map +1 -0
- package/dist/cst/types.d.ts +9 -13
- package/dist/cst/types.d.ts.map +1 -1
- package/dist/functional/doc.d.ts +2 -20
- package/dist/functional/doc.d.ts.map +1 -1
- package/dist/index.cjs +1238 -662
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +4 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1256 -6241
- package/dist/index.js.map +4 -4
- package/dist/plugin/evaluator.d.ts +7 -0
- package/dist/plugin/evaluator.d.ts.map +1 -1
- package/dist/plugin/index.cjs +1249 -369
- package/dist/plugin/index.cjs.map +4 -4
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +1249 -369
- package/dist/plugin/index.js.map +4 -4
- package/dist/types.d.ts +32 -9
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -1
- package/dist/cst/grammar.d.ts +0 -115
- package/dist/cst/grammar.d.ts.map +0 -1
- package/dist/cst/incremental.d.ts +0 -40
- package/dist/cst/incremental.d.ts.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -30,7 +30,6 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
-
Parser: () => Parser,
|
|
34
33
|
annotateSpan: () => annotateSpan,
|
|
35
34
|
balanced: () => balanced,
|
|
36
35
|
buildLineIndex: () => buildLineIndex,
|
|
@@ -41,8 +40,10 @@ __export(index_exports, {
|
|
|
41
40
|
guard: () => guard,
|
|
42
41
|
isParseError: () => isParseError,
|
|
43
42
|
keywords: () => keywords,
|
|
43
|
+
label: () => label,
|
|
44
44
|
literal: () => literal,
|
|
45
45
|
makeFunctionalDoc: () => makeFunctionalDoc,
|
|
46
|
+
makeWord: () => makeWord,
|
|
46
47
|
many: () => many,
|
|
47
48
|
node: () => node,
|
|
48
49
|
not: () => not,
|
|
@@ -61,7 +62,9 @@ __export(index_exports, {
|
|
|
61
62
|
skip: () => skip,
|
|
62
63
|
transform: () => transform,
|
|
63
64
|
trivia: () => trivia,
|
|
64
|
-
|
|
65
|
+
triviaEntries: () => triviaEntries,
|
|
66
|
+
withCtx: () => withCtx,
|
|
67
|
+
word: () => word
|
|
65
68
|
});
|
|
66
69
|
module.exports = __toCommonJS(index_exports);
|
|
67
70
|
|
|
@@ -125,6 +128,151 @@ function failAt(ctx, expected, pos) {
|
|
|
125
128
|
return r;
|
|
126
129
|
}
|
|
127
130
|
|
|
131
|
+
// src/cst/capture-buffer.ts
|
|
132
|
+
var EMPTY = [];
|
|
133
|
+
var EMPTY_TL = [];
|
|
134
|
+
function cstCaptureActive(ctx) {
|
|
135
|
+
return ctx._cstBuf !== void 0 || ctx._cstLeaves !== void 0;
|
|
136
|
+
}
|
|
137
|
+
function beginCstNodeCapture(ctx) {
|
|
138
|
+
const saved = {
|
|
139
|
+
ch: ctx._cstChildren,
|
|
140
|
+
lv: ctx._cstLeaves,
|
|
141
|
+
raw: ctx._cstRawChildren,
|
|
142
|
+
tl: ctx._cstTriviaLog,
|
|
143
|
+
cap: ctx.captureTrivia,
|
|
144
|
+
buf: ctx._cstBuf
|
|
145
|
+
};
|
|
146
|
+
ctx._cstBuf = {};
|
|
147
|
+
ctx._cstChildren = void 0;
|
|
148
|
+
ctx._cstLeaves = void 0;
|
|
149
|
+
ctx._cstRawChildren = void 0;
|
|
150
|
+
ctx._cstTriviaLog = void 0;
|
|
151
|
+
ctx.captureTrivia = true;
|
|
152
|
+
return saved;
|
|
153
|
+
}
|
|
154
|
+
function finishCstBuf(buf) {
|
|
155
|
+
if (!buf) return { children: EMPTY, rawChildren: EMPTY, triviaLog: EMPTY_TL };
|
|
156
|
+
const children = buf.ch ?? (buf.single !== void 0 ? [buf.single] : EMPTY);
|
|
157
|
+
const rawChildren = buf.raw ?? (buf.rawSingle !== void 0 ? [buf.rawSingle] : EMPTY);
|
|
158
|
+
const triviaLog = buf.tl ?? EMPTY_TL;
|
|
159
|
+
return { children, rawChildren, triviaLog };
|
|
160
|
+
}
|
|
161
|
+
function endCstNodeCapture(ctx, saved) {
|
|
162
|
+
const materialized = finishCstBuf(ctx._cstBuf);
|
|
163
|
+
ctx._cstBuf = saved.buf;
|
|
164
|
+
ctx._cstChildren = saved.ch;
|
|
165
|
+
ctx._cstLeaves = saved.lv;
|
|
166
|
+
ctx._cstRawChildren = saved.raw;
|
|
167
|
+
ctx._cstTriviaLog = saved.tl;
|
|
168
|
+
ctx.captureTrivia = saved.cap;
|
|
169
|
+
return materialized;
|
|
170
|
+
}
|
|
171
|
+
function pushCstLeaf(ctx, leaf) {
|
|
172
|
+
pushCstChild(ctx, leaf, leaf);
|
|
173
|
+
}
|
|
174
|
+
function pushCstChild(ctx, built, rawEntry) {
|
|
175
|
+
const b = ctx._cstBuf;
|
|
176
|
+
if (b) {
|
|
177
|
+
if (b.ch) b.ch.push(built);
|
|
178
|
+
else if (b.single !== void 0) {
|
|
179
|
+
b.ch = [b.single, built];
|
|
180
|
+
b.single = void 0;
|
|
181
|
+
} else b.single = built;
|
|
182
|
+
if (b.raw) b.raw.push(rawEntry);
|
|
183
|
+
else if (b.rawSingle !== void 0) {
|
|
184
|
+
b.raw = [b.rawSingle, rawEntry];
|
|
185
|
+
b.rawSingle = void 0;
|
|
186
|
+
} else b.rawSingle = rawEntry;
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
if (ctx._cstChildren) ctx._cstChildren.push(built);
|
|
190
|
+
else if (ctx._cstLeaves) ctx._cstLeaves.push(built);
|
|
191
|
+
if (ctx._cstRawChildren) ctx._cstRawChildren.push(rawEntry);
|
|
192
|
+
}
|
|
193
|
+
function cstRawLen(ctx) {
|
|
194
|
+
const b = ctx._cstBuf;
|
|
195
|
+
if (b) {
|
|
196
|
+
if (b.raw) return b.raw.length;
|
|
197
|
+
return b.rawSingle !== void 0 ? 1 : 0;
|
|
198
|
+
}
|
|
199
|
+
return ctx._cstRawChildren?.length ?? 0;
|
|
200
|
+
}
|
|
201
|
+
function cstLeavesLen(ctx) {
|
|
202
|
+
const b = ctx._cstBuf;
|
|
203
|
+
if (b) {
|
|
204
|
+
if (b.ch) return b.ch.length;
|
|
205
|
+
return b.single !== void 0 ? 1 : 0;
|
|
206
|
+
}
|
|
207
|
+
return ctx._cstLeaves?.length ?? 0;
|
|
208
|
+
}
|
|
209
|
+
function cstTlLen(ctx) {
|
|
210
|
+
const b = ctx._cstBuf;
|
|
211
|
+
if (b) return b.tl?.length ?? 0;
|
|
212
|
+
return ctx._cstTriviaLog?.length ?? 0;
|
|
213
|
+
}
|
|
214
|
+
function saveCstMark(ctx) {
|
|
215
|
+
return {
|
|
216
|
+
raw: cstRawLen(ctx),
|
|
217
|
+
tlog: cstTlLen(ctx),
|
|
218
|
+
leaves: cstLeavesLen(ctx)
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
function rollbackBufList(b, keyMulti, keySingle, len) {
|
|
222
|
+
const arr = b[keyMulti];
|
|
223
|
+
if (arr) {
|
|
224
|
+
if (len === 0) b[keyMulti] = void 0;
|
|
225
|
+
else if (len === 1) {
|
|
226
|
+
b[keySingle] = arr[0];
|
|
227
|
+
b[keyMulti] = void 0;
|
|
228
|
+
} else arr.length = len;
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
if (len === 0) b[keySingle] = void 0;
|
|
232
|
+
}
|
|
233
|
+
function rollbackCstCapture(ctx, mark) {
|
|
234
|
+
const b = ctx._cstBuf;
|
|
235
|
+
if (b) {
|
|
236
|
+
rollbackBufList(b, "raw", "rawSingle", mark.raw);
|
|
237
|
+
rollbackBufList(b, "ch", "single", mark.leaves);
|
|
238
|
+
if (b.tl) {
|
|
239
|
+
if (mark.tlog === 0) b.tl = void 0;
|
|
240
|
+
else b.tl.length = mark.tlog;
|
|
241
|
+
}
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
if (ctx._cstRawChildren) ctx._cstRawChildren.length = mark.raw;
|
|
245
|
+
if (ctx._cstTriviaLog) ctx._cstTriviaLog.length = mark.tlog;
|
|
246
|
+
if (ctx._cstLeaves) ctx._cstLeaves.length = mark.leaves;
|
|
247
|
+
}
|
|
248
|
+
function pushCstTriviaEntry(ctx, start, end, kindIndex) {
|
|
249
|
+
const insertIdx = cstRawLen(ctx);
|
|
250
|
+
const b = ctx._cstBuf;
|
|
251
|
+
const withKind = ctx.triviaKindLabels !== void 0 && kindIndex !== void 0;
|
|
252
|
+
if (b) {
|
|
253
|
+
if (!b.tl) {
|
|
254
|
+
b.tl = withKind ? [start, end, insertIdx, kindIndex] : [start, end, insertIdx];
|
|
255
|
+
} else if (withKind) {
|
|
256
|
+
b.tl.push(start, end, insertIdx, kindIndex);
|
|
257
|
+
} else {
|
|
258
|
+
b.tl.push(start, end, insertIdx);
|
|
259
|
+
}
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
if (ctx._cstTriviaLog) {
|
|
263
|
+
if (withKind) ctx._cstTriviaLog.push(start, end, insertIdx, kindIndex);
|
|
264
|
+
else ctx._cstTriviaLog.push(start, end, insertIdx);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
function pushTriviaLogEntry(ctx, start, end, kindIndex) {
|
|
268
|
+
if (!ctx._triviaLog) return;
|
|
269
|
+
if (ctx.triviaKindLabels !== void 0 && kindIndex !== void 0) {
|
|
270
|
+
ctx._triviaLog.push(start, end, kindIndex);
|
|
271
|
+
} else {
|
|
272
|
+
ctx._triviaLog.push(start, end);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
128
276
|
// src/combinators/literal.ts
|
|
129
277
|
var _collatorCache = null;
|
|
130
278
|
function collator() {
|
|
@@ -164,8 +312,7 @@ function literal(value, opts = {}) {
|
|
|
164
312
|
if (matched) {
|
|
165
313
|
const span = { start: pos, end };
|
|
166
314
|
const leaf = { _tag: "leaf", value: slice, span };
|
|
167
|
-
if (ctx
|
|
168
|
-
if (ctx._cstRawChildren) ctx._cstRawChildren.push(leaf);
|
|
315
|
+
if (cstCaptureActive(ctx)) pushCstLeaf(ctx, leaf);
|
|
169
316
|
return { ok: true, value: slice, span };
|
|
170
317
|
}
|
|
171
318
|
return failAt(ctx, [JSON.stringify(value)], pos);
|
|
@@ -307,14 +454,19 @@ function regex(pattern, flags = "") {
|
|
|
307
454
|
}
|
|
308
455
|
const span = { start: pos, end: pos + m[0].length };
|
|
309
456
|
const leaf = { _tag: "leaf", value: m[0], span };
|
|
310
|
-
if (ctx
|
|
311
|
-
if (ctx._cstRawChildren) ctx._cstRawChildren.push(leaf);
|
|
457
|
+
if (cstCaptureActive(ctx)) pushCstLeaf(ctx, leaf);
|
|
312
458
|
return { ok: true, value: m[0], span };
|
|
313
459
|
}
|
|
314
460
|
};
|
|
315
461
|
}
|
|
316
462
|
|
|
317
463
|
// src/combinators/keywords.ts
|
|
464
|
+
function word(str, boundary = "_0-9A-Za-z") {
|
|
465
|
+
return keywords([str], { boundary });
|
|
466
|
+
}
|
|
467
|
+
function makeWord(boundary = "_0-9A-Za-z") {
|
|
468
|
+
return (str) => keywords([str], { boundary });
|
|
469
|
+
}
|
|
318
470
|
function escapeRe(s) {
|
|
319
471
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
320
472
|
}
|
|
@@ -350,109 +502,15 @@ function keywords(words, opts = {}) {
|
|
|
350
502
|
const value = m[0];
|
|
351
503
|
const span = { start: pos, end: pos + value.length };
|
|
352
504
|
const leaf = { _tag: "leaf", value, span };
|
|
353
|
-
if (ctx
|
|
354
|
-
if (ctx._cstRawChildren) ctx._cstRawChildren.push(leaf);
|
|
505
|
+
if (cstCaptureActive(ctx)) pushCstLeaf(ctx, leaf);
|
|
355
506
|
return { ok: true, value, span };
|
|
356
507
|
}
|
|
357
508
|
};
|
|
358
509
|
}
|
|
359
510
|
|
|
360
|
-
// src/combinators/trivia-skip.ts
|
|
361
|
-
var NOOP_COMMIT = () => {
|
|
362
|
-
};
|
|
363
|
-
function scanTrivia(input, cur, ctx) {
|
|
364
|
-
const triviaP = ctx.trivia;
|
|
365
|
-
if (!triviaP) return { end: cur, commit: NOOP_COMMIT };
|
|
366
|
-
const log = ctx._triviaLog;
|
|
367
|
-
if (log !== void 0) {
|
|
368
|
-
const tr2 = triviaP.parse(input, cur, { trackLines: false, state: ctx.state });
|
|
369
|
-
if (!tr2.ok || tr2.span.end === cur) return { end: cur, commit: NOOP_COMMIT };
|
|
370
|
-
const end = tr2.span.end;
|
|
371
|
-
return {
|
|
372
|
-
end,
|
|
373
|
-
commit: () => {
|
|
374
|
-
log.push(cur, end);
|
|
375
|
-
}
|
|
376
|
-
};
|
|
377
|
-
}
|
|
378
|
-
if (ctx.captureTrivia && ctx._cstRawChildren) {
|
|
379
|
-
const sink = [];
|
|
380
|
-
const tr2 = triviaP.parse(input, cur, {
|
|
381
|
-
trackLines: ctx.trackLines,
|
|
382
|
-
state: ctx.state,
|
|
383
|
-
_cstLeaves: sink
|
|
384
|
-
});
|
|
385
|
-
if (tr2.ok && tr2.span.end > cur) {
|
|
386
|
-
const out = ctx._cstRawChildren;
|
|
387
|
-
return {
|
|
388
|
-
end: tr2.span.end,
|
|
389
|
-
commit: () => {
|
|
390
|
-
for (const tok of sink) {
|
|
391
|
-
if (tok._tag === "leaf" && tok.span.end > tok.span.start) {
|
|
392
|
-
out.push({ _tag: "trivia", value: tok.value, span: tok.span });
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
};
|
|
397
|
-
}
|
|
398
|
-
return { end: cur, commit: NOOP_COMMIT };
|
|
399
|
-
}
|
|
400
|
-
const tr = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
|
|
401
|
-
return { end: tr.ok ? tr.span.end : cur, commit: NOOP_COMMIT };
|
|
402
|
-
}
|
|
403
|
-
function consumeTrivia(input, cur, ctx) {
|
|
404
|
-
const scan = scanTrivia(input, cur, ctx);
|
|
405
|
-
scan.commit();
|
|
406
|
-
return scan.end;
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
// src/combinators/sequence.ts
|
|
410
|
-
function sequence(...parsers) {
|
|
411
|
-
const meta = {
|
|
412
|
-
firstSet: parsers[0]?._meta.firstSet ?? empty(),
|
|
413
|
-
canMatchNewline: parsers.some((p) => p._meta.canMatchNewline),
|
|
414
|
-
isTrivia: false
|
|
415
|
-
};
|
|
416
|
-
return {
|
|
417
|
-
_tag: "sequence",
|
|
418
|
-
_meta: meta,
|
|
419
|
-
_def: { tag: "sequence", parsers },
|
|
420
|
-
parse(input, pos, ctx) {
|
|
421
|
-
const values = [];
|
|
422
|
-
let cur = pos;
|
|
423
|
-
for (let i = 0; i < parsers.length; i++) {
|
|
424
|
-
if (ctx.trivia && i > 0) {
|
|
425
|
-
const scan = scanTrivia(input, cur, ctx);
|
|
426
|
-
const raw = ctx._cstRawChildren;
|
|
427
|
-
const mark = raw ? raw.length : 0;
|
|
428
|
-
scan.commit();
|
|
429
|
-
const result2 = parsers[i].parse(input, scan.end, ctx);
|
|
430
|
-
if (!result2.ok) return result2;
|
|
431
|
-
if (result2.span.end > scan.end) {
|
|
432
|
-
cur = result2.span.end;
|
|
433
|
-
} else if (raw) {
|
|
434
|
-
raw.length = mark;
|
|
435
|
-
}
|
|
436
|
-
values.push(result2.value);
|
|
437
|
-
continue;
|
|
438
|
-
}
|
|
439
|
-
const result = parsers[i].parse(input, cur, ctx);
|
|
440
|
-
if (!result.ok) return result;
|
|
441
|
-
values.push(result.value);
|
|
442
|
-
cur = result.span.end;
|
|
443
|
-
}
|
|
444
|
-
return {
|
|
445
|
-
ok: true,
|
|
446
|
-
value: values,
|
|
447
|
-
span: { start: pos, end: cur }
|
|
448
|
-
};
|
|
449
|
-
}
|
|
450
|
-
};
|
|
451
|
-
}
|
|
452
|
-
|
|
453
511
|
// src/combinators/choice.ts
|
|
454
512
|
function choice(...args) {
|
|
455
|
-
const parsers = args.map((a) => "gate" in a ? a.
|
|
513
|
+
const parsers = args.map((a) => "gate" in a ? a.combinator : a);
|
|
456
514
|
const gates = args.map((a) => "gate" in a ? a.gate : null);
|
|
457
515
|
const hasGates = gates.some((g) => g !== null);
|
|
458
516
|
const disjoint = !hasGates && areDisjoint(parsers.map((p) => p._meta.firstSet));
|
|
@@ -536,19 +594,19 @@ function choice(...args) {
|
|
|
536
594
|
}
|
|
537
595
|
for (let i = 0; i < parsers.length; i++) {
|
|
538
596
|
if (gates[i] && !gates[i](ctx.state)) continue;
|
|
539
|
-
const
|
|
540
|
-
const
|
|
597
|
+
const mark = saveCstMark(ctx);
|
|
598
|
+
const logLen = ctx._triviaLog?.length;
|
|
541
599
|
const result = parsers[i].parse(input, pos, ctx);
|
|
542
600
|
if (!result.ok) {
|
|
543
|
-
|
|
544
|
-
if (
|
|
601
|
+
rollbackCstCapture(ctx, mark);
|
|
602
|
+
if (logLen !== void 0 && ctx._triviaLog) ctx._triviaLog.length = logLen;
|
|
545
603
|
expected.push(...result.expected);
|
|
546
604
|
continue;
|
|
547
605
|
}
|
|
548
606
|
const checks = autoNot[i];
|
|
549
607
|
if (checks && autoNotFires(input, result.span.end, checks)) {
|
|
550
|
-
|
|
551
|
-
if (
|
|
608
|
+
rollbackCstCapture(ctx, mark);
|
|
609
|
+
if (logLen !== void 0 && ctx._triviaLog) ctx._triviaLog.length = logLen;
|
|
552
610
|
continue;
|
|
553
611
|
}
|
|
554
612
|
return result;
|
|
@@ -627,6 +685,7 @@ function getCoreRegexDef(p) {
|
|
|
627
685
|
const def = p._def;
|
|
628
686
|
if (def.tag === "regex") return { source: def.source, flags: def.flags };
|
|
629
687
|
if (def.tag === "transform") return getCoreRegexDef(def.parser);
|
|
688
|
+
if (def.tag === "label") return getCoreRegexDef(def.parser);
|
|
630
689
|
return null;
|
|
631
690
|
}
|
|
632
691
|
function applyTransforms(p, value, span) {
|
|
@@ -680,46 +739,275 @@ function areDisjoint(sets) {
|
|
|
680
739
|
return true;
|
|
681
740
|
}
|
|
682
741
|
|
|
742
|
+
// src/cst/trivia-kinds.ts
|
|
743
|
+
function unwrapTrivia(p) {
|
|
744
|
+
let cur = p;
|
|
745
|
+
while (cur._def.tag === "trivia") cur = cur._def.parser;
|
|
746
|
+
return cur;
|
|
747
|
+
}
|
|
748
|
+
function peelLabel(p) {
|
|
749
|
+
if (p._def.tag === "label") return { label: p._def.label, parser: p._def.parser };
|
|
750
|
+
return null;
|
|
751
|
+
}
|
|
752
|
+
function analyzeLabeledTrivia(trivia2) {
|
|
753
|
+
let core = unwrapTrivia(trivia2);
|
|
754
|
+
let minRepeats = 1;
|
|
755
|
+
if (core._def.tag === "oneOrMore") {
|
|
756
|
+
core = core._def.parser;
|
|
757
|
+
minRepeats = 1;
|
|
758
|
+
} else if (core._def.tag === "many") {
|
|
759
|
+
core = core._def.parser;
|
|
760
|
+
minRepeats = 0;
|
|
761
|
+
}
|
|
762
|
+
const arms = [];
|
|
763
|
+
if (core._def.tag === "choice") {
|
|
764
|
+
for (let i = 0; i < core._def.parsers.length; i++) {
|
|
765
|
+
const peeled = peelLabel(core._def.parsers[i]);
|
|
766
|
+
if (!peeled) return null;
|
|
767
|
+
arms.push({ label: peeled.label, kindIndex: i, parser: peeled.parser });
|
|
768
|
+
}
|
|
769
|
+
} else {
|
|
770
|
+
const peeled = peelLabel(core);
|
|
771
|
+
if (!peeled) return null;
|
|
772
|
+
arms.push({ label: peeled.label, kindIndex: 0, parser: peeled.parser });
|
|
773
|
+
}
|
|
774
|
+
return { labels: arms.map((a) => a.label), arms, minRepeats };
|
|
775
|
+
}
|
|
776
|
+
function matchArmAt(input, pos, arm) {
|
|
777
|
+
const r = arm.parse(input, pos, { trackLines: false });
|
|
778
|
+
if (!r.ok || r.span.end <= pos) return null;
|
|
779
|
+
return { end: r.span.end };
|
|
780
|
+
}
|
|
781
|
+
function scanLabeledTriviaChunks(input, cur, spec) {
|
|
782
|
+
const chunks = [];
|
|
783
|
+
let pos = cur;
|
|
784
|
+
while (pos < input.length) {
|
|
785
|
+
let matched = null;
|
|
786
|
+
for (const arm of spec.arms) {
|
|
787
|
+
const m = matchArmAt(input, pos, arm.parser);
|
|
788
|
+
if (m) {
|
|
789
|
+
matched = { end: m.end, kindIndex: arm.kindIndex };
|
|
790
|
+
break;
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
if (!matched) break;
|
|
794
|
+
chunks.push({ start: pos, end: matched.end, kindIndex: matched.kindIndex });
|
|
795
|
+
pos = matched.end;
|
|
796
|
+
}
|
|
797
|
+
if (chunks.length < spec.minRepeats) {
|
|
798
|
+
return { end: cur, chunks: [] };
|
|
799
|
+
}
|
|
800
|
+
return { end: pos, chunks };
|
|
801
|
+
}
|
|
802
|
+
function scanFastWsCommentsChunks(input, cur, wsKind, commentKind) {
|
|
803
|
+
const chunks = [];
|
|
804
|
+
let pos = cur;
|
|
805
|
+
while (pos < input.length) {
|
|
806
|
+
const c = input.charCodeAt(pos);
|
|
807
|
+
if (c === 32 || c === 9 || c === 10 || c === 13 || c === 12) {
|
|
808
|
+
const start = pos;
|
|
809
|
+
pos++;
|
|
810
|
+
while (pos < input.length) {
|
|
811
|
+
const c2 = input.charCodeAt(pos);
|
|
812
|
+
if (c2 === 32 || c2 === 9 || c2 === 10 || c2 === 13 || c2 === 12) pos++;
|
|
813
|
+
else break;
|
|
814
|
+
}
|
|
815
|
+
chunks.push({ start, end: pos, kindIndex: wsKind });
|
|
816
|
+
continue;
|
|
817
|
+
}
|
|
818
|
+
if (c === 47 && input.charCodeAt(pos + 1) === 42) {
|
|
819
|
+
const start = pos;
|
|
820
|
+
let j = pos + 2;
|
|
821
|
+
while (j + 1 < input.length && !(input.charCodeAt(j) === 42 && input.charCodeAt(j + 1) === 47)) j++;
|
|
822
|
+
pos = j + 2 <= input.length ? j + 2 : input.length;
|
|
823
|
+
chunks.push({ start, end: pos, kindIndex: commentKind });
|
|
824
|
+
continue;
|
|
825
|
+
}
|
|
826
|
+
break;
|
|
827
|
+
}
|
|
828
|
+
return { end: pos, chunks };
|
|
829
|
+
}
|
|
830
|
+
function tryFastLabeledScan(input, cur, trivia2) {
|
|
831
|
+
const spec = analyzeLabeledTrivia(trivia2);
|
|
832
|
+
if (!spec || spec.arms.length !== 2) return null;
|
|
833
|
+
const wsArm = spec.arms.find((a) => {
|
|
834
|
+
const src = getCoreRegexDef(a.parser)?.source;
|
|
835
|
+
return src != null && !src.includes("\\*");
|
|
836
|
+
});
|
|
837
|
+
const commentArm = spec.arms.find((a) => {
|
|
838
|
+
const src = getCoreRegexDef(a.parser)?.source;
|
|
839
|
+
return src != null && src.includes("\\*");
|
|
840
|
+
});
|
|
841
|
+
if (!wsArm || !commentArm) return null;
|
|
842
|
+
const { chunks } = scanFastWsCommentsChunks(input, cur, wsArm.kindIndex, commentArm.kindIndex);
|
|
843
|
+
if (chunks.length < spec.minRepeats) return { end: cur, chunks: [] };
|
|
844
|
+
return scanFastWsCommentsChunks(input, cur, wsArm.kindIndex, commentArm.kindIndex);
|
|
845
|
+
}
|
|
846
|
+
function recordTriviaChunks(ctx, chunks) {
|
|
847
|
+
const kinds = ctx.triviaKindLabels;
|
|
848
|
+
for (const ch of chunks) {
|
|
849
|
+
pushTriviaLogEntry(ctx, ch.start, ch.end, kinds ? ch.kindIndex : void 0);
|
|
850
|
+
if (ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0)) {
|
|
851
|
+
pushCstTriviaEntry(ctx, ch.start, ch.end, kinds ? ch.kindIndex : void 0);
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
// src/combinators/trivia-skip.ts
|
|
857
|
+
var NOOP_COMMIT = () => {
|
|
858
|
+
};
|
|
859
|
+
function needsDeferredTriviaCommit(ctx) {
|
|
860
|
+
return ctx._triviaLog !== void 0 || ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0;
|
|
861
|
+
}
|
|
862
|
+
function saveTriviaMark(ctx) {
|
|
863
|
+
const m = saveCstMark(ctx);
|
|
864
|
+
return { raw: m.raw, tlog: m.tlog, leaves: m.leaves, log: ctx._triviaLog ? ctx._triviaLog.length : 0 };
|
|
865
|
+
}
|
|
866
|
+
function rollbackTrivia(ctx, mark) {
|
|
867
|
+
rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves });
|
|
868
|
+
if (ctx._triviaLog) ctx._triviaLog.length = mark.log;
|
|
869
|
+
}
|
|
870
|
+
function scanWithLabels(input, cur, ctx) {
|
|
871
|
+
const triviaP = ctx.trivia;
|
|
872
|
+
const spec = analyzeLabeledTrivia(triviaP);
|
|
873
|
+
if (!spec) return { end: cur, commit: NOOP_COMMIT };
|
|
874
|
+
const fast = tryFastLabeledScan(input, cur, triviaP);
|
|
875
|
+
const { end, chunks } = fast ?? scanLabeledTriviaChunks(input, cur, spec);
|
|
876
|
+
if (end === cur) return { end: cur, commit: NOOP_COMMIT };
|
|
877
|
+
return {
|
|
878
|
+
end,
|
|
879
|
+
commit: () => recordTriviaChunks(ctx, chunks)
|
|
880
|
+
};
|
|
881
|
+
}
|
|
882
|
+
function advanceTrivia(input, cur, ctx) {
|
|
883
|
+
const triviaP = ctx.trivia;
|
|
884
|
+
if (!triviaP) return cur;
|
|
885
|
+
if (ctx.triviaKindLabels) {
|
|
886
|
+
const scan = scanWithLabels(input, cur, ctx);
|
|
887
|
+
return scan.end;
|
|
888
|
+
}
|
|
889
|
+
const tr = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
|
|
890
|
+
return tr.ok && tr.span.end > cur ? tr.span.end : cur;
|
|
891
|
+
}
|
|
892
|
+
function scanTrivia(input, cur, ctx) {
|
|
893
|
+
const triviaP = ctx.trivia;
|
|
894
|
+
if (!triviaP) return { end: cur, commit: NOOP_COMMIT };
|
|
895
|
+
const log = ctx._triviaLog;
|
|
896
|
+
const captureTl = ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0);
|
|
897
|
+
if (ctx.triviaKindLabels && (log !== void 0 || captureTl)) {
|
|
898
|
+
return scanWithLabels(input, cur, ctx);
|
|
899
|
+
}
|
|
900
|
+
if (log !== void 0 || captureTl) {
|
|
901
|
+
const tr2 = triviaP.parse(input, cur, {
|
|
902
|
+
trackLines: log !== void 0 ? false : ctx.trackLines,
|
|
903
|
+
state: ctx.state
|
|
904
|
+
});
|
|
905
|
+
if (!tr2.ok || tr2.span.end === cur) return { end: cur, commit: NOOP_COMMIT };
|
|
906
|
+
const end = tr2.span.end;
|
|
907
|
+
return {
|
|
908
|
+
end,
|
|
909
|
+
commit: () => {
|
|
910
|
+
pushTriviaLogEntry(ctx, cur, end);
|
|
911
|
+
if (captureTl) pushCstTriviaEntry(ctx, cur, end);
|
|
912
|
+
}
|
|
913
|
+
};
|
|
914
|
+
}
|
|
915
|
+
const tr = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
|
|
916
|
+
return { end: tr.ok ? tr.span.end : cur, commit: NOOP_COMMIT };
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
// src/combinators/sequence.ts
|
|
920
|
+
function sequence(...parsers) {
|
|
921
|
+
const meta = {
|
|
922
|
+
firstSet: parsers[0]?._meta.firstSet ?? empty(),
|
|
923
|
+
canMatchNewline: parsers.some((p) => p._meta.canMatchNewline),
|
|
924
|
+
isTrivia: false
|
|
925
|
+
};
|
|
926
|
+
return {
|
|
927
|
+
_tag: "sequence",
|
|
928
|
+
_meta: meta,
|
|
929
|
+
_def: { tag: "sequence", parsers },
|
|
930
|
+
parse(input, pos, ctx) {
|
|
931
|
+
const values = [];
|
|
932
|
+
let cur = pos;
|
|
933
|
+
for (let i = 0; i < parsers.length; i++) {
|
|
934
|
+
if (ctx.trivia && i > 0) {
|
|
935
|
+
let scanEnd;
|
|
936
|
+
let mark = saveTriviaMark(ctx);
|
|
937
|
+
if (needsDeferredTriviaCommit(ctx)) {
|
|
938
|
+
const scan = scanTrivia(input, cur, ctx);
|
|
939
|
+
scan.commit();
|
|
940
|
+
scanEnd = scan.end;
|
|
941
|
+
} else {
|
|
942
|
+
scanEnd = advanceTrivia(input, cur, ctx);
|
|
943
|
+
}
|
|
944
|
+
const result2 = parsers[i].parse(input, scanEnd, ctx);
|
|
945
|
+
if (!result2.ok) return result2;
|
|
946
|
+
if (result2.span.end > scanEnd) {
|
|
947
|
+
cur = result2.span.end;
|
|
948
|
+
} else {
|
|
949
|
+
rollbackTrivia(ctx, mark);
|
|
950
|
+
}
|
|
951
|
+
values.push(result2.value);
|
|
952
|
+
continue;
|
|
953
|
+
}
|
|
954
|
+
const result = parsers[i].parse(input, cur, ctx);
|
|
955
|
+
if (!result.ok) return result;
|
|
956
|
+
values.push(result.value);
|
|
957
|
+
cur = result.span.end;
|
|
958
|
+
}
|
|
959
|
+
return {
|
|
960
|
+
ok: true,
|
|
961
|
+
value: values,
|
|
962
|
+
span: { start: pos, end: cur }
|
|
963
|
+
};
|
|
964
|
+
}
|
|
965
|
+
};
|
|
966
|
+
}
|
|
967
|
+
|
|
683
968
|
// src/combinators/repeat.ts
|
|
684
|
-
function repItem(
|
|
685
|
-
const
|
|
686
|
-
const mark = raw ? raw.length : 0;
|
|
969
|
+
function repItem(combinator, input, cur, ctx) {
|
|
970
|
+
const mark = saveTriviaMark(ctx);
|
|
687
971
|
let pos = cur;
|
|
688
972
|
if (ctx.trivia) {
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
973
|
+
if (needsDeferredTriviaCommit(ctx)) {
|
|
974
|
+
const scan = scanTrivia(input, cur, ctx);
|
|
975
|
+
scan.commit();
|
|
976
|
+
pos = scan.end;
|
|
977
|
+
} else {
|
|
978
|
+
pos = advanceTrivia(input, cur, ctx);
|
|
979
|
+
}
|
|
692
980
|
}
|
|
693
981
|
if (pos >= input.length) {
|
|
694
|
-
|
|
982
|
+
rollbackTrivia(ctx, mark);
|
|
695
983
|
return "stop";
|
|
696
984
|
}
|
|
697
|
-
const result =
|
|
985
|
+
const result = combinator.parse(input, pos, ctx);
|
|
698
986
|
if (!result.ok) {
|
|
699
|
-
|
|
987
|
+
rollbackTrivia(ctx, mark);
|
|
700
988
|
return { fail: result };
|
|
701
989
|
}
|
|
702
990
|
if (result.span.end === pos) {
|
|
703
|
-
|
|
991
|
+
rollbackTrivia(ctx, mark);
|
|
704
992
|
return "stop";
|
|
705
993
|
}
|
|
706
994
|
return { value: result.value, end: result.span.end };
|
|
707
995
|
}
|
|
708
|
-
function many(
|
|
996
|
+
function many(combinator) {
|
|
709
997
|
const meta = {
|
|
710
|
-
firstSet:
|
|
711
|
-
canMatchNewline:
|
|
998
|
+
firstSet: combinator._meta.firstSet,
|
|
999
|
+
canMatchNewline: combinator._meta.canMatchNewline,
|
|
712
1000
|
isTrivia: false
|
|
713
1001
|
};
|
|
714
1002
|
return {
|
|
715
1003
|
_tag: "many",
|
|
716
1004
|
_meta: meta,
|
|
717
|
-
_def: { tag: "many", parser:
|
|
1005
|
+
_def: { tag: "many", parser: combinator, min: 0 },
|
|
718
1006
|
parse(input, pos, ctx) {
|
|
719
1007
|
const values = [];
|
|
720
1008
|
let cur = pos;
|
|
721
1009
|
while (cur < input.length) {
|
|
722
|
-
const item = repItem(
|
|
1010
|
+
const item = repItem(combinator, input, cur, ctx);
|
|
723
1011
|
if (item === "stop" || "fail" in item) break;
|
|
724
1012
|
values.push(item.value);
|
|
725
1013
|
cur = item.end;
|
|
@@ -728,23 +1016,23 @@ function many(parser2) {
|
|
|
728
1016
|
}
|
|
729
1017
|
};
|
|
730
1018
|
}
|
|
731
|
-
function oneOrMore(
|
|
1019
|
+
function oneOrMore(combinator) {
|
|
732
1020
|
const meta = {
|
|
733
|
-
firstSet:
|
|
734
|
-
canMatchNewline:
|
|
1021
|
+
firstSet: combinator._meta.firstSet,
|
|
1022
|
+
canMatchNewline: combinator._meta.canMatchNewline,
|
|
735
1023
|
isTrivia: false
|
|
736
1024
|
};
|
|
737
1025
|
return {
|
|
738
1026
|
_tag: "oneOrMore",
|
|
739
1027
|
_meta: meta,
|
|
740
|
-
_def: { tag: "oneOrMore", parser:
|
|
1028
|
+
_def: { tag: "oneOrMore", parser: combinator, min: 1 },
|
|
741
1029
|
parse(input, pos, ctx) {
|
|
742
|
-
const first =
|
|
1030
|
+
const first = combinator.parse(input, pos, ctx);
|
|
743
1031
|
if (!first.ok) return first;
|
|
744
1032
|
const values = [first.value];
|
|
745
1033
|
let cur = first.span.end;
|
|
746
1034
|
while (cur < input.length) {
|
|
747
|
-
const item = repItem(
|
|
1035
|
+
const item = repItem(combinator, input, cur, ctx);
|
|
748
1036
|
if (item === "stop" || "fail" in item) break;
|
|
749
1037
|
values.push(item.value);
|
|
750
1038
|
cur = item.end;
|
|
@@ -753,45 +1041,71 @@ function oneOrMore(parser2) {
|
|
|
753
1041
|
}
|
|
754
1042
|
};
|
|
755
1043
|
}
|
|
756
|
-
function optional(
|
|
1044
|
+
function optional(combinator) {
|
|
757
1045
|
const meta = {
|
|
758
|
-
firstSet:
|
|
759
|
-
canMatchNewline:
|
|
1046
|
+
firstSet: combinator._meta.firstSet,
|
|
1047
|
+
canMatchNewline: combinator._meta.canMatchNewline,
|
|
760
1048
|
isTrivia: false
|
|
761
1049
|
};
|
|
762
1050
|
return {
|
|
763
1051
|
_tag: "optional",
|
|
764
1052
|
_meta: meta,
|
|
765
|
-
_def: { tag: "optional", parser:
|
|
1053
|
+
_def: { tag: "optional", parser: combinator },
|
|
766
1054
|
parse(input, pos, ctx) {
|
|
767
|
-
const result =
|
|
1055
|
+
const result = combinator.parse(input, pos, ctx);
|
|
768
1056
|
if (result.ok) return result;
|
|
769
1057
|
return { ok: true, value: null, span: { start: pos, end: pos } };
|
|
770
1058
|
}
|
|
771
1059
|
};
|
|
772
1060
|
}
|
|
773
|
-
function sepBy(
|
|
1061
|
+
function sepBy(combinator, separator) {
|
|
774
1062
|
const meta = {
|
|
775
|
-
firstSet:
|
|
776
|
-
canMatchNewline:
|
|
1063
|
+
firstSet: combinator._meta.firstSet,
|
|
1064
|
+
canMatchNewline: combinator._meta.canMatchNewline || separator._meta.canMatchNewline,
|
|
777
1065
|
isTrivia: false
|
|
778
1066
|
};
|
|
779
1067
|
return {
|
|
780
1068
|
_tag: "sepBy",
|
|
781
1069
|
_meta: meta,
|
|
782
|
-
_def: { tag: "sepBy", parser:
|
|
1070
|
+
_def: { tag: "sepBy", parser: combinator, separator },
|
|
783
1071
|
parse(input, pos, ctx) {
|
|
784
|
-
const first =
|
|
1072
|
+
const first = combinator.parse(input, pos, ctx);
|
|
785
1073
|
if (!first.ok) return { ok: true, value: [], span: { start: pos, end: pos } };
|
|
786
1074
|
const values = [first.value];
|
|
787
1075
|
let cur = first.span.end;
|
|
788
1076
|
while (cur < input.length) {
|
|
789
|
-
|
|
1077
|
+
let mark = saveTriviaMark(ctx);
|
|
1078
|
+
let sepPos = cur;
|
|
1079
|
+
if (ctx.trivia) {
|
|
1080
|
+
if (needsDeferredTriviaCommit(ctx)) {
|
|
1081
|
+
const scan = scanTrivia(input, cur, ctx);
|
|
1082
|
+
scan.commit();
|
|
1083
|
+
sepPos = scan.end;
|
|
1084
|
+
} else {
|
|
1085
|
+
sepPos = advanceTrivia(input, cur, ctx);
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
790
1088
|
const sep = separator.parse(input, sepPos, ctx);
|
|
791
|
-
if (!sep.ok)
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
1089
|
+
if (!sep.ok) {
|
|
1090
|
+
rollbackTrivia(ctx, mark);
|
|
1091
|
+
break;
|
|
1092
|
+
}
|
|
1093
|
+
mark = saveTriviaMark(ctx);
|
|
1094
|
+
let nextPos = sep.span.end;
|
|
1095
|
+
if (ctx.trivia) {
|
|
1096
|
+
if (needsDeferredTriviaCommit(ctx)) {
|
|
1097
|
+
const scan = scanTrivia(input, sep.span.end, ctx);
|
|
1098
|
+
scan.commit();
|
|
1099
|
+
nextPos = scan.end;
|
|
1100
|
+
} else {
|
|
1101
|
+
nextPos = advanceTrivia(input, sep.span.end, ctx);
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
const next = combinator.parse(input, nextPos, ctx);
|
|
1105
|
+
if (!next.ok) {
|
|
1106
|
+
rollbackTrivia(ctx, mark);
|
|
1107
|
+
break;
|
|
1108
|
+
}
|
|
795
1109
|
values.push(next.value);
|
|
796
1110
|
cur = next.span.end;
|
|
797
1111
|
}
|
|
@@ -861,7 +1175,7 @@ function rules(factory) {
|
|
|
861
1175
|
}
|
|
862
1176
|
|
|
863
1177
|
// src/combinators/not.ts
|
|
864
|
-
function not(
|
|
1178
|
+
function not(combinator) {
|
|
865
1179
|
const meta = {
|
|
866
1180
|
firstSet: any(),
|
|
867
1181
|
// we don't know what NOT matches
|
|
@@ -871,11 +1185,11 @@ function not(parser2) {
|
|
|
871
1185
|
return {
|
|
872
1186
|
_tag: "not",
|
|
873
1187
|
_meta: meta,
|
|
874
|
-
_def: { tag: "not", parser:
|
|
1188
|
+
_def: { tag: "not", parser: combinator },
|
|
875
1189
|
parse(input, pos, ctx) {
|
|
876
|
-
const result =
|
|
1190
|
+
const result = combinator.parse(input, pos, ctx);
|
|
877
1191
|
if (result.ok) {
|
|
878
|
-
return { ok: false, expected: [`not(${
|
|
1192
|
+
return { ok: false, expected: [`not(${combinator._tag})`], span: { start: pos, end: pos } };
|
|
879
1193
|
}
|
|
880
1194
|
return { ok: true, value: null, span: { start: pos, end: pos } };
|
|
881
1195
|
}
|
|
@@ -883,37 +1197,27 @@ function not(parser2) {
|
|
|
883
1197
|
}
|
|
884
1198
|
|
|
885
1199
|
// src/combinators/node.ts
|
|
886
|
-
function node(type,
|
|
1200
|
+
function node(type, combinator, build) {
|
|
887
1201
|
const meta = {
|
|
888
|
-
firstSet:
|
|
889
|
-
canMatchNewline:
|
|
1202
|
+
firstSet: combinator._meta.firstSet,
|
|
1203
|
+
canMatchNewline: combinator._meta.canMatchNewline,
|
|
890
1204
|
isTrivia: false
|
|
891
1205
|
};
|
|
892
1206
|
return {
|
|
893
1207
|
_tag: "node",
|
|
894
1208
|
_meta: meta,
|
|
895
|
-
_def: { tag: "node", type, parser:
|
|
1209
|
+
_def: { tag: "node", type, parser: combinator, build },
|
|
896
1210
|
parse(input, pos, ctx) {
|
|
897
|
-
const
|
|
898
|
-
const
|
|
899
|
-
const
|
|
900
|
-
...ctx,
|
|
901
|
-
// A node() always records the trivia between its terms — the library owns
|
|
902
|
-
// capture so grammar authors don't reconstruct it. (Matches the compiler.)
|
|
903
|
-
captureTrivia: true,
|
|
904
|
-
_cstChildren: children,
|
|
905
|
-
_cstLeaves: children,
|
|
906
|
-
_cstRawChildren: rawChildren
|
|
907
|
-
};
|
|
908
|
-
const r = parser2.parse(input, pos, innerCtx);
|
|
1211
|
+
const saved = beginCstNodeCapture(ctx);
|
|
1212
|
+
const r = combinator.parse(input, pos, ctx);
|
|
1213
|
+
const { children, rawChildren, triviaLog } = endCstNodeCapture(ctx, saved);
|
|
909
1214
|
if (!r.ok) return r;
|
|
910
|
-
const
|
|
1215
|
+
const state = ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
|
|
1216
|
+
const built = build(children, rawChildren, r.span, triviaLog, state);
|
|
911
1217
|
const isNodeLike = typeof built === "object" && built !== null && built._tag === "node";
|
|
912
|
-
|
|
913
|
-
if (
|
|
914
|
-
ctx
|
|
915
|
-
isNodeLike ? built : { _tag: "leaf", value: typeof built === "string" ? built : "", span: r.span }
|
|
916
|
-
);
|
|
1218
|
+
const rawEntry = isNodeLike ? built : { _tag: "leaf", value: typeof built === "string" ? built : "", span: r.span };
|
|
1219
|
+
if (saved.buf !== void 0 || saved.ch !== void 0) {
|
|
1220
|
+
pushCstChild(ctx, built, rawEntry);
|
|
917
1221
|
}
|
|
918
1222
|
return { ok: true, value: built, span: r.span };
|
|
919
1223
|
}
|
|
@@ -921,13 +1225,13 @@ function node(type, parser2, build) {
|
|
|
921
1225
|
}
|
|
922
1226
|
|
|
923
1227
|
// src/combinators/map.ts
|
|
924
|
-
function transform(
|
|
1228
|
+
function transform(combinator, fn) {
|
|
925
1229
|
return {
|
|
926
1230
|
_tag: "transform",
|
|
927
|
-
_meta:
|
|
928
|
-
_def: { tag: "transform", parser:
|
|
1231
|
+
_meta: combinator._meta,
|
|
1232
|
+
_def: { tag: "transform", parser: combinator, fn },
|
|
929
1233
|
parse(input, pos, ctx) {
|
|
930
|
-
const result =
|
|
1234
|
+
const result = combinator.parse(input, pos, ctx);
|
|
931
1235
|
if (!result.ok) return result;
|
|
932
1236
|
return { ...result, value: fn(result.value, result.span) };
|
|
933
1237
|
}
|
|
@@ -947,12 +1251,25 @@ function skip(main, skipped) {
|
|
|
947
1251
|
}
|
|
948
1252
|
};
|
|
949
1253
|
}
|
|
950
|
-
function trivia(
|
|
1254
|
+
function trivia(combinator) {
|
|
1255
|
+
const kindLabels = analyzeLabeledTrivia(combinator)?.labels;
|
|
951
1256
|
return {
|
|
952
|
-
_tag:
|
|
953
|
-
_meta: {
|
|
954
|
-
|
|
955
|
-
|
|
1257
|
+
_tag: combinator._tag,
|
|
1258
|
+
_meta: {
|
|
1259
|
+
...combinator._meta,
|
|
1260
|
+
isTrivia: true,
|
|
1261
|
+
...kindLabels ? { triviaKindLabels: kindLabels } : {}
|
|
1262
|
+
},
|
|
1263
|
+
_def: { tag: "trivia", parser: combinator },
|
|
1264
|
+
parse: combinator.parse.bind(combinator)
|
|
1265
|
+
};
|
|
1266
|
+
}
|
|
1267
|
+
function label(name, combinator) {
|
|
1268
|
+
return {
|
|
1269
|
+
_tag: combinator._tag,
|
|
1270
|
+
_meta: combinator._meta,
|
|
1271
|
+
_def: { tag: "label", label: name, parser: combinator },
|
|
1272
|
+
parse: combinator.parse.bind(combinator)
|
|
956
1273
|
};
|
|
957
1274
|
}
|
|
958
1275
|
|
|
@@ -1003,7 +1320,10 @@ function parser(opts, root) {
|
|
|
1003
1320
|
const ctx = {
|
|
1004
1321
|
..._ctx,
|
|
1005
1322
|
trackLines,
|
|
1006
|
-
...opts.trivia !== void 0 ? {
|
|
1323
|
+
...opts.trivia !== void 0 ? {
|
|
1324
|
+
trivia: opts.trivia,
|
|
1325
|
+
...opts.trivia._meta.triviaKindLabels ? { triviaKindLabels: opts.trivia._meta.triviaKindLabels } : {}
|
|
1326
|
+
} : {},
|
|
1007
1327
|
...opts.captureTrivia || _ctx?.captureTrivia ? { captureTrivia: true } : {}
|
|
1008
1328
|
};
|
|
1009
1329
|
const result = root.parse(input, pos ?? 0, ctx);
|
|
@@ -1032,6 +1352,320 @@ function parse(combinator, input, opts = {}) {
|
|
|
1032
1352
|
return withErrors;
|
|
1033
1353
|
}
|
|
1034
1354
|
|
|
1355
|
+
// src/compiler/trivia-fast-path.ts
|
|
1356
|
+
var BLOCK_COMMENT = String.raw`\/\*(?:[^*]|\*(?!\/))*\*\/`;
|
|
1357
|
+
var WS_CLASS_SOURCES = /* @__PURE__ */ new Set([
|
|
1358
|
+
String.raw`[ \t\n\r\f]+`,
|
|
1359
|
+
String.raw`[ \t\n]+`,
|
|
1360
|
+
String.raw`[ \t]+`,
|
|
1361
|
+
String.raw`[\t\n\f\r ]+`
|
|
1362
|
+
]);
|
|
1363
|
+
function unwrapTrivia2(p) {
|
|
1364
|
+
let cur = p;
|
|
1365
|
+
while (cur._def.tag === "trivia") cur = cur._def.parser;
|
|
1366
|
+
return cur;
|
|
1367
|
+
}
|
|
1368
|
+
function oneOrMoreInner(p) {
|
|
1369
|
+
const d = p._def;
|
|
1370
|
+
if (d.tag === "oneOrMore") return d.parser;
|
|
1371
|
+
if (d.tag === "many" && d.min >= 1) return d.parser;
|
|
1372
|
+
return null;
|
|
1373
|
+
}
|
|
1374
|
+
function choiceArms(p) {
|
|
1375
|
+
if (p._def.tag === "choice") return p._def.parsers;
|
|
1376
|
+
return null;
|
|
1377
|
+
}
|
|
1378
|
+
function isWsClassSource(source) {
|
|
1379
|
+
return WS_CLASS_SOURCES.has(source);
|
|
1380
|
+
}
|
|
1381
|
+
function isBlockCommentSource(source) {
|
|
1382
|
+
return source === BLOCK_COMMENT;
|
|
1383
|
+
}
|
|
1384
|
+
function analyzeTriviaFastPath(trivia2) {
|
|
1385
|
+
const core = unwrapTrivia2(trivia2);
|
|
1386
|
+
const direct = getCoreRegexDef(core)?.source;
|
|
1387
|
+
if (direct) {
|
|
1388
|
+
if (isWsClassSource(direct)) return "wsOnly";
|
|
1389
|
+
return null;
|
|
1390
|
+
}
|
|
1391
|
+
const inner = oneOrMoreInner(core);
|
|
1392
|
+
if (!inner) return null;
|
|
1393
|
+
const innerSrc = getCoreRegexDef(inner)?.source;
|
|
1394
|
+
if (innerSrc && isWsClassSource(innerSrc)) return "wsOnly";
|
|
1395
|
+
const arms = choiceArms(inner);
|
|
1396
|
+
if (!arms || arms.length !== 2) return null;
|
|
1397
|
+
let hasWs = false;
|
|
1398
|
+
let hasComment = false;
|
|
1399
|
+
for (const arm of arms) {
|
|
1400
|
+
const src = getCoreRegexDef(arm)?.source;
|
|
1401
|
+
if (!src) return null;
|
|
1402
|
+
if (isWsClassSource(src)) hasWs = true;
|
|
1403
|
+
else if (isBlockCommentSource(src)) hasComment = true;
|
|
1404
|
+
else return null;
|
|
1405
|
+
}
|
|
1406
|
+
if (hasWs && hasComment) return "wsComments";
|
|
1407
|
+
return null;
|
|
1408
|
+
}
|
|
1409
|
+
var CAP_RECORD = [
|
|
1410
|
+
` if (_cap && _e > _pos) {`,
|
|
1411
|
+
` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_pos, _e)`,
|
|
1412
|
+
` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
|
|
1413
|
+
` }`
|
|
1414
|
+
].join("\n");
|
|
1415
|
+
var WS_ONLY_LOOP = [
|
|
1416
|
+
` while (_e < input.length) {`,
|
|
1417
|
+
` const c = input.charCodeAt(_e)`,
|
|
1418
|
+
` if (c === 32 || c === 9 || c === 10 || c === 13 || c === 12) { _e++; continue }`,
|
|
1419
|
+
` break`,
|
|
1420
|
+
` }`
|
|
1421
|
+
].join("\n");
|
|
1422
|
+
var WS_COMMENTS_LOOP = [
|
|
1423
|
+
` while (_e < input.length) {`,
|
|
1424
|
+
` const c = input.charCodeAt(_e)`,
|
|
1425
|
+
` if (c === 32 || c === 9 || c === 10 || c === 13 || c === 12) { _e++; continue }`,
|
|
1426
|
+
` if (c === 47 && input.charCodeAt(_e + 1) === 42) {`,
|
|
1427
|
+
` let j = _e + 2`,
|
|
1428
|
+
` while (j + 1 < input.length && !(input.charCodeAt(j) === 42 && input.charCodeAt(j + 1) === 47)) j++`,
|
|
1429
|
+
` _e = j + 2 <= input.length ? j + 2 : input.length`,
|
|
1430
|
+
` continue`,
|
|
1431
|
+
` }`,
|
|
1432
|
+
` break`,
|
|
1433
|
+
` }`
|
|
1434
|
+
].join("\n");
|
|
1435
|
+
var CAP_CHUNK = (wsKind, commentKind) => [
|
|
1436
|
+
` if (c === 32 || c === 9 || c === 10 || c === 13 || c === 12) {`,
|
|
1437
|
+
` const _cs = _e`,
|
|
1438
|
+
` _e++`,
|
|
1439
|
+
` while (_e < input.length) {`,
|
|
1440
|
+
` const c2 = input.charCodeAt(_e)`,
|
|
1441
|
+
` if (c2 === 32 || c2 === 9 || c2 === 10 || c2 === 13 || c2 === 12) _e++`,
|
|
1442
|
+
` else break`,
|
|
1443
|
+
` }`,
|
|
1444
|
+
` if (_cap) {`,
|
|
1445
|
+
` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_cs, _e, ${wsKind})`,
|
|
1446
|
+
` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(_cs, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${wsKind})`,
|
|
1447
|
+
` }`,
|
|
1448
|
+
` continue`,
|
|
1449
|
+
` }`,
|
|
1450
|
+
` if (c === 47 && input.charCodeAt(_e + 1) === 42) {`,
|
|
1451
|
+
` const _cs = _e`,
|
|
1452
|
+
` let j = _e + 2`,
|
|
1453
|
+
` while (j + 1 < input.length && !(input.charCodeAt(j) === 42 && input.charCodeAt(j + 1) === 47)) j++`,
|
|
1454
|
+
` _e = j + 2 <= input.length ? j + 2 : input.length`,
|
|
1455
|
+
` if (_cap) {`,
|
|
1456
|
+
` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_cs, _e, ${commentKind})`,
|
|
1457
|
+
` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(_cs, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${commentKind})`,
|
|
1458
|
+
` }`,
|
|
1459
|
+
` continue`,
|
|
1460
|
+
` }`
|
|
1461
|
+
].join("\n");
|
|
1462
|
+
var WS_COMMENTS_LOOP_LABELED = (wsKind, commentKind) => [
|
|
1463
|
+
` while (_e < input.length) {`,
|
|
1464
|
+
` const c = input.charCodeAt(_e)`,
|
|
1465
|
+
CAP_CHUNK(wsKind, commentKind),
|
|
1466
|
+
` break`,
|
|
1467
|
+
` }`
|
|
1468
|
+
].join("\n");
|
|
1469
|
+
function buildFastTriviaFnDecl(fnName, kind, kindIndices) {
|
|
1470
|
+
const loop = kind === "wsComments" && kindIndices ? WS_COMMENTS_LOOP_LABELED(kindIndices.ws, kindIndices.comment) : kind === "wsComments" ? WS_COMMENTS_LOOP : WS_ONLY_LOOP;
|
|
1471
|
+
const cap = kindIndices ? "" : CAP_RECORD;
|
|
1472
|
+
const lines = [
|
|
1473
|
+
`function ${fnName}(input, _pos, _ctx, _cap) {`,
|
|
1474
|
+
` let _e = _pos`,
|
|
1475
|
+
loop
|
|
1476
|
+
];
|
|
1477
|
+
if (cap) lines.push(cap);
|
|
1478
|
+
lines.push(` return _e`, `}`);
|
|
1479
|
+
return lines.join("\n");
|
|
1480
|
+
}
|
|
1481
|
+
function regexArmIndex(spec, isComment) {
|
|
1482
|
+
for (const arm of spec.arms) {
|
|
1483
|
+
const src = getCoreRegexDef(arm.parser)?.source;
|
|
1484
|
+
if (!src) return null;
|
|
1485
|
+
const comment = src.includes("\\*") || src.startsWith("\\/\\/");
|
|
1486
|
+
if (comment === isComment) return arm.kindIndex;
|
|
1487
|
+
}
|
|
1488
|
+
return null;
|
|
1489
|
+
}
|
|
1490
|
+
function buildLabeledRegexTriviaFnDecl(fnName, spec, reNames) {
|
|
1491
|
+
const tryArms = spec.arms.map((arm, i) => {
|
|
1492
|
+
const re = reNames[i];
|
|
1493
|
+
const k = arm.kindIndex;
|
|
1494
|
+
return [
|
|
1495
|
+
` ${re}.lastIndex = _e`,
|
|
1496
|
+
` const _m${i} = ${re}.exec(input)`,
|
|
1497
|
+
` if (_m${i} && _m${i}.index === _e) {`,
|
|
1498
|
+
` const _ce = _e + _m${i}[0].length`,
|
|
1499
|
+
` if (_cap) {`,
|
|
1500
|
+
` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, _ce, ${k})`,
|
|
1501
|
+
` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(_e, _ce, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${k})`,
|
|
1502
|
+
` }`,
|
|
1503
|
+
` _e = _ce`,
|
|
1504
|
+
` _matched = true`,
|
|
1505
|
+
` continue`,
|
|
1506
|
+
` }`
|
|
1507
|
+
].join("\n");
|
|
1508
|
+
}).join("\n");
|
|
1509
|
+
return [
|
|
1510
|
+
`function ${fnName}(input, _pos, _ctx, _cap) {`,
|
|
1511
|
+
` let _e = _pos`,
|
|
1512
|
+
` while (_e < input.length) {`,
|
|
1513
|
+
` let _matched = false`,
|
|
1514
|
+
tryArms,
|
|
1515
|
+
` if (!_matched) break`,
|
|
1516
|
+
` }`,
|
|
1517
|
+
` return _e`,
|
|
1518
|
+
`}`
|
|
1519
|
+
].join("\n");
|
|
1520
|
+
}
|
|
1521
|
+
function labeledTriviaKindIndices(trivia2) {
|
|
1522
|
+
const spec = analyzeLabeledTrivia(trivia2);
|
|
1523
|
+
if (!spec || spec.arms.length !== 2) return null;
|
|
1524
|
+
const ws = regexArmIndex(spec, false);
|
|
1525
|
+
const comment = regexArmIndex(spec, true);
|
|
1526
|
+
if (ws === null || comment === null) return null;
|
|
1527
|
+
return { ws, comment };
|
|
1528
|
+
}
|
|
1529
|
+
function labeledTriviaRegexArms(trivia2) {
|
|
1530
|
+
const spec = analyzeLabeledTrivia(trivia2);
|
|
1531
|
+
if (!spec) return null;
|
|
1532
|
+
for (const arm of spec.arms) {
|
|
1533
|
+
if (!getCoreRegexDef(arm.parser)) return null;
|
|
1534
|
+
}
|
|
1535
|
+
return spec;
|
|
1536
|
+
}
|
|
1537
|
+
function buildLabeledRuntimeTriviaFnDecl(fnName, spec, rpStartIndex) {
|
|
1538
|
+
const tryArms = spec.arms.map((arm, i) => {
|
|
1539
|
+
const k = arm.kindIndex;
|
|
1540
|
+
const ri = rpStartIndex + i;
|
|
1541
|
+
return [
|
|
1542
|
+
` const _r${i} = _rp[${ri}].parse(input, _e, _ctx)`,
|
|
1543
|
+
` if (_r${i}.ok && _r${i}.span.end > _e) {`,
|
|
1544
|
+
` const _ce = _r${i}.span.end`,
|
|
1545
|
+
` if (_cap) {`,
|
|
1546
|
+
` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, _ce, ${k})`,
|
|
1547
|
+
` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(_e, _ce, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${k})`,
|
|
1548
|
+
` }`,
|
|
1549
|
+
` _e = _ce`,
|
|
1550
|
+
` _matched = true`,
|
|
1551
|
+
` continue`,
|
|
1552
|
+
` }`
|
|
1553
|
+
].join("\n");
|
|
1554
|
+
}).join("\n");
|
|
1555
|
+
return [
|
|
1556
|
+
`function ${fnName}(input, _pos, _ctx, _cap) {`,
|
|
1557
|
+
` let _e = _pos`,
|
|
1558
|
+
` while (_e < input.length) {`,
|
|
1559
|
+
` let _matched = false`,
|
|
1560
|
+
tryArms,
|
|
1561
|
+
` if (!_matched) break`,
|
|
1562
|
+
` }`,
|
|
1563
|
+
` return _e`,
|
|
1564
|
+
`}`
|
|
1565
|
+
].join("\n");
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1568
|
+
// src/compiler/inline-build.ts
|
|
1569
|
+
var MK_BUILD_RE = /^\(\s*(?:\w+\s*,\s*){3}\w+\s*\)\s*=>\s*mk\s*\(\s*(['"])([^'"]+)\1\s*,\s*\w+\s*,\s*\w+\s*,\s*\w+\s*,\s*\w+\s*\)\s*$/;
|
|
1570
|
+
function escapeRegExp(s) {
|
|
1571
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1572
|
+
}
|
|
1573
|
+
function looseMkBuildRe(type) {
|
|
1574
|
+
return new RegExp(
|
|
1575
|
+
String.raw`^\(\s*(?:\w+\s*,\s*){3}\w+\s*\)\s*=>\s*.+\(\s*(['"])${escapeRegExp(type)}\1\s*,\s*\w+\s*,\s*\w+\s*,\s*\w+\s*,\s*\w+\s*\)\s*$`
|
|
1576
|
+
);
|
|
1577
|
+
}
|
|
1578
|
+
function analyzeMkInlineBuild(def) {
|
|
1579
|
+
const src = (def.buildSrc ?? def.build.toString()).trim();
|
|
1580
|
+
const strict = src.match(MK_BUILD_RE);
|
|
1581
|
+
if (strict) {
|
|
1582
|
+
const mkType = strict[2];
|
|
1583
|
+
return mkType === def.type ? def.type : null;
|
|
1584
|
+
}
|
|
1585
|
+
if (looseMkBuildRe(def.type).test(src)) return def.type;
|
|
1586
|
+
return null;
|
|
1587
|
+
}
|
|
1588
|
+
function emitInlineMkNodeExpr(type, chV, rawV, pos, endVar, tlV) {
|
|
1589
|
+
return `{ _tag: 'node', type: ${JSON.stringify(type)}, span: { start: ${pos}, end: ${endVar} }, children: ${chV}, rawCount: ${rawV}.length, localTriviaLen: ${tlV}.length }`;
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
// src/compiler/inline-callback.ts
|
|
1593
|
+
var INLINE_BUILTINS = /* @__PURE__ */ new Set([
|
|
1594
|
+
"parseInt",
|
|
1595
|
+
"parseFloat",
|
|
1596
|
+
"String",
|
|
1597
|
+
"Number",
|
|
1598
|
+
"Boolean",
|
|
1599
|
+
"Object",
|
|
1600
|
+
"Array",
|
|
1601
|
+
"Math",
|
|
1602
|
+
"JSON",
|
|
1603
|
+
"undefined",
|
|
1604
|
+
"null",
|
|
1605
|
+
"true",
|
|
1606
|
+
"false",
|
|
1607
|
+
"NaN",
|
|
1608
|
+
"Infinity"
|
|
1609
|
+
]);
|
|
1610
|
+
function escapeRegExp2(s) {
|
|
1611
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1612
|
+
}
|
|
1613
|
+
function transformFnSource(fn, fnSrc) {
|
|
1614
|
+
if (fnSrc) return fnSrc.trim();
|
|
1615
|
+
const s = fn.toString().trim();
|
|
1616
|
+
if (s.includes("[native code]")) return null;
|
|
1617
|
+
return s;
|
|
1618
|
+
}
|
|
1619
|
+
function replaceParam(body, param, valueVar) {
|
|
1620
|
+
return body.replace(new RegExp(`\\b${escapeRegExp2(param)}\\b`, "g"), valueVar);
|
|
1621
|
+
}
|
|
1622
|
+
function stripForIdCheck(body) {
|
|
1623
|
+
return body.replace(/'[^'\\]*(?:\\.[^'\\]*)*'|"[^"\\]*(?:\\.[^"\\]*)*"/g, '""').replace(/\bas\s+const\b/g, "").replace(/\b[A-Za-z_$][\w$]*\s*:/g, ":");
|
|
1624
|
+
}
|
|
1625
|
+
function hasFreeIdentifiers(body, allowed) {
|
|
1626
|
+
const stripped = stripForIdCheck(body);
|
|
1627
|
+
const ids = stripped.match(/\b[A-Za-z_$][\w$]*\b/g) ?? [];
|
|
1628
|
+
for (const id of ids) {
|
|
1629
|
+
if (INLINE_BUILTINS.has(id)) continue;
|
|
1630
|
+
if (allowed.has(id)) continue;
|
|
1631
|
+
return true;
|
|
1632
|
+
}
|
|
1633
|
+
return false;
|
|
1634
|
+
}
|
|
1635
|
+
function tryInlineUnaryTransform(src, valueVar) {
|
|
1636
|
+
const allowed = /* @__PURE__ */ new Set([valueVar]);
|
|
1637
|
+
const nullary = src.match(/^\(\s*\)\s*=>\s*(.+)$/);
|
|
1638
|
+
if (nullary) {
|
|
1639
|
+
const body2 = nullary[1].trim();
|
|
1640
|
+
return hasFreeIdentifiers(body2, allowed) ? null : body2;
|
|
1641
|
+
}
|
|
1642
|
+
const m = src.match(/^(\w+)\s*=>\s*(.+)$/);
|
|
1643
|
+
if (!m) return null;
|
|
1644
|
+
const body = replaceParam(m[2].trim(), m[1], valueVar);
|
|
1645
|
+
return hasFreeIdentifiers(body, allowed) ? null : body;
|
|
1646
|
+
}
|
|
1647
|
+
function parseArrayDestructure(pattern, arity) {
|
|
1648
|
+
const slots = [];
|
|
1649
|
+
for (const part of pattern.split(",")) {
|
|
1650
|
+
const name = part.trim();
|
|
1651
|
+
slots.push(name === "" || name === "_" ? null : name);
|
|
1652
|
+
}
|
|
1653
|
+
while (slots.length < arity) slots.push(null);
|
|
1654
|
+
return slots.slice(0, arity);
|
|
1655
|
+
}
|
|
1656
|
+
function tryInlineDestructureTransform(src, valueVars) {
|
|
1657
|
+
const m = src.match(/^\(\s*\[([^\]]*)\]\s*\)\s*=>\s*(.+)$/s);
|
|
1658
|
+
if (!m) return null;
|
|
1659
|
+
const slots = parseArrayDestructure(m[1], valueVars.length);
|
|
1660
|
+
let body = m[2].trim();
|
|
1661
|
+
const allowed = new Set(valueVars);
|
|
1662
|
+
for (let i = 0; i < slots.length; i++) {
|
|
1663
|
+
const name = slots[i];
|
|
1664
|
+
if (name) body = replaceParam(body, name, valueVars[i]);
|
|
1665
|
+
}
|
|
1666
|
+
return hasFreeIdentifiers(body, allowed) ? null : body;
|
|
1667
|
+
}
|
|
1668
|
+
|
|
1035
1669
|
// src/compiler/codegen.ts
|
|
1036
1670
|
function v(ctx, prefix = "_v") {
|
|
1037
1671
|
return `${prefix}${ctx.vars++}`;
|
|
@@ -1039,12 +1673,42 @@ function v(ctx, prefix = "_v") {
|
|
|
1039
1673
|
function ind(ctx) {
|
|
1040
1674
|
return " ".repeat(ctx.indent);
|
|
1041
1675
|
}
|
|
1676
|
+
var NAMED_FN_FAIL = "_pfFail";
|
|
1677
|
+
var NAMED_FN_END = "_pfEnd";
|
|
1678
|
+
function namedFnPrelude() {
|
|
1679
|
+
return [`const ${NAMED_FN_FAIL} = {}`, `let ${NAMED_FN_END}`];
|
|
1680
|
+
}
|
|
1681
|
+
function pushNamedFnDecl(ctx, fnName, bodyStmts, valueVar, endVar) {
|
|
1682
|
+
ctx.namedFnDecls.push([
|
|
1683
|
+
`function ${fnName}(input, _pos, _ctx) {`,
|
|
1684
|
+
` let _pfok = false, _pfv, _pfe = _pos`,
|
|
1685
|
+
` _pfail: {`,
|
|
1686
|
+
...bodyStmts,
|
|
1687
|
+
` _pfv = ${valueVar}; _pfe = ${endVar}; _pfok = true`,
|
|
1688
|
+
` }`,
|
|
1689
|
+
` if (!_pfok) return ${NAMED_FN_FAIL}`,
|
|
1690
|
+
` ${NAMED_FN_END} = _pfe`,
|
|
1691
|
+
` return _pfv`,
|
|
1692
|
+
`}`
|
|
1693
|
+
].join("\n"));
|
|
1694
|
+
}
|
|
1695
|
+
function emitNamedFnCall(ctx, fnName, pos, failExpected) {
|
|
1696
|
+
const vv = v(ctx, "_pfv");
|
|
1697
|
+
const ev = v(ctx, "_pfe");
|
|
1698
|
+
return {
|
|
1699
|
+
stmts: [
|
|
1700
|
+
`${ind(ctx)}const ${vv} = ${fnName}(input, ${pos}, _ctx)`,
|
|
1701
|
+
`${ind(ctx)}if (${vv} === ${NAMED_FN_FAIL}) ${failStmt({ ...ctx, indent: 0 }, failExpected, pos).trim()}`,
|
|
1702
|
+
`${ind(ctx)}const ${ev} = ${NAMED_FN_END}`
|
|
1703
|
+
],
|
|
1704
|
+
valueVar: vv,
|
|
1705
|
+
endVar: ev
|
|
1706
|
+
};
|
|
1707
|
+
}
|
|
1042
1708
|
function emitLeafCapture(ctx, valExpr, startExpr, endExpr) {
|
|
1043
1709
|
if (!ctx.capturing) return [];
|
|
1710
|
+
if (ctx.capAsTrivia) return [];
|
|
1044
1711
|
const i = ind(ctx);
|
|
1045
|
-
if (ctx.capAsTrivia) {
|
|
1046
|
-
return [`${i}if (_ctx._cstRawChildren) _ctx._cstRawChildren.push({ _tag: 'trivia', value: ${valExpr}, span: { start: ${startExpr}, end: ${endExpr} } })`];
|
|
1047
|
-
}
|
|
1048
1712
|
const lf = v(ctx, "_lf");
|
|
1049
1713
|
return [
|
|
1050
1714
|
`${i}if (_ctx._cstLeaves) {`,
|
|
@@ -1054,35 +1718,84 @@ function emitLeafCapture(ctx, valExpr, startExpr, endExpr) {
|
|
|
1054
1718
|
`${i}}`
|
|
1055
1719
|
];
|
|
1056
1720
|
}
|
|
1057
|
-
function
|
|
1721
|
+
function ensureRegexDecl(ctx, optimizedSource, flags) {
|
|
1722
|
+
const f = "y" + flags.replace(/[gy]/g, "");
|
|
1723
|
+
const key = `${optimizedSource}/${f}`;
|
|
1724
|
+
let rName = ctx.regexMap.get(key);
|
|
1725
|
+
if (rName === void 0) {
|
|
1726
|
+
rName = `_re${ctx.regexDecls.length}`;
|
|
1727
|
+
ctx.regexDecls.push(`const ${rName} = /${optimizedSource}/${f}`);
|
|
1728
|
+
ctx.regexMap.set(key, rName);
|
|
1729
|
+
}
|
|
1730
|
+
return rName;
|
|
1731
|
+
}
|
|
1732
|
+
function ensureTriviaFn(ctx) {
|
|
1058
1733
|
const trivia2 = ctx.activeTrivia;
|
|
1059
|
-
const existing = ctx.
|
|
1734
|
+
const existing = ctx.triviaFnNames.get(trivia2);
|
|
1060
1735
|
if (existing) return existing;
|
|
1061
|
-
const fnName = `
|
|
1736
|
+
const fnName = `_tf${ctx.triviaFnNames.size}`;
|
|
1737
|
+
ctx.triviaFnNames.set(trivia2, fnName);
|
|
1062
1738
|
ctx.triviaCaptureNames.set(trivia2, fnName);
|
|
1063
|
-
const
|
|
1739
|
+
const fastKind = analyzeTriviaFastPath(trivia2);
|
|
1740
|
+
const kindIndices = labeledTriviaKindIndices(trivia2);
|
|
1741
|
+
if (fastKind) {
|
|
1742
|
+
ctx.namedFnDecls.push(buildFastTriviaFnDecl(fnName, fastKind, kindIndices ?? void 0));
|
|
1743
|
+
return fnName;
|
|
1744
|
+
}
|
|
1745
|
+
const labeledSpec = analyzeLabeledTrivia(trivia2);
|
|
1746
|
+
if (labeledSpec) {
|
|
1747
|
+
const regexSpec = labeledTriviaRegexArms(trivia2);
|
|
1748
|
+
if (regexSpec) {
|
|
1749
|
+
const reNames = [];
|
|
1750
|
+
for (const arm of regexSpec.arms) {
|
|
1751
|
+
const def = arm.parser._def;
|
|
1752
|
+
if (def.tag !== "regex") break;
|
|
1753
|
+
reNames.push(ensureRegexDecl(ctx, def.optimizedSource, def.flags));
|
|
1754
|
+
}
|
|
1755
|
+
if (reNames.length === regexSpec.arms.length) {
|
|
1756
|
+
ctx.namedFnDecls.push(buildLabeledRegexTriviaFnDecl(fnName, regexSpec, reNames));
|
|
1757
|
+
return fnName;
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
const rpStart = ctx.runtimeParsers.length;
|
|
1761
|
+
for (const arm of labeledSpec.arms) {
|
|
1762
|
+
ctx.runtimeParsers.push(arm.parser);
|
|
1763
|
+
}
|
|
1764
|
+
ctx.namedFnDecls.push(buildLabeledRuntimeTriviaFnDecl(fnName, labeledSpec, rpStart));
|
|
1765
|
+
return fnName;
|
|
1766
|
+
}
|
|
1767
|
+
const savedIndent = ctx.indent;
|
|
1768
|
+
const savedFailLabel = ctx.failLabel;
|
|
1769
|
+
const savedTrivia = ctx.activeTrivia;
|
|
1770
|
+
const savedCapAsTrivia = ctx.capAsTrivia;
|
|
1064
1771
|
ctx.indent = 2;
|
|
1065
|
-
ctx.failLabel = "
|
|
1772
|
+
ctx.failLabel = "_triv";
|
|
1066
1773
|
ctx.capAsTrivia = true;
|
|
1067
|
-
|
|
1774
|
+
ctx.activeTrivia = void 0;
|
|
1068
1775
|
const r = emit(trivia2, ctx, "_pos");
|
|
1069
|
-
ctx.indent =
|
|
1070
|
-
ctx.failLabel =
|
|
1071
|
-
ctx.capAsTrivia =
|
|
1072
|
-
|
|
1776
|
+
ctx.indent = savedIndent;
|
|
1777
|
+
ctx.failLabel = savedFailLabel;
|
|
1778
|
+
ctx.capAsTrivia = savedCapAsTrivia;
|
|
1779
|
+
ctx.activeTrivia = savedTrivia;
|
|
1073
1780
|
ctx.namedFnDecls.push([
|
|
1074
|
-
`function ${fnName}(input, _pos, _ctx) {`,
|
|
1781
|
+
`function ${fnName}(input, _pos, _ctx, _cap) {`,
|
|
1075
1782
|
` let _e = _pos`,
|
|
1076
|
-
`
|
|
1783
|
+
` _triv: {`,
|
|
1077
1784
|
...r.stmts,
|
|
1078
1785
|
` _e = ${r.endVar}`,
|
|
1079
1786
|
` }`,
|
|
1080
|
-
` if (
|
|
1787
|
+
` if (_cap && _e > _pos) {`,
|
|
1788
|
+
` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_pos, _e)`,
|
|
1789
|
+
` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
|
|
1790
|
+
` }`,
|
|
1081
1791
|
` return _e`,
|
|
1082
1792
|
`}`
|
|
1083
1793
|
].join("\n"));
|
|
1084
1794
|
return fnName;
|
|
1085
1795
|
}
|
|
1796
|
+
function ensureTriviaCaptureFn(ctx) {
|
|
1797
|
+
return ensureTriviaFn(ctx);
|
|
1798
|
+
}
|
|
1086
1799
|
function failStmt(ctx, expected, posExpr) {
|
|
1087
1800
|
if (ctx.failLabel) return `${ind(ctx)}break ${ctx.failLabel}`;
|
|
1088
1801
|
return `${ind(ctx)}return { ok: false, expected: [${expected}], span: { start: ${posExpr}, end: ${posExpr} } }`;
|
|
@@ -1098,14 +1811,6 @@ function firstSetCond(codeVar, fs) {
|
|
|
1098
1811
|
(r) => r.lo === r.hi ? `${codeVar} === ${r.lo}` : `(${codeVar} >= ${r.lo} && ${codeVar} <= ${r.hi})`
|
|
1099
1812
|
).join(" || ");
|
|
1100
1813
|
}
|
|
1101
|
-
function asIIFE(stmts, valueVar, endVar, startPos, indent) {
|
|
1102
|
-
return [
|
|
1103
|
-
`(() => {`,
|
|
1104
|
-
...stmts,
|
|
1105
|
-
`${indent} return { ok: true, value: ${valueVar}, span: { start: ${startPos}, end: ${endVar} } }`,
|
|
1106
|
-
`${indent}})()`
|
|
1107
|
-
].join("\n");
|
|
1108
|
-
}
|
|
1109
1814
|
function emitFallible(inner, ctx, pos) {
|
|
1110
1815
|
const lbl = v(ctx, "_lbl");
|
|
1111
1816
|
const okV = `${lbl}ok`;
|
|
@@ -1171,6 +1876,33 @@ function emitLit(def, ctx, pos) {
|
|
|
1171
1876
|
stmts.push(...emitLeafCapture(ctx, vv, pos, endVar));
|
|
1172
1877
|
return { stmts, valueVar: vv, endVar };
|
|
1173
1878
|
}
|
|
1879
|
+
function escapeKeywordRe(s) {
|
|
1880
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1881
|
+
}
|
|
1882
|
+
function emitKeywords(def, ctx, pos) {
|
|
1883
|
+
const alt = def.words.map(escapeKeywordRe).join("|");
|
|
1884
|
+
const boundary = def.boundary ? `(?![${def.boundary}])` : "";
|
|
1885
|
+
const flags = def.caseInsensitive ? "iuy" : "uy";
|
|
1886
|
+
const source = `(?:${alt})${boundary}`;
|
|
1887
|
+
const key = `${source}/${flags}`;
|
|
1888
|
+
let rName = ctx.regexMap.get(key);
|
|
1889
|
+
if (rName === void 0) {
|
|
1890
|
+
rName = `_re${ctx.regexDecls.length}`;
|
|
1891
|
+
ctx.regexDecls.push(`const ${rName} = /${source}/${flags}`);
|
|
1892
|
+
ctx.regexMap.set(key, rName);
|
|
1893
|
+
}
|
|
1894
|
+
const mv = v(ctx, "_m");
|
|
1895
|
+
const vv = v(ctx);
|
|
1896
|
+
const stmts = [
|
|
1897
|
+
`${ind(ctx)}${rName}.lastIndex = ${pos}`,
|
|
1898
|
+
`${ind(ctx)}const ${mv} = ${rName}.exec(input)`,
|
|
1899
|
+
`${ind(ctx)}if (${mv} === null) ${failStmt({ ...ctx, indent: 0 }, '"keyword"', pos).trim()}`,
|
|
1900
|
+
`${ind(ctx)}const ${vv} = ${mv}[0]`
|
|
1901
|
+
];
|
|
1902
|
+
const endVar = `${pos} + ${vv}.length`;
|
|
1903
|
+
stmts.push(...emitLeafCapture(ctx, vv, pos, endVar));
|
|
1904
|
+
return { stmts, valueVar: vv, endVar };
|
|
1905
|
+
}
|
|
1174
1906
|
function emitRegex(def, ctx, pos) {
|
|
1175
1907
|
const flags = "y" + def.flags.replace(/[gy]/g, "");
|
|
1176
1908
|
const key = `${def.optimizedSource}/${flags}`;
|
|
@@ -1193,31 +1925,7 @@ function emitRegex(def, ctx, pos) {
|
|
|
1193
1925
|
stmts.push(...emitLeafCapture(ctx, vv, pos, endVar));
|
|
1194
1926
|
return { stmts, valueVar: vv, endVar };
|
|
1195
1927
|
}
|
|
1196
|
-
function
|
|
1197
|
-
const trivia2 = ctx.activeTrivia;
|
|
1198
|
-
if (!ctx.namedParsers.has(trivia2)) {
|
|
1199
|
-
const fnName = `_pf${ctx.namedParsers.size}`;
|
|
1200
|
-
ctx.namedParsers.set(trivia2, fnName);
|
|
1201
|
-
const savedIndent = ctx.indent;
|
|
1202
|
-
const savedFailLabel = ctx.failLabel;
|
|
1203
|
-
const savedTrivia = ctx.activeTrivia;
|
|
1204
|
-
ctx.indent = 1;
|
|
1205
|
-
ctx.failLabel = void 0;
|
|
1206
|
-
delete ctx.activeTrivia;
|
|
1207
|
-
const r = emit(trivia2, ctx, "_pos");
|
|
1208
|
-
ctx.indent = savedIndent;
|
|
1209
|
-
ctx.failLabel = savedFailLabel;
|
|
1210
|
-
if (savedTrivia) ctx.activeTrivia = savedTrivia;
|
|
1211
|
-
ctx.namedFnDecls.push([
|
|
1212
|
-
`function ${fnName}(input, _pos, _ctx) {`,
|
|
1213
|
-
...r.stmts,
|
|
1214
|
-
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
|
|
1215
|
-
`}`
|
|
1216
|
-
].join("\n"));
|
|
1217
|
-
}
|
|
1218
|
-
return ctx.namedParsers.get(trivia2);
|
|
1219
|
-
}
|
|
1220
|
-
function emitSeq(def, ctx, pos) {
|
|
1928
|
+
function emitSeqValues(def, ctx, pos) {
|
|
1221
1929
|
const startV = v(ctx, "_start");
|
|
1222
1930
|
const curV = v(ctx, "_cur");
|
|
1223
1931
|
const stmts = [
|
|
@@ -1229,23 +1937,41 @@ function emitSeq(def, ctx, pos) {
|
|
|
1229
1937
|
if (i > 0 && ctx.activeTrivia) {
|
|
1230
1938
|
if (ctx.capturing) {
|
|
1231
1939
|
const capFn = ensureTriviaCaptureFn(ctx);
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
const
|
|
1235
|
-
const
|
|
1940
|
+
const markV = v(ctx, "_mk");
|
|
1941
|
+
const markTl = v(ctx, "_mktl");
|
|
1942
|
+
const markLog = v(ctx, "_mklg");
|
|
1943
|
+
const scanEndV = v(ctx, "_sne");
|
|
1944
|
+
stmts.push(
|
|
1945
|
+
`${ind(ctx)}const ${markV} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
|
|
1946
|
+
`${ind(ctx)}const ${markTl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
|
|
1947
|
+
`${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
|
|
1948
|
+
`${ind(ctx)}const ${scanEndV} = ${capFn}(input, ${curV}, _ctx, 1)`
|
|
1949
|
+
);
|
|
1950
|
+
const r2 = emit(def.parsers[i], ctx, scanEndV);
|
|
1951
|
+
stmts.push(...r2.stmts);
|
|
1952
|
+
const endAfterV = v(ctx, "_sea");
|
|
1236
1953
|
stmts.push(
|
|
1237
|
-
`${ind(ctx)}const ${
|
|
1238
|
-
`${ind(ctx)}if (${
|
|
1954
|
+
`${ind(ctx)}const ${endAfterV} = ${r2.endVar}`,
|
|
1955
|
+
`${ind(ctx)}if (${endAfterV} > ${scanEndV}) { ${curV} = ${endAfterV} } else { if (_ctx._cstRawChildren) _ctx._cstRawChildren.length = ${markV}; if (_ctx._cstTriviaLog) _ctx._cstTriviaLog.length = ${markTl}; if (_ctx._triviaLog) _ctx._triviaLog.length = ${markLog}; }`
|
|
1239
1956
|
);
|
|
1957
|
+
valueVars.push(r2.valueVar);
|
|
1958
|
+
continue;
|
|
1959
|
+
} else {
|
|
1960
|
+
const trivFn = ensureTriviaFn(ctx);
|
|
1961
|
+
stmts.push(`${ind(ctx)}${curV} = ${trivFn}(input, ${curV}, _ctx)`);
|
|
1240
1962
|
}
|
|
1241
1963
|
}
|
|
1242
1964
|
const r = emit(def.parsers[i], ctx, curV);
|
|
1243
1965
|
stmts.push(...r.stmts, `${ind(ctx)}${curV} = ${r.endVar}`);
|
|
1244
1966
|
valueVars.push(r.valueVar);
|
|
1245
1967
|
}
|
|
1968
|
+
return { stmts, valueVar: valueVars[valueVars.length - 1] ?? "null", endVar: curV, valueVars };
|
|
1969
|
+
}
|
|
1970
|
+
function emitSeq(def, ctx, pos) {
|
|
1971
|
+
const { stmts, endVar, valueVars } = emitSeqValues(def, ctx, pos);
|
|
1246
1972
|
const arrV = v(ctx, "_arr");
|
|
1247
1973
|
stmts.push(`${ind(ctx)}const ${arrV} = [${valueVars.join(", ")}]`);
|
|
1248
|
-
return { stmts, valueVar: arrV, endVar
|
|
1974
|
+
return { stmts, valueVar: arrV, endVar };
|
|
1249
1975
|
}
|
|
1250
1976
|
function emitChoice(def, ctx, pos) {
|
|
1251
1977
|
const allExpected = JSON.stringify(
|
|
@@ -1296,29 +2022,39 @@ function emitGreedyClassify(def, superIndex, allExpected, ctx, pos) {
|
|
|
1296
2022
|
const matchV = v(ctx, "_gm");
|
|
1297
2023
|
const wordV = v(ctx, "_gw");
|
|
1298
2024
|
const endV = v(ctx, "_ge");
|
|
2025
|
+
const valV = v(ctx, "_gcv");
|
|
1299
2026
|
const stmts = [
|
|
1300
2027
|
`${ind(ctx)}${reVar}.lastIndex = ${pos}`,
|
|
1301
2028
|
`${ind(ctx)}const ${matchV} = ${reVar}.exec(input)`,
|
|
1302
2029
|
`${ind(ctx)}if (${matchV} === null) ${failArr({ ...ctx, indent: 0 }, allExpected, pos)}`,
|
|
1303
2030
|
`${ind(ctx)}const ${wordV} = ${matchV}[0]`,
|
|
1304
|
-
`${ind(ctx)}const ${endV} = ${pos} + ${wordV}.length
|
|
2031
|
+
`${ind(ctx)}const ${endV} = ${pos} + ${wordV}.length`,
|
|
2032
|
+
`${ind(ctx)}let ${valV}`
|
|
1305
2033
|
];
|
|
2034
|
+
let first = true;
|
|
1306
2035
|
for (let i = 0; i < def.parsers.length; i++) {
|
|
1307
2036
|
if (i === superIndex) continue;
|
|
1308
2037
|
const p = def.parsers[i];
|
|
1309
2038
|
const litVal = getCoreLiteralValue(p);
|
|
1310
2039
|
if (litVal === null) continue;
|
|
1311
|
-
|
|
2040
|
+
const kw = first ? "if" : "else if";
|
|
2041
|
+
first = false;
|
|
2042
|
+
stmts.push(`${ind(ctx)}${kw} (${wordV} === ${JSON.stringify(litVal)}) {`);
|
|
1312
2043
|
ctx.indent++;
|
|
1313
2044
|
const tR = emitTransformChain(p, JSON.stringify(litVal), endV, pos, ctx);
|
|
1314
|
-
stmts.push(...
|
|
1315
|
-
stmts.push(`${ind(ctx)}
|
|
2045
|
+
stmts.push(...emitLeafCapture(ctx, JSON.stringify(litVal), pos, endV));
|
|
2046
|
+
stmts.push(...tR.stmts, `${ind(ctx)}${valV} = ${tR.valueVar}`);
|
|
1316
2047
|
ctx.indent--;
|
|
1317
2048
|
stmts.push(`${ind(ctx)}}`);
|
|
1318
2049
|
}
|
|
1319
2050
|
const rR = emitTransformChain(superParser, wordV, endV, pos, ctx);
|
|
1320
|
-
|
|
1321
|
-
|
|
2051
|
+
const regexKw = first ? "if" : "else";
|
|
2052
|
+
stmts.push(`${ind(ctx)}${regexKw} {`);
|
|
2053
|
+
ctx.indent++;
|
|
2054
|
+
stmts.push(...emitLeafCapture(ctx, wordV, pos, endV), ...rR.stmts, `${ind(ctx)}${valV} = ${rR.valueVar}`);
|
|
2055
|
+
ctx.indent--;
|
|
2056
|
+
stmts.push(`${ind(ctx)}}`);
|
|
2057
|
+
return { stmts, valueVar: valV, endVar: endV };
|
|
1322
2058
|
}
|
|
1323
2059
|
function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos) {
|
|
1324
2060
|
const valV = v(ctx, "_llv");
|
|
@@ -1332,10 +2068,15 @@ function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos) {
|
|
|
1332
2068
|
const litCond = emitLiteralCondition(litVal, pos);
|
|
1333
2069
|
const kw = first ? "if" : "else if";
|
|
1334
2070
|
first = false;
|
|
2071
|
+
const litEnd = `${pos} + ${litLen}`;
|
|
1335
2072
|
stmts.push(`${ind(ctx)}${kw} (${litCond}) {`);
|
|
1336
2073
|
ctx.indent++;
|
|
1337
|
-
const tR = emitTransformChain(p, JSON.stringify(litVal),
|
|
1338
|
-
stmts.push(
|
|
2074
|
+
const tR = emitTransformChain(p, JSON.stringify(litVal), litEnd, pos, ctx);
|
|
2075
|
+
stmts.push(
|
|
2076
|
+
...emitLeafCapture(ctx, JSON.stringify(litVal), pos, litEnd),
|
|
2077
|
+
...tR.stmts,
|
|
2078
|
+
`${ind(ctx)}${valV} = ${tR.valueVar}; ${endV} = ${litEnd}`
|
|
2079
|
+
);
|
|
1339
2080
|
ctx.indent--;
|
|
1340
2081
|
stmts.push(`${ind(ctx)}}`);
|
|
1341
2082
|
}
|
|
@@ -1343,67 +2084,66 @@ function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos) {
|
|
|
1343
2084
|
return { stmts, valueVar: valV, endVar: endV };
|
|
1344
2085
|
}
|
|
1345
2086
|
function emitFirstMatch(def, allExpected, ctx, pos) {
|
|
1346
|
-
const
|
|
1347
|
-
const
|
|
2087
|
+
const resValV = v(ctx, "_crv");
|
|
2088
|
+
const resEndV = v(ctx, "_cre");
|
|
2089
|
+
const resOkV = v(ctx, "_crok");
|
|
2090
|
+
const ind0 = ind(ctx);
|
|
2091
|
+
const stmts = [
|
|
2092
|
+
`${ind0}let ${resValV}, ${resEndV} = ${pos}, ${resOkV} = false`
|
|
2093
|
+
];
|
|
1348
2094
|
for (let i = 0; i < def.parsers.length; i++) {
|
|
1349
2095
|
const p = def.parsers[i];
|
|
1350
2096
|
const gate = def.gates[i];
|
|
1351
2097
|
const autoNot = def.autoNot[i];
|
|
1352
|
-
const savedIndent = ctx.indent;
|
|
1353
|
-
const savedFailLabel = ctx.failLabel;
|
|
1354
|
-
ctx.indent = 0;
|
|
1355
|
-
ctx.failLabel = void 0;
|
|
1356
|
-
const r = emit(p, ctx, pos);
|
|
1357
|
-
ctx.indent = savedIndent;
|
|
1358
|
-
ctx.failLabel = savedFailLabel;
|
|
1359
|
-
const iife = asIIFE(r.stmts, r.valueVar, r.endVar, pos, ind(ctx));
|
|
1360
2098
|
let gateCond = null;
|
|
1361
2099
|
if (gate) {
|
|
1362
2100
|
const gateIdx = ctx.mapFns.length;
|
|
1363
2101
|
ctx.mapFns.push(gate);
|
|
1364
2102
|
gateCond = `_mf[${gateIdx}](_ctx.state)`;
|
|
1365
2103
|
}
|
|
1366
|
-
const skipCond = gateCond ? `!${
|
|
2104
|
+
const skipCond = gateCond ? `!${resOkV} && ${gateCond}` : `!${resOkV}`;
|
|
1367
2105
|
const markLeaves = ctx.capturing ? v(ctx, "_cml") : null;
|
|
1368
2106
|
const markRaw = ctx.capturing ? v(ctx, "_cmr") : null;
|
|
1369
|
-
const
|
|
1370
|
-
const
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
const
|
|
2107
|
+
const markTl = ctx.capturing ? v(ctx, "_cmtl") : null;
|
|
2108
|
+
const markLog = ctx.capturing ? v(ctx, "_cmlg") : null;
|
|
2109
|
+
const rollback = markLeaves ? `if (_ctx._cstLeaves) _ctx._cstLeaves.length = ${markLeaves}; if (_ctx._cstRawChildren) _ctx._cstRawChildren.length = ${markRaw}; if (_ctx._cstTriviaLog) _ctx._cstTriviaLog.length = ${markTl}; if (_ctx._triviaLog) _ctx._triviaLog.length = ${markLog}` : "";
|
|
2110
|
+
stmts.push(`${ind0}if (${skipCond}) {`);
|
|
2111
|
+
ctx.indent++;
|
|
2112
|
+
const ind1 = ind(ctx);
|
|
2113
|
+
if (markLeaves) {
|
|
2114
|
+
stmts.push(
|
|
2115
|
+
`${ind1}const ${markLeaves} = _ctx._cstLeaves?.length ?? 0`,
|
|
2116
|
+
`${ind1}const ${markRaw} = _ctx._cstRawChildren?.length ?? 0`,
|
|
2117
|
+
`${ind1}const ${markTl} = _ctx._cstTriviaLog?.length ?? 0`,
|
|
2118
|
+
`${ind1}const ${markLog} = _ctx._triviaLog?.length ?? 0`
|
|
2119
|
+
);
|
|
2120
|
+
}
|
|
2121
|
+
const { stmts: armStmts, okVar, valVar, endVar } = emitFallible(p, ctx, pos);
|
|
2122
|
+
stmts.push(...armStmts);
|
|
2123
|
+
ctx.indent--;
|
|
1375
2124
|
if (autoNot && autoNot.length > 0) {
|
|
1376
|
-
const tmp = v(ctx, "_ct");
|
|
1377
2125
|
const anCode = v(ctx, "_anc");
|
|
1378
2126
|
const rejectCond = autoNot.map(
|
|
1379
|
-
(check) => check.kind === "firstSet" ? firstSetCond(anCode, check.set) : `input.startsWith(${JSON.stringify(check.value)}, ${
|
|
2127
|
+
(check) => check.kind === "firstSet" ? firstSetCond(anCode, check.set) : `input.startsWith(${JSON.stringify(check.value)}, ${endVar})`
|
|
1380
2128
|
).join(" || ");
|
|
1381
|
-
stmts.push(`${ind(ctx)}if (${skipCond}) {`);
|
|
1382
|
-
stmts.push(...markStmts);
|
|
1383
2129
|
stmts.push(
|
|
1384
|
-
`${
|
|
1385
|
-
`${ind(ctx)} if (${tmp}?.ok) { const ${anCode} = ${tmp}.span.end < input.length ? input.charCodeAt(${tmp}.span.end) : -1; if (!(${rejectCond})) ${resV} = ${tmp} }`
|
|
2130
|
+
`${ind0} if (${okVar}) { const ${anCode} = ${endVar} < input.length ? input.charCodeAt(${endVar}) : -1; if (!(${rejectCond})) { ${resValV} = ${valVar}; ${resEndV} = ${endVar}; ${resOkV} = true } }`
|
|
1386
2131
|
);
|
|
1387
|
-
if (
|
|
1388
|
-
stmts.push(`${ind(ctx)}}`);
|
|
2132
|
+
if (rollback) stmts.push(`${ind0} if (!${resOkV}) { ${rollback} }`);
|
|
1389
2133
|
} else {
|
|
1390
|
-
stmts.push(`${
|
|
1391
|
-
stmts.push(
|
|
1392
|
-
stmts.push(`${ind(ctx)} try { ${resV} = ${iife} } catch {}`);
|
|
1393
|
-
if (rollbackStmt) stmts.push(rollbackStmt);
|
|
1394
|
-
stmts.push(`${ind(ctx)}}`);
|
|
2134
|
+
stmts.push(`${ind0} if (${okVar}) { ${resValV} = ${valVar}; ${resEndV} = ${endVar}; ${resOkV} = true }`);
|
|
2135
|
+
if (rollback) stmts.push(`${ind0} else { ${rollback} }`);
|
|
1395
2136
|
}
|
|
2137
|
+
stmts.push(`${ind0}}`);
|
|
1396
2138
|
}
|
|
1397
|
-
stmts.push(`${
|
|
1398
|
-
return { stmts, valueVar:
|
|
2139
|
+
stmts.push(`${ind0}if (!${resOkV}) ${failArr({ ...ctx, indent: 0 }, allExpected, pos)}`);
|
|
2140
|
+
return { stmts, valueVar: resValV, endVar: resEndV };
|
|
1399
2141
|
}
|
|
1400
2142
|
function emitNonDisjoint(def, strategy, allExpected, ctx, pos) {
|
|
1401
|
-
if (
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
return emitLiteralsLongestFirst(def, strategy.sortedIndices, allExpected, ctx, pos);
|
|
1406
|
-
}
|
|
2143
|
+
if (strategy.tag === "greedyClassify")
|
|
2144
|
+
return emitGreedyClassify(def, strategy.superIndex, allExpected, ctx, pos);
|
|
2145
|
+
if (strategy.tag === "literalsLongestFirst")
|
|
2146
|
+
return emitLiteralsLongestFirst(def, strategy.sortedIndices, allExpected, ctx, pos);
|
|
1407
2147
|
return emitFirstMatch(def, allExpected, ctx, pos);
|
|
1408
2148
|
}
|
|
1409
2149
|
function emitTransformChain(p, baseValue, endV, startPos, ctx) {
|
|
@@ -1456,27 +2196,28 @@ function emitMany(def, ctx, pos) {
|
|
|
1456
2196
|
if (ctx.capturing) {
|
|
1457
2197
|
const capFn = ensureTriviaCaptureFn(ctx);
|
|
1458
2198
|
const markV = v(ctx, "_mk");
|
|
2199
|
+
const markTl = v(ctx, "_mktl");
|
|
2200
|
+
const markLog = v(ctx, "_mklg");
|
|
1459
2201
|
const npV = v(ctx, "_np");
|
|
1460
2202
|
stmts.push(
|
|
1461
2203
|
`${ind(ctx)}const ${markV} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
|
|
1462
|
-
`${ind(ctx)}const ${
|
|
2204
|
+
`${ind(ctx)}const ${markTl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
|
|
2205
|
+
`${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
|
|
2206
|
+
`${ind(ctx)}const ${npV} = ${capFn}(input, ${curV}, _ctx, 1)`
|
|
1463
2207
|
);
|
|
1464
2208
|
itemPos = npV;
|
|
1465
|
-
rollback = `if (_ctx._cstRawChildren) _ctx._cstRawChildren.length = ${markV}; `;
|
|
2209
|
+
rollback = `if (_ctx._cstRawChildren) _ctx._cstRawChildren.length = ${markV}; if (_ctx._cstTriviaLog) _ctx._cstTriviaLog.length = ${markTl}; if (_ctx._triviaLog) _ctx._triviaLog.length = ${markLog}; `;
|
|
1466
2210
|
} else {
|
|
1467
2211
|
const trivFn = ensureTriviaFn(ctx);
|
|
1468
2212
|
const npV = v(ctx, "_np");
|
|
1469
|
-
stmts.push(
|
|
1470
|
-
`${ind(ctx)}let ${npV} = ${curV}`,
|
|
1471
|
-
`${ind(ctx)}{ const _trv = ${trivFn}(input, ${npV}, _ctx); if (_trv.ok) ${npV} = _trv.span.end }`
|
|
1472
|
-
);
|
|
2213
|
+
stmts.push(`${ind(ctx)}const ${npV} = ${trivFn}(input, ${curV}, _ctx)`);
|
|
1473
2214
|
itemPos = npV;
|
|
1474
2215
|
}
|
|
1475
2216
|
}
|
|
1476
2217
|
const { stmts: iterStmts, okVar: iterOk, valVar: iterVal, endVar: iterEnd } = emitFallible(def.parser, ctx, itemPos);
|
|
1477
2218
|
stmts.push(
|
|
1478
2219
|
...iterStmts,
|
|
1479
|
-
`${ind(ctx)}if (!${iterOk} || ${iterEnd}
|
|
2220
|
+
`${ind(ctx)}if (!${iterOk} || ${iterEnd} <= ${itemPos}) { ${rollback}break }`,
|
|
1480
2221
|
`${ind(ctx)}${arrV}.push(${iterVal})`,
|
|
1481
2222
|
`${ind(ctx)}${curV} = ${iterEnd}`
|
|
1482
2223
|
);
|
|
@@ -1513,55 +2254,70 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
1513
2254
|
`${ind(ctx)}while (${curV} < input.length) {`
|
|
1514
2255
|
);
|
|
1515
2256
|
ctx.indent++;
|
|
1516
|
-
let rollback = "";
|
|
1517
|
-
if (ctx.capturing) {
|
|
1518
|
-
const markV = v(ctx, "_mk");
|
|
1519
|
-
stmts.push(`${ind(ctx)}const ${markV} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`);
|
|
1520
|
-
rollback = `if (_ctx._cstRawChildren) _ctx._cstRawChildren.length = ${markV}; `;
|
|
1521
|
-
}
|
|
1522
2257
|
let sepAtPos = curV;
|
|
1523
2258
|
if (ctx.activeTrivia) {
|
|
1524
2259
|
if (ctx.capturing) {
|
|
1525
2260
|
const capFn = ensureTriviaCaptureFn(ctx);
|
|
1526
|
-
const
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
} else {
|
|
1530
|
-
const trivFn = ensureTriviaFn(ctx);
|
|
2261
|
+
const markV = v(ctx, "_mk");
|
|
2262
|
+
const markTl = v(ctx, "_mktl");
|
|
2263
|
+
const markLog = v(ctx, "_mklg");
|
|
1531
2264
|
const spV = v(ctx, "_sp");
|
|
1532
2265
|
stmts.push(
|
|
1533
|
-
`${ind(ctx)}
|
|
1534
|
-
`${ind(ctx)}
|
|
2266
|
+
`${ind(ctx)}const ${markV} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
|
|
2267
|
+
`${ind(ctx)}const ${markTl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
|
|
2268
|
+
`${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
|
|
2269
|
+
`${ind(ctx)}const ${spV} = ${capFn}(input, ${curV}, _ctx, 1)`
|
|
1535
2270
|
);
|
|
1536
2271
|
sepAtPos = spV;
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
if (ctx.capturing) {
|
|
1544
|
-
const capFn = ensureTriviaCaptureFn(ctx);
|
|
2272
|
+
const sepRollback = `if (_ctx._cstRawChildren) _ctx._cstRawChildren.length = ${markV}; if (_ctx._cstTriviaLog) _ctx._cstTriviaLog.length = ${markTl}; if (_ctx._triviaLog) _ctx._triviaLog.length = ${markLog}; `;
|
|
2273
|
+
const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = emitFallible(def.separator, ctx, sepAtPos);
|
|
2274
|
+
stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${sepRollback}break }`);
|
|
2275
|
+
const mark2V = v(ctx, "_mk2");
|
|
2276
|
+
const mark2Tl = v(ctx, "_mktl2");
|
|
2277
|
+
const mark2Log = v(ctx, "_mklg2");
|
|
1545
2278
|
const npV = v(ctx, "_np");
|
|
1546
|
-
stmts.push(
|
|
1547
|
-
|
|
2279
|
+
stmts.push(
|
|
2280
|
+
`${ind(ctx)}const ${mark2V} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
|
|
2281
|
+
`${ind(ctx)}const ${mark2Tl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
|
|
2282
|
+
`${ind(ctx)}const ${mark2Log} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
|
|
2283
|
+
`${ind(ctx)}const ${npV} = ${capFn}(input, ${sepEnd}, _ctx, 1)`
|
|
2284
|
+
);
|
|
2285
|
+
const nextRollback = `if (_ctx._cstRawChildren) _ctx._cstRawChildren.length = ${mark2V}; if (_ctx._cstTriviaLog) _ctx._cstTriviaLog.length = ${mark2Tl}; if (_ctx._triviaLog) _ctx._triviaLog.length = ${mark2Log}; `;
|
|
2286
|
+
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, npV);
|
|
2287
|
+
stmts.push(
|
|
2288
|
+
...nextStmts,
|
|
2289
|
+
`${ind(ctx)}if (!${nextOk}) { ${nextRollback}break }`,
|
|
2290
|
+
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
2291
|
+
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
2292
|
+
);
|
|
1548
2293
|
} else {
|
|
1549
2294
|
const trivFn = ensureTriviaFn(ctx);
|
|
2295
|
+
const spV = v(ctx, "_sp");
|
|
2296
|
+
stmts.push(`${ind(ctx)}const ${spV} = ${trivFn}(input, ${curV}, _ctx)`);
|
|
2297
|
+
sepAtPos = spV;
|
|
2298
|
+
const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = emitFallible(def.separator, ctx, sepAtPos);
|
|
2299
|
+
stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) break`);
|
|
1550
2300
|
const npV = v(ctx, "_np");
|
|
2301
|
+
stmts.push(`${ind(ctx)}const ${npV} = ${trivFn}(input, ${sepEnd}, _ctx)`);
|
|
2302
|
+
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, npV);
|
|
1551
2303
|
stmts.push(
|
|
1552
|
-
|
|
1553
|
-
`${ind(ctx)}
|
|
2304
|
+
...nextStmts,
|
|
2305
|
+
`${ind(ctx)}if (!${nextOk}) break`,
|
|
2306
|
+
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
2307
|
+
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
1554
2308
|
);
|
|
1555
|
-
nextAtPos = npV;
|
|
1556
2309
|
}
|
|
2310
|
+
} else {
|
|
2311
|
+
const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = emitFallible(def.separator, ctx, sepAtPos);
|
|
2312
|
+
stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) break`);
|
|
2313
|
+
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, sepEnd);
|
|
2314
|
+
stmts.push(
|
|
2315
|
+
...nextStmts,
|
|
2316
|
+
`${ind(ctx)}if (!${nextOk}) break`,
|
|
2317
|
+
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
2318
|
+
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
2319
|
+
);
|
|
1557
2320
|
}
|
|
1558
|
-
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, nextAtPos);
|
|
1559
|
-
stmts.push(
|
|
1560
|
-
...nextStmts,
|
|
1561
|
-
`${ind(ctx)}if (!${nextOk}) { ${rollback}break }`,
|
|
1562
|
-
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
1563
|
-
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
1564
|
-
);
|
|
1565
2321
|
ctx.indent--;
|
|
1566
2322
|
stmts.push(`${ind(ctx)}}`);
|
|
1567
2323
|
ctx.indent--;
|
|
@@ -1623,27 +2379,33 @@ function emitNot(def, ctx, pos) {
|
|
|
1623
2379
|
};
|
|
1624
2380
|
}
|
|
1625
2381
|
function emitNode(def, ctx, pos) {
|
|
1626
|
-
const
|
|
1627
|
-
|
|
1628
|
-
|
|
2382
|
+
const mkType = analyzeMkInlineBuild(def);
|
|
2383
|
+
let buildIdx = null;
|
|
2384
|
+
if (!mkType) {
|
|
2385
|
+
buildIdx = ctx.buildFns.length;
|
|
2386
|
+
ctx.buildFns.push(def.build);
|
|
2387
|
+
ctx.buildSrcs.push(def.buildSrc ?? null);
|
|
2388
|
+
}
|
|
1629
2389
|
const i = ind(ctx);
|
|
1630
2390
|
const chV = v(ctx, "_ch");
|
|
1631
2391
|
const rawV = v(ctx, "_raw");
|
|
1632
|
-
const
|
|
2392
|
+
const tlV = v(ctx, "_tl");
|
|
2393
|
+
const sc = v(ctx, "_sc"), sl = v(ctx, "_sl"), sr = v(ctx, "_sr"), st = v(ctx, "_st"), stl = v(ctx, "_stl");
|
|
1633
2394
|
const stmts = [
|
|
1634
|
-
`${i}const ${chV} = [], ${rawV} = []`,
|
|
1635
|
-
`${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren, ${st} = _ctx.captureTrivia`,
|
|
1636
|
-
`${i}_ctx._cstChildren = ${chV}; _ctx._cstLeaves = ${chV}; _ctx._cstRawChildren = ${rawV}; _ctx.captureTrivia = true`
|
|
2395
|
+
`${i}const ${chV} = [], ${rawV} = [], ${tlV} = []`,
|
|
2396
|
+
`${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren, ${st} = _ctx.captureTrivia, ${stl} = _ctx._cstTriviaLog`,
|
|
2397
|
+
`${i}_ctx._cstChildren = ${chV}; _ctx._cstLeaves = ${chV}; _ctx._cstRawChildren = ${rawV}; _ctx.captureTrivia = true; _ctx._cstTriviaLog = ${tlV}`
|
|
1637
2398
|
];
|
|
1638
2399
|
const { stmts: innerStmts, okVar, endVar } = emitFallible(def.parser, ctx, pos);
|
|
1639
2400
|
stmts.push(...innerStmts);
|
|
1640
|
-
stmts.push(`${i}_ctx._cstChildren = ${sc}; _ctx._cstLeaves = ${sl}; _ctx._cstRawChildren = ${sr}; _ctx.captureTrivia = ${st}`);
|
|
2401
|
+
stmts.push(`${i}_ctx._cstChildren = ${sc}; _ctx._cstLeaves = ${sl}; _ctx._cstRawChildren = ${sr}; _ctx.captureTrivia = ${st}; _ctx._cstTriviaLog = ${stl}`);
|
|
1641
2402
|
stmts.push(`${i}if (!${okVar}) ${failStmt({ ...ctx, indent: 0 }, '"node"', pos).trim()}`);
|
|
2403
|
+
const stV = v(ctx, "_nst");
|
|
2404
|
+
stmts.push(`${i}const ${stV} = _ctx.state !== undefined ? Object.assign({}, _ctx.state) : undefined`);
|
|
1642
2405
|
const ndV = v(ctx, "_nd");
|
|
2406
|
+
const ndExpr = mkType ? emitInlineMkNodeExpr(mkType, chV, rawV, pos, endVar, tlV) : `_build[${buildIdx}](${chV}, ${rawV}, { start: ${pos}, end: ${endVar} }, ${tlV}, ${stV})`;
|
|
1643
2407
|
stmts.push(
|
|
1644
|
-
`${i}const ${ndV} =
|
|
1645
|
-
// Record into the caller's collectors (the node in children; the node, or a
|
|
1646
|
-
// spanned leaf if build collapsed to a non-node value, in rawChildren).
|
|
2408
|
+
`${i}const ${ndV} = ${ndExpr}`,
|
|
1647
2409
|
`${i}if (${sc}) ${sc}.push(${ndV})`,
|
|
1648
2410
|
`${i}if (${sr}) ${sr}.push((typeof ${ndV} === 'object' && ${ndV} !== null && ${ndV}._tag === 'node') ? ${ndV} : { _tag: 'leaf', value: typeof ${ndV} === 'string' ? ${ndV} : '', span: { start: ${pos}, end: ${endVar} } })`
|
|
1649
2411
|
);
|
|
@@ -1677,31 +2439,14 @@ function emitLazy(p, def, ctx, pos) {
|
|
|
1677
2439
|
const savedIndent = ctx.indent;
|
|
1678
2440
|
const savedFailLabel = ctx.failLabel;
|
|
1679
2441
|
ctx.indent = 1;
|
|
1680
|
-
ctx.failLabel =
|
|
2442
|
+
ctx.failLabel = "_pfail";
|
|
1681
2443
|
const r = emit(resolved, ctx, "_pos");
|
|
1682
2444
|
ctx.indent = savedIndent;
|
|
1683
2445
|
ctx.failLabel = savedFailLabel;
|
|
1684
|
-
ctx.
|
|
1685
|
-
`function ${fnName2}(input, _pos, _ctx) {`,
|
|
1686
|
-
...r.stmts,
|
|
1687
|
-
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
|
|
1688
|
-
`}`
|
|
1689
|
-
].join("\n"));
|
|
2446
|
+
pushNamedFnDecl(ctx, fnName2, r.stmts, r.valueVar, r.endVar);
|
|
1690
2447
|
}
|
|
1691
2448
|
const fnName = ctx.namedParsers.get(p);
|
|
1692
|
-
|
|
1693
|
-
const vv = v(ctx, "_pfv");
|
|
1694
|
-
const ev = v(ctx, "_pfe");
|
|
1695
|
-
return {
|
|
1696
|
-
stmts: [
|
|
1697
|
-
`${ind(ctx)}const ${rv} = ${fnName}(input, ${pos}, _ctx)`,
|
|
1698
|
-
`${ind(ctx)}if (!${rv}.ok) ${failStmt({ ...ctx, indent: 0 }, '"parser"', pos).trim()}`,
|
|
1699
|
-
`${ind(ctx)}const ${vv} = ${rv}.value`,
|
|
1700
|
-
`${ind(ctx)}const ${ev} = ${rv}.span.end`
|
|
1701
|
-
],
|
|
1702
|
-
valueVar: vv,
|
|
1703
|
-
endVar: ev
|
|
1704
|
-
};
|
|
2449
|
+
return emitNamedFnCall(ctx, fnName, pos, '"parser"');
|
|
1705
2450
|
}
|
|
1706
2451
|
function emitRecover(def, ctx, pos) {
|
|
1707
2452
|
const { stmts: innerStmts, okVar, valVar, endVar } = emitFallible(def.parser, ctx, pos);
|
|
@@ -1737,6 +2482,8 @@ function emit(p, ctx, pos) {
|
|
|
1737
2482
|
return emitLit(def, ctx, pos);
|
|
1738
2483
|
case "regex":
|
|
1739
2484
|
return emitRegex(def, ctx, pos);
|
|
2485
|
+
case "keywords":
|
|
2486
|
+
return emitKeywords(def, ctx, pos);
|
|
1740
2487
|
case "sequence":
|
|
1741
2488
|
return emitSeq(def, ctx, pos);
|
|
1742
2489
|
case "choice":
|
|
@@ -1749,7 +2496,31 @@ function emit(p, ctx, pos) {
|
|
|
1749
2496
|
case "sepBy":
|
|
1750
2497
|
return emitSepBy(p, def, ctx, pos);
|
|
1751
2498
|
case "transform": {
|
|
2499
|
+
const fnSrc = transformFnSource(def.fn, def.fnSrc);
|
|
2500
|
+
if (fnSrc && def.parser._def.tag === "sequence") {
|
|
2501
|
+
const seqR = emitSeqValues(def.parser._def, ctx, pos);
|
|
2502
|
+
const inlined = tryInlineDestructureTransform(fnSrc, seqR.valueVars);
|
|
2503
|
+
if (inlined) {
|
|
2504
|
+
const mv2 = v(ctx, "_mapped");
|
|
2505
|
+
return {
|
|
2506
|
+
stmts: [...seqR.stmts, `${ind(ctx)}const ${mv2} = ${inlined}`],
|
|
2507
|
+
valueVar: mv2,
|
|
2508
|
+
endVar: seqR.endVar
|
|
2509
|
+
};
|
|
2510
|
+
}
|
|
2511
|
+
}
|
|
1752
2512
|
const inner = emit(def.parser, ctx, pos);
|
|
2513
|
+
if (fnSrc) {
|
|
2514
|
+
const unary = tryInlineUnaryTransform(fnSrc, inner.valueVar);
|
|
2515
|
+
if (unary) {
|
|
2516
|
+
const mv2 = v(ctx, "_mapped");
|
|
2517
|
+
return {
|
|
2518
|
+
stmts: [...inner.stmts, `${ind(ctx)}const ${mv2} = ${unary}`],
|
|
2519
|
+
valueVar: mv2,
|
|
2520
|
+
endVar: inner.endVar
|
|
2521
|
+
};
|
|
2522
|
+
}
|
|
2523
|
+
}
|
|
1753
2524
|
const fnIdx = ctx.mapFns.length;
|
|
1754
2525
|
ctx.mapFns.push(def.fn);
|
|
1755
2526
|
ctx.mapFnSrcs.push(def.fnSrc ?? null);
|
|
@@ -1785,12 +2556,20 @@ function emit(p, ctx, pos) {
|
|
|
1785
2556
|
return emitLazy(p, def, ctx, pos);
|
|
1786
2557
|
case "trivia":
|
|
1787
2558
|
return emit(def.parser, ctx, pos);
|
|
2559
|
+
case "label":
|
|
2560
|
+
return emit(def.parser, ctx, pos);
|
|
1788
2561
|
case "grammar": {
|
|
1789
2562
|
const savedTrivia = ctx.activeTrivia;
|
|
1790
|
-
|
|
2563
|
+
const savedKindLabels = ctx.triviaKindLabels;
|
|
2564
|
+
if (def.triviaParser) {
|
|
2565
|
+
ctx.activeTrivia = def.triviaParser;
|
|
2566
|
+
if (def.triviaParser._meta.triviaKindLabels) {
|
|
2567
|
+
ctx.triviaKindLabels = def.triviaParser._meta.triviaKindLabels;
|
|
2568
|
+
}
|
|
2569
|
+
}
|
|
1791
2570
|
const r = emit(def.parser, ctx, pos);
|
|
1792
|
-
|
|
1793
|
-
|
|
2571
|
+
ctx.activeTrivia = savedTrivia;
|
|
2572
|
+
ctx.triviaKindLabels = savedKindLabels;
|
|
1794
2573
|
return r;
|
|
1795
2574
|
}
|
|
1796
2575
|
case "not":
|
|
@@ -1825,27 +2604,22 @@ function emit(p, ctx, pos) {
|
|
|
1825
2604
|
const savedIndent = ctx.indent;
|
|
1826
2605
|
const savedFailLabel = ctx.failLabel;
|
|
1827
2606
|
ctx.indent = 1;
|
|
1828
|
-
ctx.failLabel =
|
|
2607
|
+
ctx.failLabel = "_pfail";
|
|
1829
2608
|
const innerR = emit(innerParser, ctx, "_pos");
|
|
1830
2609
|
ctx.indent = savedIndent;
|
|
1831
2610
|
ctx.failLabel = savedFailLabel;
|
|
1832
|
-
ctx.
|
|
1833
|
-
`function ${fnName}(input, _pos, _ctx) {`,
|
|
1834
|
-
...innerR.stmts,
|
|
1835
|
-
` return { ok: true, value: ${innerR.valueVar}, span: { start: _pos, end: ${innerR.endVar} } }`,
|
|
1836
|
-
`}`
|
|
1837
|
-
].join("\n"));
|
|
2611
|
+
pushNamedFnDecl(ctx, fnName, innerR.stmts, innerR.valueVar, innerR.endVar);
|
|
1838
2612
|
}
|
|
1839
2613
|
const fn = ctx.namedParsers.get(innerParser);
|
|
1840
2614
|
const rv = v(ctx, "_wcr");
|
|
1841
|
-
const vv = v(ctx);
|
|
2615
|
+
const vv = v(ctx, "_wcv");
|
|
1842
2616
|
const ev = v(ctx, "_wce");
|
|
1843
2617
|
return {
|
|
1844
2618
|
stmts: [
|
|
1845
|
-
`${ind(ctx)}const ${rv} =
|
|
1846
|
-
`${ind(ctx)}
|
|
1847
|
-
`${ind(ctx)}
|
|
1848
|
-
`${ind(ctx)}const ${ev} = ${
|
|
2619
|
+
`${ind(ctx)}const ${rv} = { ..._ctx, state: _mf[${evIdx}]() }`,
|
|
2620
|
+
`${ind(ctx)}const ${vv} = ${fn}(input, ${pos}, ${rv})`,
|
|
2621
|
+
`${ind(ctx)}if (${vv} === ${NAMED_FN_FAIL}) ${failStmt({ ...ctx, indent: 0 }, '"withCtx"', pos).trim()}`,
|
|
2622
|
+
`${ind(ctx)}const ${ev} = ${NAMED_FN_END}`
|
|
1849
2623
|
],
|
|
1850
2624
|
valueVar: vv,
|
|
1851
2625
|
endVar: ev
|
|
@@ -1871,6 +2645,7 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
1871
2645
|
}
|
|
1872
2646
|
case "grammar":
|
|
1873
2647
|
case "trivia":
|
|
2648
|
+
case "label":
|
|
1874
2649
|
case "optional":
|
|
1875
2650
|
case "many":
|
|
1876
2651
|
case "oneOrMore":
|
|
@@ -1894,7 +2669,7 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
1894
2669
|
return false;
|
|
1895
2670
|
}
|
|
1896
2671
|
}
|
|
1897
|
-
function compile(
|
|
2672
|
+
function compile(combinator, mapFnSources) {
|
|
1898
2673
|
const ctx = {
|
|
1899
2674
|
vars: 0,
|
|
1900
2675
|
indent: 1,
|
|
@@ -1908,15 +2683,18 @@ function compile(parser2, mapFnSources) {
|
|
|
1908
2683
|
needsCollator: false,
|
|
1909
2684
|
namedParsers: /* @__PURE__ */ new Map(),
|
|
1910
2685
|
triviaCaptureNames: /* @__PURE__ */ new Map(),
|
|
2686
|
+
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
1911
2687
|
namedFnDecls: [],
|
|
1912
|
-
capturing: hasNodeDef(
|
|
2688
|
+
capturing: hasNodeDef(combinator)
|
|
1913
2689
|
};
|
|
1914
|
-
const r = emit(
|
|
2690
|
+
const r = emit(combinator, ctx, "_pos");
|
|
1915
2691
|
const collatorDecl = ctx.needsCollator ? `const _collator = new Intl.Collator(undefined, { sensitivity: 'accent' })
|
|
1916
2692
|
` : "";
|
|
2693
|
+
const namedPrelude = ctx.namedFnDecls.length > 0 ? [...namedFnPrelude(), ""] : [];
|
|
1917
2694
|
const source = [
|
|
1918
2695
|
...ctx.regexDecls,
|
|
1919
2696
|
"",
|
|
2697
|
+
...namedPrelude,
|
|
1920
2698
|
...ctx.namedFnDecls,
|
|
1921
2699
|
`${collatorDecl}function _parse(input, _pos, _rp, _mf, _build, _ctx) {`,
|
|
1922
2700
|
` let pos = _pos`,
|
|
@@ -1927,12 +2705,16 @@ function compile(parser2, mapFnSources) {
|
|
|
1927
2705
|
const fn = new Function("input", "_pos", "_rp", "_mf", "_build", "_ctx", [
|
|
1928
2706
|
...ctx.regexDecls,
|
|
1929
2707
|
collatorDecl,
|
|
2708
|
+
...namedPrelude,
|
|
1930
2709
|
...ctx.namedFnDecls,
|
|
1931
2710
|
`let pos = _pos`,
|
|
1932
2711
|
...r.stmts,
|
|
1933
2712
|
`return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`
|
|
1934
2713
|
].join("\n"));
|
|
1935
|
-
const defaultCtx = {
|
|
2714
|
+
const defaultCtx = {
|
|
2715
|
+
trackLines: false,
|
|
2716
|
+
...ctx.triviaKindLabels ? { triviaKindLabels: ctx.triviaKindLabels } : {}
|
|
2717
|
+
};
|
|
1936
2718
|
const derivedSrcs = ctx.mapFnSrcs.length === ctx.mapFns.length && ctx.mapFnSrcs.every((s) => s !== null) ? ctx.mapFnSrcs : void 0;
|
|
1937
2719
|
const effectiveSources = mapFnSources ?? derivedSrcs;
|
|
1938
2720
|
const buildCovered = ctx.buildFns.length === 0 || ctx.buildSrcs.every((s) => s !== null);
|
|
@@ -1946,6 +2728,9 @@ function compile(parser2, mapFnSources) {
|
|
|
1946
2728
|
parse(input, pos = 0) {
|
|
1947
2729
|
return fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, defaultCtx);
|
|
1948
2730
|
},
|
|
2731
|
+
parseWithContext(input, parseCtx, pos = 0) {
|
|
2732
|
+
return fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, parseCtx);
|
|
2733
|
+
},
|
|
1949
2734
|
parseWithErrors(input, pos = 0) {
|
|
1950
2735
|
const errors = [];
|
|
1951
2736
|
const result = fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, { ...defaultCtx, _errors: errors });
|
|
@@ -1968,12 +2753,14 @@ function buildInlineExpression(ctx, r, collatorDecl, mapFnSources, buildSources)
|
|
|
1968
2753
|
const buildDecl = buildSources?.length ? ` const _build = [${buildSources.join(", ")}]` : "";
|
|
1969
2754
|
const needsWrapper = ctx.regexDecls.length > 0 || !!collatorDecl || ctx.namedFnDecls.length > 0 || !!mfDecl || !!buildDecl;
|
|
1970
2755
|
if (!needsWrapper) return innerFn;
|
|
2756
|
+
const namedPrelude = ctx.namedFnDecls.length > 0 ? namedFnPrelude() : [];
|
|
1971
2757
|
return [
|
|
1972
2758
|
`/* @__PURE__ */ (() => {`,
|
|
1973
2759
|
...ctx.regexDecls.map((d) => ` ${d}`),
|
|
1974
2760
|
collatorDecl ? ` ${collatorDecl.trim()}` : "",
|
|
1975
2761
|
mfDecl,
|
|
1976
2762
|
buildDecl,
|
|
2763
|
+
...namedPrelude.map((l) => ` ${l}`),
|
|
1977
2764
|
...ctx.namedFnDecls.flatMap((f) => f.split("\n").map((l) => ` ${l}`)),
|
|
1978
2765
|
` return ${innerFn}`,
|
|
1979
2766
|
`})()`
|
|
@@ -2000,24 +2787,24 @@ function guard(predicate) {
|
|
|
2000
2787
|
}
|
|
2001
2788
|
|
|
2002
2789
|
// src/combinators/withCtx.ts
|
|
2003
|
-
function withCtx(extra,
|
|
2790
|
+
function withCtx(extra, combinator) {
|
|
2004
2791
|
const meta = {
|
|
2005
|
-
firstSet:
|
|
2006
|
-
canMatchNewline:
|
|
2792
|
+
firstSet: combinator._meta.firstSet,
|
|
2793
|
+
canMatchNewline: combinator._meta.canMatchNewline,
|
|
2007
2794
|
isTrivia: false
|
|
2008
2795
|
};
|
|
2009
2796
|
return {
|
|
2010
2797
|
_tag: "withCtx",
|
|
2011
2798
|
_meta: meta,
|
|
2012
|
-
_def: { tag: "withCtx", extra, parser:
|
|
2799
|
+
_def: { tag: "withCtx", extra, parser: combinator },
|
|
2013
2800
|
parse(input, pos, ctx) {
|
|
2014
|
-
return
|
|
2801
|
+
return combinator.parse(input, pos, { ...ctx, state: extra });
|
|
2015
2802
|
}
|
|
2016
2803
|
};
|
|
2017
2804
|
}
|
|
2018
2805
|
|
|
2019
2806
|
// src/combinators/recover.ts
|
|
2020
|
-
function recover(
|
|
2807
|
+
function recover(combinator, sentinel) {
|
|
2021
2808
|
const meta = {
|
|
2022
2809
|
firstSet: { kind: "any" },
|
|
2023
2810
|
canMatchNewline: true,
|
|
@@ -2026,9 +2813,9 @@ function recover(parser2, sentinel) {
|
|
|
2026
2813
|
return {
|
|
2027
2814
|
_tag: "recover",
|
|
2028
2815
|
_meta: meta,
|
|
2029
|
-
_def: { tag: "recover", parser:
|
|
2816
|
+
_def: { tag: "recover", parser: combinator, sentinel },
|
|
2030
2817
|
parse(input, pos, ctx) {
|
|
2031
|
-
const result =
|
|
2818
|
+
const result = combinator.parse(input, pos, ctx);
|
|
2032
2819
|
if (result.ok) return result;
|
|
2033
2820
|
let scanPos = pos;
|
|
2034
2821
|
while (scanPos < input.length) {
|
|
@@ -2050,10 +2837,10 @@ function isParseError(value) {
|
|
|
2050
2837
|
}
|
|
2051
2838
|
|
|
2052
2839
|
// src/combinators/completions.ts
|
|
2053
|
-
function completionsAt(
|
|
2840
|
+
function completionsAt(combinator, input, offset) {
|
|
2054
2841
|
const probe = { offset, best: null };
|
|
2055
2842
|
const ctx = { trackLines: false, _probe: probe };
|
|
2056
|
-
const result =
|
|
2843
|
+
const result = combinator.parse(input.slice(0, offset), 0, ctx);
|
|
2057
2844
|
if (result.ok) return [];
|
|
2058
2845
|
const best = deeperFail(probe.best, result);
|
|
2059
2846
|
return best?.expected ?? [];
|
|
@@ -2079,10 +2866,9 @@ function scanTo(sentinel, { skip: skip2 = [], orEOF = false } = {}) {
|
|
|
2079
2866
|
let cur = pos;
|
|
2080
2867
|
const probeCtx = { trackLines: ctx.trackLines, state: ctx.state };
|
|
2081
2868
|
const emit2 = (end) => {
|
|
2082
|
-
if (end > pos && (ctx
|
|
2869
|
+
if (end > pos && cstCaptureActive(ctx)) {
|
|
2083
2870
|
const leaf = { _tag: "leaf", value: input.slice(pos, end), span: { start: pos, end } };
|
|
2084
|
-
|
|
2085
|
-
if (ctx._cstRawChildren) ctx._cstRawChildren.push(leaf);
|
|
2871
|
+
pushCstLeaf(ctx, leaf);
|
|
2086
2872
|
}
|
|
2087
2873
|
};
|
|
2088
2874
|
while (cur < input.length) {
|
|
@@ -2124,7 +2910,7 @@ function balanced(open, close, options = {}) {
|
|
|
2124
2910
|
return combi;
|
|
2125
2911
|
}
|
|
2126
2912
|
|
|
2127
|
-
// src/
|
|
2913
|
+
// src/functional/doc.ts
|
|
2128
2914
|
function isNode(x) {
|
|
2129
2915
|
return typeof x === "object" && x !== null && x._tag === "node";
|
|
2130
2916
|
}
|
|
@@ -2133,7 +2919,8 @@ function findContaining(node2, pos, path = []) {
|
|
|
2133
2919
|
const child = node2.children[i];
|
|
2134
2920
|
if (!isNode(child)) continue;
|
|
2135
2921
|
if (child.span.start <= pos && pos < child.span.end) {
|
|
2136
|
-
|
|
2922
|
+
const inner = findContaining(child, pos, [...path, i]);
|
|
2923
|
+
return inner ?? { node: child, path: [...path, i] };
|
|
2137
2924
|
}
|
|
2138
2925
|
}
|
|
2139
2926
|
return null;
|
|
@@ -2149,249 +2936,11 @@ function ancestorsAt(root, path) {
|
|
|
2149
2936
|
}
|
|
2150
2937
|
return ancestors;
|
|
2151
2938
|
}
|
|
2152
|
-
function replaceAtPath(
|
|
2153
|
-
if (path.length === 0) return newNode;
|
|
2154
|
-
const [idx, ...rest] = path;
|
|
2155
|
-
const newChildren = [...root.children];
|
|
2156
|
-
newChildren[idx] = rest.length === 0 ? newNode : replaceAtPath(grammar, root.children[idx], rest, newNode);
|
|
2157
|
-
return grammar.rebuild(root, newChildren);
|
|
2158
|
-
}
|
|
2159
|
-
var ParseDocImpl = class _ParseDocImpl {
|
|
2160
|
-
_parser;
|
|
2161
|
-
_ruleName;
|
|
2162
|
-
_trivia;
|
|
2163
|
-
_captureTrivia;
|
|
2164
|
-
tree;
|
|
2165
|
-
errors;
|
|
2166
|
-
input;
|
|
2167
|
-
/** Offset reached by the top-level rule. < input.length means input was left unconsumed. */
|
|
2168
|
-
consumedEnd;
|
|
2169
|
-
constructor(parser2, ruleName, tree, errors, input, trivia2, captureTrivia, consumedEnd = 0) {
|
|
2170
|
-
this._parser = parser2;
|
|
2171
|
-
this._ruleName = ruleName;
|
|
2172
|
-
this._trivia = trivia2;
|
|
2173
|
-
this._captureTrivia = captureTrivia;
|
|
2174
|
-
this.tree = tree;
|
|
2175
|
-
this.errors = errors;
|
|
2176
|
-
this.input = input;
|
|
2177
|
-
this.consumedEnd = consumedEnd;
|
|
2178
|
-
}
|
|
2179
|
-
edit(from, to, replacement) {
|
|
2180
|
-
const newInput = this.input.slice(0, from) + replacement + this.input.slice(to);
|
|
2181
|
-
if (!this.tree) return makeParseDoc(this._parser, this._ruleName, newInput, this._trivia, this._captureTrivia);
|
|
2182
|
-
const delta = replacement.length - (to - from);
|
|
2183
|
-
const found = findContaining(this.tree, from);
|
|
2184
|
-
if (!found) return makeParseDoc(this._parser, this._ruleName, newInput, this._trivia, this._captureTrivia);
|
|
2185
|
-
const ancestors = ancestorsAt(this.tree, found.path);
|
|
2186
|
-
const candidates = [found];
|
|
2187
|
-
const pathCopy = [...found.path];
|
|
2188
|
-
for (let i = ancestors.length - 2; i >= 0; i--) {
|
|
2189
|
-
pathCopy.pop();
|
|
2190
|
-
candidates.push({ node: ancestors[i + 1], path: [...pathCopy] });
|
|
2191
|
-
}
|
|
2192
|
-
for (const candidate of candidates) {
|
|
2193
|
-
const { node: node2, path } = candidate;
|
|
2194
|
-
const expectedEnd = node2.span.end + delta;
|
|
2195
|
-
const parser2 = this._parser.rule(node2.type);
|
|
2196
|
-
const ctx = { trackLines: false, state: node2.state, ...this._trivia !== void 0 ? { trivia: this._trivia } : {}, ...this._captureTrivia ? { captureTrivia: true } : {} };
|
|
2197
|
-
const r = parser2.parse(newInput, node2.span.start, ctx);
|
|
2198
|
-
if (!r.ok) continue;
|
|
2199
|
-
if (r.span.end === expectedEnd) {
|
|
2200
|
-
const newTree = replaceAtPath(this._parser, this.tree, path, r.value);
|
|
2201
|
-
return new _ParseDocImpl(this._parser, this._ruleName, newTree, [], newInput, this._trivia, this._captureTrivia);
|
|
2202
|
-
}
|
|
2203
|
-
}
|
|
2204
|
-
return makeParseDoc(this._parser, this._ruleName, newInput, this._trivia, this._captureTrivia);
|
|
2205
|
-
}
|
|
2206
|
-
};
|
|
2207
|
-
function makeParseDoc(parser2, ruleName, input, trivia2, captureTrivia, triviaLog) {
|
|
2208
|
-
const ctx = {
|
|
2209
|
-
trackLines: false,
|
|
2210
|
-
...trivia2 !== void 0 ? { trivia: trivia2 } : {},
|
|
2211
|
-
...captureTrivia ? { captureTrivia: true } : {},
|
|
2212
|
-
...triviaLog !== void 0 ? { _triviaLog: triviaLog } : {}
|
|
2213
|
-
};
|
|
2214
|
-
const r = parser2.rule(ruleName).parse(input, 0, ctx);
|
|
2215
|
-
if (r.ok) {
|
|
2216
|
-
return new ParseDocImpl(parser2, ruleName, r.value, [], input, trivia2, captureTrivia, r.span.end);
|
|
2217
|
-
}
|
|
2218
|
-
return new ParseDocImpl(parser2, ruleName, null, [{ ok: false, expected: r.expected, span: r.span }], input, trivia2, captureTrivia, r.span.start);
|
|
2219
|
-
}
|
|
2220
|
-
|
|
2221
|
-
// src/cst/grammar.ts
|
|
2222
|
-
var Parser = class {
|
|
2223
|
-
_built = false;
|
|
2224
|
-
/** Set in a subclass to enable automatic trivia skipping between sequence terms. */
|
|
2225
|
-
_trivia;
|
|
2226
|
-
/**
|
|
2227
|
-
* Set in a subclass to make the rule name optional in `parse()`.
|
|
2228
|
-
* When defined, `parse(input)` is equivalent to `parse(defaultRule, input)`.
|
|
2229
|
-
*/
|
|
2230
|
-
_defaultRule;
|
|
2231
|
-
/**
|
|
2232
|
-
* Set `true` in a subclass to record trivia (whitespace/comments) consumed
|
|
2233
|
-
* between terms into each node's rawChildren as separate CSTTrivia tokens.
|
|
2234
|
-
* Requires `_trivia` to be set. Default: trivia is skipped without recording.
|
|
2235
|
-
*/
|
|
2236
|
-
_captureTrivia;
|
|
2237
|
-
/**
|
|
2238
|
-
* When set, makeParseDoc injects this array as ctx._triviaLog so each
|
|
2239
|
-
* scanTrivia.commit() pushes [runStart, runEnd] pairs into it.
|
|
2240
|
-
* Reset to [] before each parse() call in any subclass that uses it.
|
|
2241
|
-
*/
|
|
2242
|
-
_triviaLog;
|
|
2243
|
-
/**
|
|
2244
|
-
* Optional map of public entry-point aliases → actual rule names. Lets callers
|
|
2245
|
-
* `parse('value', src)` when the grammar's rule is `ValueList`, removing
|
|
2246
|
-
* per-adapter name-translation tables.
|
|
2247
|
-
*/
|
|
2248
|
-
_aliases;
|
|
2249
|
-
/** Resolve an alias to its target rule name (identity if not aliased). */
|
|
2250
|
-
_resolveRule(name) {
|
|
2251
|
-
return this._aliases?.[name] ?? name;
|
|
2252
|
-
}
|
|
2253
|
-
_build() {
|
|
2254
|
-
if (this._built) return;
|
|
2255
|
-
this._built = true;
|
|
2256
|
-
const keys = Object.keys(this).filter((k) => !k.startsWith("_"));
|
|
2257
|
-
const slots = /* @__PURE__ */ new Map();
|
|
2258
|
-
const g = {};
|
|
2259
|
-
for (const key of keys) {
|
|
2260
|
-
const val = this[key];
|
|
2261
|
-
if (isCombinator(val)) {
|
|
2262
|
-
const isRule = /^[A-Z]/.test(key);
|
|
2263
|
-
const final = isRule ? this._makeNodeParser(key, val) : val;
|
|
2264
|
-
g[key] = final;
|
|
2265
|
-
Object.defineProperty(this, key, { value: final, writable: false, configurable: false });
|
|
2266
|
-
} else if (typeof val === "function") {
|
|
2267
|
-
const slot = ref();
|
|
2268
|
-
slots.set(key, slot);
|
|
2269
|
-
g[key] = slot;
|
|
2270
|
-
}
|
|
2271
|
-
}
|
|
2272
|
-
for (const [key, slot] of slots) {
|
|
2273
|
-
const thunk = this[key];
|
|
2274
|
-
const inner = thunk(g);
|
|
2275
|
-
const isRule = /^[A-Z]/.test(key);
|
|
2276
|
-
const final = isRule ? this._makeNodeParser(key, inner) : inner;
|
|
2277
|
-
slot.define(final);
|
|
2278
|
-
slot._meta.firstSet = final._meta.firstSet;
|
|
2279
|
-
slot._meta.canMatchNewline = final._meta.canMatchNewline;
|
|
2280
|
-
Object.defineProperty(this, key, { value: final, writable: false, configurable: false });
|
|
2281
|
-
}
|
|
2282
|
-
}
|
|
2283
|
-
/**
|
|
2284
|
-
* Override to produce a custom AST node instead of a plain CSTNode.
|
|
2285
|
-
* The returned object must satisfy NodeLike for IncrementalParser to work.
|
|
2286
|
-
*
|
|
2287
|
-
* `rawChildren` is `children` plus any trivia tokens (whitespace/comments)
|
|
2288
|
-
* consumed between terms, in parse order. Use it to inspect trivia when the
|
|
2289
|
-
* grammar is whitespace-sensitive (e.g. CSS descendant vs adjacent combinators).
|
|
2290
|
-
* The default implementation ignores `rawChildren`.
|
|
2291
|
-
*/
|
|
2292
|
-
buildNode(type, span, children, state, _rawChildren) {
|
|
2293
|
-
return { _tag: "node", type, span, children, state };
|
|
2294
|
-
}
|
|
2295
|
-
/** Wrap an inner combinator so it produces a CSTNode on each match. */
|
|
2296
|
-
_makeNodeParser(type, inner) {
|
|
2297
|
-
const self = this;
|
|
2298
|
-
const meta = {
|
|
2299
|
-
firstSet: inner._meta.firstSet,
|
|
2300
|
-
canMatchNewline: inner._meta.canMatchNewline,
|
|
2301
|
-
isTrivia: false
|
|
2302
|
-
};
|
|
2303
|
-
return {
|
|
2304
|
-
_tag: "cstNode",
|
|
2305
|
-
_meta: meta,
|
|
2306
|
-
_def: { tag: "unknown" },
|
|
2307
|
-
parse(input, pos, ctx) {
|
|
2308
|
-
const state = ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
|
|
2309
|
-
const children = [];
|
|
2310
|
-
const rawChildren = [];
|
|
2311
|
-
const innerCtx = {
|
|
2312
|
-
...ctx,
|
|
2313
|
-
_cstChildren: children,
|
|
2314
|
-
_cstLeaves: children,
|
|
2315
|
-
_cstRawChildren: rawChildren
|
|
2316
|
-
};
|
|
2317
|
-
const r = inner.parse(input, pos, innerCtx);
|
|
2318
|
-
if (!r.ok) return r;
|
|
2319
|
-
const node2 = self.buildNode(type, r.span, children, state, rawChildren);
|
|
2320
|
-
const isNodeLike = typeof node2 === "object" && node2 !== null && node2._tag === "node";
|
|
2321
|
-
if (ctx._cstChildren) ctx._cstChildren.push(node2);
|
|
2322
|
-
if (ctx._cstRawChildren) ctx._cstRawChildren.push(
|
|
2323
|
-
isNodeLike ? node2 : { _tag: "leaf", value: typeof node2 === "string" ? node2 : "", span: r.span }
|
|
2324
|
-
);
|
|
2325
|
-
return { ok: true, value: node2, span: r.span };
|
|
2326
|
-
}
|
|
2327
|
-
};
|
|
2328
|
-
}
|
|
2329
|
-
/** Reconstruct a node with a new children array (used by IncrementalParser). */
|
|
2330
|
-
rebuild(node2, newChildren) {
|
|
2331
|
-
return this.buildNode(node2.type, node2.span, newChildren, node2.state, []);
|
|
2332
|
-
}
|
|
2333
|
-
parse(ruleNameOrInput, input) {
|
|
2334
|
-
let ruleName;
|
|
2335
|
-
let src;
|
|
2336
|
-
if (input === void 0) {
|
|
2337
|
-
if (this._defaultRule === void 0) {
|
|
2338
|
-
throw new Error("parse(input) requires a _defaultRule to be set on the grammar");
|
|
2339
|
-
}
|
|
2340
|
-
ruleName = this._defaultRule;
|
|
2341
|
-
src = ruleNameOrInput;
|
|
2342
|
-
} else {
|
|
2343
|
-
ruleName = ruleNameOrInput;
|
|
2344
|
-
src = input;
|
|
2345
|
-
}
|
|
2346
|
-
return makeParseDoc(this, this._resolveRule(ruleName), src, this._trivia, this._captureTrivia, this._triviaLog);
|
|
2347
|
-
}
|
|
2348
|
-
/**
|
|
2349
|
-
* Get the compiled Combinator for a named rule.
|
|
2350
|
-
* Triggers lazy initialization on first call.
|
|
2351
|
-
*/
|
|
2352
|
-
rule(name) {
|
|
2353
|
-
this._build();
|
|
2354
|
-
const resolved = this._resolveRule(name);
|
|
2355
|
-
const p = this[resolved];
|
|
2356
|
-
if (!p) throw new Error(`No rule '${String(name)}' on this parser`);
|
|
2357
|
-
return p;
|
|
2358
|
-
}
|
|
2359
|
-
};
|
|
2360
|
-
function isCombinator(val) {
|
|
2361
|
-
return val !== null && typeof val === "object" && "_tag" in val;
|
|
2362
|
-
}
|
|
2363
|
-
|
|
2364
|
-
// src/functional/doc.ts
|
|
2365
|
-
function isNode2(x) {
|
|
2366
|
-
return typeof x === "object" && x !== null && x._tag === "node";
|
|
2367
|
-
}
|
|
2368
|
-
function findContaining2(node2, pos, path = []) {
|
|
2369
|
-
for (let i = 0; i < node2.children.length; i++) {
|
|
2370
|
-
const child = node2.children[i];
|
|
2371
|
-
if (!isNode2(child)) continue;
|
|
2372
|
-
if (child.span.start <= pos && pos < child.span.end) {
|
|
2373
|
-
const inner = findContaining2(child, pos, [...path, i]);
|
|
2374
|
-
return inner ?? { node: child, path: [...path, i] };
|
|
2375
|
-
}
|
|
2376
|
-
}
|
|
2377
|
-
return null;
|
|
2378
|
-
}
|
|
2379
|
-
function ancestorsAt2(root, path) {
|
|
2380
|
-
const ancestors = [root];
|
|
2381
|
-
let cur = root;
|
|
2382
|
-
for (const idx of path.slice(0, -1)) {
|
|
2383
|
-
const child = cur.children[idx];
|
|
2384
|
-
if (!child || !isNode2(child)) break;
|
|
2385
|
-
ancestors.push(child);
|
|
2386
|
-
cur = child;
|
|
2387
|
-
}
|
|
2388
|
-
return ancestors;
|
|
2389
|
-
}
|
|
2390
|
-
function replaceAtPath2(rebuild, root, path, newNode) {
|
|
2939
|
+
function replaceAtPath(rebuild, root, path, newNode) {
|
|
2391
2940
|
if (path.length === 0) return newNode;
|
|
2392
2941
|
const [idx, ...rest] = path;
|
|
2393
2942
|
const newChildren = [...root.children];
|
|
2394
|
-
newChildren[idx] = rest.length === 0 ? newNode :
|
|
2943
|
+
newChildren[idx] = rest.length === 0 ? newNode : replaceAtPath(rebuild, root.children[idx], rest, newNode);
|
|
2395
2944
|
return rebuild(root, newChildren);
|
|
2396
2945
|
}
|
|
2397
2946
|
function defaultRebuild(node2, children) {
|
|
@@ -2417,9 +2966,9 @@ var FunctionalDocImpl = class _FunctionalDocImpl {
|
|
|
2417
2966
|
const reparse = () => makeFunctionalDoc(this._registry, this._rootRule, newInput, this._opts);
|
|
2418
2967
|
if (!this.tree) return reparse();
|
|
2419
2968
|
const delta = replacement.length - (to - from);
|
|
2420
|
-
const found =
|
|
2969
|
+
const found = findContaining(this.tree, from);
|
|
2421
2970
|
if (!found) return reparse();
|
|
2422
|
-
const ancestors =
|
|
2971
|
+
const ancestors = ancestorsAt(this.tree, found.path);
|
|
2423
2972
|
const candidates = [found];
|
|
2424
2973
|
const pathCopy = [...found.path];
|
|
2425
2974
|
for (let i = ancestors.length - 2; i >= 0; i--) {
|
|
@@ -2434,7 +2983,7 @@ var FunctionalDocImpl = class _FunctionalDocImpl {
|
|
|
2434
2983
|
const r = ruleFn(newInput, node2.span.start, ctx);
|
|
2435
2984
|
if (!r.ok) continue;
|
|
2436
2985
|
if (r.span.end === node2.span.end + delta) {
|
|
2437
|
-
const newTree =
|
|
2986
|
+
const newTree = replaceAtPath(rebuild, this.tree, path, r.value);
|
|
2438
2987
|
return new _FunctionalDocImpl(this._registry, this._rootRule, this._opts, newTree, [], newInput);
|
|
2439
2988
|
}
|
|
2440
2989
|
}
|
|
@@ -2453,59 +3002,52 @@ function makeFunctionalDoc(registry, rootRule, input, opts = {}) {
|
|
|
2453
3002
|
}
|
|
2454
3003
|
|
|
2455
3004
|
// src/cst/trivia-index.ts
|
|
2456
|
-
function spanOf(c) {
|
|
2457
|
-
const s = c.span;
|
|
2458
|
-
return s && typeof s.start === "number" ? s : void 0;
|
|
2459
|
-
}
|
|
2460
3005
|
function merge(map, key, run) {
|
|
2461
3006
|
if (run.length === 0) return;
|
|
2462
3007
|
const existing = map.get(key);
|
|
2463
3008
|
if (existing) existing.push(...run);
|
|
2464
3009
|
else map.set(key, [...run]);
|
|
2465
3010
|
}
|
|
2466
|
-
function buildTriviaIndex(root, opts) {
|
|
3011
|
+
function buildTriviaIndex(root, input = "", opts) {
|
|
2467
3012
|
const before = /* @__PURE__ */ new Map();
|
|
2468
3013
|
const after = /* @__PURE__ */ new Map();
|
|
2469
3014
|
const visit = (node2) => {
|
|
2470
|
-
const
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
const
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
3015
|
+
const log = node2.triviaLog;
|
|
3016
|
+
const raw = node2.rawChildren;
|
|
3017
|
+
if (log && log.length && raw) {
|
|
3018
|
+
for (let i = 0; i < log.length; i += 3) {
|
|
3019
|
+
const tStart = log[i], tEnd = log[i + 1], insertIdx = log[i + 2];
|
|
3020
|
+
if (tEnd <= tStart) continue;
|
|
3021
|
+
const run = [{ value: input.slice(tStart, tEnd), span: { start: tStart, end: tEnd } }];
|
|
3022
|
+
const next = raw[insertIdx];
|
|
3023
|
+
if (next) merge(before, next.span.start, run);
|
|
3024
|
+
const prev = insertIdx > 0 ? raw[insertIdx - 1] : void 0;
|
|
3025
|
+
if (prev) merge(after, prev.span.end, run);
|
|
3026
|
+
}
|
|
3027
|
+
}
|
|
3028
|
+
const ch = node2.children;
|
|
3029
|
+
if (ch) {
|
|
3030
|
+
for (const c of ch) {
|
|
3031
|
+
if (typeof c === "object" && c !== null && c.children !== void 0) {
|
|
3032
|
+
visit(c);
|
|
2483
3033
|
}
|
|
2484
|
-
const next = i < raw.length ? spanOf(raw[i]) : void 0;
|
|
2485
|
-
if (next) merge(before, next.start, run);
|
|
2486
|
-
if (prevEnd !== void 0) merge(after, prevEnd, run);
|
|
2487
|
-
continue;
|
|
2488
3034
|
}
|
|
2489
|
-
const sp = spanOf(c);
|
|
2490
|
-
if (sp) prevEnd = sp.end;
|
|
2491
|
-
if (c._tag === "node") visit(c);
|
|
2492
|
-
i++;
|
|
2493
3035
|
}
|
|
2494
3036
|
};
|
|
2495
|
-
if (root
|
|
2496
|
-
if (opts) {
|
|
2497
|
-
const rootSpan =
|
|
3037
|
+
if (root) visit(root);
|
|
3038
|
+
if (opts && input) {
|
|
3039
|
+
const rootSpan = root?.span;
|
|
2498
3040
|
const re = new RegExp(opts.trivia.source, opts.trivia.flags.replace(/[gy]/g, "") + "y");
|
|
2499
3041
|
const scanFrom = (from) => {
|
|
2500
3042
|
const run = [];
|
|
2501
3043
|
let pos = from;
|
|
2502
3044
|
re.lastIndex = pos;
|
|
2503
|
-
let m = re.exec(
|
|
3045
|
+
let m = re.exec(input);
|
|
2504
3046
|
while (m && m.index === pos && m[0].length > 0) {
|
|
2505
3047
|
run.push({ value: m[0], span: { start: pos, end: pos + m[0].length } });
|
|
2506
3048
|
pos += m[0].length;
|
|
2507
3049
|
re.lastIndex = pos;
|
|
2508
|
-
m = re.exec(
|
|
3050
|
+
m = re.exec(input);
|
|
2509
3051
|
}
|
|
2510
3052
|
return run;
|
|
2511
3053
|
};
|
|
@@ -2514,7 +3056,7 @@ function buildTriviaIndex(root, opts) {
|
|
|
2514
3056
|
if (lead.length) merge(before, rootSpan.start, lead);
|
|
2515
3057
|
}
|
|
2516
3058
|
const end = rootSpan ? rootSpan.end : 0;
|
|
2517
|
-
if (end <
|
|
3059
|
+
if (end < input.length) {
|
|
2518
3060
|
const trail = scanFrom(end);
|
|
2519
3061
|
if (trail.length) {
|
|
2520
3062
|
merge(after, end, trail);
|
|
@@ -2524,4 +3066,38 @@ function buildTriviaIndex(root, opts) {
|
|
|
2524
3066
|
}
|
|
2525
3067
|
return { before, after };
|
|
2526
3068
|
}
|
|
3069
|
+
|
|
3070
|
+
// src/cst/trivia-entries.ts
|
|
3071
|
+
function entryOffset(i, stride) {
|
|
3072
|
+
return i * stride;
|
|
3073
|
+
}
|
|
3074
|
+
function triviaEntries(log, labels, opts) {
|
|
3075
|
+
const baseStride = opts?.nodeLog ? 3 : 2;
|
|
3076
|
+
const stride = labels ? baseStride + 1 : baseStride;
|
|
3077
|
+
const length = Math.floor(log.length / stride);
|
|
3078
|
+
return {
|
|
3079
|
+
length,
|
|
3080
|
+
labels,
|
|
3081
|
+
stride,
|
|
3082
|
+
start(i) {
|
|
3083
|
+
return log[entryOffset(i, stride)];
|
|
3084
|
+
},
|
|
3085
|
+
end(i) {
|
|
3086
|
+
return log[entryOffset(i, stride) + 1];
|
|
3087
|
+
},
|
|
3088
|
+
kindIndex(i) {
|
|
3089
|
+
if (!labels) return void 0;
|
|
3090
|
+
return log[entryOffset(i, stride) + baseStride];
|
|
3091
|
+
},
|
|
3092
|
+
kind(i) {
|
|
3093
|
+
const ki = labels ? log[entryOffset(i, stride) + baseStride] : void 0;
|
|
3094
|
+
return ki !== void 0 ? labels[ki] : void 0;
|
|
3095
|
+
},
|
|
3096
|
+
text(i, input) {
|
|
3097
|
+
const s = log[entryOffset(i, stride)];
|
|
3098
|
+
const e = log[entryOffset(i, stride) + 1];
|
|
3099
|
+
return input.slice(s, e);
|
|
3100
|
+
}
|
|
3101
|
+
};
|
|
3102
|
+
}
|
|
2527
3103
|
//# sourceMappingURL=index.cjs.map
|