parseman 0.8.0 → 0.10.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/README.md +33 -551
- package/dist/combinators/node.d.ts +15 -1
- package/dist/combinators/node.d.ts.map +1 -1
- package/dist/compiler/build-arity.d.ts +26 -0
- package/dist/compiler/build-arity.d.ts.map +1 -0
- 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/functional/doc.d.ts.map +1 -1
- package/dist/index.cjs +387 -126
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +387 -126
- 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 +542 -144
- package/dist/plugin/index.cjs.map +4 -4
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +542 -144
- package/dist/plugin/index.js.map +4 -4
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +8 -1
package/dist/index.cjs
CHANGED
|
@@ -1200,24 +1200,70 @@ function not(combinator) {
|
|
|
1200
1200
|
};
|
|
1201
1201
|
}
|
|
1202
1202
|
|
|
1203
|
+
// src/compiler/build-arity.ts
|
|
1204
|
+
var PARAM_LIST_RE = (
|
|
1205
|
+
// (params) => ... | function name?(params) ... | single-ident arrow `x => ...`
|
|
1206
|
+
/^(?:function\b[^(]*\(([^)]*)\)|\(([^)]*)\)\s*=>|([A-Za-z_$][\w$]*)\s*=>)/
|
|
1207
|
+
);
|
|
1208
|
+
var CONFIRMABLE_PARAM_RE = /^[A-Za-z_$][\w$]*\s*\??\s*(?::[^,=]+)?$/;
|
|
1209
|
+
function confirmedBuildArity(src) {
|
|
1210
|
+
const s = src.trim();
|
|
1211
|
+
const m = PARAM_LIST_RE.exec(s);
|
|
1212
|
+
if (!m) return null;
|
|
1213
|
+
if (m[3] !== void 0) return 1;
|
|
1214
|
+
const inner = (m[1] ?? m[2] ?? "").trim();
|
|
1215
|
+
if (inner === "") return 0;
|
|
1216
|
+
const parts = inner.split(",");
|
|
1217
|
+
for (const part of parts) {
|
|
1218
|
+
if (!CONFIRMABLE_PARAM_RE.test(part.trim())) return null;
|
|
1219
|
+
}
|
|
1220
|
+
if (/\barguments\b/.test(s)) return null;
|
|
1221
|
+
return parts.length;
|
|
1222
|
+
}
|
|
1223
|
+
function buildReadsTrivia(def) {
|
|
1224
|
+
const src = def.buildSrc ?? def.build.toString();
|
|
1225
|
+
const arity = confirmedBuildArity(src);
|
|
1226
|
+
if (arity === null) return true;
|
|
1227
|
+
return arity >= 4;
|
|
1228
|
+
}
|
|
1229
|
+
function buildReadsState(def) {
|
|
1230
|
+
const src = def.buildSrc ?? def.build.toString();
|
|
1231
|
+
const arity = confirmedBuildArity(src);
|
|
1232
|
+
if (arity === null) return true;
|
|
1233
|
+
return arity >= 5;
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1203
1236
|
// src/combinators/node.ts
|
|
1204
|
-
function
|
|
1237
|
+
function collapseChild(child) {
|
|
1238
|
+
return child !== null && typeof child === "object" && child._tag === "leaf" ? child.value : child;
|
|
1239
|
+
}
|
|
1240
|
+
function node(type, combinator, build, opts) {
|
|
1205
1241
|
const meta = {
|
|
1206
1242
|
firstSet: combinator._meta.firstSet,
|
|
1207
1243
|
canMatchNewline: combinator._meta.canMatchNewline,
|
|
1208
1244
|
isTrivia: false
|
|
1209
1245
|
};
|
|
1246
|
+
const collapse = opts?.collapse === true;
|
|
1247
|
+
const def = collapse ? { tag: "node", type, parser: combinator, build, collapse: true } : { tag: "node", type, parser: combinator, build };
|
|
1248
|
+
const capturesTrivia = buildReadsTrivia(def);
|
|
1249
|
+
const clonesState = buildReadsState(def);
|
|
1210
1250
|
return {
|
|
1211
1251
|
_tag: "node",
|
|
1212
1252
|
_meta: meta,
|
|
1213
|
-
_def:
|
|
1253
|
+
_def: def,
|
|
1214
1254
|
parse(input, pos, ctx) {
|
|
1215
1255
|
const saved = beginCstNodeCapture(ctx);
|
|
1256
|
+
if (!capturesTrivia) ctx.captureTrivia = false;
|
|
1216
1257
|
const r = combinator.parse(input, pos, ctx);
|
|
1217
1258
|
const { children, rawChildren, triviaLog } = endCstNodeCapture(ctx, saved);
|
|
1218
1259
|
if (!r.ok) return r;
|
|
1219
|
-
const
|
|
1220
|
-
|
|
1260
|
+
const built = collapse && children.length === 1 ? collapseChild(children[0]) : build(
|
|
1261
|
+
children,
|
|
1262
|
+
rawChildren,
|
|
1263
|
+
r.span,
|
|
1264
|
+
triviaLog,
|
|
1265
|
+
clonesState && ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0
|
|
1266
|
+
);
|
|
1221
1267
|
const isNodeLike = typeof built === "object" && built !== null && built._tag === "node";
|
|
1222
1268
|
const rawEntry = isNodeLike ? built : { _tag: "leaf", value: typeof built === "string" ? built : "", span: r.span };
|
|
1223
1269
|
if (saved.buf !== void 0 || saved.ch !== void 0) {
|
|
@@ -1367,14 +1413,140 @@ function parse(combinator, input, opts = {}) {
|
|
|
1367
1413
|
return withErrors;
|
|
1368
1414
|
}
|
|
1369
1415
|
|
|
1416
|
+
// src/compiler/scannable-run.ts
|
|
1417
|
+
var CLASS_ESCAPES = { t: 9, n: 10, r: 13, f: 12, v: 11, "0": 0 };
|
|
1418
|
+
var META = new Set("()[]{}*+?|^$.".split(""));
|
|
1419
|
+
function parseClassRanges(body) {
|
|
1420
|
+
const ranges = [];
|
|
1421
|
+
let i = 0;
|
|
1422
|
+
const readCp = () => {
|
|
1423
|
+
const ch = body[i];
|
|
1424
|
+
if (ch === void 0) return null;
|
|
1425
|
+
if (ch === "\\") {
|
|
1426
|
+
const e = body[i + 1];
|
|
1427
|
+
if (e === void 0) return null;
|
|
1428
|
+
i += 2;
|
|
1429
|
+
return e in CLASS_ESCAPES ? CLASS_ESCAPES[e] : e.codePointAt(0);
|
|
1430
|
+
}
|
|
1431
|
+
i += ch.length;
|
|
1432
|
+
return ch.codePointAt(0);
|
|
1433
|
+
};
|
|
1434
|
+
while (i < body.length) {
|
|
1435
|
+
const lo = readCp();
|
|
1436
|
+
if (lo === null) return null;
|
|
1437
|
+
if (body[i] === "-" && body[i + 1] !== void 0 && body[i + 1] !== "]") {
|
|
1438
|
+
i += 1;
|
|
1439
|
+
const hi = readCp();
|
|
1440
|
+
if (hi === null) return null;
|
|
1441
|
+
ranges.push([lo, hi]);
|
|
1442
|
+
} else {
|
|
1443
|
+
ranges.push([lo, lo]);
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
return ranges.length ? ranges : null;
|
|
1447
|
+
}
|
|
1448
|
+
function literalCodePoints(frag) {
|
|
1449
|
+
const out = [];
|
|
1450
|
+
let i = 0;
|
|
1451
|
+
while (i < frag.length) {
|
|
1452
|
+
const ch = frag[i];
|
|
1453
|
+
if (ch === "\\") {
|
|
1454
|
+
const e = frag[i + 1];
|
|
1455
|
+
if (e === void 0) return null;
|
|
1456
|
+
out.push(e in CLASS_ESCAPES ? CLASS_ESCAPES[e] : e.codePointAt(0));
|
|
1457
|
+
i += 2;
|
|
1458
|
+
continue;
|
|
1459
|
+
}
|
|
1460
|
+
if (META.has(ch)) return null;
|
|
1461
|
+
out.push(ch.codePointAt(0));
|
|
1462
|
+
i += 1;
|
|
1463
|
+
}
|
|
1464
|
+
return out.length ? out : null;
|
|
1465
|
+
}
|
|
1466
|
+
function parseScanShape(source) {
|
|
1467
|
+
let m = /^\[((?:\\.|[^\]])+)\]([+*])$/.exec(source);
|
|
1468
|
+
if (m) {
|
|
1469
|
+
if (m[1].startsWith("^")) return null;
|
|
1470
|
+
const ranges = parseClassRanges(m[1]);
|
|
1471
|
+
return ranges ? { kind: "chars", ranges } : null;
|
|
1472
|
+
}
|
|
1473
|
+
m = /^(.*?)\[\^((?:\\.|[^\]])+)\]\*$/.exec(source);
|
|
1474
|
+
if (m) {
|
|
1475
|
+
const open = literalCodePoints(m[1]);
|
|
1476
|
+
const stop = parseClassRanges(m[2]);
|
|
1477
|
+
if (open && stop) return { kind: "until", open, stop };
|
|
1478
|
+
return null;
|
|
1479
|
+
}
|
|
1480
|
+
if (!source.includes("\\\\")) {
|
|
1481
|
+
m = /^(.*?)\((?:\?:)?[\s\S]*\)\*(.*?)$/.exec(source);
|
|
1482
|
+
if (m && m[1] && m[2]) {
|
|
1483
|
+
const open = literalCodePoints(m[1]);
|
|
1484
|
+
const close = literalCodePoints(m[2]);
|
|
1485
|
+
if (open && close) return { kind: "delimited", open, close };
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
return null;
|
|
1489
|
+
}
|
|
1490
|
+
var classCond = (cVar, ranges) => ranges.map(([lo, hi]) => lo === hi ? `${cVar} === ${lo}` : `(${cVar} >= ${lo} && ${cVar} <= ${hi})`).join(" || ");
|
|
1491
|
+
var litCond = (base, cps, firstVar) => cps.map(
|
|
1492
|
+
(cp, k) => k === 0 && firstVar ? `${firstVar} === ${cp}` : `input.charCodeAt(${base}${k ? ` + ${k}` : ""}) === ${cp}`
|
|
1493
|
+
).join(" && ");
|
|
1494
|
+
function advanceExpr(shape) {
|
|
1495
|
+
if (shape.kind === "chars") {
|
|
1496
|
+
return {
|
|
1497
|
+
setup: [
|
|
1498
|
+
` _e++`,
|
|
1499
|
+
` while (_e < input.length) { const c2 = input.charCodeAt(_e); if (${classCond("c2", shape.ranges)}) _e++; else break }`
|
|
1500
|
+
],
|
|
1501
|
+
endVar: "_e"
|
|
1502
|
+
};
|
|
1503
|
+
}
|
|
1504
|
+
if (shape.kind === "until") {
|
|
1505
|
+
return {
|
|
1506
|
+
setup: [
|
|
1507
|
+
` let j = _e + ${shape.open.length}`,
|
|
1508
|
+
` while (j < input.length && !(${classCond("input.charCodeAt(j)", shape.stop)})) j++`
|
|
1509
|
+
],
|
|
1510
|
+
endVar: "j"
|
|
1511
|
+
};
|
|
1512
|
+
}
|
|
1513
|
+
const n = shape.close.length;
|
|
1514
|
+
return {
|
|
1515
|
+
setup: [
|
|
1516
|
+
` let j = _e + ${shape.open.length}`,
|
|
1517
|
+
` while (j + ${n - 1} < input.length && !(${litCond("j", shape.close)})) j++`
|
|
1518
|
+
],
|
|
1519
|
+
endVar: n === 1 ? "(j + 1 <= input.length ? j + 1 : input.length)" : `(j + ${n} <= input.length ? j + ${n} : input.length)`
|
|
1520
|
+
};
|
|
1521
|
+
}
|
|
1522
|
+
function guardLine(shape) {
|
|
1523
|
+
const cond = shape.kind === "chars" ? classCond("c", shape.ranges) : litCond("_e", shape.open, "c");
|
|
1524
|
+
return ` if (${cond}) {`;
|
|
1525
|
+
}
|
|
1526
|
+
function scanBranch(shape) {
|
|
1527
|
+
if (shape.kind === "chars") {
|
|
1528
|
+
return ` if (${classCond("c", shape.ranges)}) { _e++; continue }`;
|
|
1529
|
+
}
|
|
1530
|
+
const { setup, endVar } = advanceExpr(shape);
|
|
1531
|
+
return [guardLine(shape), ...setup, ` _e = ${endVar}`, ` continue`, ` }`].join("\n");
|
|
1532
|
+
}
|
|
1533
|
+
function captureChunk(startVar, kindIndex) {
|
|
1534
|
+
return [
|
|
1535
|
+
` if (_cap) {`,
|
|
1536
|
+
` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(${startVar}, _e, ${kindIndex})`,
|
|
1537
|
+
` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(${startVar}, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${kindIndex})`,
|
|
1538
|
+
` }`
|
|
1539
|
+
];
|
|
1540
|
+
}
|
|
1541
|
+
function scanBranchLabeled(shape, kindIndex) {
|
|
1542
|
+
const { setup, endVar } = advanceExpr(shape);
|
|
1543
|
+
const lines = [guardLine(shape), ` const _cs = _e`, ...setup];
|
|
1544
|
+
if (endVar !== "_e") lines.push(` _e = ${endVar}`);
|
|
1545
|
+
lines.push(...captureChunk("_cs", kindIndex), ` continue`, ` }`);
|
|
1546
|
+
return lines.join("\n");
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1370
1549
|
// src/compiler/trivia-fast-path.ts
|
|
1371
|
-
var BLOCK_COMMENT = String.raw`\/\*(?:[^*]|\*(?!\/))*\*\/`;
|
|
1372
|
-
var WS_CLASS_SOURCES = /* @__PURE__ */ new Set([
|
|
1373
|
-
String.raw`[ \t\n\r\f]+`,
|
|
1374
|
-
String.raw`[ \t\n]+`,
|
|
1375
|
-
String.raw`[ \t]+`,
|
|
1376
|
-
String.raw`[\t\n\f\r ]+`
|
|
1377
|
-
]);
|
|
1378
1550
|
function unwrapTrivia2(p) {
|
|
1379
1551
|
let cur = p;
|
|
1380
1552
|
while (cur._def.tag === "trivia") cur = cur._def.parser;
|
|
@@ -1390,36 +1562,30 @@ function choiceArms(p) {
|
|
|
1390
1562
|
if (p._def.tag === "choice") return p._def.parsers;
|
|
1391
1563
|
return null;
|
|
1392
1564
|
}
|
|
1393
|
-
function
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
function isBlockCommentSource(source) {
|
|
1397
|
-
return source === BLOCK_COMMENT;
|
|
1565
|
+
function armShape(arm) {
|
|
1566
|
+
const src = getCoreRegexDef(arm)?.source;
|
|
1567
|
+
return src ? parseScanShape(src) : null;
|
|
1398
1568
|
}
|
|
1399
1569
|
function analyzeTriviaFastPath(trivia2) {
|
|
1400
1570
|
const core = unwrapTrivia2(trivia2);
|
|
1401
|
-
const
|
|
1402
|
-
if (
|
|
1403
|
-
|
|
1404
|
-
return null;
|
|
1571
|
+
const directSrc = getCoreRegexDef(core)?.source;
|
|
1572
|
+
if (directSrc) {
|
|
1573
|
+
const shape = parseScanShape(directSrc);
|
|
1574
|
+
return shape && shape.kind === "chars" ? [shape] : null;
|
|
1405
1575
|
}
|
|
1406
1576
|
const inner = oneOrMoreInner(core);
|
|
1407
1577
|
if (!inner) return null;
|
|
1408
|
-
const
|
|
1409
|
-
if (
|
|
1578
|
+
const innerShape = armShape(inner);
|
|
1579
|
+
if (innerShape) return innerShape.kind === "chars" ? [innerShape] : null;
|
|
1410
1580
|
const arms = choiceArms(inner);
|
|
1411
|
-
if (!arms || arms.length
|
|
1412
|
-
|
|
1413
|
-
let hasComment = false;
|
|
1581
|
+
if (!arms || arms.length < 2) return null;
|
|
1582
|
+
const shapes = [];
|
|
1414
1583
|
for (const arm of arms) {
|
|
1415
|
-
const
|
|
1416
|
-
if (!
|
|
1417
|
-
|
|
1418
|
-
else if (isBlockCommentSource(src)) hasComment = true;
|
|
1419
|
-
else return null;
|
|
1584
|
+
const shape = armShape(arm);
|
|
1585
|
+
if (!shape) return null;
|
|
1586
|
+
shapes.push(shape);
|
|
1420
1587
|
}
|
|
1421
|
-
|
|
1422
|
-
return null;
|
|
1588
|
+
return shapes;
|
|
1423
1589
|
}
|
|
1424
1590
|
var CAP_RECORD = [
|
|
1425
1591
|
` if (_cap && _e > _pos) {`,
|
|
@@ -1427,80 +1593,49 @@ var CAP_RECORD = [
|
|
|
1427
1593
|
` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
|
|
1428
1594
|
` }`
|
|
1429
1595
|
].join("\n");
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
` if (c === 47 && input.charCodeAt(_e + 1) === 42) {`,
|
|
1442
|
-
` let j = _e + 2`,
|
|
1443
|
-
` while (j + 1 < input.length && !(input.charCodeAt(j) === 42 && input.charCodeAt(j + 1) === 47)) j++`,
|
|
1444
|
-
` _e = j + 2 <= input.length ? j + 2 : input.length`,
|
|
1445
|
-
` continue`,
|
|
1446
|
-
` }`,
|
|
1447
|
-
` break`,
|
|
1448
|
-
` }`
|
|
1449
|
-
].join("\n");
|
|
1450
|
-
var CAP_CHUNK = (wsKind, commentKind) => [
|
|
1451
|
-
` if (c === 32 || c === 9 || c === 10 || c === 13 || c === 12) {`,
|
|
1452
|
-
` const _cs = _e`,
|
|
1453
|
-
` _e++`,
|
|
1454
|
-
` while (_e < input.length) {`,
|
|
1455
|
-
` const c2 = input.charCodeAt(_e)`,
|
|
1456
|
-
` if (c2 === 32 || c2 === 9 || c2 === 10 || c2 === 13 || c2 === 12) _e++`,
|
|
1457
|
-
` else break`,
|
|
1458
|
-
` }`,
|
|
1459
|
-
` if (_cap) {`,
|
|
1460
|
-
` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_cs, _e, ${wsKind})`,
|
|
1461
|
-
` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(_cs, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${wsKind})`,
|
|
1462
|
-
` }`,
|
|
1463
|
-
` continue`,
|
|
1464
|
-
` }`,
|
|
1465
|
-
` if (c === 47 && input.charCodeAt(_e + 1) === 42) {`,
|
|
1466
|
-
` const _cs = _e`,
|
|
1467
|
-
` let j = _e + 2`,
|
|
1468
|
-
` while (j + 1 < input.length && !(input.charCodeAt(j) === 42 && input.charCodeAt(j + 1) === 47)) j++`,
|
|
1469
|
-
` _e = j + 2 <= input.length ? j + 2 : input.length`,
|
|
1470
|
-
` if (_cap) {`,
|
|
1471
|
-
` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_cs, _e, ${commentKind})`,
|
|
1472
|
-
` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(_cs, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${commentKind})`,
|
|
1473
|
-
` }`,
|
|
1474
|
-
` continue`,
|
|
1475
|
-
` }`
|
|
1476
|
-
].join("\n");
|
|
1477
|
-
var WS_COMMENTS_LOOP_LABELED = (wsKind, commentKind) => [
|
|
1478
|
-
` while (_e < input.length) {`,
|
|
1479
|
-
` const c = input.charCodeAt(_e)`,
|
|
1480
|
-
CAP_CHUNK(wsKind, commentKind),
|
|
1481
|
-
` break`,
|
|
1482
|
-
` }`
|
|
1483
|
-
].join("\n");
|
|
1484
|
-
function buildFastTriviaFnDecl(fnName, kind, kindIndices) {
|
|
1485
|
-
const loop = kind === "wsComments" && kindIndices ? WS_COMMENTS_LOOP_LABELED(kindIndices.ws, kindIndices.comment) : kind === "wsComments" ? WS_COMMENTS_LOOP : WS_ONLY_LOOP;
|
|
1486
|
-
const cap = kindIndices ? "" : CAP_RECORD;
|
|
1487
|
-
const lines = [
|
|
1596
|
+
function composeFastLoop(shapes) {
|
|
1597
|
+
return [
|
|
1598
|
+
` while (_e < input.length) {`,
|
|
1599
|
+
` const c = input.charCodeAt(_e)`,
|
|
1600
|
+
...shapes.map(scanBranch),
|
|
1601
|
+
` break`,
|
|
1602
|
+
` }`
|
|
1603
|
+
].join("\n");
|
|
1604
|
+
}
|
|
1605
|
+
function buildFastTriviaFnDecl(fnName, shapes) {
|
|
1606
|
+
return [
|
|
1488
1607
|
`function ${fnName}(input, _pos, _ctx, _cap) {`,
|
|
1489
1608
|
` let _e = _pos`,
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1609
|
+
composeFastLoop(shapes),
|
|
1610
|
+
CAP_RECORD,
|
|
1611
|
+
` return _e`,
|
|
1612
|
+
`}`
|
|
1613
|
+
].join("\n");
|
|
1495
1614
|
}
|
|
1496
|
-
function
|
|
1615
|
+
function analyzeLabeledScannableRun(trivia2) {
|
|
1616
|
+
const spec = analyzeLabeledTrivia(trivia2);
|
|
1617
|
+
if (!spec) return null;
|
|
1618
|
+
const out = [];
|
|
1497
1619
|
for (const arm of spec.arms) {
|
|
1498
1620
|
const src = getCoreRegexDef(arm.parser)?.source;
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1621
|
+
const shape = src ? parseScanShape(src) : null;
|
|
1622
|
+
if (!shape) return null;
|
|
1623
|
+
out.push({ shape, kindIndex: arm.kindIndex });
|
|
1502
1624
|
}
|
|
1503
|
-
return
|
|
1625
|
+
return out;
|
|
1626
|
+
}
|
|
1627
|
+
function buildLabeledScannableTriviaFnDecl(fnName, arms) {
|
|
1628
|
+
return [
|
|
1629
|
+
`function ${fnName}(input, _pos, _ctx, _cap) {`,
|
|
1630
|
+
` let _e = _pos`,
|
|
1631
|
+
` while (_e < input.length) {`,
|
|
1632
|
+
` const c = input.charCodeAt(_e)`,
|
|
1633
|
+
...arms.map((a) => scanBranchLabeled(a.shape, a.kindIndex)),
|
|
1634
|
+
` break`,
|
|
1635
|
+
` }`,
|
|
1636
|
+
` return _e`,
|
|
1637
|
+
`}`
|
|
1638
|
+
].join("\n");
|
|
1504
1639
|
}
|
|
1505
1640
|
function buildLabeledRegexTriviaFnDecl(fnName, spec, reNames) {
|
|
1506
1641
|
const tryArms = spec.arms.map((arm, i) => {
|
|
@@ -1533,14 +1668,6 @@ function buildLabeledRegexTriviaFnDecl(fnName, spec, reNames) {
|
|
|
1533
1668
|
`}`
|
|
1534
1669
|
].join("\n");
|
|
1535
1670
|
}
|
|
1536
|
-
function labeledTriviaKindIndices(trivia2) {
|
|
1537
|
-
const spec = analyzeLabeledTrivia(trivia2);
|
|
1538
|
-
if (!spec || spec.arms.length !== 2) return null;
|
|
1539
|
-
const ws = regexArmIndex(spec, false);
|
|
1540
|
-
const comment = regexArmIndex(spec, true);
|
|
1541
|
-
if (ws === null || comment === null) return null;
|
|
1542
|
-
return { ws, comment };
|
|
1543
|
-
}
|
|
1544
1671
|
function labeledTriviaRegexArms(trivia2) {
|
|
1545
1672
|
const spec = analyzeLabeledTrivia(trivia2);
|
|
1546
1673
|
if (!spec) return null;
|
|
@@ -1788,14 +1915,19 @@ function ensureTriviaFn(ctx) {
|
|
|
1788
1915
|
const fnName = `_tf${ctx.triviaFnNames.size}`;
|
|
1789
1916
|
ctx.triviaFnNames.set(trivia2, fnName);
|
|
1790
1917
|
ctx.triviaCaptureNames.set(trivia2, fnName);
|
|
1791
|
-
const fastKind = analyzeTriviaFastPath(trivia2);
|
|
1792
|
-
const kindIndices = labeledTriviaKindIndices(trivia2);
|
|
1793
|
-
if (fastKind) {
|
|
1794
|
-
ctx.namedFnDecls.push(buildFastTriviaFnDecl(fnName, fastKind, kindIndices ?? void 0));
|
|
1795
|
-
return fnName;
|
|
1796
|
-
}
|
|
1797
1918
|
const labeledSpec = analyzeLabeledTrivia(trivia2);
|
|
1798
|
-
if (labeledSpec) {
|
|
1919
|
+
if (!labeledSpec) {
|
|
1920
|
+
const fastShapes = analyzeTriviaFastPath(trivia2);
|
|
1921
|
+
if (fastShapes) {
|
|
1922
|
+
ctx.namedFnDecls.push(buildFastTriviaFnDecl(fnName, fastShapes));
|
|
1923
|
+
return fnName;
|
|
1924
|
+
}
|
|
1925
|
+
} else {
|
|
1926
|
+
const labeledShapes = analyzeLabeledScannableRun(trivia2);
|
|
1927
|
+
if (labeledShapes) {
|
|
1928
|
+
ctx.namedFnDecls.push(buildLabeledScannableTriviaFnDecl(fnName, labeledShapes));
|
|
1929
|
+
return fnName;
|
|
1930
|
+
}
|
|
1799
1931
|
const regexSpec = labeledTriviaRegexArms(trivia2);
|
|
1800
1932
|
if (regexSpec) {
|
|
1801
1933
|
const reNames = [];
|
|
@@ -2233,11 +2365,11 @@ function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos) {
|
|
|
2233
2365
|
const p = def.parsers[idx];
|
|
2234
2366
|
const litVal = getCoreLiteralValue(p);
|
|
2235
2367
|
const litLen = litVal.length;
|
|
2236
|
-
const
|
|
2368
|
+
const litCond2 = emitLiteralCondition(litVal, pos);
|
|
2237
2369
|
const kw = first ? "if" : "else if";
|
|
2238
2370
|
first = false;
|
|
2239
2371
|
const litEnd = `${pos} + ${litLen}`;
|
|
2240
|
-
stmts.push(`${ind(ctx)}${kw} (${
|
|
2372
|
+
stmts.push(`${ind(ctx)}${kw} (${litCond2}) {`);
|
|
2241
2373
|
ctx.indent++;
|
|
2242
2374
|
const tR = emitTransformChain(p, JSON.stringify(litVal), litEnd, pos, ctx);
|
|
2243
2375
|
stmts.push(
|
|
@@ -2566,25 +2698,34 @@ function emitNode(def, ctx, pos) {
|
|
|
2566
2698
|
ctx.buildSrcs.push(def.buildSrc ?? null);
|
|
2567
2699
|
}
|
|
2568
2700
|
const i = ind(ctx);
|
|
2701
|
+
const capturesTrivia = mkType !== null || buildReadsTrivia(def);
|
|
2702
|
+
const clonesState = buildReadsState(def);
|
|
2569
2703
|
const chV = v(ctx, "_ch");
|
|
2570
2704
|
const rawV = v(ctx, "_raw");
|
|
2571
|
-
const tlV = v(ctx, "_tl");
|
|
2705
|
+
const tlV = capturesTrivia ? v(ctx, "_tl") : "_EMPTY_TL";
|
|
2706
|
+
if (!capturesTrivia) ctx.needsEmptyTl = true;
|
|
2572
2707
|
const sc = v(ctx, "_sc"), sl = v(ctx, "_sl"), sr = v(ctx, "_sr"), st = v(ctx, "_st"), stl = v(ctx, "_stl");
|
|
2708
|
+
const allocStmt = capturesTrivia ? `${i}const ${chV} = [], ${rawV} = [], ${tlV} = []` : `${i}const ${chV} = [], ${rawV} = []`;
|
|
2709
|
+
const innerTl = capturesTrivia ? tlV : "undefined";
|
|
2573
2710
|
const stmts = [
|
|
2574
|
-
|
|
2711
|
+
allocStmt,
|
|
2575
2712
|
`${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren, ${st} = _ctx.captureTrivia, ${stl} = _ctx._cstTriviaLog`,
|
|
2576
|
-
`${i}_ctx._cstChildren = ${chV}; _ctx._cstLeaves = ${chV}; _ctx._cstRawChildren = ${rawV}; _ctx.captureTrivia = true; _ctx._cstTriviaLog = ${
|
|
2713
|
+
`${i}_ctx._cstChildren = ${chV}; _ctx._cstLeaves = ${chV}; _ctx._cstRawChildren = ${rawV}; _ctx.captureTrivia = true; _ctx._cstTriviaLog = ${innerTl}`
|
|
2577
2714
|
];
|
|
2578
2715
|
const { stmts: innerStmts, okVar, endVar } = emitFallible(def.parser, ctx, pos);
|
|
2579
2716
|
stmts.push(...innerStmts);
|
|
2580
2717
|
stmts.push(`${i}_ctx._cstChildren = ${sc}; _ctx._cstLeaves = ${sl}; _ctx._cstRawChildren = ${sr}; _ctx.captureTrivia = ${st}; _ctx._cstTriviaLog = ${stl}`);
|
|
2581
2718
|
stmts.push(...emitIfFail(ctx, `!${okVar}`, failBody(ctx, '"node"', pos)));
|
|
2582
|
-
|
|
2583
|
-
|
|
2719
|
+
let stV = "undefined";
|
|
2720
|
+
if (clonesState) {
|
|
2721
|
+
stV = v(ctx, "_nst");
|
|
2722
|
+
stmts.push(`${i}const ${stV} = _ctx.state !== undefined ? Object.assign({}, _ctx.state) : undefined`);
|
|
2723
|
+
}
|
|
2584
2724
|
const ndV = v(ctx, "_nd");
|
|
2585
2725
|
const ndExpr = mkType ? emitInlineMkNodeExpr(mkType, chV, rawV, pos, endVar, tlV) : `_build[${buildIdx}](${chV}, ${rawV}, { start: ${pos}, end: ${endVar} }, ${tlV}, ${stV})`;
|
|
2726
|
+
const finalExpr = def.collapse ? `${chV}.length === 1 ? (${chV}[0] !== null && typeof ${chV}[0] === 'object' && ${chV}[0]._tag === 'leaf' ? ${chV}[0].value : ${chV}[0]) : (${ndExpr})` : ndExpr;
|
|
2586
2727
|
stmts.push(
|
|
2587
|
-
`${i}const ${ndV} = ${
|
|
2728
|
+
`${i}const ${ndV} = ${finalExpr}`,
|
|
2588
2729
|
`${i}if (${sc}) ${sc}.push(${ndV})`,
|
|
2589
2730
|
`${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} } })`
|
|
2590
2731
|
);
|
|
@@ -2605,6 +2746,16 @@ function emitRuntimeFallback(parser2, ctx, pos) {
|
|
|
2605
2746
|
return { stmts, valueVar: vv, endVar: ev };
|
|
2606
2747
|
}
|
|
2607
2748
|
function emitLazy(p, def, ctx, pos) {
|
|
2749
|
+
const usage = ctx.lazyUsage;
|
|
2750
|
+
if (usage && (usage.counts.get(p) ?? 0) <= 1 && !usage.recursive.has(p)) {
|
|
2751
|
+
let resolved;
|
|
2752
|
+
try {
|
|
2753
|
+
resolved = def.thunk();
|
|
2754
|
+
} catch {
|
|
2755
|
+
return emitRuntimeFallback(p, ctx, pos);
|
|
2756
|
+
}
|
|
2757
|
+
return emit(resolved, ctx, pos);
|
|
2758
|
+
}
|
|
2608
2759
|
if (!ctx.namedParsers.has(p)) {
|
|
2609
2760
|
const fnName2 = `_pf${ctx.namedParsers.size}`;
|
|
2610
2761
|
ctx.namedParsers.set(p, fnName2);
|
|
@@ -2869,6 +3020,80 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2869
3020
|
return false;
|
|
2870
3021
|
}
|
|
2871
3022
|
}
|
|
3023
|
+
function childrenOf(def) {
|
|
3024
|
+
switch (def.tag) {
|
|
3025
|
+
case "sequence":
|
|
3026
|
+
case "choice":
|
|
3027
|
+
return def.parsers;
|
|
3028
|
+
case "many":
|
|
3029
|
+
case "optional":
|
|
3030
|
+
case "transform":
|
|
3031
|
+
case "trivia":
|
|
3032
|
+
case "label":
|
|
3033
|
+
case "grammar":
|
|
3034
|
+
case "not":
|
|
3035
|
+
case "node":
|
|
3036
|
+
case "withCtx":
|
|
3037
|
+
case "expect":
|
|
3038
|
+
return [def.parser];
|
|
3039
|
+
// emitMany's oneOrMore branch and emitSepBy both codegen `def.parser` TWICE
|
|
3040
|
+
// (a mandatory first match, then again inside the repeat loop) — two real
|
|
3041
|
+
// emit() call sites, so the usage analysis must see two edges here or it
|
|
3042
|
+
// undercounts a single-use `parser` ref as inline-safe when it's actually
|
|
3043
|
+
// referenced from two positions within this one compiled function.
|
|
3044
|
+
case "oneOrMore":
|
|
3045
|
+
return [def.parser, def.parser];
|
|
3046
|
+
case "sepBy":
|
|
3047
|
+
return [def.parser, def.parser, def.separator];
|
|
3048
|
+
case "skip":
|
|
3049
|
+
return [def.main, def.skipped];
|
|
3050
|
+
case "recover":
|
|
3051
|
+
return [def.parser, def.sentinel];
|
|
3052
|
+
case "scanTo":
|
|
3053
|
+
return [def.sentinel, ...def.skip];
|
|
3054
|
+
case "lazy":
|
|
3055
|
+
case "literal":
|
|
3056
|
+
case "regex":
|
|
3057
|
+
case "keywords":
|
|
3058
|
+
case "guard":
|
|
3059
|
+
case "unknown":
|
|
3060
|
+
return [];
|
|
3061
|
+
}
|
|
3062
|
+
}
|
|
3063
|
+
function analyzeLazyUsage(root) {
|
|
3064
|
+
return analyzeLazyUsageMulti([root]);
|
|
3065
|
+
}
|
|
3066
|
+
function analyzeLazyUsageMulti(roots) {
|
|
3067
|
+
const counts = /* @__PURE__ */ new Map();
|
|
3068
|
+
const recursive = /* @__PURE__ */ new Set();
|
|
3069
|
+
const descended = /* @__PURE__ */ new Set();
|
|
3070
|
+
const active = /* @__PURE__ */ new Set();
|
|
3071
|
+
function walk(p) {
|
|
3072
|
+
const def = p._def;
|
|
3073
|
+
if (def.tag === "lazy") {
|
|
3074
|
+
counts.set(p, (counts.get(p) ?? 0) + 1);
|
|
3075
|
+
if (active.has(p)) {
|
|
3076
|
+
recursive.add(p);
|
|
3077
|
+
return;
|
|
3078
|
+
}
|
|
3079
|
+
if (descended.has(p)) return;
|
|
3080
|
+
descended.add(p);
|
|
3081
|
+
let resolved;
|
|
3082
|
+
try {
|
|
3083
|
+
resolved = def.thunk();
|
|
3084
|
+
} catch {
|
|
3085
|
+
return;
|
|
3086
|
+
}
|
|
3087
|
+
active.add(p);
|
|
3088
|
+
walk(resolved);
|
|
3089
|
+
active.delete(p);
|
|
3090
|
+
return;
|
|
3091
|
+
}
|
|
3092
|
+
for (const child of childrenOf(def)) walk(child);
|
|
3093
|
+
}
|
|
3094
|
+
for (const root of roots) walk(root);
|
|
3095
|
+
return { counts, recursive };
|
|
3096
|
+
}
|
|
2872
3097
|
function compile(combinator, mapFnSources) {
|
|
2873
3098
|
const ctx = {
|
|
2874
3099
|
vars: 0,
|
|
@@ -2885,13 +3110,16 @@ function compile(combinator, mapFnSources) {
|
|
|
2885
3110
|
triviaCaptureNames: /* @__PURE__ */ new Map(),
|
|
2886
3111
|
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
2887
3112
|
namedFnDecls: [],
|
|
2888
|
-
capturing: hasNodeDef(combinator)
|
|
3113
|
+
capturing: hasNodeDef(combinator),
|
|
3114
|
+
lazyUsage: analyzeLazyUsage(combinator)
|
|
2889
3115
|
};
|
|
2890
3116
|
const r = emit(combinator, ctx, "_pos");
|
|
2891
3117
|
const collatorDecl = ctx.needsCollator ? `const _collator = new Intl.Collator(undefined, { sensitivity: 'accent' })
|
|
2892
3118
|
` : "";
|
|
2893
3119
|
const namedPrelude = ctx.namedFnDecls.length > 0 ? [...namedFnPrelude(), ""] : [];
|
|
3120
|
+
const emptyTlDecls = ctx.needsEmptyTl ? ["const _EMPTY_TL = Object.freeze([])"] : [];
|
|
2894
3121
|
const source = [
|
|
3122
|
+
...emptyTlDecls,
|
|
2895
3123
|
...ctx.regexDecls,
|
|
2896
3124
|
"",
|
|
2897
3125
|
...namedPrelude,
|
|
@@ -2903,6 +3131,7 @@ function compile(combinator, mapFnSources) {
|
|
|
2903
3131
|
`}`
|
|
2904
3132
|
].join("\n");
|
|
2905
3133
|
const fn = new Function("input", "_pos", "_rp", "_mf", "_build", "_ctx", [
|
|
3134
|
+
...emptyTlDecls,
|
|
2906
3135
|
...ctx.regexDecls,
|
|
2907
3136
|
collatorDecl,
|
|
2908
3137
|
...namedPrelude,
|
|
@@ -2956,10 +3185,12 @@ function buildInlineExpression(ctx, r, collatorDecl, mapFnSources, buildSources)
|
|
|
2956
3185
|
].join("\n");
|
|
2957
3186
|
const mfDecl = mapFnSources?.length ? ` const _mf = [${mapFnSources.join(", ")}]` : "";
|
|
2958
3187
|
const buildDecl = buildSources?.length ? ` const _build = [${buildSources.join(", ")}]` : "";
|
|
2959
|
-
const
|
|
3188
|
+
const emptyTlDecl = ctx.needsEmptyTl ? ` const _EMPTY_TL = Object.freeze([])` : "";
|
|
3189
|
+
const needsWrapper = ctx.regexDecls.length > 0 || !!collatorDecl || ctx.namedFnDecls.length > 0 || !!mfDecl || !!buildDecl || !!emptyTlDecl;
|
|
2960
3190
|
if (!needsWrapper) return innerFn;
|
|
2961
3191
|
const namedPrelude = ctx.namedFnDecls.length > 0 ? namedFnPrelude() : [];
|
|
2962
3192
|
const hoistedDecls = [
|
|
3193
|
+
emptyTlDecl,
|
|
2963
3194
|
...ctx.regexDecls.map((d) => ` ${d}`),
|
|
2964
3195
|
collatorDecl ? ` ${collatorDecl.trim()}` : "",
|
|
2965
3196
|
mfDecl,
|
|
@@ -3244,6 +3475,31 @@ function replaceAtPath(rebuild, root, path, newNode) {
|
|
|
3244
3475
|
function defaultRebuild(node2, children) {
|
|
3245
3476
|
return { ...node2, children };
|
|
3246
3477
|
}
|
|
3478
|
+
function shiftSpans(child, delta) {
|
|
3479
|
+
const c = child;
|
|
3480
|
+
const span = { start: c.span.start + delta, end: c.span.end + delta };
|
|
3481
|
+
if (Array.isArray(c.children)) {
|
|
3482
|
+
return { ...c, span, children: c.children.map((g) => shiftSpans(g, delta)) };
|
|
3483
|
+
}
|
|
3484
|
+
return { ...c, span };
|
|
3485
|
+
}
|
|
3486
|
+
function graftAndShift(root, path, newNode, delta) {
|
|
3487
|
+
if (path.length === 0) return newNode;
|
|
3488
|
+
const [idx, ...rest] = path;
|
|
3489
|
+
const oldChildren = root.children;
|
|
3490
|
+
const newChildren = oldChildren.map((child, i) => {
|
|
3491
|
+
if (i < idx) return child;
|
|
3492
|
+
if (i === idx) {
|
|
3493
|
+
return rest.length === 0 ? newNode : graftAndShift(child, rest, newNode, delta);
|
|
3494
|
+
}
|
|
3495
|
+
return shiftSpans(child, delta);
|
|
3496
|
+
});
|
|
3497
|
+
return {
|
|
3498
|
+
...root,
|
|
3499
|
+
span: { start: root.span.start, end: root.span.end + delta },
|
|
3500
|
+
children: newChildren
|
|
3501
|
+
};
|
|
3502
|
+
}
|
|
3247
3503
|
var FunctionalDocImpl = class _FunctionalDocImpl {
|
|
3248
3504
|
_registry;
|
|
3249
3505
|
_rootRule;
|
|
@@ -3281,7 +3537,12 @@ var FunctionalDocImpl = class _FunctionalDocImpl {
|
|
|
3281
3537
|
const r = ruleFn(newInput, node2.span.start, ctx);
|
|
3282
3538
|
if (!r.ok) continue;
|
|
3283
3539
|
if (r.span.end === node2.span.end + delta) {
|
|
3284
|
-
|
|
3540
|
+
if (delta === 0) {
|
|
3541
|
+
const newTree2 = replaceAtPath(rebuild, this.tree, path, r.value);
|
|
3542
|
+
return new _FunctionalDocImpl(this._registry, this._rootRule, this._opts, newTree2, [], newInput);
|
|
3543
|
+
}
|
|
3544
|
+
if (this._opts.rebuild) return reparse();
|
|
3545
|
+
const newTree = graftAndShift(this.tree, path, r.value, delta);
|
|
3285
3546
|
return new _FunctionalDocImpl(this._registry, this._rootRule, this._opts, newTree, [], newInput);
|
|
3286
3547
|
}
|
|
3287
3548
|
}
|