parseman 0.7.1 → 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/combinators/expect.d.ts +36 -0
- package/dist/combinators/expect.d.ts.map +1 -0
- package/dist/combinators/grammar.d.ts.map +1 -1
- package/dist/combinators/scanTo.d.ts.map +1 -1
- 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 +534 -144
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +534 -144
- 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 +701 -162
- package/dist/plugin/index.cjs.map +4 -4
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +701 -162
- package/dist/plugin/index.js.map +4 -4
- package/dist/types.d.ts +12 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +6 -2
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 = [];
|
|
@@ -1722,6 +1808,119 @@ function firstSetCond(codeVar, fs) {
|
|
|
1722
1808
|
(r) => r.lo === r.hi ? `${codeVar} === ${r.lo}` : `(${codeVar} >= ${r.lo} && ${codeVar} <= ${r.hi})`
|
|
1723
1809
|
).join(" || ");
|
|
1724
1810
|
}
|
|
1811
|
+
function captureRestoreBody(mL, mR, mTl, mLg) {
|
|
1812
|
+
const base = `if (_ctx._cstLeaves) _ctx._cstLeaves.length = ${mL}; if (_ctx._cstRawChildren) _ctx._cstRawChildren.length = ${mR}; if (_ctx._cstTriviaLog) _ctx._cstTriviaLog.length = ${mTl}`;
|
|
1813
|
+
return mLg ? `${base}; if (_ctx._triviaLog) _ctx._triviaLog.length = ${mLg}` : base;
|
|
1814
|
+
}
|
|
1815
|
+
function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
1816
|
+
if (seen.has(p)) return false;
|
|
1817
|
+
seen.add(p);
|
|
1818
|
+
const d = p._def;
|
|
1819
|
+
switch (d.tag) {
|
|
1820
|
+
// Atomic / non-capturing-then-failing: a failure happens before any push.
|
|
1821
|
+
case "literal":
|
|
1822
|
+
case "regex":
|
|
1823
|
+
case "keywords":
|
|
1824
|
+
case "guard":
|
|
1825
|
+
case "not":
|
|
1826
|
+
case "trivia":
|
|
1827
|
+
case "scanTo":
|
|
1828
|
+
case "unknown":
|
|
1829
|
+
return false;
|
|
1830
|
+
// node() captures into its own private buffers and rolls them back on
|
|
1831
|
+
// failure (emitNode restores _ctx.* and never pushes on the !ok path).
|
|
1832
|
+
case "node":
|
|
1833
|
+
return false;
|
|
1834
|
+
// choice/firstMatch already roll back each failed arm; on overall failure
|
|
1835
|
+
// nothing committed remains.
|
|
1836
|
+
case "choice":
|
|
1837
|
+
return false;
|
|
1838
|
+
// optional never fails; many/oneOrMore only "fail" with zero captured items.
|
|
1839
|
+
case "optional":
|
|
1840
|
+
case "many":
|
|
1841
|
+
case "oneOrMore":
|
|
1842
|
+
return false;
|
|
1843
|
+
// sepBy emits its own per-iteration rollback in emitSepBy.
|
|
1844
|
+
case "sepBy":
|
|
1845
|
+
return false;
|
|
1846
|
+
// A sequence is the real case: an earlier capturing term followed by a term
|
|
1847
|
+
// that can fail leaves the earlier captures buffered.
|
|
1848
|
+
case "sequence": {
|
|
1849
|
+
const parts = d.parsers;
|
|
1850
|
+
if (parts.length < 2) return parts.some((x) => mayLeavePartialCapture(x, seen));
|
|
1851
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
1852
|
+
if (hasNodeDef(parts[i]) || capturesLeaf(parts[i])) return true;
|
|
1853
|
+
}
|
|
1854
|
+
return false;
|
|
1855
|
+
}
|
|
1856
|
+
// Delegating wrappers: defer to the wrapped parser.
|
|
1857
|
+
case "transform":
|
|
1858
|
+
case "label":
|
|
1859
|
+
case "expect":
|
|
1860
|
+
case "withCtx":
|
|
1861
|
+
case "grammar":
|
|
1862
|
+
return mayLeavePartialCapture(d.parser, seen);
|
|
1863
|
+
case "skip":
|
|
1864
|
+
return mayLeavePartialCapture(d.main, seen);
|
|
1865
|
+
case "recover":
|
|
1866
|
+
return mayLeavePartialCapture(d.parser, seen);
|
|
1867
|
+
case "lazy": {
|
|
1868
|
+
try {
|
|
1869
|
+
return mayLeavePartialCapture(d.thunk(), seen);
|
|
1870
|
+
} catch {
|
|
1871
|
+
return true;
|
|
1872
|
+
}
|
|
1873
|
+
}
|
|
1874
|
+
// Unknown shapes: be safe and keep the rollback.
|
|
1875
|
+
default:
|
|
1876
|
+
return true;
|
|
1877
|
+
}
|
|
1878
|
+
}
|
|
1879
|
+
function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
1880
|
+
if (seen.has(p)) return false;
|
|
1881
|
+
seen.add(p);
|
|
1882
|
+
const d = p._def;
|
|
1883
|
+
switch (d.tag) {
|
|
1884
|
+
case "literal":
|
|
1885
|
+
case "regex":
|
|
1886
|
+
case "keywords":
|
|
1887
|
+
case "node":
|
|
1888
|
+
return true;
|
|
1889
|
+
case "not":
|
|
1890
|
+
case "guard":
|
|
1891
|
+
case "trivia":
|
|
1892
|
+
case "unknown":
|
|
1893
|
+
return false;
|
|
1894
|
+
case "sequence":
|
|
1895
|
+
case "choice":
|
|
1896
|
+
return d.parsers.some((x) => capturesLeaf(x, seen));
|
|
1897
|
+
case "sepBy":
|
|
1898
|
+
return capturesLeaf(d.parser, seen) || capturesLeaf(d.separator, seen);
|
|
1899
|
+
case "many":
|
|
1900
|
+
case "oneOrMore":
|
|
1901
|
+
case "optional":
|
|
1902
|
+
case "transform":
|
|
1903
|
+
case "label":
|
|
1904
|
+
case "expect":
|
|
1905
|
+
case "withCtx":
|
|
1906
|
+
case "grammar":
|
|
1907
|
+
case "recover":
|
|
1908
|
+
return capturesLeaf(d.parser, seen);
|
|
1909
|
+
case "skip":
|
|
1910
|
+
return capturesLeaf(d.main, seen);
|
|
1911
|
+
case "scanTo":
|
|
1912
|
+
return true;
|
|
1913
|
+
case "lazy": {
|
|
1914
|
+
try {
|
|
1915
|
+
return capturesLeaf(d.thunk(), seen);
|
|
1916
|
+
} catch {
|
|
1917
|
+
return true;
|
|
1918
|
+
}
|
|
1919
|
+
}
|
|
1920
|
+
default:
|
|
1921
|
+
return true;
|
|
1922
|
+
}
|
|
1923
|
+
}
|
|
1725
1924
|
function emitFallible(inner, ctx, pos) {
|
|
1726
1925
|
const lbl = v(ctx, "_lbl");
|
|
1727
1926
|
const okV = `${lbl}ok`;
|
|
@@ -1735,26 +1934,23 @@ function emitFallible(inner, ctx, pos) {
|
|
|
1735
1934
|
ctx.failLabel = savedLabel;
|
|
1736
1935
|
ctx.indent = savedIndent;
|
|
1737
1936
|
const ind0 = ind(ctx);
|
|
1738
|
-
const
|
|
1739
|
-
const
|
|
1740
|
-
const
|
|
1741
|
-
const
|
|
1937
|
+
const needsRollback = ctx.capturing && mayLeavePartialCapture(inner);
|
|
1938
|
+
const mL = needsRollback ? v(ctx, "_fcl") : null;
|
|
1939
|
+
const mR = needsRollback ? v(ctx, "_fcr") : null;
|
|
1940
|
+
const mTl = needsRollback ? v(ctx, "_fctl") : null;
|
|
1742
1941
|
const stmts = [
|
|
1743
1942
|
`${ind0}let ${okV} = false, ${valV}, ${endV} = ${pos}`,
|
|
1744
1943
|
...mL ? [
|
|
1745
1944
|
`${ind0}const ${mL} = _ctx._cstLeaves?.length ?? 0`,
|
|
1746
1945
|
`${ind0}const ${mR} = _ctx._cstRawChildren?.length ?? 0`,
|
|
1747
|
-
`${ind0}const ${mTl} = _ctx._cstTriviaLog?.length ?? 0
|
|
1748
|
-
`${ind0}const ${mLg} = _ctx._triviaLog?.length ?? 0`
|
|
1946
|
+
`${ind0}const ${mTl} = _ctx._cstTriviaLog?.length ?? 0`
|
|
1749
1947
|
] : [],
|
|
1750
1948
|
`${ind0}${lbl}: {`,
|
|
1751
1949
|
...r.stmts,
|
|
1752
|
-
`${ind0} ${valV} = ${r.valueVar}`,
|
|
1753
|
-
`${ind0} ${endV} = ${r.endVar}`,
|
|
1754
|
-
`${ind0} ${okV} = true`,
|
|
1950
|
+
`${ind0} ${valV} = ${r.valueVar}; ${endV} = ${r.endVar}; ${okV} = true`,
|
|
1755
1951
|
`${ind0}}`,
|
|
1756
1952
|
...mL ? [
|
|
1757
|
-
`${ind0}if (!${okV}) {
|
|
1953
|
+
`${ind0}if (!${okV}) { ${captureRestoreBody(mL, mR, mTl, null)} }`
|
|
1758
1954
|
] : []
|
|
1759
1955
|
];
|
|
1760
1956
|
return { stmts, okVar: okV, valVar: valV, endVar: endV };
|
|
@@ -1990,11 +2186,11 @@ function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos) {
|
|
|
1990
2186
|
const p = def.parsers[idx];
|
|
1991
2187
|
const litVal = getCoreLiteralValue(p);
|
|
1992
2188
|
const litLen = litVal.length;
|
|
1993
|
-
const
|
|
2189
|
+
const litCond2 = emitLiteralCondition(litVal, pos);
|
|
1994
2190
|
const kw = first ? "if" : "else if";
|
|
1995
2191
|
first = false;
|
|
1996
2192
|
const litEnd = `${pos} + ${litLen}`;
|
|
1997
|
-
stmts.push(`${ind(ctx)}${kw} (${
|
|
2193
|
+
stmts.push(`${ind(ctx)}${kw} (${litCond2}) {`);
|
|
1998
2194
|
ctx.indent++;
|
|
1999
2195
|
const tR = emitTransformChain(p, JSON.stringify(litVal), litEnd, pos, ctx);
|
|
2000
2196
|
stmts.push(
|
|
@@ -2028,11 +2224,13 @@ function emitFirstMatch(def, allExpected, ctx, pos) {
|
|
|
2028
2224
|
gateCond = `_mf[${gateIdx}](_ctx.state)`;
|
|
2029
2225
|
}
|
|
2030
2226
|
const skipCond = gateCond ? `!${resOkV} && ${gateCond}` : `!${resOkV}`;
|
|
2031
|
-
const
|
|
2032
|
-
const
|
|
2033
|
-
const
|
|
2034
|
-
const
|
|
2035
|
-
const
|
|
2227
|
+
const armHasAutoNot = !!(autoNot && autoNot.length > 0);
|
|
2228
|
+
const armNeedsRollback = ctx.capturing && (mayLeavePartialCapture(p) || armHasAutoNot && capturesLeaf(p));
|
|
2229
|
+
const markLeaves = armNeedsRollback ? v(ctx, "_cml") : null;
|
|
2230
|
+
const markRaw = armNeedsRollback ? v(ctx, "_cmr") : null;
|
|
2231
|
+
const markTl = armNeedsRollback ? v(ctx, "_cmtl") : null;
|
|
2232
|
+
const markLog = armNeedsRollback ? v(ctx, "_cmlg") : null;
|
|
2233
|
+
const rollback = markLeaves ? captureRestoreBody(markLeaves, markRaw, markTl, markLog) : "";
|
|
2036
2234
|
stmts.push(`${ind0}if (${skipCond}) {`);
|
|
2037
2235
|
ctx.indent++;
|
|
2038
2236
|
const ind1 = ind(ctx);
|
|
@@ -2062,11 +2260,7 @@ function emitFirstMatch(def, allExpected, ctx, pos) {
|
|
|
2062
2260
|
stmts.push(`${ind0} }`);
|
|
2063
2261
|
if (rollback) stmts.push(`${ind0} if (!${resOkV}) { ${rollback} }`);
|
|
2064
2262
|
} else {
|
|
2065
|
-
stmts.push(`${ind0} if (${okVar}) {`);
|
|
2066
|
-
stmts.push(`${ind0} ${resValV} = ${valVar}`);
|
|
2067
|
-
stmts.push(`${ind0} ${resEndV} = ${endVar}`);
|
|
2068
|
-
stmts.push(`${ind0} ${resOkV} = true`);
|
|
2069
|
-
stmts.push(`${ind0} }`);
|
|
2263
|
+
stmts.push(`${ind0} if (${okVar}) { ${resValV} = ${valVar}; ${resEndV} = ${endVar}; ${resOkV} = true }`);
|
|
2070
2264
|
if (rollback) stmts.push(`${ind0} else { ${rollback} }`);
|
|
2071
2265
|
}
|
|
2072
2266
|
stmts.push(`${ind0}}`);
|
|
@@ -2364,6 +2558,16 @@ function emitRuntimeFallback(parser2, ctx, pos) {
|
|
|
2364
2558
|
return { stmts, valueVar: vv, endVar: ev };
|
|
2365
2559
|
}
|
|
2366
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
|
+
}
|
|
2367
2571
|
if (!ctx.namedParsers.has(p)) {
|
|
2368
2572
|
const fnName2 = `_pf${ctx.namedParsers.size}`;
|
|
2369
2573
|
ctx.namedParsers.set(p, fnName2);
|
|
@@ -2411,6 +2615,22 @@ function emitRecover(def, ctx, pos) {
|
|
|
2411
2615
|
];
|
|
2412
2616
|
return { stmts, valueVar: valVar, endVar };
|
|
2413
2617
|
}
|
|
2618
|
+
function emitExpect(def, ctx, pos) {
|
|
2619
|
+
const { stmts: innerStmts, okVar, valVar, endVar } = emitFallible(def.parser, ctx, pos);
|
|
2620
|
+
const ind0 = ind(ctx);
|
|
2621
|
+
const errV = v(ctx, "_err");
|
|
2622
|
+
const stmts = [
|
|
2623
|
+
...innerStmts,
|
|
2624
|
+
`${ind0}if (!${okVar}) {`,
|
|
2625
|
+
`${ind0} const ${errV} = { _tag: 'parseError', span: { start: ${pos}, end: ${pos} }, expected: ${JSON.stringify(def.expected)} }`,
|
|
2626
|
+
`${ind0} if (_ctx._errors) _ctx._errors.push(${errV})`,
|
|
2627
|
+
`${ind0} ${valVar} = ${errV}`,
|
|
2628
|
+
`${ind0} ${endVar} = ${pos}`,
|
|
2629
|
+
`${ind0} ${okVar} = true`,
|
|
2630
|
+
`${ind0}}`
|
|
2631
|
+
];
|
|
2632
|
+
return { stmts, valueVar: valVar, endVar };
|
|
2633
|
+
}
|
|
2414
2634
|
function emit(p, ctx, pos) {
|
|
2415
2635
|
const def = p._def;
|
|
2416
2636
|
switch (def.tag) {
|
|
@@ -2519,6 +2739,8 @@ function emit(p, ctx, pos) {
|
|
|
2519
2739
|
return emitScanTo(def, ctx, pos);
|
|
2520
2740
|
case "recover":
|
|
2521
2741
|
return emitRecover(def, ctx, pos);
|
|
2742
|
+
case "expect":
|
|
2743
|
+
return emitExpect(def, ctx, pos);
|
|
2522
2744
|
case "guard": {
|
|
2523
2745
|
const fnIdx = ctx.mapFns.length;
|
|
2524
2746
|
ctx.mapFns.push(def.predicate);
|
|
@@ -2602,12 +2824,88 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2602
2824
|
return hasNodeDef(d.sentinel, seen) || d.skip.some((x) => hasNodeDef(x, seen));
|
|
2603
2825
|
case "recover":
|
|
2604
2826
|
return hasNodeDef(d.parser, seen) || hasNodeDef(d.sentinel, seen);
|
|
2827
|
+
case "expect":
|
|
2828
|
+
return hasNodeDef(d.parser, seen);
|
|
2605
2829
|
case "withCtx":
|
|
2606
2830
|
return hasNodeDef(d.parser, seen);
|
|
2607
2831
|
default:
|
|
2608
2832
|
return false;
|
|
2609
2833
|
}
|
|
2610
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
|
+
}
|
|
2611
2909
|
function compile(combinator, mapFnSources) {
|
|
2612
2910
|
const ctx = {
|
|
2613
2911
|
vars: 0,
|
|
@@ -2624,7 +2922,8 @@ function compile(combinator, mapFnSources) {
|
|
|
2624
2922
|
triviaCaptureNames: /* @__PURE__ */ new Map(),
|
|
2625
2923
|
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
2626
2924
|
namedFnDecls: [],
|
|
2627
|
-
capturing: hasNodeDef(combinator)
|
|
2925
|
+
capturing: hasNodeDef(combinator),
|
|
2926
|
+
lazyUsage: analyzeLazyUsage(combinator)
|
|
2628
2927
|
};
|
|
2629
2928
|
const r = emit(combinator, ctx, "_pos");
|
|
2630
2929
|
const collatorDecl = ctx.needsCollator ? `const _collator = new Intl.Collator(undefined, { sensitivity: 'accent' })
|
|
@@ -2670,6 +2969,11 @@ function compile(combinator, mapFnSources) {
|
|
|
2670
2969
|
parseWithContext(input, parseCtx, pos = 0) {
|
|
2671
2970
|
return fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, parseCtx);
|
|
2672
2971
|
},
|
|
2972
|
+
// Note: collects recover()/expect() errors via _errors. Unlike interpreter
|
|
2973
|
+
// parse({recover:true}) it does NOT populate furthestFail — the compiled path
|
|
2974
|
+
// inlines failures for throughput and deliberately skips _probe bookkeeping.
|
|
2975
|
+
// Callers wanting a furthest-position diagnostic detect unconsumed input
|
|
2976
|
+
// (span.end < input.length) instead, which is mode-agnostic.
|
|
2673
2977
|
parseWithErrors(input, pos = 0) {
|
|
2674
2978
|
const errors = [];
|
|
2675
2979
|
const result = fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, { ...defaultCtx, _errors: errors });
|
|
@@ -2677,6 +2981,66 @@ function compile(combinator, mapFnSources) {
|
|
|
2677
2981
|
}
|
|
2678
2982
|
};
|
|
2679
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
|
+
}
|
|
2680
3044
|
function buildInlineExpression(ctx, r, collatorDecl, mapFnSources, buildSources) {
|
|
2681
3045
|
const bodyLines = [
|
|
2682
3046
|
` let pos = _pos`,
|
|
@@ -2712,6 +3076,58 @@ function buildInlineExpression(ctx, r, collatorDecl, mapFnSources, buildSources)
|
|
|
2712
3076
|
].join("\n");
|
|
2713
3077
|
}
|
|
2714
3078
|
|
|
3079
|
+
// src/combinators/expect.ts
|
|
3080
|
+
function staticExpected(c) {
|
|
3081
|
+
const def = c._def;
|
|
3082
|
+
switch (def.tag) {
|
|
3083
|
+
case "literal":
|
|
3084
|
+
return [JSON.stringify(def.value)];
|
|
3085
|
+
case "regex":
|
|
3086
|
+
return [`/${def.source}/`];
|
|
3087
|
+
case "keywords":
|
|
3088
|
+
return def.words.map((w) => JSON.stringify(w));
|
|
3089
|
+
case "label":
|
|
3090
|
+
return [def.label];
|
|
3091
|
+
case "choice":
|
|
3092
|
+
return def.parsers.flatMap(staticExpected);
|
|
3093
|
+
case "sequence":
|
|
3094
|
+
return def.parsers.length > 0 ? staticExpected(def.parsers[0]) : [];
|
|
3095
|
+
case "node":
|
|
3096
|
+
case "grammar":
|
|
3097
|
+
case "trivia":
|
|
3098
|
+
case "optional":
|
|
3099
|
+
case "many":
|
|
3100
|
+
case "oneOrMore":
|
|
3101
|
+
case "transform":
|
|
3102
|
+
case "not":
|
|
3103
|
+
return staticExpected(def.parser);
|
|
3104
|
+
case "lazy":
|
|
3105
|
+
return staticExpected(def.thunk());
|
|
3106
|
+
default:
|
|
3107
|
+
return [];
|
|
3108
|
+
}
|
|
3109
|
+
}
|
|
3110
|
+
function expect(combinator, label2) {
|
|
3111
|
+
const expected = label2 !== void 0 ? [label2] : staticExpected(combinator);
|
|
3112
|
+
const meta = {
|
|
3113
|
+
firstSet: combinator._meta.firstSet,
|
|
3114
|
+
canMatchNewline: combinator._meta.canMatchNewline,
|
|
3115
|
+
isTrivia: false
|
|
3116
|
+
};
|
|
3117
|
+
return {
|
|
3118
|
+
_tag: "expect",
|
|
3119
|
+
_meta: meta,
|
|
3120
|
+
_def: { tag: "expect", parser: combinator, label: label2, expected },
|
|
3121
|
+
parse(input, pos, ctx) {
|
|
3122
|
+
const result = combinator.parse(input, pos, ctx);
|
|
3123
|
+
if (result.ok) return result;
|
|
3124
|
+
const error = { _tag: "parseError", span: { start: pos, end: pos }, expected };
|
|
3125
|
+
ctx._errors?.push(error);
|
|
3126
|
+
return { ok: true, value: error, span: { start: pos, end: pos } };
|
|
3127
|
+
}
|
|
3128
|
+
};
|
|
3129
|
+
}
|
|
3130
|
+
|
|
2715
3131
|
// src/combinators/scanTo.ts
|
|
2716
3132
|
function scanTo(sentinel, { skip: skip2 = [], orEOF = false } = {}) {
|
|
2717
3133
|
const meta = {
|
|
@@ -2725,7 +3141,11 @@ function scanTo(sentinel, { skip: skip2 = [], orEOF = false } = {}) {
|
|
|
2725
3141
|
_def: { tag: "scanTo", sentinel, skip: skip2, orEOF },
|
|
2726
3142
|
parse(input, pos, ctx) {
|
|
2727
3143
|
let cur = pos;
|
|
2728
|
-
const probeCtx = {
|
|
3144
|
+
const probeCtx = {
|
|
3145
|
+
trackLines: ctx.trackLines,
|
|
3146
|
+
state: ctx.state,
|
|
3147
|
+
...ctx._errors !== void 0 ? { _errors: ctx._errors } : {}
|
|
3148
|
+
};
|
|
2729
3149
|
const emit2 = (end) => {
|
|
2730
3150
|
if (end > pos && cstCaptureActive(ctx)) {
|
|
2731
3151
|
const leaf = { _tag: "leaf", value: input.slice(pos, end), span: { start: pos, end } };
|
|
@@ -2761,20 +3181,46 @@ function scanTo(sentinel, { skip: skip2 = [], orEOF = false } = {}) {
|
|
|
2761
3181
|
}
|
|
2762
3182
|
function balanced(open, close, options = {}) {
|
|
2763
3183
|
const self = ref();
|
|
2764
|
-
const
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
3184
|
+
const skips = options.skip ?? [];
|
|
3185
|
+
const stop = /* @__PURE__ */ new Set([open, close]);
|
|
3186
|
+
let bounded = true;
|
|
3187
|
+
for (const sk of skips) {
|
|
3188
|
+
const cs = firstSetClassChars(sk);
|
|
3189
|
+
if (cs === null) {
|
|
3190
|
+
bounded = false;
|
|
3191
|
+
break;
|
|
3192
|
+
}
|
|
3193
|
+
for (const ch of cs) stop.add(ch);
|
|
3194
|
+
}
|
|
3195
|
+
const cls = [...stop].map(escapeClassChar).join("");
|
|
3196
|
+
const content = bounded ? regex(new RegExp(`[^${cls}]+`)) : regex(new RegExp(`[^${escapeClassChar(open)}${escapeClassChar(close)}]`));
|
|
3197
|
+
const inner = many(choice(self, ...skips, content));
|
|
2768
3198
|
const combi = transform(
|
|
2769
|
-
sequence(literal(open), inner, literal(close)),
|
|
2770
|
-
(
|
|
3199
|
+
sequence(literal(open), inner, expect(literal(close), close)),
|
|
3200
|
+
// parts: strings (content/self) or arrays (a sequence-shaped skip) or a
|
|
3201
|
+
// ParseError (recovered close). `c` is the close string or a ParseError.
|
|
3202
|
+
([o, parts, c]) => o + parts.map((p) => typeof p === "string" ? p : Array.isArray(p) ? p.join("") : "").join("") + (typeof c === "string" ? c : "")
|
|
2771
3203
|
);
|
|
2772
3204
|
if (combi._def.tag === "transform") {
|
|
2773
|
-
combi._def.fnSrc =
|
|
3205
|
+
combi._def.fnSrc = '([o, parts, c]) => o + parts.map(p => typeof p === "string" ? p : Array.isArray(p) ? p.join("") : "").join("") + (typeof c === "string" ? c : "")';
|
|
2774
3206
|
}
|
|
2775
3207
|
self.define(combi);
|
|
2776
3208
|
return combi;
|
|
2777
3209
|
}
|
|
3210
|
+
function firstSetClassChars(c) {
|
|
3211
|
+
const fs = c._meta.firstSet;
|
|
3212
|
+
if (fs.kind === "empty") return [];
|
|
3213
|
+
if (fs.kind !== "ranges") return null;
|
|
3214
|
+
const out = [];
|
|
3215
|
+
for (const { lo, hi } of fs.ranges) {
|
|
3216
|
+
if (hi - lo > 8) return null;
|
|
3217
|
+
for (let cp = lo; cp <= hi; cp++) out.push(String.fromCodePoint(cp));
|
|
3218
|
+
}
|
|
3219
|
+
return out;
|
|
3220
|
+
}
|
|
3221
|
+
function escapeClassChar(ch) {
|
|
3222
|
+
return ch.replace(/[\\\]^-]/g, "\\$&");
|
|
3223
|
+
}
|
|
2778
3224
|
|
|
2779
3225
|
// src/plugin/evaluator.ts
|
|
2780
3226
|
function isWordFactory(v2) {
|
|
@@ -2793,7 +3239,8 @@ var SUPPORTED = {
|
|
|
2793
3239
|
sepBy: (...a) => sepBy(a[0], a[1]),
|
|
2794
3240
|
trivia: (...a) => trivia(a[0]),
|
|
2795
3241
|
label: (...a) => label(a[0], a[1]),
|
|
2796
|
-
noTrivia: (...a) => noTrivia(a[0])
|
|
3242
|
+
noTrivia: (...a) => noTrivia(a[0]),
|
|
3243
|
+
expect: (...a) => expect(a[0], a[1])
|
|
2797
3244
|
};
|
|
2798
3245
|
function isScopeEntry(v2) {
|
|
2799
3246
|
return !!v2 && typeof v2 === "object" && "combi" in v2 && "mfSrcs" in v2;
|
|
@@ -2875,6 +3322,10 @@ function exprToCombi(node2, scope, code, mfs) {
|
|
|
2875
3322
|
}
|
|
2876
3323
|
}
|
|
2877
3324
|
if (callee.name === "rules") return null;
|
|
3325
|
+
if (callee.name === "ref") {
|
|
3326
|
+
if (node2.arguments.length !== 0) return null;
|
|
3327
|
+
return ref();
|
|
3328
|
+
}
|
|
2878
3329
|
if (callee.name === "parser") {
|
|
2879
3330
|
const [optsArg, rootArg] = node2.arguments;
|
|
2880
3331
|
if (!optsArg || !rootArg || optsArg.type === "SpreadElement" || rootArg.type === "SpreadElement") return null;
|
|
@@ -2929,13 +3380,14 @@ function exprToCombi(node2, scope, code, mfs) {
|
|
|
2929
3380
|
}
|
|
2930
3381
|
}
|
|
2931
3382
|
if (callee.name === "balanced") {
|
|
2932
|
-
const [openArg, closeArg] = node2.arguments;
|
|
3383
|
+
const [openArg, closeArg, optsArg] = node2.arguments;
|
|
2933
3384
|
if (!openArg || !closeArg || openArg.type === "SpreadElement" || closeArg.type === "SpreadElement") return null;
|
|
2934
3385
|
const open = anyValue(openArg, scope, code, []);
|
|
2935
3386
|
const close = anyValue(closeArg, scope, code, []);
|
|
2936
3387
|
if (typeof open !== "string" || typeof close !== "string") return null;
|
|
3388
|
+
const opts = optsArg && optsArg.type !== "SpreadElement" ? anyValue(optsArg, scope, code, []) : void 0;
|
|
2937
3389
|
try {
|
|
2938
|
-
return balanced(open, close);
|
|
3390
|
+
return balanced(open, close, opts);
|
|
2939
3391
|
} catch {
|
|
2940
3392
|
return null;
|
|
2941
3393
|
}
|
|
@@ -3113,6 +3565,40 @@ function evaluateParserFactory(factoryNode, scope, code, mapFnSources) {
|
|
|
3113
3565
|
}
|
|
3114
3566
|
return ruleRefs;
|
|
3115
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
|
+
}
|
|
3116
3602
|
function referencesAny(node2, names, scope) {
|
|
3117
3603
|
if (node2.type === "Identifier") {
|
|
3118
3604
|
return names.has(node2.name) || scope.has(node2.name);
|
|
@@ -3187,6 +3673,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
3187
3673
|
const replacements = [];
|
|
3188
3674
|
const warnings = [];
|
|
3189
3675
|
let anyUnresolved = false;
|
|
3676
|
+
let ruleMapHolderCounter = 0;
|
|
3190
3677
|
const lineOf = (pos) => {
|
|
3191
3678
|
let line = 1;
|
|
3192
3679
|
for (let i = 0; i < pos && i < code.length; i++) if (code.charCodeAt(i) === 10) line++;
|
|
@@ -3208,18 +3695,53 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
3208
3695
|
warn(init.start, `${label2}: rules(...) factory isn't statically evaluable`);
|
|
3209
3696
|
return null;
|
|
3210
3697
|
}
|
|
3211
|
-
const
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
warn(init.start, `${label2}: rule "${ruleKey}" couldn't be inlined`);
|
|
3216
|
-
return null;
|
|
3217
|
-
}
|
|
3218
|
-
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;
|
|
3219
3702
|
}
|
|
3220
|
-
return {
|
|
3703
|
+
return { replacement: compiled.replacement, ruleMap };
|
|
3221
3704
|
};
|
|
3222
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
|
+
}
|
|
3223
3745
|
for (const stmt of body) {
|
|
3224
3746
|
let vd = null;
|
|
3225
3747
|
let stmtStart = stmt.start;
|
|
@@ -3243,15 +3765,26 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
3243
3765
|
if (d.id.type === "Identifier") {
|
|
3244
3766
|
const varName = d.id.name;
|
|
3245
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
|
+
}
|
|
3246
3781
|
if (isRulesCall(init)) {
|
|
3247
3782
|
const compiledRules = compileRulesFactory(init, varName);
|
|
3248
3783
|
if (!compiledRules) continue;
|
|
3249
3784
|
replacements.push({
|
|
3250
3785
|
start: init.start,
|
|
3251
3786
|
end: init.end,
|
|
3252
|
-
replacement:
|
|
3253
|
-
${compiledRules.entries.map(([k, expr]) => ` ${k}: ${expr}`).join(",\n")}
|
|
3254
|
-
}`
|
|
3787
|
+
replacement: compiledRules.replacement
|
|
3255
3788
|
});
|
|
3256
3789
|
continue;
|
|
3257
3790
|
}
|
|
@@ -3286,9 +3819,8 @@ ${compiledRules.entries.map(([k, expr]) => ` ${k}: ${expr}`).join(",\n")}
|
|
|
3286
3819
|
}
|
|
3287
3820
|
const compiledRules = compileRulesFactory(init, "{ \u2026 }");
|
|
3288
3821
|
if (!compiledRules) continue;
|
|
3289
|
-
const byKey = new Map(compiledRules.entries);
|
|
3290
3822
|
const pattern = d.id;
|
|
3291
|
-
const
|
|
3823
|
+
const bindings = [];
|
|
3292
3824
|
let allOk = true;
|
|
3293
3825
|
for (const prop of pattern.properties) {
|
|
3294
3826
|
const p = prop;
|
|
@@ -3303,17 +3835,21 @@ ${compiledRules.entries.map(([k, expr]) => ` ${k}: ${expr}`).join(",\n")}
|
|
|
3303
3835
|
allOk = false;
|
|
3304
3836
|
break;
|
|
3305
3837
|
}
|
|
3306
|
-
|
|
3307
|
-
if (inlineExpr === void 0) {
|
|
3838
|
+
if (!compiledRules.ruleMap.has(ruleKey)) {
|
|
3308
3839
|
warn(init.start, `destructured rule "${ruleKey}" isn't returned by the rules() factory`);
|
|
3309
3840
|
allOk = false;
|
|
3310
3841
|
break;
|
|
3311
3842
|
}
|
|
3312
|
-
|
|
3843
|
+
bindings.push({ ruleKey, localName });
|
|
3313
3844
|
const rule = compiledRules.ruleMap.get(ruleKey);
|
|
3314
3845
|
if (rule) scope.set(localName, { combi: rule, mfSrcs: [] });
|
|
3315
3846
|
}
|
|
3316
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
|
+
];
|
|
3317
3853
|
replacements.push({
|
|
3318
3854
|
start: stmtStart,
|
|
3319
3855
|
end: stmtEnd,
|
|
@@ -3327,6 +3863,9 @@ ${compiledRules.entries.map(([k, expr]) => ` ${k}: ${expr}`).join(",\n")}
|
|
|
3327
3863
|
imp.fullyResolved = !anyUnresolved;
|
|
3328
3864
|
}
|
|
3329
3865
|
const ms = new MagicString(code);
|
|
3866
|
+
if (!anyUnresolved) {
|
|
3867
|
+
for (const { start, end } of defineRemovals) ms.remove(start, end);
|
|
3868
|
+
}
|
|
3330
3869
|
for (const imp of macroImports) {
|
|
3331
3870
|
if (imp.fullyResolved) {
|
|
3332
3871
|
ms.remove(imp.start, imp.end);
|