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.js
CHANGED
|
@@ -1127,24 +1127,70 @@ function not(combinator) {
|
|
|
1127
1127
|
};
|
|
1128
1128
|
}
|
|
1129
1129
|
|
|
1130
|
+
// src/compiler/build-arity.ts
|
|
1131
|
+
var PARAM_LIST_RE = (
|
|
1132
|
+
// (params) => ... | function name?(params) ... | single-ident arrow `x => ...`
|
|
1133
|
+
/^(?:function\b[^(]*\(([^)]*)\)|\(([^)]*)\)\s*=>|([A-Za-z_$][\w$]*)\s*=>)/
|
|
1134
|
+
);
|
|
1135
|
+
var CONFIRMABLE_PARAM_RE = /^[A-Za-z_$][\w$]*\s*\??\s*(?::[^,=]+)?$/;
|
|
1136
|
+
function confirmedBuildArity(src) {
|
|
1137
|
+
const s = src.trim();
|
|
1138
|
+
const m = PARAM_LIST_RE.exec(s);
|
|
1139
|
+
if (!m) return null;
|
|
1140
|
+
if (m[3] !== void 0) return 1;
|
|
1141
|
+
const inner = (m[1] ?? m[2] ?? "").trim();
|
|
1142
|
+
if (inner === "") return 0;
|
|
1143
|
+
const parts = inner.split(",");
|
|
1144
|
+
for (const part of parts) {
|
|
1145
|
+
if (!CONFIRMABLE_PARAM_RE.test(part.trim())) return null;
|
|
1146
|
+
}
|
|
1147
|
+
if (/\barguments\b/.test(s)) return null;
|
|
1148
|
+
return parts.length;
|
|
1149
|
+
}
|
|
1150
|
+
function buildReadsTrivia(def) {
|
|
1151
|
+
const src = def.buildSrc ?? def.build.toString();
|
|
1152
|
+
const arity = confirmedBuildArity(src);
|
|
1153
|
+
if (arity === null) return true;
|
|
1154
|
+
return arity >= 4;
|
|
1155
|
+
}
|
|
1156
|
+
function buildReadsState(def) {
|
|
1157
|
+
const src = def.buildSrc ?? def.build.toString();
|
|
1158
|
+
const arity = confirmedBuildArity(src);
|
|
1159
|
+
if (arity === null) return true;
|
|
1160
|
+
return arity >= 5;
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1130
1163
|
// src/combinators/node.ts
|
|
1131
|
-
function
|
|
1164
|
+
function collapseChild(child) {
|
|
1165
|
+
return child !== null && typeof child === "object" && child._tag === "leaf" ? child.value : child;
|
|
1166
|
+
}
|
|
1167
|
+
function node(type, combinator, build, opts) {
|
|
1132
1168
|
const meta = {
|
|
1133
1169
|
firstSet: combinator._meta.firstSet,
|
|
1134
1170
|
canMatchNewline: combinator._meta.canMatchNewline,
|
|
1135
1171
|
isTrivia: false
|
|
1136
1172
|
};
|
|
1173
|
+
const collapse = opts?.collapse === true;
|
|
1174
|
+
const def = collapse ? { tag: "node", type, parser: combinator, build, collapse: true } : { tag: "node", type, parser: combinator, build };
|
|
1175
|
+
const capturesTrivia = buildReadsTrivia(def);
|
|
1176
|
+
const clonesState = buildReadsState(def);
|
|
1137
1177
|
return {
|
|
1138
1178
|
_tag: "node",
|
|
1139
1179
|
_meta: meta,
|
|
1140
|
-
_def:
|
|
1180
|
+
_def: def,
|
|
1141
1181
|
parse(input, pos, ctx) {
|
|
1142
1182
|
const saved = beginCstNodeCapture(ctx);
|
|
1183
|
+
if (!capturesTrivia) ctx.captureTrivia = false;
|
|
1143
1184
|
const r = combinator.parse(input, pos, ctx);
|
|
1144
1185
|
const { children, rawChildren, triviaLog } = endCstNodeCapture(ctx, saved);
|
|
1145
1186
|
if (!r.ok) return r;
|
|
1146
|
-
const
|
|
1147
|
-
|
|
1187
|
+
const built = collapse && children.length === 1 ? collapseChild(children[0]) : build(
|
|
1188
|
+
children,
|
|
1189
|
+
rawChildren,
|
|
1190
|
+
r.span,
|
|
1191
|
+
triviaLog,
|
|
1192
|
+
clonesState && ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0
|
|
1193
|
+
);
|
|
1148
1194
|
const isNodeLike = typeof built === "object" && built !== null && built._tag === "node";
|
|
1149
1195
|
const rawEntry = isNodeLike ? built : { _tag: "leaf", value: typeof built === "string" ? built : "", span: r.span };
|
|
1150
1196
|
if (saved.buf !== void 0 || saved.ch !== void 0) {
|
|
@@ -1294,14 +1340,140 @@ function parse(combinator, input, opts = {}) {
|
|
|
1294
1340
|
return withErrors;
|
|
1295
1341
|
}
|
|
1296
1342
|
|
|
1343
|
+
// src/compiler/scannable-run.ts
|
|
1344
|
+
var CLASS_ESCAPES = { t: 9, n: 10, r: 13, f: 12, v: 11, "0": 0 };
|
|
1345
|
+
var META = new Set("()[]{}*+?|^$.".split(""));
|
|
1346
|
+
function parseClassRanges(body) {
|
|
1347
|
+
const ranges = [];
|
|
1348
|
+
let i = 0;
|
|
1349
|
+
const readCp = () => {
|
|
1350
|
+
const ch = body[i];
|
|
1351
|
+
if (ch === void 0) return null;
|
|
1352
|
+
if (ch === "\\") {
|
|
1353
|
+
const e = body[i + 1];
|
|
1354
|
+
if (e === void 0) return null;
|
|
1355
|
+
i += 2;
|
|
1356
|
+
return e in CLASS_ESCAPES ? CLASS_ESCAPES[e] : e.codePointAt(0);
|
|
1357
|
+
}
|
|
1358
|
+
i += ch.length;
|
|
1359
|
+
return ch.codePointAt(0);
|
|
1360
|
+
};
|
|
1361
|
+
while (i < body.length) {
|
|
1362
|
+
const lo = readCp();
|
|
1363
|
+
if (lo === null) return null;
|
|
1364
|
+
if (body[i] === "-" && body[i + 1] !== void 0 && body[i + 1] !== "]") {
|
|
1365
|
+
i += 1;
|
|
1366
|
+
const hi = readCp();
|
|
1367
|
+
if (hi === null) return null;
|
|
1368
|
+
ranges.push([lo, hi]);
|
|
1369
|
+
} else {
|
|
1370
|
+
ranges.push([lo, lo]);
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
return ranges.length ? ranges : null;
|
|
1374
|
+
}
|
|
1375
|
+
function literalCodePoints(frag) {
|
|
1376
|
+
const out = [];
|
|
1377
|
+
let i = 0;
|
|
1378
|
+
while (i < frag.length) {
|
|
1379
|
+
const ch = frag[i];
|
|
1380
|
+
if (ch === "\\") {
|
|
1381
|
+
const e = frag[i + 1];
|
|
1382
|
+
if (e === void 0) return null;
|
|
1383
|
+
out.push(e in CLASS_ESCAPES ? CLASS_ESCAPES[e] : e.codePointAt(0));
|
|
1384
|
+
i += 2;
|
|
1385
|
+
continue;
|
|
1386
|
+
}
|
|
1387
|
+
if (META.has(ch)) return null;
|
|
1388
|
+
out.push(ch.codePointAt(0));
|
|
1389
|
+
i += 1;
|
|
1390
|
+
}
|
|
1391
|
+
return out.length ? out : null;
|
|
1392
|
+
}
|
|
1393
|
+
function parseScanShape(source) {
|
|
1394
|
+
let m = /^\[((?:\\.|[^\]])+)\]([+*])$/.exec(source);
|
|
1395
|
+
if (m) {
|
|
1396
|
+
if (m[1].startsWith("^")) return null;
|
|
1397
|
+
const ranges = parseClassRanges(m[1]);
|
|
1398
|
+
return ranges ? { kind: "chars", ranges } : null;
|
|
1399
|
+
}
|
|
1400
|
+
m = /^(.*?)\[\^((?:\\.|[^\]])+)\]\*$/.exec(source);
|
|
1401
|
+
if (m) {
|
|
1402
|
+
const open = literalCodePoints(m[1]);
|
|
1403
|
+
const stop = parseClassRanges(m[2]);
|
|
1404
|
+
if (open && stop) return { kind: "until", open, stop };
|
|
1405
|
+
return null;
|
|
1406
|
+
}
|
|
1407
|
+
if (!source.includes("\\\\")) {
|
|
1408
|
+
m = /^(.*?)\((?:\?:)?[\s\S]*\)\*(.*?)$/.exec(source);
|
|
1409
|
+
if (m && m[1] && m[2]) {
|
|
1410
|
+
const open = literalCodePoints(m[1]);
|
|
1411
|
+
const close = literalCodePoints(m[2]);
|
|
1412
|
+
if (open && close) return { kind: "delimited", open, close };
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
return null;
|
|
1416
|
+
}
|
|
1417
|
+
var classCond = (cVar, ranges) => ranges.map(([lo, hi]) => lo === hi ? `${cVar} === ${lo}` : `(${cVar} >= ${lo} && ${cVar} <= ${hi})`).join(" || ");
|
|
1418
|
+
var litCond = (base, cps, firstVar) => cps.map(
|
|
1419
|
+
(cp, k) => k === 0 && firstVar ? `${firstVar} === ${cp}` : `input.charCodeAt(${base}${k ? ` + ${k}` : ""}) === ${cp}`
|
|
1420
|
+
).join(" && ");
|
|
1421
|
+
function advanceExpr(shape) {
|
|
1422
|
+
if (shape.kind === "chars") {
|
|
1423
|
+
return {
|
|
1424
|
+
setup: [
|
|
1425
|
+
` _e++`,
|
|
1426
|
+
` while (_e < input.length) { const c2 = input.charCodeAt(_e); if (${classCond("c2", shape.ranges)}) _e++; else break }`
|
|
1427
|
+
],
|
|
1428
|
+
endVar: "_e"
|
|
1429
|
+
};
|
|
1430
|
+
}
|
|
1431
|
+
if (shape.kind === "until") {
|
|
1432
|
+
return {
|
|
1433
|
+
setup: [
|
|
1434
|
+
` let j = _e + ${shape.open.length}`,
|
|
1435
|
+
` while (j < input.length && !(${classCond("input.charCodeAt(j)", shape.stop)})) j++`
|
|
1436
|
+
],
|
|
1437
|
+
endVar: "j"
|
|
1438
|
+
};
|
|
1439
|
+
}
|
|
1440
|
+
const n = shape.close.length;
|
|
1441
|
+
return {
|
|
1442
|
+
setup: [
|
|
1443
|
+
` let j = _e + ${shape.open.length}`,
|
|
1444
|
+
` while (j + ${n - 1} < input.length && !(${litCond("j", shape.close)})) j++`
|
|
1445
|
+
],
|
|
1446
|
+
endVar: n === 1 ? "(j + 1 <= input.length ? j + 1 : input.length)" : `(j + ${n} <= input.length ? j + ${n} : input.length)`
|
|
1447
|
+
};
|
|
1448
|
+
}
|
|
1449
|
+
function guardLine(shape) {
|
|
1450
|
+
const cond = shape.kind === "chars" ? classCond("c", shape.ranges) : litCond("_e", shape.open, "c");
|
|
1451
|
+
return ` if (${cond}) {`;
|
|
1452
|
+
}
|
|
1453
|
+
function scanBranch(shape) {
|
|
1454
|
+
if (shape.kind === "chars") {
|
|
1455
|
+
return ` if (${classCond("c", shape.ranges)}) { _e++; continue }`;
|
|
1456
|
+
}
|
|
1457
|
+
const { setup, endVar } = advanceExpr(shape);
|
|
1458
|
+
return [guardLine(shape), ...setup, ` _e = ${endVar}`, ` continue`, ` }`].join("\n");
|
|
1459
|
+
}
|
|
1460
|
+
function captureChunk(startVar, kindIndex) {
|
|
1461
|
+
return [
|
|
1462
|
+
` if (_cap) {`,
|
|
1463
|
+
` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(${startVar}, _e, ${kindIndex})`,
|
|
1464
|
+
` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(${startVar}, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${kindIndex})`,
|
|
1465
|
+
` }`
|
|
1466
|
+
];
|
|
1467
|
+
}
|
|
1468
|
+
function scanBranchLabeled(shape, kindIndex) {
|
|
1469
|
+
const { setup, endVar } = advanceExpr(shape);
|
|
1470
|
+
const lines = [guardLine(shape), ` const _cs = _e`, ...setup];
|
|
1471
|
+
if (endVar !== "_e") lines.push(` _e = ${endVar}`);
|
|
1472
|
+
lines.push(...captureChunk("_cs", kindIndex), ` continue`, ` }`);
|
|
1473
|
+
return lines.join("\n");
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1297
1476
|
// src/compiler/trivia-fast-path.ts
|
|
1298
|
-
var BLOCK_COMMENT = String.raw`\/\*(?:[^*]|\*(?!\/))*\*\/`;
|
|
1299
|
-
var WS_CLASS_SOURCES = /* @__PURE__ */ new Set([
|
|
1300
|
-
String.raw`[ \t\n\r\f]+`,
|
|
1301
|
-
String.raw`[ \t\n]+`,
|
|
1302
|
-
String.raw`[ \t]+`,
|
|
1303
|
-
String.raw`[\t\n\f\r ]+`
|
|
1304
|
-
]);
|
|
1305
1477
|
function unwrapTrivia2(p) {
|
|
1306
1478
|
let cur = p;
|
|
1307
1479
|
while (cur._def.tag === "trivia") cur = cur._def.parser;
|
|
@@ -1317,36 +1489,30 @@ function choiceArms(p) {
|
|
|
1317
1489
|
if (p._def.tag === "choice") return p._def.parsers;
|
|
1318
1490
|
return null;
|
|
1319
1491
|
}
|
|
1320
|
-
function
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
function isBlockCommentSource(source) {
|
|
1324
|
-
return source === BLOCK_COMMENT;
|
|
1492
|
+
function armShape(arm) {
|
|
1493
|
+
const src = getCoreRegexDef(arm)?.source;
|
|
1494
|
+
return src ? parseScanShape(src) : null;
|
|
1325
1495
|
}
|
|
1326
1496
|
function analyzeTriviaFastPath(trivia2) {
|
|
1327
1497
|
const core = unwrapTrivia2(trivia2);
|
|
1328
|
-
const
|
|
1329
|
-
if (
|
|
1330
|
-
|
|
1331
|
-
return null;
|
|
1498
|
+
const directSrc = getCoreRegexDef(core)?.source;
|
|
1499
|
+
if (directSrc) {
|
|
1500
|
+
const shape = parseScanShape(directSrc);
|
|
1501
|
+
return shape && shape.kind === "chars" ? [shape] : null;
|
|
1332
1502
|
}
|
|
1333
1503
|
const inner = oneOrMoreInner(core);
|
|
1334
1504
|
if (!inner) return null;
|
|
1335
|
-
const
|
|
1336
|
-
if (
|
|
1505
|
+
const innerShape = armShape(inner);
|
|
1506
|
+
if (innerShape) return innerShape.kind === "chars" ? [innerShape] : null;
|
|
1337
1507
|
const arms = choiceArms(inner);
|
|
1338
|
-
if (!arms || arms.length
|
|
1339
|
-
|
|
1340
|
-
let hasComment = false;
|
|
1508
|
+
if (!arms || arms.length < 2) return null;
|
|
1509
|
+
const shapes = [];
|
|
1341
1510
|
for (const arm of arms) {
|
|
1342
|
-
const
|
|
1343
|
-
if (!
|
|
1344
|
-
|
|
1345
|
-
else if (isBlockCommentSource(src)) hasComment = true;
|
|
1346
|
-
else return null;
|
|
1511
|
+
const shape = armShape(arm);
|
|
1512
|
+
if (!shape) return null;
|
|
1513
|
+
shapes.push(shape);
|
|
1347
1514
|
}
|
|
1348
|
-
|
|
1349
|
-
return null;
|
|
1515
|
+
return shapes;
|
|
1350
1516
|
}
|
|
1351
1517
|
var CAP_RECORD = [
|
|
1352
1518
|
` if (_cap && _e > _pos) {`,
|
|
@@ -1354,80 +1520,49 @@ var CAP_RECORD = [
|
|
|
1354
1520
|
` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
|
|
1355
1521
|
` }`
|
|
1356
1522
|
].join("\n");
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
` if (c === 47 && input.charCodeAt(_e + 1) === 42) {`,
|
|
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
|
-
` continue`,
|
|
1373
|
-
` }`,
|
|
1374
|
-
` break`,
|
|
1375
|
-
` }`
|
|
1376
|
-
].join("\n");
|
|
1377
|
-
var CAP_CHUNK = (wsKind, commentKind) => [
|
|
1378
|
-
` if (c === 32 || c === 9 || c === 10 || c === 13 || c === 12) {`,
|
|
1379
|
-
` const _cs = _e`,
|
|
1380
|
-
` _e++`,
|
|
1381
|
-
` while (_e < input.length) {`,
|
|
1382
|
-
` const c2 = input.charCodeAt(_e)`,
|
|
1383
|
-
` if (c2 === 32 || c2 === 9 || c2 === 10 || c2 === 13 || c2 === 12) _e++`,
|
|
1384
|
-
` else break`,
|
|
1385
|
-
` }`,
|
|
1386
|
-
` if (_cap) {`,
|
|
1387
|
-
` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_cs, _e, ${wsKind})`,
|
|
1388
|
-
` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(_cs, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${wsKind})`,
|
|
1389
|
-
` }`,
|
|
1390
|
-
` continue`,
|
|
1391
|
-
` }`,
|
|
1392
|
-
` if (c === 47 && input.charCodeAt(_e + 1) === 42) {`,
|
|
1393
|
-
` const _cs = _e`,
|
|
1394
|
-
` let j = _e + 2`,
|
|
1395
|
-
` while (j + 1 < input.length && !(input.charCodeAt(j) === 42 && input.charCodeAt(j + 1) === 47)) j++`,
|
|
1396
|
-
` _e = j + 2 <= input.length ? j + 2 : input.length`,
|
|
1397
|
-
` if (_cap) {`,
|
|
1398
|
-
` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_cs, _e, ${commentKind})`,
|
|
1399
|
-
` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(_cs, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${commentKind})`,
|
|
1400
|
-
` }`,
|
|
1401
|
-
` continue`,
|
|
1402
|
-
` }`
|
|
1403
|
-
].join("\n");
|
|
1404
|
-
var WS_COMMENTS_LOOP_LABELED = (wsKind, commentKind) => [
|
|
1405
|
-
` while (_e < input.length) {`,
|
|
1406
|
-
` const c = input.charCodeAt(_e)`,
|
|
1407
|
-
CAP_CHUNK(wsKind, commentKind),
|
|
1408
|
-
` break`,
|
|
1409
|
-
` }`
|
|
1410
|
-
].join("\n");
|
|
1411
|
-
function buildFastTriviaFnDecl(fnName, kind, kindIndices) {
|
|
1412
|
-
const loop = kind === "wsComments" && kindIndices ? WS_COMMENTS_LOOP_LABELED(kindIndices.ws, kindIndices.comment) : kind === "wsComments" ? WS_COMMENTS_LOOP : WS_ONLY_LOOP;
|
|
1413
|
-
const cap = kindIndices ? "" : CAP_RECORD;
|
|
1414
|
-
const lines = [
|
|
1523
|
+
function composeFastLoop(shapes) {
|
|
1524
|
+
return [
|
|
1525
|
+
` while (_e < input.length) {`,
|
|
1526
|
+
` const c = input.charCodeAt(_e)`,
|
|
1527
|
+
...shapes.map(scanBranch),
|
|
1528
|
+
` break`,
|
|
1529
|
+
` }`
|
|
1530
|
+
].join("\n");
|
|
1531
|
+
}
|
|
1532
|
+
function buildFastTriviaFnDecl(fnName, shapes) {
|
|
1533
|
+
return [
|
|
1415
1534
|
`function ${fnName}(input, _pos, _ctx, _cap) {`,
|
|
1416
1535
|
` let _e = _pos`,
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1536
|
+
composeFastLoop(shapes),
|
|
1537
|
+
CAP_RECORD,
|
|
1538
|
+
` return _e`,
|
|
1539
|
+
`}`
|
|
1540
|
+
].join("\n");
|
|
1422
1541
|
}
|
|
1423
|
-
function
|
|
1542
|
+
function analyzeLabeledScannableRun(trivia2) {
|
|
1543
|
+
const spec = analyzeLabeledTrivia(trivia2);
|
|
1544
|
+
if (!spec) return null;
|
|
1545
|
+
const out = [];
|
|
1424
1546
|
for (const arm of spec.arms) {
|
|
1425
1547
|
const src = getCoreRegexDef(arm.parser)?.source;
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1548
|
+
const shape = src ? parseScanShape(src) : null;
|
|
1549
|
+
if (!shape) return null;
|
|
1550
|
+
out.push({ shape, kindIndex: arm.kindIndex });
|
|
1429
1551
|
}
|
|
1430
|
-
return
|
|
1552
|
+
return out;
|
|
1553
|
+
}
|
|
1554
|
+
function buildLabeledScannableTriviaFnDecl(fnName, arms) {
|
|
1555
|
+
return [
|
|
1556
|
+
`function ${fnName}(input, _pos, _ctx, _cap) {`,
|
|
1557
|
+
` let _e = _pos`,
|
|
1558
|
+
` while (_e < input.length) {`,
|
|
1559
|
+
` const c = input.charCodeAt(_e)`,
|
|
1560
|
+
...arms.map((a) => scanBranchLabeled(a.shape, a.kindIndex)),
|
|
1561
|
+
` break`,
|
|
1562
|
+
` }`,
|
|
1563
|
+
` return _e`,
|
|
1564
|
+
`}`
|
|
1565
|
+
].join("\n");
|
|
1431
1566
|
}
|
|
1432
1567
|
function buildLabeledRegexTriviaFnDecl(fnName, spec, reNames) {
|
|
1433
1568
|
const tryArms = spec.arms.map((arm, i) => {
|
|
@@ -1460,14 +1595,6 @@ function buildLabeledRegexTriviaFnDecl(fnName, spec, reNames) {
|
|
|
1460
1595
|
`}`
|
|
1461
1596
|
].join("\n");
|
|
1462
1597
|
}
|
|
1463
|
-
function labeledTriviaKindIndices(trivia2) {
|
|
1464
|
-
const spec = analyzeLabeledTrivia(trivia2);
|
|
1465
|
-
if (!spec || spec.arms.length !== 2) return null;
|
|
1466
|
-
const ws = regexArmIndex(spec, false);
|
|
1467
|
-
const comment = regexArmIndex(spec, true);
|
|
1468
|
-
if (ws === null || comment === null) return null;
|
|
1469
|
-
return { ws, comment };
|
|
1470
|
-
}
|
|
1471
1598
|
function labeledTriviaRegexArms(trivia2) {
|
|
1472
1599
|
const spec = analyzeLabeledTrivia(trivia2);
|
|
1473
1600
|
if (!spec) return null;
|
|
@@ -1715,14 +1842,19 @@ function ensureTriviaFn(ctx) {
|
|
|
1715
1842
|
const fnName = `_tf${ctx.triviaFnNames.size}`;
|
|
1716
1843
|
ctx.triviaFnNames.set(trivia2, fnName);
|
|
1717
1844
|
ctx.triviaCaptureNames.set(trivia2, fnName);
|
|
1718
|
-
const fastKind = analyzeTriviaFastPath(trivia2);
|
|
1719
|
-
const kindIndices = labeledTriviaKindIndices(trivia2);
|
|
1720
|
-
if (fastKind) {
|
|
1721
|
-
ctx.namedFnDecls.push(buildFastTriviaFnDecl(fnName, fastKind, kindIndices ?? void 0));
|
|
1722
|
-
return fnName;
|
|
1723
|
-
}
|
|
1724
1845
|
const labeledSpec = analyzeLabeledTrivia(trivia2);
|
|
1725
|
-
if (labeledSpec) {
|
|
1846
|
+
if (!labeledSpec) {
|
|
1847
|
+
const fastShapes = analyzeTriviaFastPath(trivia2);
|
|
1848
|
+
if (fastShapes) {
|
|
1849
|
+
ctx.namedFnDecls.push(buildFastTriviaFnDecl(fnName, fastShapes));
|
|
1850
|
+
return fnName;
|
|
1851
|
+
}
|
|
1852
|
+
} else {
|
|
1853
|
+
const labeledShapes = analyzeLabeledScannableRun(trivia2);
|
|
1854
|
+
if (labeledShapes) {
|
|
1855
|
+
ctx.namedFnDecls.push(buildLabeledScannableTriviaFnDecl(fnName, labeledShapes));
|
|
1856
|
+
return fnName;
|
|
1857
|
+
}
|
|
1726
1858
|
const regexSpec = labeledTriviaRegexArms(trivia2);
|
|
1727
1859
|
if (regexSpec) {
|
|
1728
1860
|
const reNames = [];
|
|
@@ -2160,11 +2292,11 @@ function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos) {
|
|
|
2160
2292
|
const p = def.parsers[idx];
|
|
2161
2293
|
const litVal = getCoreLiteralValue(p);
|
|
2162
2294
|
const litLen = litVal.length;
|
|
2163
|
-
const
|
|
2295
|
+
const litCond2 = emitLiteralCondition(litVal, pos);
|
|
2164
2296
|
const kw = first ? "if" : "else if";
|
|
2165
2297
|
first = false;
|
|
2166
2298
|
const litEnd = `${pos} + ${litLen}`;
|
|
2167
|
-
stmts.push(`${ind(ctx)}${kw} (${
|
|
2299
|
+
stmts.push(`${ind(ctx)}${kw} (${litCond2}) {`);
|
|
2168
2300
|
ctx.indent++;
|
|
2169
2301
|
const tR = emitTransformChain(p, JSON.stringify(litVal), litEnd, pos, ctx);
|
|
2170
2302
|
stmts.push(
|
|
@@ -2493,25 +2625,34 @@ function emitNode(def, ctx, pos) {
|
|
|
2493
2625
|
ctx.buildSrcs.push(def.buildSrc ?? null);
|
|
2494
2626
|
}
|
|
2495
2627
|
const i = ind(ctx);
|
|
2628
|
+
const capturesTrivia = mkType !== null || buildReadsTrivia(def);
|
|
2629
|
+
const clonesState = buildReadsState(def);
|
|
2496
2630
|
const chV = v(ctx, "_ch");
|
|
2497
2631
|
const rawV = v(ctx, "_raw");
|
|
2498
|
-
const tlV = v(ctx, "_tl");
|
|
2632
|
+
const tlV = capturesTrivia ? v(ctx, "_tl") : "_EMPTY_TL";
|
|
2633
|
+
if (!capturesTrivia) ctx.needsEmptyTl = true;
|
|
2499
2634
|
const sc = v(ctx, "_sc"), sl = v(ctx, "_sl"), sr = v(ctx, "_sr"), st = v(ctx, "_st"), stl = v(ctx, "_stl");
|
|
2635
|
+
const allocStmt = capturesTrivia ? `${i}const ${chV} = [], ${rawV} = [], ${tlV} = []` : `${i}const ${chV} = [], ${rawV} = []`;
|
|
2636
|
+
const innerTl = capturesTrivia ? tlV : "undefined";
|
|
2500
2637
|
const stmts = [
|
|
2501
|
-
|
|
2638
|
+
allocStmt,
|
|
2502
2639
|
`${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren, ${st} = _ctx.captureTrivia, ${stl} = _ctx._cstTriviaLog`,
|
|
2503
|
-
`${i}_ctx._cstChildren = ${chV}; _ctx._cstLeaves = ${chV}; _ctx._cstRawChildren = ${rawV}; _ctx.captureTrivia = true; _ctx._cstTriviaLog = ${
|
|
2640
|
+
`${i}_ctx._cstChildren = ${chV}; _ctx._cstLeaves = ${chV}; _ctx._cstRawChildren = ${rawV}; _ctx.captureTrivia = true; _ctx._cstTriviaLog = ${innerTl}`
|
|
2504
2641
|
];
|
|
2505
2642
|
const { stmts: innerStmts, okVar, endVar } = emitFallible(def.parser, ctx, pos);
|
|
2506
2643
|
stmts.push(...innerStmts);
|
|
2507
2644
|
stmts.push(`${i}_ctx._cstChildren = ${sc}; _ctx._cstLeaves = ${sl}; _ctx._cstRawChildren = ${sr}; _ctx.captureTrivia = ${st}; _ctx._cstTriviaLog = ${stl}`);
|
|
2508
2645
|
stmts.push(...emitIfFail(ctx, `!${okVar}`, failBody(ctx, '"node"', pos)));
|
|
2509
|
-
|
|
2510
|
-
|
|
2646
|
+
let stV = "undefined";
|
|
2647
|
+
if (clonesState) {
|
|
2648
|
+
stV = v(ctx, "_nst");
|
|
2649
|
+
stmts.push(`${i}const ${stV} = _ctx.state !== undefined ? Object.assign({}, _ctx.state) : undefined`);
|
|
2650
|
+
}
|
|
2511
2651
|
const ndV = v(ctx, "_nd");
|
|
2512
2652
|
const ndExpr = mkType ? emitInlineMkNodeExpr(mkType, chV, rawV, pos, endVar, tlV) : `_build[${buildIdx}](${chV}, ${rawV}, { start: ${pos}, end: ${endVar} }, ${tlV}, ${stV})`;
|
|
2653
|
+
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;
|
|
2513
2654
|
stmts.push(
|
|
2514
|
-
`${i}const ${ndV} = ${
|
|
2655
|
+
`${i}const ${ndV} = ${finalExpr}`,
|
|
2515
2656
|
`${i}if (${sc}) ${sc}.push(${ndV})`,
|
|
2516
2657
|
`${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} } })`
|
|
2517
2658
|
);
|
|
@@ -2532,6 +2673,16 @@ function emitRuntimeFallback(parser2, ctx, pos) {
|
|
|
2532
2673
|
return { stmts, valueVar: vv, endVar: ev };
|
|
2533
2674
|
}
|
|
2534
2675
|
function emitLazy(p, def, ctx, pos) {
|
|
2676
|
+
const usage = ctx.lazyUsage;
|
|
2677
|
+
if (usage && (usage.counts.get(p) ?? 0) <= 1 && !usage.recursive.has(p)) {
|
|
2678
|
+
let resolved;
|
|
2679
|
+
try {
|
|
2680
|
+
resolved = def.thunk();
|
|
2681
|
+
} catch {
|
|
2682
|
+
return emitRuntimeFallback(p, ctx, pos);
|
|
2683
|
+
}
|
|
2684
|
+
return emit(resolved, ctx, pos);
|
|
2685
|
+
}
|
|
2535
2686
|
if (!ctx.namedParsers.has(p)) {
|
|
2536
2687
|
const fnName2 = `_pf${ctx.namedParsers.size}`;
|
|
2537
2688
|
ctx.namedParsers.set(p, fnName2);
|
|
@@ -2796,6 +2947,80 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2796
2947
|
return false;
|
|
2797
2948
|
}
|
|
2798
2949
|
}
|
|
2950
|
+
function childrenOf(def) {
|
|
2951
|
+
switch (def.tag) {
|
|
2952
|
+
case "sequence":
|
|
2953
|
+
case "choice":
|
|
2954
|
+
return def.parsers;
|
|
2955
|
+
case "many":
|
|
2956
|
+
case "optional":
|
|
2957
|
+
case "transform":
|
|
2958
|
+
case "trivia":
|
|
2959
|
+
case "label":
|
|
2960
|
+
case "grammar":
|
|
2961
|
+
case "not":
|
|
2962
|
+
case "node":
|
|
2963
|
+
case "withCtx":
|
|
2964
|
+
case "expect":
|
|
2965
|
+
return [def.parser];
|
|
2966
|
+
// emitMany's oneOrMore branch and emitSepBy both codegen `def.parser` TWICE
|
|
2967
|
+
// (a mandatory first match, then again inside the repeat loop) — two real
|
|
2968
|
+
// emit() call sites, so the usage analysis must see two edges here or it
|
|
2969
|
+
// undercounts a single-use `parser` ref as inline-safe when it's actually
|
|
2970
|
+
// referenced from two positions within this one compiled function.
|
|
2971
|
+
case "oneOrMore":
|
|
2972
|
+
return [def.parser, def.parser];
|
|
2973
|
+
case "sepBy":
|
|
2974
|
+
return [def.parser, def.parser, def.separator];
|
|
2975
|
+
case "skip":
|
|
2976
|
+
return [def.main, def.skipped];
|
|
2977
|
+
case "recover":
|
|
2978
|
+
return [def.parser, def.sentinel];
|
|
2979
|
+
case "scanTo":
|
|
2980
|
+
return [def.sentinel, ...def.skip];
|
|
2981
|
+
case "lazy":
|
|
2982
|
+
case "literal":
|
|
2983
|
+
case "regex":
|
|
2984
|
+
case "keywords":
|
|
2985
|
+
case "guard":
|
|
2986
|
+
case "unknown":
|
|
2987
|
+
return [];
|
|
2988
|
+
}
|
|
2989
|
+
}
|
|
2990
|
+
function analyzeLazyUsage(root) {
|
|
2991
|
+
return analyzeLazyUsageMulti([root]);
|
|
2992
|
+
}
|
|
2993
|
+
function analyzeLazyUsageMulti(roots) {
|
|
2994
|
+
const counts = /* @__PURE__ */ new Map();
|
|
2995
|
+
const recursive = /* @__PURE__ */ new Set();
|
|
2996
|
+
const descended = /* @__PURE__ */ new Set();
|
|
2997
|
+
const active = /* @__PURE__ */ new Set();
|
|
2998
|
+
function walk(p) {
|
|
2999
|
+
const def = p._def;
|
|
3000
|
+
if (def.tag === "lazy") {
|
|
3001
|
+
counts.set(p, (counts.get(p) ?? 0) + 1);
|
|
3002
|
+
if (active.has(p)) {
|
|
3003
|
+
recursive.add(p);
|
|
3004
|
+
return;
|
|
3005
|
+
}
|
|
3006
|
+
if (descended.has(p)) return;
|
|
3007
|
+
descended.add(p);
|
|
3008
|
+
let resolved;
|
|
3009
|
+
try {
|
|
3010
|
+
resolved = def.thunk();
|
|
3011
|
+
} catch {
|
|
3012
|
+
return;
|
|
3013
|
+
}
|
|
3014
|
+
active.add(p);
|
|
3015
|
+
walk(resolved);
|
|
3016
|
+
active.delete(p);
|
|
3017
|
+
return;
|
|
3018
|
+
}
|
|
3019
|
+
for (const child of childrenOf(def)) walk(child);
|
|
3020
|
+
}
|
|
3021
|
+
for (const root of roots) walk(root);
|
|
3022
|
+
return { counts, recursive };
|
|
3023
|
+
}
|
|
2799
3024
|
function compile(combinator, mapFnSources) {
|
|
2800
3025
|
const ctx = {
|
|
2801
3026
|
vars: 0,
|
|
@@ -2812,13 +3037,16 @@ function compile(combinator, mapFnSources) {
|
|
|
2812
3037
|
triviaCaptureNames: /* @__PURE__ */ new Map(),
|
|
2813
3038
|
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
2814
3039
|
namedFnDecls: [],
|
|
2815
|
-
capturing: hasNodeDef(combinator)
|
|
3040
|
+
capturing: hasNodeDef(combinator),
|
|
3041
|
+
lazyUsage: analyzeLazyUsage(combinator)
|
|
2816
3042
|
};
|
|
2817
3043
|
const r = emit(combinator, ctx, "_pos");
|
|
2818
3044
|
const collatorDecl = ctx.needsCollator ? `const _collator = new Intl.Collator(undefined, { sensitivity: 'accent' })
|
|
2819
3045
|
` : "";
|
|
2820
3046
|
const namedPrelude = ctx.namedFnDecls.length > 0 ? [...namedFnPrelude(), ""] : [];
|
|
3047
|
+
const emptyTlDecls = ctx.needsEmptyTl ? ["const _EMPTY_TL = Object.freeze([])"] : [];
|
|
2821
3048
|
const source = [
|
|
3049
|
+
...emptyTlDecls,
|
|
2822
3050
|
...ctx.regexDecls,
|
|
2823
3051
|
"",
|
|
2824
3052
|
...namedPrelude,
|
|
@@ -2830,6 +3058,7 @@ function compile(combinator, mapFnSources) {
|
|
|
2830
3058
|
`}`
|
|
2831
3059
|
].join("\n");
|
|
2832
3060
|
const fn = new Function("input", "_pos", "_rp", "_mf", "_build", "_ctx", [
|
|
3061
|
+
...emptyTlDecls,
|
|
2833
3062
|
...ctx.regexDecls,
|
|
2834
3063
|
collatorDecl,
|
|
2835
3064
|
...namedPrelude,
|
|
@@ -2883,10 +3112,12 @@ function buildInlineExpression(ctx, r, collatorDecl, mapFnSources, buildSources)
|
|
|
2883
3112
|
].join("\n");
|
|
2884
3113
|
const mfDecl = mapFnSources?.length ? ` const _mf = [${mapFnSources.join(", ")}]` : "";
|
|
2885
3114
|
const buildDecl = buildSources?.length ? ` const _build = [${buildSources.join(", ")}]` : "";
|
|
2886
|
-
const
|
|
3115
|
+
const emptyTlDecl = ctx.needsEmptyTl ? ` const _EMPTY_TL = Object.freeze([])` : "";
|
|
3116
|
+
const needsWrapper = ctx.regexDecls.length > 0 || !!collatorDecl || ctx.namedFnDecls.length > 0 || !!mfDecl || !!buildDecl || !!emptyTlDecl;
|
|
2887
3117
|
if (!needsWrapper) return innerFn;
|
|
2888
3118
|
const namedPrelude = ctx.namedFnDecls.length > 0 ? namedFnPrelude() : [];
|
|
2889
3119
|
const hoistedDecls = [
|
|
3120
|
+
emptyTlDecl,
|
|
2890
3121
|
...ctx.regexDecls.map((d) => ` ${d}`),
|
|
2891
3122
|
collatorDecl ? ` ${collatorDecl.trim()}` : "",
|
|
2892
3123
|
mfDecl,
|
|
@@ -3171,6 +3402,31 @@ function replaceAtPath(rebuild, root, path, newNode) {
|
|
|
3171
3402
|
function defaultRebuild(node2, children) {
|
|
3172
3403
|
return { ...node2, children };
|
|
3173
3404
|
}
|
|
3405
|
+
function shiftSpans(child, delta) {
|
|
3406
|
+
const c = child;
|
|
3407
|
+
const span = { start: c.span.start + delta, end: c.span.end + delta };
|
|
3408
|
+
if (Array.isArray(c.children)) {
|
|
3409
|
+
return { ...c, span, children: c.children.map((g) => shiftSpans(g, delta)) };
|
|
3410
|
+
}
|
|
3411
|
+
return { ...c, span };
|
|
3412
|
+
}
|
|
3413
|
+
function graftAndShift(root, path, newNode, delta) {
|
|
3414
|
+
if (path.length === 0) return newNode;
|
|
3415
|
+
const [idx, ...rest] = path;
|
|
3416
|
+
const oldChildren = root.children;
|
|
3417
|
+
const newChildren = oldChildren.map((child, i) => {
|
|
3418
|
+
if (i < idx) return child;
|
|
3419
|
+
if (i === idx) {
|
|
3420
|
+
return rest.length === 0 ? newNode : graftAndShift(child, rest, newNode, delta);
|
|
3421
|
+
}
|
|
3422
|
+
return shiftSpans(child, delta);
|
|
3423
|
+
});
|
|
3424
|
+
return {
|
|
3425
|
+
...root,
|
|
3426
|
+
span: { start: root.span.start, end: root.span.end + delta },
|
|
3427
|
+
children: newChildren
|
|
3428
|
+
};
|
|
3429
|
+
}
|
|
3174
3430
|
var FunctionalDocImpl = class _FunctionalDocImpl {
|
|
3175
3431
|
_registry;
|
|
3176
3432
|
_rootRule;
|
|
@@ -3208,7 +3464,12 @@ var FunctionalDocImpl = class _FunctionalDocImpl {
|
|
|
3208
3464
|
const r = ruleFn(newInput, node2.span.start, ctx);
|
|
3209
3465
|
if (!r.ok) continue;
|
|
3210
3466
|
if (r.span.end === node2.span.end + delta) {
|
|
3211
|
-
|
|
3467
|
+
if (delta === 0) {
|
|
3468
|
+
const newTree2 = replaceAtPath(rebuild, this.tree, path, r.value);
|
|
3469
|
+
return new _FunctionalDocImpl(this._registry, this._rootRule, this._opts, newTree2, [], newInput);
|
|
3470
|
+
}
|
|
3471
|
+
if (this._opts.rebuild) return reparse();
|
|
3472
|
+
const newTree = graftAndShift(this.tree, path, r.value, delta);
|
|
3212
3473
|
return new _FunctionalDocImpl(this._registry, this._rootRule, this._opts, newTree, [], newInput);
|
|
3213
3474
|
}
|
|
3214
3475
|
}
|