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.js
CHANGED
|
@@ -1234,14 +1234,140 @@ function noTrivia(root) {
|
|
|
1234
1234
|
return parser({ trivia: null }, root);
|
|
1235
1235
|
}
|
|
1236
1236
|
|
|
1237
|
+
// src/compiler/scannable-run.ts
|
|
1238
|
+
var CLASS_ESCAPES = { t: 9, n: 10, r: 13, f: 12, v: 11, "0": 0 };
|
|
1239
|
+
var META = new Set("()[]{}*+?|^$.".split(""));
|
|
1240
|
+
function parseClassRanges(body) {
|
|
1241
|
+
const ranges = [];
|
|
1242
|
+
let i = 0;
|
|
1243
|
+
const readCp = () => {
|
|
1244
|
+
const ch = body[i];
|
|
1245
|
+
if (ch === void 0) return null;
|
|
1246
|
+
if (ch === "\\") {
|
|
1247
|
+
const e = body[i + 1];
|
|
1248
|
+
if (e === void 0) return null;
|
|
1249
|
+
i += 2;
|
|
1250
|
+
return e in CLASS_ESCAPES ? CLASS_ESCAPES[e] : e.codePointAt(0);
|
|
1251
|
+
}
|
|
1252
|
+
i += ch.length;
|
|
1253
|
+
return ch.codePointAt(0);
|
|
1254
|
+
};
|
|
1255
|
+
while (i < body.length) {
|
|
1256
|
+
const lo = readCp();
|
|
1257
|
+
if (lo === null) return null;
|
|
1258
|
+
if (body[i] === "-" && body[i + 1] !== void 0 && body[i + 1] !== "]") {
|
|
1259
|
+
i += 1;
|
|
1260
|
+
const hi = readCp();
|
|
1261
|
+
if (hi === null) return null;
|
|
1262
|
+
ranges.push([lo, hi]);
|
|
1263
|
+
} else {
|
|
1264
|
+
ranges.push([lo, lo]);
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
return ranges.length ? ranges : null;
|
|
1268
|
+
}
|
|
1269
|
+
function literalCodePoints(frag) {
|
|
1270
|
+
const out = [];
|
|
1271
|
+
let i = 0;
|
|
1272
|
+
while (i < frag.length) {
|
|
1273
|
+
const ch = frag[i];
|
|
1274
|
+
if (ch === "\\") {
|
|
1275
|
+
const e = frag[i + 1];
|
|
1276
|
+
if (e === void 0) return null;
|
|
1277
|
+
out.push(e in CLASS_ESCAPES ? CLASS_ESCAPES[e] : e.codePointAt(0));
|
|
1278
|
+
i += 2;
|
|
1279
|
+
continue;
|
|
1280
|
+
}
|
|
1281
|
+
if (META.has(ch)) return null;
|
|
1282
|
+
out.push(ch.codePointAt(0));
|
|
1283
|
+
i += 1;
|
|
1284
|
+
}
|
|
1285
|
+
return out.length ? out : null;
|
|
1286
|
+
}
|
|
1287
|
+
function parseScanShape(source) {
|
|
1288
|
+
let m = /^\[((?:\\.|[^\]])+)\]([+*])$/.exec(source);
|
|
1289
|
+
if (m) {
|
|
1290
|
+
if (m[1].startsWith("^")) return null;
|
|
1291
|
+
const ranges = parseClassRanges(m[1]);
|
|
1292
|
+
return ranges ? { kind: "chars", ranges } : null;
|
|
1293
|
+
}
|
|
1294
|
+
m = /^(.*?)\[\^((?:\\.|[^\]])+)\]\*$/.exec(source);
|
|
1295
|
+
if (m) {
|
|
1296
|
+
const open = literalCodePoints(m[1]);
|
|
1297
|
+
const stop = parseClassRanges(m[2]);
|
|
1298
|
+
if (open && stop) return { kind: "until", open, stop };
|
|
1299
|
+
return null;
|
|
1300
|
+
}
|
|
1301
|
+
if (!source.includes("\\\\")) {
|
|
1302
|
+
m = /^(.*?)\((?:\?:)?[\s\S]*\)\*(.*?)$/.exec(source);
|
|
1303
|
+
if (m && m[1] && m[2]) {
|
|
1304
|
+
const open = literalCodePoints(m[1]);
|
|
1305
|
+
const close = literalCodePoints(m[2]);
|
|
1306
|
+
if (open && close) return { kind: "delimited", open, close };
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
return null;
|
|
1310
|
+
}
|
|
1311
|
+
var classCond = (cVar, ranges) => ranges.map(([lo, hi]) => lo === hi ? `${cVar} === ${lo}` : `(${cVar} >= ${lo} && ${cVar} <= ${hi})`).join(" || ");
|
|
1312
|
+
var litCond = (base, cps, firstVar) => cps.map(
|
|
1313
|
+
(cp, k) => k === 0 && firstVar ? `${firstVar} === ${cp}` : `input.charCodeAt(${base}${k ? ` + ${k}` : ""}) === ${cp}`
|
|
1314
|
+
).join(" && ");
|
|
1315
|
+
function advanceExpr(shape) {
|
|
1316
|
+
if (shape.kind === "chars") {
|
|
1317
|
+
return {
|
|
1318
|
+
setup: [
|
|
1319
|
+
` _e++`,
|
|
1320
|
+
` while (_e < input.length) { const c2 = input.charCodeAt(_e); if (${classCond("c2", shape.ranges)}) _e++; else break }`
|
|
1321
|
+
],
|
|
1322
|
+
endVar: "_e"
|
|
1323
|
+
};
|
|
1324
|
+
}
|
|
1325
|
+
if (shape.kind === "until") {
|
|
1326
|
+
return {
|
|
1327
|
+
setup: [
|
|
1328
|
+
` let j = _e + ${shape.open.length}`,
|
|
1329
|
+
` while (j < input.length && !(${classCond("input.charCodeAt(j)", shape.stop)})) j++`
|
|
1330
|
+
],
|
|
1331
|
+
endVar: "j"
|
|
1332
|
+
};
|
|
1333
|
+
}
|
|
1334
|
+
const n = shape.close.length;
|
|
1335
|
+
return {
|
|
1336
|
+
setup: [
|
|
1337
|
+
` let j = _e + ${shape.open.length}`,
|
|
1338
|
+
` while (j + ${n - 1} < input.length && !(${litCond("j", shape.close)})) j++`
|
|
1339
|
+
],
|
|
1340
|
+
endVar: n === 1 ? "(j + 1 <= input.length ? j + 1 : input.length)" : `(j + ${n} <= input.length ? j + ${n} : input.length)`
|
|
1341
|
+
};
|
|
1342
|
+
}
|
|
1343
|
+
function guardLine(shape) {
|
|
1344
|
+
const cond = shape.kind === "chars" ? classCond("c", shape.ranges) : litCond("_e", shape.open, "c");
|
|
1345
|
+
return ` if (${cond}) {`;
|
|
1346
|
+
}
|
|
1347
|
+
function scanBranch(shape) {
|
|
1348
|
+
if (shape.kind === "chars") {
|
|
1349
|
+
return ` if (${classCond("c", shape.ranges)}) { _e++; continue }`;
|
|
1350
|
+
}
|
|
1351
|
+
const { setup, endVar } = advanceExpr(shape);
|
|
1352
|
+
return [guardLine(shape), ...setup, ` _e = ${endVar}`, ` continue`, ` }`].join("\n");
|
|
1353
|
+
}
|
|
1354
|
+
function captureChunk(startVar, kindIndex) {
|
|
1355
|
+
return [
|
|
1356
|
+
` if (_cap) {`,
|
|
1357
|
+
` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(${startVar}, _e, ${kindIndex})`,
|
|
1358
|
+
` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(${startVar}, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${kindIndex})`,
|
|
1359
|
+
` }`
|
|
1360
|
+
];
|
|
1361
|
+
}
|
|
1362
|
+
function scanBranchLabeled(shape, kindIndex) {
|
|
1363
|
+
const { setup, endVar } = advanceExpr(shape);
|
|
1364
|
+
const lines = [guardLine(shape), ` const _cs = _e`, ...setup];
|
|
1365
|
+
if (endVar !== "_e") lines.push(` _e = ${endVar}`);
|
|
1366
|
+
lines.push(...captureChunk("_cs", kindIndex), ` continue`, ` }`);
|
|
1367
|
+
return lines.join("\n");
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1237
1370
|
// src/compiler/trivia-fast-path.ts
|
|
1238
|
-
var BLOCK_COMMENT = String.raw`\/\*(?:[^*]|\*(?!\/))*\*\/`;
|
|
1239
|
-
var WS_CLASS_SOURCES = /* @__PURE__ */ new Set([
|
|
1240
|
-
String.raw`[ \t\n\r\f]+`,
|
|
1241
|
-
String.raw`[ \t\n]+`,
|
|
1242
|
-
String.raw`[ \t]+`,
|
|
1243
|
-
String.raw`[\t\n\f\r ]+`
|
|
1244
|
-
]);
|
|
1245
1371
|
function unwrapTrivia2(p) {
|
|
1246
1372
|
let cur = p;
|
|
1247
1373
|
while (cur._def.tag === "trivia") cur = cur._def.parser;
|
|
@@ -1257,36 +1383,30 @@ function choiceArms(p) {
|
|
|
1257
1383
|
if (p._def.tag === "choice") return p._def.parsers;
|
|
1258
1384
|
return null;
|
|
1259
1385
|
}
|
|
1260
|
-
function
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
function isBlockCommentSource(source) {
|
|
1264
|
-
return source === BLOCK_COMMENT;
|
|
1386
|
+
function armShape(arm) {
|
|
1387
|
+
const src = getCoreRegexDef(arm)?.source;
|
|
1388
|
+
return src ? parseScanShape(src) : null;
|
|
1265
1389
|
}
|
|
1266
1390
|
function analyzeTriviaFastPath(trivia2) {
|
|
1267
1391
|
const core = unwrapTrivia2(trivia2);
|
|
1268
|
-
const
|
|
1269
|
-
if (
|
|
1270
|
-
|
|
1271
|
-
return null;
|
|
1392
|
+
const directSrc = getCoreRegexDef(core)?.source;
|
|
1393
|
+
if (directSrc) {
|
|
1394
|
+
const shape = parseScanShape(directSrc);
|
|
1395
|
+
return shape && shape.kind === "chars" ? [shape] : null;
|
|
1272
1396
|
}
|
|
1273
1397
|
const inner = oneOrMoreInner(core);
|
|
1274
1398
|
if (!inner) return null;
|
|
1275
|
-
const
|
|
1276
|
-
if (
|
|
1399
|
+
const innerShape = armShape(inner);
|
|
1400
|
+
if (innerShape) return innerShape.kind === "chars" ? [innerShape] : null;
|
|
1277
1401
|
const arms = choiceArms(inner);
|
|
1278
|
-
if (!arms || arms.length
|
|
1279
|
-
|
|
1280
|
-
let hasComment = false;
|
|
1402
|
+
if (!arms || arms.length < 2) return null;
|
|
1403
|
+
const shapes = [];
|
|
1281
1404
|
for (const arm of arms) {
|
|
1282
|
-
const
|
|
1283
|
-
if (!
|
|
1284
|
-
|
|
1285
|
-
else if (isBlockCommentSource(src)) hasComment = true;
|
|
1286
|
-
else return null;
|
|
1405
|
+
const shape = armShape(arm);
|
|
1406
|
+
if (!shape) return null;
|
|
1407
|
+
shapes.push(shape);
|
|
1287
1408
|
}
|
|
1288
|
-
|
|
1289
|
-
return null;
|
|
1409
|
+
return shapes;
|
|
1290
1410
|
}
|
|
1291
1411
|
var CAP_RECORD = [
|
|
1292
1412
|
` if (_cap && _e > _pos) {`,
|
|
@@ -1294,80 +1414,49 @@ var CAP_RECORD = [
|
|
|
1294
1414
|
` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
|
|
1295
1415
|
` }`
|
|
1296
1416
|
].join("\n");
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
` if (c === 47 && input.charCodeAt(_e + 1) === 42) {`,
|
|
1309
|
-
` let j = _e + 2`,
|
|
1310
|
-
` while (j + 1 < input.length && !(input.charCodeAt(j) === 42 && input.charCodeAt(j + 1) === 47)) j++`,
|
|
1311
|
-
` _e = j + 2 <= input.length ? j + 2 : input.length`,
|
|
1312
|
-
` continue`,
|
|
1313
|
-
` }`,
|
|
1314
|
-
` break`,
|
|
1315
|
-
` }`
|
|
1316
|
-
].join("\n");
|
|
1317
|
-
var CAP_CHUNK = (wsKind, commentKind) => [
|
|
1318
|
-
` if (c === 32 || c === 9 || c === 10 || c === 13 || c === 12) {`,
|
|
1319
|
-
` const _cs = _e`,
|
|
1320
|
-
` _e++`,
|
|
1321
|
-
` while (_e < input.length) {`,
|
|
1322
|
-
` const c2 = input.charCodeAt(_e)`,
|
|
1323
|
-
` if (c2 === 32 || c2 === 9 || c2 === 10 || c2 === 13 || c2 === 12) _e++`,
|
|
1324
|
-
` else break`,
|
|
1325
|
-
` }`,
|
|
1326
|
-
` if (_cap) {`,
|
|
1327
|
-
` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_cs, _e, ${wsKind})`,
|
|
1328
|
-
` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(_cs, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${wsKind})`,
|
|
1329
|
-
` }`,
|
|
1330
|
-
` continue`,
|
|
1331
|
-
` }`,
|
|
1332
|
-
` if (c === 47 && input.charCodeAt(_e + 1) === 42) {`,
|
|
1333
|
-
` const _cs = _e`,
|
|
1334
|
-
` let j = _e + 2`,
|
|
1335
|
-
` while (j + 1 < input.length && !(input.charCodeAt(j) === 42 && input.charCodeAt(j + 1) === 47)) j++`,
|
|
1336
|
-
` _e = j + 2 <= input.length ? j + 2 : input.length`,
|
|
1337
|
-
` if (_cap) {`,
|
|
1338
|
-
` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_cs, _e, ${commentKind})`,
|
|
1339
|
-
` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(_cs, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${commentKind})`,
|
|
1340
|
-
` }`,
|
|
1341
|
-
` continue`,
|
|
1342
|
-
` }`
|
|
1343
|
-
].join("\n");
|
|
1344
|
-
var WS_COMMENTS_LOOP_LABELED = (wsKind, commentKind) => [
|
|
1345
|
-
` while (_e < input.length) {`,
|
|
1346
|
-
` const c = input.charCodeAt(_e)`,
|
|
1347
|
-
CAP_CHUNK(wsKind, commentKind),
|
|
1348
|
-
` break`,
|
|
1349
|
-
` }`
|
|
1350
|
-
].join("\n");
|
|
1351
|
-
function buildFastTriviaFnDecl(fnName, kind, kindIndices) {
|
|
1352
|
-
const loop = kind === "wsComments" && kindIndices ? WS_COMMENTS_LOOP_LABELED(kindIndices.ws, kindIndices.comment) : kind === "wsComments" ? WS_COMMENTS_LOOP : WS_ONLY_LOOP;
|
|
1353
|
-
const cap = kindIndices ? "" : CAP_RECORD;
|
|
1354
|
-
const lines = [
|
|
1417
|
+
function composeFastLoop(shapes) {
|
|
1418
|
+
return [
|
|
1419
|
+
` while (_e < input.length) {`,
|
|
1420
|
+
` const c = input.charCodeAt(_e)`,
|
|
1421
|
+
...shapes.map(scanBranch),
|
|
1422
|
+
` break`,
|
|
1423
|
+
` }`
|
|
1424
|
+
].join("\n");
|
|
1425
|
+
}
|
|
1426
|
+
function buildFastTriviaFnDecl(fnName, shapes) {
|
|
1427
|
+
return [
|
|
1355
1428
|
`function ${fnName}(input, _pos, _ctx, _cap) {`,
|
|
1356
1429
|
` let _e = _pos`,
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1430
|
+
composeFastLoop(shapes),
|
|
1431
|
+
CAP_RECORD,
|
|
1432
|
+
` return _e`,
|
|
1433
|
+
`}`
|
|
1434
|
+
].join("\n");
|
|
1362
1435
|
}
|
|
1363
|
-
function
|
|
1436
|
+
function analyzeLabeledScannableRun(trivia2) {
|
|
1437
|
+
const spec = analyzeLabeledTrivia(trivia2);
|
|
1438
|
+
if (!spec) return null;
|
|
1439
|
+
const out = [];
|
|
1364
1440
|
for (const arm of spec.arms) {
|
|
1365
1441
|
const src = getCoreRegexDef(arm.parser)?.source;
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1442
|
+
const shape = src ? parseScanShape(src) : null;
|
|
1443
|
+
if (!shape) return null;
|
|
1444
|
+
out.push({ shape, kindIndex: arm.kindIndex });
|
|
1369
1445
|
}
|
|
1370
|
-
return
|
|
1446
|
+
return out;
|
|
1447
|
+
}
|
|
1448
|
+
function buildLabeledScannableTriviaFnDecl(fnName, arms) {
|
|
1449
|
+
return [
|
|
1450
|
+
`function ${fnName}(input, _pos, _ctx, _cap) {`,
|
|
1451
|
+
` let _e = _pos`,
|
|
1452
|
+
` while (_e < input.length) {`,
|
|
1453
|
+
` const c = input.charCodeAt(_e)`,
|
|
1454
|
+
...arms.map((a) => scanBranchLabeled(a.shape, a.kindIndex)),
|
|
1455
|
+
` break`,
|
|
1456
|
+
` }`,
|
|
1457
|
+
` return _e`,
|
|
1458
|
+
`}`
|
|
1459
|
+
].join("\n");
|
|
1371
1460
|
}
|
|
1372
1461
|
function buildLabeledRegexTriviaFnDecl(fnName, spec, reNames) {
|
|
1373
1462
|
const tryArms = spec.arms.map((arm, i) => {
|
|
@@ -1400,14 +1489,6 @@ function buildLabeledRegexTriviaFnDecl(fnName, spec, reNames) {
|
|
|
1400
1489
|
`}`
|
|
1401
1490
|
].join("\n");
|
|
1402
1491
|
}
|
|
1403
|
-
function labeledTriviaKindIndices(trivia2) {
|
|
1404
|
-
const spec = analyzeLabeledTrivia(trivia2);
|
|
1405
|
-
if (!spec || spec.arms.length !== 2) return null;
|
|
1406
|
-
const ws = regexArmIndex(spec, false);
|
|
1407
|
-
const comment = regexArmIndex(spec, true);
|
|
1408
|
-
if (ws === null || comment === null) return null;
|
|
1409
|
-
return { ws, comment };
|
|
1410
|
-
}
|
|
1411
1492
|
function labeledTriviaRegexArms(trivia2) {
|
|
1412
1493
|
const spec = analyzeLabeledTrivia(trivia2);
|
|
1413
1494
|
if (!spec) return null;
|
|
@@ -1655,14 +1736,19 @@ function ensureTriviaFn(ctx) {
|
|
|
1655
1736
|
const fnName = `_tf${ctx.triviaFnNames.size}`;
|
|
1656
1737
|
ctx.triviaFnNames.set(trivia2, fnName);
|
|
1657
1738
|
ctx.triviaCaptureNames.set(trivia2, fnName);
|
|
1658
|
-
const fastKind = analyzeTriviaFastPath(trivia2);
|
|
1659
|
-
const kindIndices = labeledTriviaKindIndices(trivia2);
|
|
1660
|
-
if (fastKind) {
|
|
1661
|
-
ctx.namedFnDecls.push(buildFastTriviaFnDecl(fnName, fastKind, kindIndices ?? void 0));
|
|
1662
|
-
return fnName;
|
|
1663
|
-
}
|
|
1664
1739
|
const labeledSpec = analyzeLabeledTrivia(trivia2);
|
|
1665
|
-
if (labeledSpec) {
|
|
1740
|
+
if (!labeledSpec) {
|
|
1741
|
+
const fastShapes = analyzeTriviaFastPath(trivia2);
|
|
1742
|
+
if (fastShapes) {
|
|
1743
|
+
ctx.namedFnDecls.push(buildFastTriviaFnDecl(fnName, fastShapes));
|
|
1744
|
+
return fnName;
|
|
1745
|
+
}
|
|
1746
|
+
} else {
|
|
1747
|
+
const labeledShapes = analyzeLabeledScannableRun(trivia2);
|
|
1748
|
+
if (labeledShapes) {
|
|
1749
|
+
ctx.namedFnDecls.push(buildLabeledScannableTriviaFnDecl(fnName, labeledShapes));
|
|
1750
|
+
return fnName;
|
|
1751
|
+
}
|
|
1666
1752
|
const regexSpec = labeledTriviaRegexArms(trivia2);
|
|
1667
1753
|
if (regexSpec) {
|
|
1668
1754
|
const reNames = [];
|
|
@@ -2100,11 +2186,11 @@ function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos) {
|
|
|
2100
2186
|
const p = def.parsers[idx];
|
|
2101
2187
|
const litVal = getCoreLiteralValue(p);
|
|
2102
2188
|
const litLen = litVal.length;
|
|
2103
|
-
const
|
|
2189
|
+
const litCond2 = emitLiteralCondition(litVal, pos);
|
|
2104
2190
|
const kw = first ? "if" : "else if";
|
|
2105
2191
|
first = false;
|
|
2106
2192
|
const litEnd = `${pos} + ${litLen}`;
|
|
2107
|
-
stmts.push(`${ind(ctx)}${kw} (${
|
|
2193
|
+
stmts.push(`${ind(ctx)}${kw} (${litCond2}) {`);
|
|
2108
2194
|
ctx.indent++;
|
|
2109
2195
|
const tR = emitTransformChain(p, JSON.stringify(litVal), litEnd, pos, ctx);
|
|
2110
2196
|
stmts.push(
|
|
@@ -2472,6 +2558,16 @@ function emitRuntimeFallback(parser2, ctx, pos) {
|
|
|
2472
2558
|
return { stmts, valueVar: vv, endVar: ev };
|
|
2473
2559
|
}
|
|
2474
2560
|
function emitLazy(p, def, ctx, pos) {
|
|
2561
|
+
const usage = ctx.lazyUsage;
|
|
2562
|
+
if (usage && (usage.counts.get(p) ?? 0) <= 1 && !usage.recursive.has(p)) {
|
|
2563
|
+
let resolved;
|
|
2564
|
+
try {
|
|
2565
|
+
resolved = def.thunk();
|
|
2566
|
+
} catch {
|
|
2567
|
+
return emitRuntimeFallback(p, ctx, pos);
|
|
2568
|
+
}
|
|
2569
|
+
return emit(resolved, ctx, pos);
|
|
2570
|
+
}
|
|
2475
2571
|
if (!ctx.namedParsers.has(p)) {
|
|
2476
2572
|
const fnName2 = `_pf${ctx.namedParsers.size}`;
|
|
2477
2573
|
ctx.namedParsers.set(p, fnName2);
|
|
@@ -2736,6 +2832,80 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2736
2832
|
return false;
|
|
2737
2833
|
}
|
|
2738
2834
|
}
|
|
2835
|
+
function childrenOf(def) {
|
|
2836
|
+
switch (def.tag) {
|
|
2837
|
+
case "sequence":
|
|
2838
|
+
case "choice":
|
|
2839
|
+
return def.parsers;
|
|
2840
|
+
case "many":
|
|
2841
|
+
case "optional":
|
|
2842
|
+
case "transform":
|
|
2843
|
+
case "trivia":
|
|
2844
|
+
case "label":
|
|
2845
|
+
case "grammar":
|
|
2846
|
+
case "not":
|
|
2847
|
+
case "node":
|
|
2848
|
+
case "withCtx":
|
|
2849
|
+
case "expect":
|
|
2850
|
+
return [def.parser];
|
|
2851
|
+
// emitMany's oneOrMore branch and emitSepBy both codegen `def.parser` TWICE
|
|
2852
|
+
// (a mandatory first match, then again inside the repeat loop) — two real
|
|
2853
|
+
// emit() call sites, so the usage analysis must see two edges here or it
|
|
2854
|
+
// undercounts a single-use `parser` ref as inline-safe when it's actually
|
|
2855
|
+
// referenced from two positions within this one compiled function.
|
|
2856
|
+
case "oneOrMore":
|
|
2857
|
+
return [def.parser, def.parser];
|
|
2858
|
+
case "sepBy":
|
|
2859
|
+
return [def.parser, def.parser, def.separator];
|
|
2860
|
+
case "skip":
|
|
2861
|
+
return [def.main, def.skipped];
|
|
2862
|
+
case "recover":
|
|
2863
|
+
return [def.parser, def.sentinel];
|
|
2864
|
+
case "scanTo":
|
|
2865
|
+
return [def.sentinel, ...def.skip];
|
|
2866
|
+
case "lazy":
|
|
2867
|
+
case "literal":
|
|
2868
|
+
case "regex":
|
|
2869
|
+
case "keywords":
|
|
2870
|
+
case "guard":
|
|
2871
|
+
case "unknown":
|
|
2872
|
+
return [];
|
|
2873
|
+
}
|
|
2874
|
+
}
|
|
2875
|
+
function analyzeLazyUsage(root) {
|
|
2876
|
+
return analyzeLazyUsageMulti([root]);
|
|
2877
|
+
}
|
|
2878
|
+
function analyzeLazyUsageMulti(roots) {
|
|
2879
|
+
const counts = /* @__PURE__ */ new Map();
|
|
2880
|
+
const recursive = /* @__PURE__ */ new Set();
|
|
2881
|
+
const descended = /* @__PURE__ */ new Set();
|
|
2882
|
+
const active = /* @__PURE__ */ new Set();
|
|
2883
|
+
function walk(p) {
|
|
2884
|
+
const def = p._def;
|
|
2885
|
+
if (def.tag === "lazy") {
|
|
2886
|
+
counts.set(p, (counts.get(p) ?? 0) + 1);
|
|
2887
|
+
if (active.has(p)) {
|
|
2888
|
+
recursive.add(p);
|
|
2889
|
+
return;
|
|
2890
|
+
}
|
|
2891
|
+
if (descended.has(p)) return;
|
|
2892
|
+
descended.add(p);
|
|
2893
|
+
let resolved;
|
|
2894
|
+
try {
|
|
2895
|
+
resolved = def.thunk();
|
|
2896
|
+
} catch {
|
|
2897
|
+
return;
|
|
2898
|
+
}
|
|
2899
|
+
active.add(p);
|
|
2900
|
+
walk(resolved);
|
|
2901
|
+
active.delete(p);
|
|
2902
|
+
return;
|
|
2903
|
+
}
|
|
2904
|
+
for (const child of childrenOf(def)) walk(child);
|
|
2905
|
+
}
|
|
2906
|
+
for (const root of roots) walk(root);
|
|
2907
|
+
return { counts, recursive };
|
|
2908
|
+
}
|
|
2739
2909
|
function compile(combinator, mapFnSources) {
|
|
2740
2910
|
const ctx = {
|
|
2741
2911
|
vars: 0,
|
|
@@ -2752,7 +2922,8 @@ function compile(combinator, mapFnSources) {
|
|
|
2752
2922
|
triviaCaptureNames: /* @__PURE__ */ new Map(),
|
|
2753
2923
|
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
2754
2924
|
namedFnDecls: [],
|
|
2755
|
-
capturing: hasNodeDef(combinator)
|
|
2925
|
+
capturing: hasNodeDef(combinator),
|
|
2926
|
+
lazyUsage: analyzeLazyUsage(combinator)
|
|
2756
2927
|
};
|
|
2757
2928
|
const r = emit(combinator, ctx, "_pos");
|
|
2758
2929
|
const collatorDecl = ctx.needsCollator ? `const _collator = new Intl.Collator(undefined, { sensitivity: 'accent' })
|
|
@@ -2810,6 +2981,66 @@ function compile(combinator, mapFnSources) {
|
|
|
2810
2981
|
}
|
|
2811
2982
|
};
|
|
2812
2983
|
}
|
|
2984
|
+
function compileRuleMap(ruleMap) {
|
|
2985
|
+
const ctx = {
|
|
2986
|
+
vars: 0,
|
|
2987
|
+
indent: 1,
|
|
2988
|
+
regexDecls: [],
|
|
2989
|
+
regexMap: /* @__PURE__ */ new Map(),
|
|
2990
|
+
mapFns: [],
|
|
2991
|
+
mapFnSrcs: [],
|
|
2992
|
+
buildFns: [],
|
|
2993
|
+
buildSrcs: [],
|
|
2994
|
+
runtimeParsers: [],
|
|
2995
|
+
needsCollator: false,
|
|
2996
|
+
namedParsers: /* @__PURE__ */ new Map(),
|
|
2997
|
+
triviaCaptureNames: /* @__PURE__ */ new Map(),
|
|
2998
|
+
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
2999
|
+
namedFnDecls: [],
|
|
3000
|
+
capturing: ruleMap.some(([, rule]) => hasNodeDef(rule)),
|
|
3001
|
+
lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule))
|
|
3002
|
+
};
|
|
3003
|
+
const perEntry = ruleMap.map(([key, rule]) => ({ key, r: emit(rule, ctx, "_pos") }));
|
|
3004
|
+
const collatorDecl = ctx.needsCollator ? `const _collator = new Intl.Collator(undefined, { sensitivity: 'accent' })
|
|
3005
|
+
` : "";
|
|
3006
|
+
const derivedSrcs = ctx.mapFnSrcs.length === ctx.mapFns.length && ctx.mapFnSrcs.every((s) => s !== null) ? ctx.mapFnSrcs : void 0;
|
|
3007
|
+
const buildCovered = ctx.buildFns.length === 0 || ctx.buildSrcs.every((s) => s !== null);
|
|
3008
|
+
const buildSources = ctx.buildFns.length === 0 ? void 0 : ctx.buildSrcs;
|
|
3009
|
+
const mfCovered = ctx.mapFns.length === 0 || derivedSrcs !== void 0;
|
|
3010
|
+
const canInline = ctx.runtimeParsers.length === 0 && mfCovered && buildCovered;
|
|
3011
|
+
if (!canInline) return null;
|
|
3012
|
+
const mfDecl = derivedSrcs?.length ? ` const _mf = [${derivedSrcs.join(", ")}]` : "";
|
|
3013
|
+
const buildDecl = buildSources?.length ? ` const _build = [${buildSources.join(", ")}]` : "";
|
|
3014
|
+
const namedPrelude = ctx.namedFnDecls.length > 0 ? namedFnPrelude() : [];
|
|
3015
|
+
const hoistedDecls = [
|
|
3016
|
+
...ctx.regexDecls.map((d) => ` ${d}`),
|
|
3017
|
+
collatorDecl ? ` ${collatorDecl.trim()}` : "",
|
|
3018
|
+
mfDecl,
|
|
3019
|
+
buildDecl,
|
|
3020
|
+
...namedPrelude.map((l) => ` ${l}`),
|
|
3021
|
+
...ctx.namedFnDecls.flatMap((decl, i) => {
|
|
3022
|
+
const lines = decl.split("\n").map((l) => ` ${l}`);
|
|
3023
|
+
return i > 0 ? ["", ...lines] : lines;
|
|
3024
|
+
})
|
|
3025
|
+
].filter(Boolean);
|
|
3026
|
+
const entryFnText = (r) => [
|
|
3027
|
+
`function(input, _pos, _ctx) {`,
|
|
3028
|
+
` let pos = _pos`,
|
|
3029
|
+
...r.stmts,
|
|
3030
|
+
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
|
|
3031
|
+
`}`
|
|
3032
|
+
].join("\n");
|
|
3033
|
+
const objBody = perEntry.map(({ key, r }) => ` ${JSON.stringify(key)}: ${entryFnText(r).split("\n").join("\n ")}`).join(",\n");
|
|
3034
|
+
const replacement = [
|
|
3035
|
+
`/* @__PURE__ */ (() => {`,
|
|
3036
|
+
...hoistedDecls,
|
|
3037
|
+
` return {`,
|
|
3038
|
+
objBody,
|
|
3039
|
+
` }`,
|
|
3040
|
+
`})()`
|
|
3041
|
+
].join("\n");
|
|
3042
|
+
return { keys: perEntry.map((e) => e.key), replacement };
|
|
3043
|
+
}
|
|
2813
3044
|
function buildInlineExpression(ctx, r, collatorDecl, mapFnSources, buildSources) {
|
|
2814
3045
|
const bodyLines = [
|
|
2815
3046
|
` let pos = _pos`,
|
|
@@ -3091,6 +3322,10 @@ function exprToCombi(node2, scope, code, mfs) {
|
|
|
3091
3322
|
}
|
|
3092
3323
|
}
|
|
3093
3324
|
if (callee.name === "rules") return null;
|
|
3325
|
+
if (callee.name === "ref") {
|
|
3326
|
+
if (node2.arguments.length !== 0) return null;
|
|
3327
|
+
return ref();
|
|
3328
|
+
}
|
|
3094
3329
|
if (callee.name === "parser") {
|
|
3095
3330
|
const [optsArg, rootArg] = node2.arguments;
|
|
3096
3331
|
if (!optsArg || !rootArg || optsArg.type === "SpreadElement" || rootArg.type === "SpreadElement") return null;
|
|
@@ -3330,6 +3565,40 @@ function evaluateParserFactory(factoryNode, scope, code, mapFnSources) {
|
|
|
3330
3565
|
}
|
|
3331
3566
|
return ruleRefs;
|
|
3332
3567
|
}
|
|
3568
|
+
function isDefinableRef(v2) {
|
|
3569
|
+
return isCombinator(v2) && typeof v2.define === "function" && v2._def.tag === "lazy";
|
|
3570
|
+
}
|
|
3571
|
+
function evaluateRefDeclaration(init, name, scope) {
|
|
3572
|
+
if (init.type !== "CallExpression") return null;
|
|
3573
|
+
const callee = init.callee;
|
|
3574
|
+
if (callee.type !== "Identifier" || callee.name !== "ref") return null;
|
|
3575
|
+
if (init.arguments.length !== 0) return null;
|
|
3576
|
+
const slot = ref();
|
|
3577
|
+
scope.set(name, { combi: slot, mfSrcs: [] });
|
|
3578
|
+
return slot;
|
|
3579
|
+
}
|
|
3580
|
+
function applyDefineStatement(callExpr, scope, code) {
|
|
3581
|
+
if (callExpr.type !== "CallExpression") return false;
|
|
3582
|
+
const callee = callExpr.callee;
|
|
3583
|
+
if (callee.type !== "MemberExpression") return false;
|
|
3584
|
+
const mem = callee;
|
|
3585
|
+
if (mem.computed) return false;
|
|
3586
|
+
if (mem.property.type !== "Identifier" || mem.property.name !== "define") return false;
|
|
3587
|
+
if (mem.object.type !== "Identifier" || !mem.object.name) return false;
|
|
3588
|
+
const target = scope.get(mem.object.name);
|
|
3589
|
+
const refCombi = isScopeEntry(target) ? target.combi : isCombinator(target) ? target : null;
|
|
3590
|
+
if (!refCombi || !isDefinableRef(refCombi)) return false;
|
|
3591
|
+
const args = callExpr.arguments;
|
|
3592
|
+
if (args.length !== 1 || args[0].type === "SpreadElement") return false;
|
|
3593
|
+
const inner = anyValue(args[0], scope, code, []);
|
|
3594
|
+
if (!isCombinator(inner)) return false;
|
|
3595
|
+
try {
|
|
3596
|
+
refCombi.define(inner);
|
|
3597
|
+
} catch {
|
|
3598
|
+
return false;
|
|
3599
|
+
}
|
|
3600
|
+
return true;
|
|
3601
|
+
}
|
|
3333
3602
|
function referencesAny(node2, names, scope) {
|
|
3334
3603
|
if (node2.type === "Identifier") {
|
|
3335
3604
|
return names.has(node2.name) || scope.has(node2.name);
|
|
@@ -3404,6 +3673,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
3404
3673
|
const replacements = [];
|
|
3405
3674
|
const warnings = [];
|
|
3406
3675
|
let anyUnresolved = false;
|
|
3676
|
+
let ruleMapHolderCounter = 0;
|
|
3407
3677
|
const lineOf = (pos) => {
|
|
3408
3678
|
let line = 1;
|
|
3409
3679
|
for (let i = 0; i < pos && i < code.length; i++) if (code.charCodeAt(i) === 10) line++;
|
|
@@ -3425,18 +3695,53 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
3425
3695
|
warn(init.start, `${label2}: rules(...) factory isn't statically evaluable`);
|
|
3426
3696
|
return null;
|
|
3427
3697
|
}
|
|
3428
|
-
const
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
warn(init.start, `${label2}: rule "${ruleKey}" couldn't be inlined`);
|
|
3433
|
-
return null;
|
|
3434
|
-
}
|
|
3435
|
-
entries.push([ruleKey, compiled.inlineExpression]);
|
|
3698
|
+
const compiled = compileRuleMap([...ruleMap]);
|
|
3699
|
+
if (!compiled) {
|
|
3700
|
+
warn(init.start, `${label2}: rule map couldn't be inlined`);
|
|
3701
|
+
return null;
|
|
3436
3702
|
}
|
|
3437
|
-
return {
|
|
3703
|
+
return { replacement: compiled.replacement, ruleMap };
|
|
3438
3704
|
};
|
|
3439
3705
|
const isRulesCall = (init) => init.type === "CallExpression" && init.callee.type === "Identifier" && init.callee.name === "rules";
|
|
3706
|
+
const unwrapVd = (stmt) => stmt.type === "VariableDeclaration" ? stmt : stmt.type === "ExportNamedDeclaration" && stmt.declaration?.type === "VariableDeclaration" ? stmt.declaration : null;
|
|
3707
|
+
const refNames = /* @__PURE__ */ new Set();
|
|
3708
|
+
for (const stmt of body) {
|
|
3709
|
+
const innerVd = unwrapVd(stmt);
|
|
3710
|
+
if (!innerVd) continue;
|
|
3711
|
+
for (const decl of innerVd.declarations) {
|
|
3712
|
+
const d = decl;
|
|
3713
|
+
if (!d.init || d.id.type !== "Identifier") continue;
|
|
3714
|
+
const init = d.init;
|
|
3715
|
+
if (init.type === "CallExpression" && init.callee.type === "Identifier" && init.callee.name === "ref") {
|
|
3716
|
+
refNames.add(d.id.name);
|
|
3717
|
+
}
|
|
3718
|
+
}
|
|
3719
|
+
}
|
|
3720
|
+
const defineRemovals = [];
|
|
3721
|
+
if (refNames.size > 0) {
|
|
3722
|
+
for (const stmt of body) {
|
|
3723
|
+
if (stmt.type === "ExpressionStatement") {
|
|
3724
|
+
const expr = stmt.expression;
|
|
3725
|
+
if (applyDefineStatement(expr, scope, code)) {
|
|
3726
|
+
defineRemovals.push({ start: stmt.start, end: stmt.end });
|
|
3727
|
+
}
|
|
3728
|
+
continue;
|
|
3729
|
+
}
|
|
3730
|
+
const innerVd = unwrapVd(stmt);
|
|
3731
|
+
if (!innerVd) continue;
|
|
3732
|
+
for (const decl of innerVd.declarations) {
|
|
3733
|
+
const d = decl;
|
|
3734
|
+
if (!d.init || d.id.type !== "Identifier") continue;
|
|
3735
|
+
const name = d.id.name;
|
|
3736
|
+
const init = d.init;
|
|
3737
|
+
if (evaluateRefDeclaration(init, name, scope)) continue;
|
|
3738
|
+
if (scope.has(name)) continue;
|
|
3739
|
+
if (!referencesAny(init, allNames, scope)) continue;
|
|
3740
|
+
const combi = evaluateExpr(init, scope, code, []);
|
|
3741
|
+
if (combi) scope.set(name, { combi, mfSrcs: [] });
|
|
3742
|
+
}
|
|
3743
|
+
}
|
|
3744
|
+
}
|
|
3440
3745
|
for (const stmt of body) {
|
|
3441
3746
|
let vd = null;
|
|
3442
3747
|
let stmtStart = stmt.start;
|
|
@@ -3460,15 +3765,26 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
3460
3765
|
if (d.id.type === "Identifier") {
|
|
3461
3766
|
const varName = d.id.name;
|
|
3462
3767
|
if (!referencesAny(init, allNames, scope)) continue;
|
|
3768
|
+
if (refNames.has(varName)) {
|
|
3769
|
+
const refEntry = scope.get(varName);
|
|
3770
|
+
const refCombi = refEntry?.combi ?? null;
|
|
3771
|
+
if (refCombi) {
|
|
3772
|
+
const compiled2 = compile(refCombi);
|
|
3773
|
+
if (compiled2.inlineExpression === null) {
|
|
3774
|
+
warn(init.start, `"${varName}" is a ref() that couldn't be inlined (was .define() called with a static combinator?)`);
|
|
3775
|
+
continue;
|
|
3776
|
+
}
|
|
3777
|
+
replacements.push({ start: init.start, end: init.end, replacement: compiled2.inlineExpression });
|
|
3778
|
+
continue;
|
|
3779
|
+
}
|
|
3780
|
+
}
|
|
3463
3781
|
if (isRulesCall(init)) {
|
|
3464
3782
|
const compiledRules = compileRulesFactory(init, varName);
|
|
3465
3783
|
if (!compiledRules) continue;
|
|
3466
3784
|
replacements.push({
|
|
3467
3785
|
start: init.start,
|
|
3468
3786
|
end: init.end,
|
|
3469
|
-
replacement:
|
|
3470
|
-
${compiledRules.entries.map(([k, expr]) => ` ${k}: ${expr}`).join(",\n")}
|
|
3471
|
-
}`
|
|
3787
|
+
replacement: compiledRules.replacement
|
|
3472
3788
|
});
|
|
3473
3789
|
continue;
|
|
3474
3790
|
}
|
|
@@ -3503,9 +3819,8 @@ ${compiledRules.entries.map(([k, expr]) => ` ${k}: ${expr}`).join(",\n")}
|
|
|
3503
3819
|
}
|
|
3504
3820
|
const compiledRules = compileRulesFactory(init, "{ \u2026 }");
|
|
3505
3821
|
if (!compiledRules) continue;
|
|
3506
|
-
const byKey = new Map(compiledRules.entries);
|
|
3507
3822
|
const pattern = d.id;
|
|
3508
|
-
const
|
|
3823
|
+
const bindings = [];
|
|
3509
3824
|
let allOk = true;
|
|
3510
3825
|
for (const prop of pattern.properties) {
|
|
3511
3826
|
const p = prop;
|
|
@@ -3520,17 +3835,21 @@ ${compiledRules.entries.map(([k, expr]) => ` ${k}: ${expr}`).join(",\n")}
|
|
|
3520
3835
|
allOk = false;
|
|
3521
3836
|
break;
|
|
3522
3837
|
}
|
|
3523
|
-
|
|
3524
|
-
if (inlineExpr === void 0) {
|
|
3838
|
+
if (!compiledRules.ruleMap.has(ruleKey)) {
|
|
3525
3839
|
warn(init.start, `destructured rule "${ruleKey}" isn't returned by the rules() factory`);
|
|
3526
3840
|
allOk = false;
|
|
3527
3841
|
break;
|
|
3528
3842
|
}
|
|
3529
|
-
|
|
3843
|
+
bindings.push({ ruleKey, localName });
|
|
3530
3844
|
const rule = compiledRules.ruleMap.get(ruleKey);
|
|
3531
3845
|
if (rule) scope.set(localName, { combi: rule, mfSrcs: [] });
|
|
3532
3846
|
}
|
|
3533
3847
|
if (!allOk) continue;
|
|
3848
|
+
const holderVar = `__rules${ruleMapHolderCounter++}`;
|
|
3849
|
+
const lines = [
|
|
3850
|
+
`const ${holderVar} = ${compiledRules.replacement}`,
|
|
3851
|
+
...bindings.map(({ ruleKey, localName }) => `${exportPrefix}${kind} ${localName} = ${holderVar}[${JSON.stringify(ruleKey)}]`)
|
|
3852
|
+
];
|
|
3534
3853
|
replacements.push({
|
|
3535
3854
|
start: stmtStart,
|
|
3536
3855
|
end: stmtEnd,
|
|
@@ -3544,6 +3863,9 @@ ${compiledRules.entries.map(([k, expr]) => ` ${k}: ${expr}`).join(",\n")}
|
|
|
3544
3863
|
imp.fullyResolved = !anyUnresolved;
|
|
3545
3864
|
}
|
|
3546
3865
|
const ms = new MagicString(code);
|
|
3866
|
+
if (!anyUnresolved) {
|
|
3867
|
+
for (const { start, end } of defineRemovals) ms.remove(start, end);
|
|
3868
|
+
}
|
|
3547
3869
|
for (const imp of macroImports) {
|
|
3548
3870
|
if (imp.fullyResolved) {
|
|
3549
3871
|
ms.remove(imp.start, imp.end);
|