parseman 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/compiler/codegen.d.ts +33 -0
- package/dist/compiler/codegen.d.ts.map +1 -1
- package/dist/compiler/scannable-run.d.ts +46 -0
- package/dist/compiler/scannable-run.d.ts.map +1 -0
- package/dist/compiler/trivia-fast-path.d.ts +27 -14
- package/dist/compiler/trivia-fast-path.d.ts.map +1 -1
- package/dist/index.cjs +285 -114
- package/dist/index.cjs.map +4 -4
- package/dist/index.js +285 -114
- package/dist/index.js.map +4 -4
- package/dist/plugin/evaluator.d.ts +18 -0
- package/dist/plugin/evaluator.d.ts.map +1 -1
- package/dist/plugin/index.cjs +453 -131
- package/dist/plugin/index.cjs.map +4 -4
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +453 -131
- package/dist/plugin/index.js.map +4 -4
- package/package.json +1 -1
package/dist/plugin/index.cjs
CHANGED
|
@@ -1269,14 +1269,140 @@ function noTrivia(root) {
|
|
|
1269
1269
|
return parser({ trivia: null }, root);
|
|
1270
1270
|
}
|
|
1271
1271
|
|
|
1272
|
+
// src/compiler/scannable-run.ts
|
|
1273
|
+
var CLASS_ESCAPES = { t: 9, n: 10, r: 13, f: 12, v: 11, "0": 0 };
|
|
1274
|
+
var META = new Set("()[]{}*+?|^$.".split(""));
|
|
1275
|
+
function parseClassRanges(body) {
|
|
1276
|
+
const ranges = [];
|
|
1277
|
+
let i = 0;
|
|
1278
|
+
const readCp = () => {
|
|
1279
|
+
const ch = body[i];
|
|
1280
|
+
if (ch === void 0) return null;
|
|
1281
|
+
if (ch === "\\") {
|
|
1282
|
+
const e = body[i + 1];
|
|
1283
|
+
if (e === void 0) return null;
|
|
1284
|
+
i += 2;
|
|
1285
|
+
return e in CLASS_ESCAPES ? CLASS_ESCAPES[e] : e.codePointAt(0);
|
|
1286
|
+
}
|
|
1287
|
+
i += ch.length;
|
|
1288
|
+
return ch.codePointAt(0);
|
|
1289
|
+
};
|
|
1290
|
+
while (i < body.length) {
|
|
1291
|
+
const lo = readCp();
|
|
1292
|
+
if (lo === null) return null;
|
|
1293
|
+
if (body[i] === "-" && body[i + 1] !== void 0 && body[i + 1] !== "]") {
|
|
1294
|
+
i += 1;
|
|
1295
|
+
const hi = readCp();
|
|
1296
|
+
if (hi === null) return null;
|
|
1297
|
+
ranges.push([lo, hi]);
|
|
1298
|
+
} else {
|
|
1299
|
+
ranges.push([lo, lo]);
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
return ranges.length ? ranges : null;
|
|
1303
|
+
}
|
|
1304
|
+
function literalCodePoints(frag) {
|
|
1305
|
+
const out = [];
|
|
1306
|
+
let i = 0;
|
|
1307
|
+
while (i < frag.length) {
|
|
1308
|
+
const ch = frag[i];
|
|
1309
|
+
if (ch === "\\") {
|
|
1310
|
+
const e = frag[i + 1];
|
|
1311
|
+
if (e === void 0) return null;
|
|
1312
|
+
out.push(e in CLASS_ESCAPES ? CLASS_ESCAPES[e] : e.codePointAt(0));
|
|
1313
|
+
i += 2;
|
|
1314
|
+
continue;
|
|
1315
|
+
}
|
|
1316
|
+
if (META.has(ch)) return null;
|
|
1317
|
+
out.push(ch.codePointAt(0));
|
|
1318
|
+
i += 1;
|
|
1319
|
+
}
|
|
1320
|
+
return out.length ? out : null;
|
|
1321
|
+
}
|
|
1322
|
+
function parseScanShape(source) {
|
|
1323
|
+
let m = /^\[((?:\\.|[^\]])+)\]([+*])$/.exec(source);
|
|
1324
|
+
if (m) {
|
|
1325
|
+
if (m[1].startsWith("^")) return null;
|
|
1326
|
+
const ranges = parseClassRanges(m[1]);
|
|
1327
|
+
return ranges ? { kind: "chars", ranges } : null;
|
|
1328
|
+
}
|
|
1329
|
+
m = /^(.*?)\[\^((?:\\.|[^\]])+)\]\*$/.exec(source);
|
|
1330
|
+
if (m) {
|
|
1331
|
+
const open = literalCodePoints(m[1]);
|
|
1332
|
+
const stop = parseClassRanges(m[2]);
|
|
1333
|
+
if (open && stop) return { kind: "until", open, stop };
|
|
1334
|
+
return null;
|
|
1335
|
+
}
|
|
1336
|
+
if (!source.includes("\\\\")) {
|
|
1337
|
+
m = /^(.*?)\((?:\?:)?[\s\S]*\)\*(.*?)$/.exec(source);
|
|
1338
|
+
if (m && m[1] && m[2]) {
|
|
1339
|
+
const open = literalCodePoints(m[1]);
|
|
1340
|
+
const close = literalCodePoints(m[2]);
|
|
1341
|
+
if (open && close) return { kind: "delimited", open, close };
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
return null;
|
|
1345
|
+
}
|
|
1346
|
+
var classCond = (cVar, ranges) => ranges.map(([lo, hi]) => lo === hi ? `${cVar} === ${lo}` : `(${cVar} >= ${lo} && ${cVar} <= ${hi})`).join(" || ");
|
|
1347
|
+
var litCond = (base, cps, firstVar) => cps.map(
|
|
1348
|
+
(cp, k) => k === 0 && firstVar ? `${firstVar} === ${cp}` : `input.charCodeAt(${base}${k ? ` + ${k}` : ""}) === ${cp}`
|
|
1349
|
+
).join(" && ");
|
|
1350
|
+
function advanceExpr(shape) {
|
|
1351
|
+
if (shape.kind === "chars") {
|
|
1352
|
+
return {
|
|
1353
|
+
setup: [
|
|
1354
|
+
` _e++`,
|
|
1355
|
+
` while (_e < input.length) { const c2 = input.charCodeAt(_e); if (${classCond("c2", shape.ranges)}) _e++; else break }`
|
|
1356
|
+
],
|
|
1357
|
+
endVar: "_e"
|
|
1358
|
+
};
|
|
1359
|
+
}
|
|
1360
|
+
if (shape.kind === "until") {
|
|
1361
|
+
return {
|
|
1362
|
+
setup: [
|
|
1363
|
+
` let j = _e + ${shape.open.length}`,
|
|
1364
|
+
` while (j < input.length && !(${classCond("input.charCodeAt(j)", shape.stop)})) j++`
|
|
1365
|
+
],
|
|
1366
|
+
endVar: "j"
|
|
1367
|
+
};
|
|
1368
|
+
}
|
|
1369
|
+
const n = shape.close.length;
|
|
1370
|
+
return {
|
|
1371
|
+
setup: [
|
|
1372
|
+
` let j = _e + ${shape.open.length}`,
|
|
1373
|
+
` while (j + ${n - 1} < input.length && !(${litCond("j", shape.close)})) j++`
|
|
1374
|
+
],
|
|
1375
|
+
endVar: n === 1 ? "(j + 1 <= input.length ? j + 1 : input.length)" : `(j + ${n} <= input.length ? j + ${n} : input.length)`
|
|
1376
|
+
};
|
|
1377
|
+
}
|
|
1378
|
+
function guardLine(shape) {
|
|
1379
|
+
const cond = shape.kind === "chars" ? classCond("c", shape.ranges) : litCond("_e", shape.open, "c");
|
|
1380
|
+
return ` if (${cond}) {`;
|
|
1381
|
+
}
|
|
1382
|
+
function scanBranch(shape) {
|
|
1383
|
+
if (shape.kind === "chars") {
|
|
1384
|
+
return ` if (${classCond("c", shape.ranges)}) { _e++; continue }`;
|
|
1385
|
+
}
|
|
1386
|
+
const { setup, endVar } = advanceExpr(shape);
|
|
1387
|
+
return [guardLine(shape), ...setup, ` _e = ${endVar}`, ` continue`, ` }`].join("\n");
|
|
1388
|
+
}
|
|
1389
|
+
function captureChunk(startVar, kindIndex) {
|
|
1390
|
+
return [
|
|
1391
|
+
` if (_cap) {`,
|
|
1392
|
+
` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(${startVar}, _e, ${kindIndex})`,
|
|
1393
|
+
` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(${startVar}, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${kindIndex})`,
|
|
1394
|
+
` }`
|
|
1395
|
+
];
|
|
1396
|
+
}
|
|
1397
|
+
function scanBranchLabeled(shape, kindIndex) {
|
|
1398
|
+
const { setup, endVar } = advanceExpr(shape);
|
|
1399
|
+
const lines = [guardLine(shape), ` const _cs = _e`, ...setup];
|
|
1400
|
+
if (endVar !== "_e") lines.push(` _e = ${endVar}`);
|
|
1401
|
+
lines.push(...captureChunk("_cs", kindIndex), ` continue`, ` }`);
|
|
1402
|
+
return lines.join("\n");
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1272
1405
|
// src/compiler/trivia-fast-path.ts
|
|
1273
|
-
var BLOCK_COMMENT = String.raw`\/\*(?:[^*]|\*(?!\/))*\*\/`;
|
|
1274
|
-
var WS_CLASS_SOURCES = /* @__PURE__ */ new Set([
|
|
1275
|
-
String.raw`[ \t\n\r\f]+`,
|
|
1276
|
-
String.raw`[ \t\n]+`,
|
|
1277
|
-
String.raw`[ \t]+`,
|
|
1278
|
-
String.raw`[\t\n\f\r ]+`
|
|
1279
|
-
]);
|
|
1280
1406
|
function unwrapTrivia2(p) {
|
|
1281
1407
|
let cur = p;
|
|
1282
1408
|
while (cur._def.tag === "trivia") cur = cur._def.parser;
|
|
@@ -1292,36 +1418,30 @@ function choiceArms(p) {
|
|
|
1292
1418
|
if (p._def.tag === "choice") return p._def.parsers;
|
|
1293
1419
|
return null;
|
|
1294
1420
|
}
|
|
1295
|
-
function
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
function isBlockCommentSource(source) {
|
|
1299
|
-
return source === BLOCK_COMMENT;
|
|
1421
|
+
function armShape(arm) {
|
|
1422
|
+
const src = getCoreRegexDef(arm)?.source;
|
|
1423
|
+
return src ? parseScanShape(src) : null;
|
|
1300
1424
|
}
|
|
1301
1425
|
function analyzeTriviaFastPath(trivia2) {
|
|
1302
1426
|
const core = unwrapTrivia2(trivia2);
|
|
1303
|
-
const
|
|
1304
|
-
if (
|
|
1305
|
-
|
|
1306
|
-
return null;
|
|
1427
|
+
const directSrc = getCoreRegexDef(core)?.source;
|
|
1428
|
+
if (directSrc) {
|
|
1429
|
+
const shape = parseScanShape(directSrc);
|
|
1430
|
+
return shape && shape.kind === "chars" ? [shape] : null;
|
|
1307
1431
|
}
|
|
1308
1432
|
const inner = oneOrMoreInner(core);
|
|
1309
1433
|
if (!inner) return null;
|
|
1310
|
-
const
|
|
1311
|
-
if (
|
|
1434
|
+
const innerShape = armShape(inner);
|
|
1435
|
+
if (innerShape) return innerShape.kind === "chars" ? [innerShape] : null;
|
|
1312
1436
|
const arms = choiceArms(inner);
|
|
1313
|
-
if (!arms || arms.length
|
|
1314
|
-
|
|
1315
|
-
let hasComment = false;
|
|
1437
|
+
if (!arms || arms.length < 2) return null;
|
|
1438
|
+
const shapes = [];
|
|
1316
1439
|
for (const arm of arms) {
|
|
1317
|
-
const
|
|
1318
|
-
if (!
|
|
1319
|
-
|
|
1320
|
-
else if (isBlockCommentSource(src)) hasComment = true;
|
|
1321
|
-
else return null;
|
|
1440
|
+
const shape = armShape(arm);
|
|
1441
|
+
if (!shape) return null;
|
|
1442
|
+
shapes.push(shape);
|
|
1322
1443
|
}
|
|
1323
|
-
|
|
1324
|
-
return null;
|
|
1444
|
+
return shapes;
|
|
1325
1445
|
}
|
|
1326
1446
|
var CAP_RECORD = [
|
|
1327
1447
|
` if (_cap && _e > _pos) {`,
|
|
@@ -1329,80 +1449,49 @@ var CAP_RECORD = [
|
|
|
1329
1449
|
` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
|
|
1330
1450
|
` }`
|
|
1331
1451
|
].join("\n");
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
` if (c === 47 && input.charCodeAt(_e + 1) === 42) {`,
|
|
1344
|
-
` let j = _e + 2`,
|
|
1345
|
-
` while (j + 1 < input.length && !(input.charCodeAt(j) === 42 && input.charCodeAt(j + 1) === 47)) j++`,
|
|
1346
|
-
` _e = j + 2 <= input.length ? j + 2 : input.length`,
|
|
1347
|
-
` continue`,
|
|
1348
|
-
` }`,
|
|
1349
|
-
` break`,
|
|
1350
|
-
` }`
|
|
1351
|
-
].join("\n");
|
|
1352
|
-
var CAP_CHUNK = (wsKind, commentKind) => [
|
|
1353
|
-
` if (c === 32 || c === 9 || c === 10 || c === 13 || c === 12) {`,
|
|
1354
|
-
` const _cs = _e`,
|
|
1355
|
-
` _e++`,
|
|
1356
|
-
` while (_e < input.length) {`,
|
|
1357
|
-
` const c2 = input.charCodeAt(_e)`,
|
|
1358
|
-
` if (c2 === 32 || c2 === 9 || c2 === 10 || c2 === 13 || c2 === 12) _e++`,
|
|
1359
|
-
` else break`,
|
|
1360
|
-
` }`,
|
|
1361
|
-
` if (_cap) {`,
|
|
1362
|
-
` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_cs, _e, ${wsKind})`,
|
|
1363
|
-
` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(_cs, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${wsKind})`,
|
|
1364
|
-
` }`,
|
|
1365
|
-
` continue`,
|
|
1366
|
-
` }`,
|
|
1367
|
-
` if (c === 47 && input.charCodeAt(_e + 1) === 42) {`,
|
|
1368
|
-
` const _cs = _e`,
|
|
1369
|
-
` let j = _e + 2`,
|
|
1370
|
-
` while (j + 1 < input.length && !(input.charCodeAt(j) === 42 && input.charCodeAt(j + 1) === 47)) j++`,
|
|
1371
|
-
` _e = j + 2 <= input.length ? j + 2 : input.length`,
|
|
1372
|
-
` if (_cap) {`,
|
|
1373
|
-
` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_cs, _e, ${commentKind})`,
|
|
1374
|
-
` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(_cs, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${commentKind})`,
|
|
1375
|
-
` }`,
|
|
1376
|
-
` continue`,
|
|
1377
|
-
` }`
|
|
1378
|
-
].join("\n");
|
|
1379
|
-
var WS_COMMENTS_LOOP_LABELED = (wsKind, commentKind) => [
|
|
1380
|
-
` while (_e < input.length) {`,
|
|
1381
|
-
` const c = input.charCodeAt(_e)`,
|
|
1382
|
-
CAP_CHUNK(wsKind, commentKind),
|
|
1383
|
-
` break`,
|
|
1384
|
-
` }`
|
|
1385
|
-
].join("\n");
|
|
1386
|
-
function buildFastTriviaFnDecl(fnName, kind, kindIndices) {
|
|
1387
|
-
const loop = kind === "wsComments" && kindIndices ? WS_COMMENTS_LOOP_LABELED(kindIndices.ws, kindIndices.comment) : kind === "wsComments" ? WS_COMMENTS_LOOP : WS_ONLY_LOOP;
|
|
1388
|
-
const cap = kindIndices ? "" : CAP_RECORD;
|
|
1389
|
-
const lines = [
|
|
1452
|
+
function composeFastLoop(shapes) {
|
|
1453
|
+
return [
|
|
1454
|
+
` while (_e < input.length) {`,
|
|
1455
|
+
` const c = input.charCodeAt(_e)`,
|
|
1456
|
+
...shapes.map(scanBranch),
|
|
1457
|
+
` break`,
|
|
1458
|
+
` }`
|
|
1459
|
+
].join("\n");
|
|
1460
|
+
}
|
|
1461
|
+
function buildFastTriviaFnDecl(fnName, shapes) {
|
|
1462
|
+
return [
|
|
1390
1463
|
`function ${fnName}(input, _pos, _ctx, _cap) {`,
|
|
1391
1464
|
` let _e = _pos`,
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1465
|
+
composeFastLoop(shapes),
|
|
1466
|
+
CAP_RECORD,
|
|
1467
|
+
` return _e`,
|
|
1468
|
+
`}`
|
|
1469
|
+
].join("\n");
|
|
1397
1470
|
}
|
|
1398
|
-
function
|
|
1471
|
+
function analyzeLabeledScannableRun(trivia2) {
|
|
1472
|
+
const spec = analyzeLabeledTrivia(trivia2);
|
|
1473
|
+
if (!spec) return null;
|
|
1474
|
+
const out = [];
|
|
1399
1475
|
for (const arm of spec.arms) {
|
|
1400
1476
|
const src = getCoreRegexDef(arm.parser)?.source;
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1477
|
+
const shape = src ? parseScanShape(src) : null;
|
|
1478
|
+
if (!shape) return null;
|
|
1479
|
+
out.push({ shape, kindIndex: arm.kindIndex });
|
|
1404
1480
|
}
|
|
1405
|
-
return
|
|
1481
|
+
return out;
|
|
1482
|
+
}
|
|
1483
|
+
function buildLabeledScannableTriviaFnDecl(fnName, arms) {
|
|
1484
|
+
return [
|
|
1485
|
+
`function ${fnName}(input, _pos, _ctx, _cap) {`,
|
|
1486
|
+
` let _e = _pos`,
|
|
1487
|
+
` while (_e < input.length) {`,
|
|
1488
|
+
` const c = input.charCodeAt(_e)`,
|
|
1489
|
+
...arms.map((a) => scanBranchLabeled(a.shape, a.kindIndex)),
|
|
1490
|
+
` break`,
|
|
1491
|
+
` }`,
|
|
1492
|
+
` return _e`,
|
|
1493
|
+
`}`
|
|
1494
|
+
].join("\n");
|
|
1406
1495
|
}
|
|
1407
1496
|
function buildLabeledRegexTriviaFnDecl(fnName, spec, reNames) {
|
|
1408
1497
|
const tryArms = spec.arms.map((arm, i) => {
|
|
@@ -1435,14 +1524,6 @@ function buildLabeledRegexTriviaFnDecl(fnName, spec, reNames) {
|
|
|
1435
1524
|
`}`
|
|
1436
1525
|
].join("\n");
|
|
1437
1526
|
}
|
|
1438
|
-
function labeledTriviaKindIndices(trivia2) {
|
|
1439
|
-
const spec = analyzeLabeledTrivia(trivia2);
|
|
1440
|
-
if (!spec || spec.arms.length !== 2) return null;
|
|
1441
|
-
const ws = regexArmIndex(spec, false);
|
|
1442
|
-
const comment = regexArmIndex(spec, true);
|
|
1443
|
-
if (ws === null || comment === null) return null;
|
|
1444
|
-
return { ws, comment };
|
|
1445
|
-
}
|
|
1446
1527
|
function labeledTriviaRegexArms(trivia2) {
|
|
1447
1528
|
const spec = analyzeLabeledTrivia(trivia2);
|
|
1448
1529
|
if (!spec) return null;
|
|
@@ -1690,14 +1771,19 @@ function ensureTriviaFn(ctx) {
|
|
|
1690
1771
|
const fnName = `_tf${ctx.triviaFnNames.size}`;
|
|
1691
1772
|
ctx.triviaFnNames.set(trivia2, fnName);
|
|
1692
1773
|
ctx.triviaCaptureNames.set(trivia2, fnName);
|
|
1693
|
-
const fastKind = analyzeTriviaFastPath(trivia2);
|
|
1694
|
-
const kindIndices = labeledTriviaKindIndices(trivia2);
|
|
1695
|
-
if (fastKind) {
|
|
1696
|
-
ctx.namedFnDecls.push(buildFastTriviaFnDecl(fnName, fastKind, kindIndices ?? void 0));
|
|
1697
|
-
return fnName;
|
|
1698
|
-
}
|
|
1699
1774
|
const labeledSpec = analyzeLabeledTrivia(trivia2);
|
|
1700
|
-
if (labeledSpec) {
|
|
1775
|
+
if (!labeledSpec) {
|
|
1776
|
+
const fastShapes = analyzeTriviaFastPath(trivia2);
|
|
1777
|
+
if (fastShapes) {
|
|
1778
|
+
ctx.namedFnDecls.push(buildFastTriviaFnDecl(fnName, fastShapes));
|
|
1779
|
+
return fnName;
|
|
1780
|
+
}
|
|
1781
|
+
} else {
|
|
1782
|
+
const labeledShapes = analyzeLabeledScannableRun(trivia2);
|
|
1783
|
+
if (labeledShapes) {
|
|
1784
|
+
ctx.namedFnDecls.push(buildLabeledScannableTriviaFnDecl(fnName, labeledShapes));
|
|
1785
|
+
return fnName;
|
|
1786
|
+
}
|
|
1701
1787
|
const regexSpec = labeledTriviaRegexArms(trivia2);
|
|
1702
1788
|
if (regexSpec) {
|
|
1703
1789
|
const reNames = [];
|
|
@@ -2135,11 +2221,11 @@ function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos) {
|
|
|
2135
2221
|
const p = def.parsers[idx];
|
|
2136
2222
|
const litVal = getCoreLiteralValue(p);
|
|
2137
2223
|
const litLen = litVal.length;
|
|
2138
|
-
const
|
|
2224
|
+
const litCond2 = emitLiteralCondition(litVal, pos);
|
|
2139
2225
|
const kw = first ? "if" : "else if";
|
|
2140
2226
|
first = false;
|
|
2141
2227
|
const litEnd = `${pos} + ${litLen}`;
|
|
2142
|
-
stmts.push(`${ind(ctx)}${kw} (${
|
|
2228
|
+
stmts.push(`${ind(ctx)}${kw} (${litCond2}) {`);
|
|
2143
2229
|
ctx.indent++;
|
|
2144
2230
|
const tR = emitTransformChain(p, JSON.stringify(litVal), litEnd, pos, ctx);
|
|
2145
2231
|
stmts.push(
|
|
@@ -2507,6 +2593,16 @@ function emitRuntimeFallback(parser2, ctx, pos) {
|
|
|
2507
2593
|
return { stmts, valueVar: vv, endVar: ev };
|
|
2508
2594
|
}
|
|
2509
2595
|
function emitLazy(p, def, ctx, pos) {
|
|
2596
|
+
const usage = ctx.lazyUsage;
|
|
2597
|
+
if (usage && (usage.counts.get(p) ?? 0) <= 1 && !usage.recursive.has(p)) {
|
|
2598
|
+
let resolved;
|
|
2599
|
+
try {
|
|
2600
|
+
resolved = def.thunk();
|
|
2601
|
+
} catch {
|
|
2602
|
+
return emitRuntimeFallback(p, ctx, pos);
|
|
2603
|
+
}
|
|
2604
|
+
return emit(resolved, ctx, pos);
|
|
2605
|
+
}
|
|
2510
2606
|
if (!ctx.namedParsers.has(p)) {
|
|
2511
2607
|
const fnName2 = `_pf${ctx.namedParsers.size}`;
|
|
2512
2608
|
ctx.namedParsers.set(p, fnName2);
|
|
@@ -2771,6 +2867,80 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2771
2867
|
return false;
|
|
2772
2868
|
}
|
|
2773
2869
|
}
|
|
2870
|
+
function childrenOf(def) {
|
|
2871
|
+
switch (def.tag) {
|
|
2872
|
+
case "sequence":
|
|
2873
|
+
case "choice":
|
|
2874
|
+
return def.parsers;
|
|
2875
|
+
case "many":
|
|
2876
|
+
case "optional":
|
|
2877
|
+
case "transform":
|
|
2878
|
+
case "trivia":
|
|
2879
|
+
case "label":
|
|
2880
|
+
case "grammar":
|
|
2881
|
+
case "not":
|
|
2882
|
+
case "node":
|
|
2883
|
+
case "withCtx":
|
|
2884
|
+
case "expect":
|
|
2885
|
+
return [def.parser];
|
|
2886
|
+
// emitMany's oneOrMore branch and emitSepBy both codegen `def.parser` TWICE
|
|
2887
|
+
// (a mandatory first match, then again inside the repeat loop) — two real
|
|
2888
|
+
// emit() call sites, so the usage analysis must see two edges here or it
|
|
2889
|
+
// undercounts a single-use `parser` ref as inline-safe when it's actually
|
|
2890
|
+
// referenced from two positions within this one compiled function.
|
|
2891
|
+
case "oneOrMore":
|
|
2892
|
+
return [def.parser, def.parser];
|
|
2893
|
+
case "sepBy":
|
|
2894
|
+
return [def.parser, def.parser, def.separator];
|
|
2895
|
+
case "skip":
|
|
2896
|
+
return [def.main, def.skipped];
|
|
2897
|
+
case "recover":
|
|
2898
|
+
return [def.parser, def.sentinel];
|
|
2899
|
+
case "scanTo":
|
|
2900
|
+
return [def.sentinel, ...def.skip];
|
|
2901
|
+
case "lazy":
|
|
2902
|
+
case "literal":
|
|
2903
|
+
case "regex":
|
|
2904
|
+
case "keywords":
|
|
2905
|
+
case "guard":
|
|
2906
|
+
case "unknown":
|
|
2907
|
+
return [];
|
|
2908
|
+
}
|
|
2909
|
+
}
|
|
2910
|
+
function analyzeLazyUsage(root) {
|
|
2911
|
+
return analyzeLazyUsageMulti([root]);
|
|
2912
|
+
}
|
|
2913
|
+
function analyzeLazyUsageMulti(roots) {
|
|
2914
|
+
const counts = /* @__PURE__ */ new Map();
|
|
2915
|
+
const recursive = /* @__PURE__ */ new Set();
|
|
2916
|
+
const descended = /* @__PURE__ */ new Set();
|
|
2917
|
+
const active = /* @__PURE__ */ new Set();
|
|
2918
|
+
function walk(p) {
|
|
2919
|
+
const def = p._def;
|
|
2920
|
+
if (def.tag === "lazy") {
|
|
2921
|
+
counts.set(p, (counts.get(p) ?? 0) + 1);
|
|
2922
|
+
if (active.has(p)) {
|
|
2923
|
+
recursive.add(p);
|
|
2924
|
+
return;
|
|
2925
|
+
}
|
|
2926
|
+
if (descended.has(p)) return;
|
|
2927
|
+
descended.add(p);
|
|
2928
|
+
let resolved;
|
|
2929
|
+
try {
|
|
2930
|
+
resolved = def.thunk();
|
|
2931
|
+
} catch {
|
|
2932
|
+
return;
|
|
2933
|
+
}
|
|
2934
|
+
active.add(p);
|
|
2935
|
+
walk(resolved);
|
|
2936
|
+
active.delete(p);
|
|
2937
|
+
return;
|
|
2938
|
+
}
|
|
2939
|
+
for (const child of childrenOf(def)) walk(child);
|
|
2940
|
+
}
|
|
2941
|
+
for (const root of roots) walk(root);
|
|
2942
|
+
return { counts, recursive };
|
|
2943
|
+
}
|
|
2774
2944
|
function compile(combinator, mapFnSources) {
|
|
2775
2945
|
const ctx = {
|
|
2776
2946
|
vars: 0,
|
|
@@ -2787,7 +2957,8 @@ function compile(combinator, mapFnSources) {
|
|
|
2787
2957
|
triviaCaptureNames: /* @__PURE__ */ new Map(),
|
|
2788
2958
|
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
2789
2959
|
namedFnDecls: [],
|
|
2790
|
-
capturing: hasNodeDef(combinator)
|
|
2960
|
+
capturing: hasNodeDef(combinator),
|
|
2961
|
+
lazyUsage: analyzeLazyUsage(combinator)
|
|
2791
2962
|
};
|
|
2792
2963
|
const r = emit(combinator, ctx, "_pos");
|
|
2793
2964
|
const collatorDecl = ctx.needsCollator ? `const _collator = new Intl.Collator(undefined, { sensitivity: 'accent' })
|
|
@@ -2845,6 +3016,66 @@ function compile(combinator, mapFnSources) {
|
|
|
2845
3016
|
}
|
|
2846
3017
|
};
|
|
2847
3018
|
}
|
|
3019
|
+
function compileRuleMap(ruleMap) {
|
|
3020
|
+
const ctx = {
|
|
3021
|
+
vars: 0,
|
|
3022
|
+
indent: 1,
|
|
3023
|
+
regexDecls: [],
|
|
3024
|
+
regexMap: /* @__PURE__ */ new Map(),
|
|
3025
|
+
mapFns: [],
|
|
3026
|
+
mapFnSrcs: [],
|
|
3027
|
+
buildFns: [],
|
|
3028
|
+
buildSrcs: [],
|
|
3029
|
+
runtimeParsers: [],
|
|
3030
|
+
needsCollator: false,
|
|
3031
|
+
namedParsers: /* @__PURE__ */ new Map(),
|
|
3032
|
+
triviaCaptureNames: /* @__PURE__ */ new Map(),
|
|
3033
|
+
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
3034
|
+
namedFnDecls: [],
|
|
3035
|
+
capturing: ruleMap.some(([, rule]) => hasNodeDef(rule)),
|
|
3036
|
+
lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule))
|
|
3037
|
+
};
|
|
3038
|
+
const perEntry = ruleMap.map(([key, rule]) => ({ key, r: emit(rule, ctx, "_pos") }));
|
|
3039
|
+
const collatorDecl = ctx.needsCollator ? `const _collator = new Intl.Collator(undefined, { sensitivity: 'accent' })
|
|
3040
|
+
` : "";
|
|
3041
|
+
const derivedSrcs = ctx.mapFnSrcs.length === ctx.mapFns.length && ctx.mapFnSrcs.every((s) => s !== null) ? ctx.mapFnSrcs : void 0;
|
|
3042
|
+
const buildCovered = ctx.buildFns.length === 0 || ctx.buildSrcs.every((s) => s !== null);
|
|
3043
|
+
const buildSources = ctx.buildFns.length === 0 ? void 0 : ctx.buildSrcs;
|
|
3044
|
+
const mfCovered = ctx.mapFns.length === 0 || derivedSrcs !== void 0;
|
|
3045
|
+
const canInline = ctx.runtimeParsers.length === 0 && mfCovered && buildCovered;
|
|
3046
|
+
if (!canInline) return null;
|
|
3047
|
+
const mfDecl = derivedSrcs?.length ? ` const _mf = [${derivedSrcs.join(", ")}]` : "";
|
|
3048
|
+
const buildDecl = buildSources?.length ? ` const _build = [${buildSources.join(", ")}]` : "";
|
|
3049
|
+
const namedPrelude = ctx.namedFnDecls.length > 0 ? namedFnPrelude() : [];
|
|
3050
|
+
const hoistedDecls = [
|
|
3051
|
+
...ctx.regexDecls.map((d) => ` ${d}`),
|
|
3052
|
+
collatorDecl ? ` ${collatorDecl.trim()}` : "",
|
|
3053
|
+
mfDecl,
|
|
3054
|
+
buildDecl,
|
|
3055
|
+
...namedPrelude.map((l) => ` ${l}`),
|
|
3056
|
+
...ctx.namedFnDecls.flatMap((decl, i) => {
|
|
3057
|
+
const lines = decl.split("\n").map((l) => ` ${l}`);
|
|
3058
|
+
return i > 0 ? ["", ...lines] : lines;
|
|
3059
|
+
})
|
|
3060
|
+
].filter(Boolean);
|
|
3061
|
+
const entryFnText = (r) => [
|
|
3062
|
+
`function(input, _pos, _ctx) {`,
|
|
3063
|
+
` let pos = _pos`,
|
|
3064
|
+
...r.stmts,
|
|
3065
|
+
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
|
|
3066
|
+
`}`
|
|
3067
|
+
].join("\n");
|
|
3068
|
+
const objBody = perEntry.map(({ key, r }) => ` ${JSON.stringify(key)}: ${entryFnText(r).split("\n").join("\n ")}`).join(",\n");
|
|
3069
|
+
const replacement = [
|
|
3070
|
+
`/* @__PURE__ */ (() => {`,
|
|
3071
|
+
...hoistedDecls,
|
|
3072
|
+
` return {`,
|
|
3073
|
+
objBody,
|
|
3074
|
+
` }`,
|
|
3075
|
+
`})()`
|
|
3076
|
+
].join("\n");
|
|
3077
|
+
return { keys: perEntry.map((e) => e.key), replacement };
|
|
3078
|
+
}
|
|
2848
3079
|
function buildInlineExpression(ctx, r, collatorDecl, mapFnSources, buildSources) {
|
|
2849
3080
|
const bodyLines = [
|
|
2850
3081
|
` let pos = _pos`,
|
|
@@ -3126,6 +3357,10 @@ function exprToCombi(node2, scope, code, mfs) {
|
|
|
3126
3357
|
}
|
|
3127
3358
|
}
|
|
3128
3359
|
if (callee.name === "rules") return null;
|
|
3360
|
+
if (callee.name === "ref") {
|
|
3361
|
+
if (node2.arguments.length !== 0) return null;
|
|
3362
|
+
return ref();
|
|
3363
|
+
}
|
|
3129
3364
|
if (callee.name === "parser") {
|
|
3130
3365
|
const [optsArg, rootArg] = node2.arguments;
|
|
3131
3366
|
if (!optsArg || !rootArg || optsArg.type === "SpreadElement" || rootArg.type === "SpreadElement") return null;
|
|
@@ -3365,6 +3600,40 @@ function evaluateParserFactory(factoryNode, scope, code, mapFnSources) {
|
|
|
3365
3600
|
}
|
|
3366
3601
|
return ruleRefs;
|
|
3367
3602
|
}
|
|
3603
|
+
function isDefinableRef(v2) {
|
|
3604
|
+
return isCombinator(v2) && typeof v2.define === "function" && v2._def.tag === "lazy";
|
|
3605
|
+
}
|
|
3606
|
+
function evaluateRefDeclaration(init, name, scope) {
|
|
3607
|
+
if (init.type !== "CallExpression") return null;
|
|
3608
|
+
const callee = init.callee;
|
|
3609
|
+
if (callee.type !== "Identifier" || callee.name !== "ref") return null;
|
|
3610
|
+
if (init.arguments.length !== 0) return null;
|
|
3611
|
+
const slot = ref();
|
|
3612
|
+
scope.set(name, { combi: slot, mfSrcs: [] });
|
|
3613
|
+
return slot;
|
|
3614
|
+
}
|
|
3615
|
+
function applyDefineStatement(callExpr, scope, code) {
|
|
3616
|
+
if (callExpr.type !== "CallExpression") return false;
|
|
3617
|
+
const callee = callExpr.callee;
|
|
3618
|
+
if (callee.type !== "MemberExpression") return false;
|
|
3619
|
+
const mem = callee;
|
|
3620
|
+
if (mem.computed) return false;
|
|
3621
|
+
if (mem.property.type !== "Identifier" || mem.property.name !== "define") return false;
|
|
3622
|
+
if (mem.object.type !== "Identifier" || !mem.object.name) return false;
|
|
3623
|
+
const target = scope.get(mem.object.name);
|
|
3624
|
+
const refCombi = isScopeEntry(target) ? target.combi : isCombinator(target) ? target : null;
|
|
3625
|
+
if (!refCombi || !isDefinableRef(refCombi)) return false;
|
|
3626
|
+
const args = callExpr.arguments;
|
|
3627
|
+
if (args.length !== 1 || args[0].type === "SpreadElement") return false;
|
|
3628
|
+
const inner = anyValue(args[0], scope, code, []);
|
|
3629
|
+
if (!isCombinator(inner)) return false;
|
|
3630
|
+
try {
|
|
3631
|
+
refCombi.define(inner);
|
|
3632
|
+
} catch {
|
|
3633
|
+
return false;
|
|
3634
|
+
}
|
|
3635
|
+
return true;
|
|
3636
|
+
}
|
|
3368
3637
|
function referencesAny(node2, names, scope) {
|
|
3369
3638
|
if (node2.type === "Identifier") {
|
|
3370
3639
|
return names.has(node2.name) || scope.has(node2.name);
|
|
@@ -3439,6 +3708,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
3439
3708
|
const replacements = [];
|
|
3440
3709
|
const warnings = [];
|
|
3441
3710
|
let anyUnresolved = false;
|
|
3711
|
+
let ruleMapHolderCounter = 0;
|
|
3442
3712
|
const lineOf = (pos) => {
|
|
3443
3713
|
let line = 1;
|
|
3444
3714
|
for (let i = 0; i < pos && i < code.length; i++) if (code.charCodeAt(i) === 10) line++;
|
|
@@ -3460,18 +3730,53 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
3460
3730
|
warn(init.start, `${label2}: rules(...) factory isn't statically evaluable`);
|
|
3461
3731
|
return null;
|
|
3462
3732
|
}
|
|
3463
|
-
const
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
warn(init.start, `${label2}: rule "${ruleKey}" couldn't be inlined`);
|
|
3468
|
-
return null;
|
|
3469
|
-
}
|
|
3470
|
-
entries.push([ruleKey, compiled.inlineExpression]);
|
|
3733
|
+
const compiled = compileRuleMap([...ruleMap]);
|
|
3734
|
+
if (!compiled) {
|
|
3735
|
+
warn(init.start, `${label2}: rule map couldn't be inlined`);
|
|
3736
|
+
return null;
|
|
3471
3737
|
}
|
|
3472
|
-
return {
|
|
3738
|
+
return { replacement: compiled.replacement, ruleMap };
|
|
3473
3739
|
};
|
|
3474
3740
|
const isRulesCall = (init) => init.type === "CallExpression" && init.callee.type === "Identifier" && init.callee.name === "rules";
|
|
3741
|
+
const unwrapVd = (stmt) => stmt.type === "VariableDeclaration" ? stmt : stmt.type === "ExportNamedDeclaration" && stmt.declaration?.type === "VariableDeclaration" ? stmt.declaration : null;
|
|
3742
|
+
const refNames = /* @__PURE__ */ new Set();
|
|
3743
|
+
for (const stmt of body) {
|
|
3744
|
+
const innerVd = unwrapVd(stmt);
|
|
3745
|
+
if (!innerVd) continue;
|
|
3746
|
+
for (const decl of innerVd.declarations) {
|
|
3747
|
+
const d = decl;
|
|
3748
|
+
if (!d.init || d.id.type !== "Identifier") continue;
|
|
3749
|
+
const init = d.init;
|
|
3750
|
+
if (init.type === "CallExpression" && init.callee.type === "Identifier" && init.callee.name === "ref") {
|
|
3751
|
+
refNames.add(d.id.name);
|
|
3752
|
+
}
|
|
3753
|
+
}
|
|
3754
|
+
}
|
|
3755
|
+
const defineRemovals = [];
|
|
3756
|
+
if (refNames.size > 0) {
|
|
3757
|
+
for (const stmt of body) {
|
|
3758
|
+
if (stmt.type === "ExpressionStatement") {
|
|
3759
|
+
const expr = stmt.expression;
|
|
3760
|
+
if (applyDefineStatement(expr, scope, code)) {
|
|
3761
|
+
defineRemovals.push({ start: stmt.start, end: stmt.end });
|
|
3762
|
+
}
|
|
3763
|
+
continue;
|
|
3764
|
+
}
|
|
3765
|
+
const innerVd = unwrapVd(stmt);
|
|
3766
|
+
if (!innerVd) continue;
|
|
3767
|
+
for (const decl of innerVd.declarations) {
|
|
3768
|
+
const d = decl;
|
|
3769
|
+
if (!d.init || d.id.type !== "Identifier") continue;
|
|
3770
|
+
const name = d.id.name;
|
|
3771
|
+
const init = d.init;
|
|
3772
|
+
if (evaluateRefDeclaration(init, name, scope)) continue;
|
|
3773
|
+
if (scope.has(name)) continue;
|
|
3774
|
+
if (!referencesAny(init, allNames, scope)) continue;
|
|
3775
|
+
const combi = evaluateExpr(init, scope, code, []);
|
|
3776
|
+
if (combi) scope.set(name, { combi, mfSrcs: [] });
|
|
3777
|
+
}
|
|
3778
|
+
}
|
|
3779
|
+
}
|
|
3475
3780
|
for (const stmt of body) {
|
|
3476
3781
|
let vd = null;
|
|
3477
3782
|
let stmtStart = stmt.start;
|
|
@@ -3495,15 +3800,26 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
3495
3800
|
if (d.id.type === "Identifier") {
|
|
3496
3801
|
const varName = d.id.name;
|
|
3497
3802
|
if (!referencesAny(init, allNames, scope)) continue;
|
|
3803
|
+
if (refNames.has(varName)) {
|
|
3804
|
+
const refEntry = scope.get(varName);
|
|
3805
|
+
const refCombi = refEntry?.combi ?? null;
|
|
3806
|
+
if (refCombi) {
|
|
3807
|
+
const compiled2 = compile(refCombi);
|
|
3808
|
+
if (compiled2.inlineExpression === null) {
|
|
3809
|
+
warn(init.start, `"${varName}" is a ref() that couldn't be inlined (was .define() called with a static combinator?)`);
|
|
3810
|
+
continue;
|
|
3811
|
+
}
|
|
3812
|
+
replacements.push({ start: init.start, end: init.end, replacement: compiled2.inlineExpression });
|
|
3813
|
+
continue;
|
|
3814
|
+
}
|
|
3815
|
+
}
|
|
3498
3816
|
if (isRulesCall(init)) {
|
|
3499
3817
|
const compiledRules = compileRulesFactory(init, varName);
|
|
3500
3818
|
if (!compiledRules) continue;
|
|
3501
3819
|
replacements.push({
|
|
3502
3820
|
start: init.start,
|
|
3503
3821
|
end: init.end,
|
|
3504
|
-
replacement:
|
|
3505
|
-
${compiledRules.entries.map(([k, expr]) => ` ${k}: ${expr}`).join(",\n")}
|
|
3506
|
-
}`
|
|
3822
|
+
replacement: compiledRules.replacement
|
|
3507
3823
|
});
|
|
3508
3824
|
continue;
|
|
3509
3825
|
}
|
|
@@ -3538,9 +3854,8 @@ ${compiledRules.entries.map(([k, expr]) => ` ${k}: ${expr}`).join(",\n")}
|
|
|
3538
3854
|
}
|
|
3539
3855
|
const compiledRules = compileRulesFactory(init, "{ \u2026 }");
|
|
3540
3856
|
if (!compiledRules) continue;
|
|
3541
|
-
const byKey = new Map(compiledRules.entries);
|
|
3542
3857
|
const pattern = d.id;
|
|
3543
|
-
const
|
|
3858
|
+
const bindings = [];
|
|
3544
3859
|
let allOk = true;
|
|
3545
3860
|
for (const prop of pattern.properties) {
|
|
3546
3861
|
const p = prop;
|
|
@@ -3555,17 +3870,21 @@ ${compiledRules.entries.map(([k, expr]) => ` ${k}: ${expr}`).join(",\n")}
|
|
|
3555
3870
|
allOk = false;
|
|
3556
3871
|
break;
|
|
3557
3872
|
}
|
|
3558
|
-
|
|
3559
|
-
if (inlineExpr === void 0) {
|
|
3873
|
+
if (!compiledRules.ruleMap.has(ruleKey)) {
|
|
3560
3874
|
warn(init.start, `destructured rule "${ruleKey}" isn't returned by the rules() factory`);
|
|
3561
3875
|
allOk = false;
|
|
3562
3876
|
break;
|
|
3563
3877
|
}
|
|
3564
|
-
|
|
3878
|
+
bindings.push({ ruleKey, localName });
|
|
3565
3879
|
const rule = compiledRules.ruleMap.get(ruleKey);
|
|
3566
3880
|
if (rule) scope.set(localName, { combi: rule, mfSrcs: [] });
|
|
3567
3881
|
}
|
|
3568
3882
|
if (!allOk) continue;
|
|
3883
|
+
const holderVar = `__rules${ruleMapHolderCounter++}`;
|
|
3884
|
+
const lines = [
|
|
3885
|
+
`const ${holderVar} = ${compiledRules.replacement}`,
|
|
3886
|
+
...bindings.map(({ ruleKey, localName }) => `${exportPrefix}${kind} ${localName} = ${holderVar}[${JSON.stringify(ruleKey)}]`)
|
|
3887
|
+
];
|
|
3569
3888
|
replacements.push({
|
|
3570
3889
|
start: stmtStart,
|
|
3571
3890
|
end: stmtEnd,
|
|
@@ -3579,6 +3898,9 @@ ${compiledRules.entries.map(([k, expr]) => ` ${k}: ${expr}`).join(",\n")}
|
|
|
3579
3898
|
imp.fullyResolved = !anyUnresolved;
|
|
3580
3899
|
}
|
|
3581
3900
|
const ms = new import_magic_string.default(code);
|
|
3901
|
+
if (!anyUnresolved) {
|
|
3902
|
+
for (const { start, end } of defineRemovals) ms.remove(start, end);
|
|
3903
|
+
}
|
|
3582
3904
|
for (const imp of macroImports) {
|
|
3583
3905
|
if (imp.fullyResolved) {
|
|
3584
3906
|
ms.remove(imp.start, imp.end);
|