parseman 0.44.0 → 0.45.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/analysis/diagnose.d.ts +118 -0
- package/dist/analysis/diagnose.d.ts.map +1 -0
- package/dist/analysis/gating.d.ts +9 -9
- package/dist/analysis/gating.d.ts.map +1 -1
- package/dist/analysis/grammar.d.ts.map +1 -1
- package/dist/combinators/choice.d.ts.map +1 -1
- package/dist/combinators/dispatch.d.ts +19 -1
- package/dist/combinators/dispatch.d.ts.map +1 -1
- package/dist/combinators/expect.d.ts.map +1 -1
- package/dist/combinators/first-set.d.ts.map +1 -1
- package/dist/combinators/node.d.ts +19 -0
- package/dist/combinators/node.d.ts.map +1 -1
- package/dist/compiler/build-arity.d.ts +28 -0
- package/dist/compiler/build-arity.d.ts.map +1 -1
- package/dist/compiler/codegen.d.ts +80 -60
- package/dist/compiler/codegen.d.ts.map +1 -1
- package/dist/compiler/degradation.d.ts +123 -0
- package/dist/compiler/degradation.d.ts.map +1 -0
- package/dist/compiler/fields.d.ts.map +1 -1
- package/dist/compiler/grammar-coverage-ids.d.ts.map +1 -1
- package/dist/compiler/inline-build.d.ts.map +1 -1
- package/dist/compiler/ir-serialize.d.ts.map +1 -1
- package/dist/compiler/linker.d.ts +1 -1
- package/dist/compiler/linker.d.ts.map +1 -1
- package/dist/coverage.d.ts +13 -0
- package/dist/coverage.d.ts.map +1 -1
- package/dist/cst/reflection.d.ts.map +1 -1
- package/dist/functional/run.d.ts.map +1 -1
- package/dist/index.cjs +707 -471
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +4 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +707 -471
- package/dist/index.js.map +4 -4
- package/dist/language-service/index.cjs +40 -30
- package/dist/language-service/index.cjs.map +3 -3
- package/dist/language-service/index.js +40 -30
- package/dist/language-service/index.js.map +3 -3
- package/dist/oracle/digest.d.ts +132 -6
- package/dist/oracle/digest.d.ts.map +1 -1
- package/dist/oracle/index.cjs +136 -305
- package/dist/oracle/index.cjs.map +4 -4
- package/dist/oracle/index.d.ts +43 -31
- package/dist/oracle/index.d.ts.map +1 -1
- package/dist/oracle/index.js +136 -305
- package/dist/oracle/index.js.map +4 -4
- package/dist/plugin/evaluator.d.ts +3 -0
- package/dist/plugin/evaluator.d.ts.map +1 -1
- package/dist/plugin/index.cjs +1127 -747
- package/dist/plugin/index.cjs.map +4 -4
- package/dist/plugin/index.d.ts +18 -0
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +1127 -747
- package/dist/plugin/index.js.map +4 -4
- package/dist/plugin/reducer-resolver.d.ts +41 -0
- package/dist/plugin/reducer-resolver.d.ts.map +1 -0
- package/dist/run/index.cjs +33 -30
- package/dist/run/index.cjs.map +2 -2
- package/dist/run/index.js +33 -30
- package/dist/run/index.js.map +2 -2
- package/dist/spec/index.cjs +221 -34
- package/dist/spec/index.cjs.map +4 -4
- package/dist/spec/index.js +221 -34
- package/dist/spec/index.js.map +4 -4
- package/dist/spec/model.d.ts.map +1 -1
- package/dist/types.d.ts +6 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +7 -3
- package/dist/combinators/guard.d.ts +0 -8
- package/dist/combinators/guard.d.ts.map +0 -1
- package/dist/cst/offset-model.d.ts +0 -119
- package/dist/cst/offset-model.d.ts.map +0 -1
- package/dist/oracle/corpus.d.ts +0 -32
- package/dist/oracle/corpus.d.ts.map +0 -1
- package/dist/oracle/identity.d.ts +0 -117
- package/dist/oracle/identity.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -51,8 +51,9 @@ function matchesEmpty(p, seen = /* @__PURE__ */ new Set(), resolve) {
|
|
|
51
51
|
return d.value.length === 0;
|
|
52
52
|
case "keywords":
|
|
53
53
|
return false;
|
|
54
|
+
// The routed token itself is the selector's match, never empty; a fallback can be.
|
|
54
55
|
case "routed":
|
|
55
|
-
return false;
|
|
56
|
+
return d.fallback === void 0 ? false : me(d.fallback);
|
|
56
57
|
case "regex":
|
|
57
58
|
try {
|
|
58
59
|
const m = new RegExp(d.source).exec("");
|
|
@@ -1814,8 +1815,11 @@ function derive(c, seen) {
|
|
|
1814
1815
|
case "not":
|
|
1815
1816
|
case "peek":
|
|
1816
1817
|
return deriveExpected2(def.parser);
|
|
1818
|
+
// A bare routed() can only fail as "there is no routed token here". With a
|
|
1819
|
+
// fallback, THAT is the branch that can fail, so its expectations are the useful
|
|
1820
|
+
// ones — the routed path either succeeds or is not taken.
|
|
1817
1821
|
case "routed":
|
|
1818
|
-
return ["routed()"];
|
|
1822
|
+
return def.fallback === void 0 ? ["routed()"] : deriveExpected2(def.fallback);
|
|
1819
1823
|
case "lazy": {
|
|
1820
1824
|
const name = c._ruleName;
|
|
1821
1825
|
if (seen.has(c)) return name ? [name] : [];
|
|
@@ -2005,7 +2009,7 @@ function detectStrategy(parsers) {
|
|
|
2005
2009
|
function bareLeadingTermKey(term) {
|
|
2006
2010
|
const d = term._def;
|
|
2007
2011
|
if (d.tag === "literal" && !d.caseInsensitive) return `L:${d.value}`;
|
|
2008
|
-
if (d.tag === "regex") return `R:${d.source
|
|
2012
|
+
if (d.tag === "regex") return `R:${JSON.stringify([d.source, d.flags])}`;
|
|
2009
2013
|
return null;
|
|
2010
2014
|
}
|
|
2011
2015
|
function detectSharedPrefix(parsers) {
|
|
@@ -2263,17 +2267,21 @@ function makeWhen(opts = {}) {
|
|
|
2263
2267
|
function otherwise(parser2) {
|
|
2264
2268
|
return { kind: "otherwise", parser: parser2, usesRouted: parserUsesRouted(parser2) };
|
|
2265
2269
|
}
|
|
2266
|
-
function routed() {
|
|
2270
|
+
function routed(fallback) {
|
|
2267
2271
|
return {
|
|
2268
2272
|
_tag: "routed",
|
|
2269
|
-
_meta: {
|
|
2270
|
-
|
|
2273
|
+
_meta: {
|
|
2274
|
+
// The routed token is whatever the selector matched, so the first set stays
|
|
2275
|
+
// `any` even with a fallback — `any` already subsumes the fallback's.
|
|
2276
|
+
firstSet: { kind: "any" },
|
|
2277
|
+
canMatchNewline: fallback?._meta.canMatchNewline ?? false,
|
|
2278
|
+
isTrivia: false
|
|
2279
|
+
},
|
|
2280
|
+
_def: fallback === void 0 ? { tag: "routed" } : { tag: "routed", fallback },
|
|
2271
2281
|
parse(_input, pos, ctx) {
|
|
2272
2282
|
const item = ctx._routed;
|
|
2273
|
-
if (item === void 0) {
|
|
2274
|
-
|
|
2275
|
-
}
|
|
2276
|
-
if (pos !== item.span.start) {
|
|
2283
|
+
if (item === void 0 || pos !== item.span.start) {
|
|
2284
|
+
if (fallback !== void 0) return fallback.parse(_input, pos, ctx);
|
|
2277
2285
|
return { ok: false, expected: ["routed()"], span: { start: pos, end: pos } };
|
|
2278
2286
|
}
|
|
2279
2287
|
if (cstCaptureActive(ctx)) {
|
|
@@ -2817,12 +2825,12 @@ function markUnusedValues(root) {
|
|
|
2817
2825
|
}
|
|
2818
2826
|
};
|
|
2819
2827
|
const resolveRoot = (c) => {
|
|
2820
|
-
const
|
|
2828
|
+
const guard = /* @__PURE__ */ new Set();
|
|
2821
2829
|
let cur = c;
|
|
2822
|
-
while (!
|
|
2830
|
+
while (!guard.has(cur)) {
|
|
2823
2831
|
const d = cur._def;
|
|
2824
2832
|
if (d.tag !== "lazy") return cur;
|
|
2825
|
-
|
|
2833
|
+
guard.add(cur);
|
|
2826
2834
|
try {
|
|
2827
2835
|
cur = d.thunk();
|
|
2828
2836
|
} catch {
|
|
@@ -2991,10 +2999,11 @@ function childrenOf(def) {
|
|
|
2991
2999
|
return [def.main, def.skipped];
|
|
2992
3000
|
case "scanTo":
|
|
2993
3001
|
return [def.sentinel, ...def.skip];
|
|
3002
|
+
case "routed":
|
|
3003
|
+
return def.fallback ? [def.fallback] : [];
|
|
2994
3004
|
case "literal":
|
|
2995
3005
|
case "regex":
|
|
2996
3006
|
case "keywords":
|
|
2997
|
-
case "routed":
|
|
2998
3007
|
case "guard":
|
|
2999
3008
|
case "lazy":
|
|
3000
3009
|
case "unknown":
|
|
@@ -3220,54 +3229,271 @@ function peek(combinator) {
|
|
|
3220
3229
|
};
|
|
3221
3230
|
}
|
|
3222
3231
|
|
|
3232
|
+
// src/compiler/degradation.ts
|
|
3233
|
+
function formatDegradation(d) {
|
|
3234
|
+
return `[parseman] degraded [${d.code}] ${d.where}: ${d.subject} \u2014 ${d.fellBackTo}; otherwise ${d.otherwise}`;
|
|
3235
|
+
}
|
|
3236
|
+
var DETAIL_CAP = 8;
|
|
3237
|
+
function formatDegradations(list) {
|
|
3238
|
+
const byCode = /* @__PURE__ */ new Map();
|
|
3239
|
+
for (const d of list) {
|
|
3240
|
+
const bucket = byCode.get(d.code);
|
|
3241
|
+
if (bucket) bucket.push(d);
|
|
3242
|
+
else byCode.set(d.code, [d]);
|
|
3243
|
+
}
|
|
3244
|
+
const out = [];
|
|
3245
|
+
for (const [code, items] of byCode) {
|
|
3246
|
+
for (const d of items.slice(0, DETAIL_CAP)) out.push(formatDegradation(d));
|
|
3247
|
+
if (items.length > DETAIL_CAP) {
|
|
3248
|
+
out.push(
|
|
3249
|
+
`[parseman] degraded [${code}] +${items.length - DETAIL_CAP} more site(s) not listed (${items.length} total). Set PARSEMAN_DEGRADATION=error to fail the build on these.`
|
|
3250
|
+
);
|
|
3251
|
+
}
|
|
3252
|
+
}
|
|
3253
|
+
return out;
|
|
3254
|
+
}
|
|
3255
|
+
var _sinks = [];
|
|
3256
|
+
function beginDegradationCapture() {
|
|
3257
|
+
_sinks.push(/* @__PURE__ */ new Map());
|
|
3258
|
+
}
|
|
3259
|
+
function degradationCaptureDepth() {
|
|
3260
|
+
return _sinks.length;
|
|
3261
|
+
}
|
|
3262
|
+
function unwindDegradationCapture(depth) {
|
|
3263
|
+
const found = [];
|
|
3264
|
+
while (_sinks.length > depth) {
|
|
3265
|
+
const sink = _sinks.pop();
|
|
3266
|
+
found.unshift(...sink.values());
|
|
3267
|
+
}
|
|
3268
|
+
return found;
|
|
3269
|
+
}
|
|
3270
|
+
function resolveDegradationLevel(explicit) {
|
|
3271
|
+
if (explicit !== void 0) return explicit;
|
|
3272
|
+
const env = typeof process !== "undefined" ? process.env?.PARSEMAN_DEGRADATION : void 0;
|
|
3273
|
+
if (env === "off" || env === "warn" || env === "error") return env;
|
|
3274
|
+
return "warn";
|
|
3275
|
+
}
|
|
3276
|
+
function degradationKey(d) {
|
|
3277
|
+
return JSON.stringify([d.code, d.where, d.subject]);
|
|
3278
|
+
}
|
|
3279
|
+
function recordDegradation(d) {
|
|
3280
|
+
const level = resolveDegradationLevel();
|
|
3281
|
+
if (level === "off") return;
|
|
3282
|
+
const key = degradationKey(d);
|
|
3283
|
+
const sink = _sinks[_sinks.length - 1];
|
|
3284
|
+
if (sink) {
|
|
3285
|
+
if (!sink.has(key)) sink.set(key, d);
|
|
3286
|
+
return;
|
|
3287
|
+
}
|
|
3288
|
+
if (_immediate.has(key)) return;
|
|
3289
|
+
_immediate.add(key);
|
|
3290
|
+
if (level === "error") throw new Error(`parseman: degraded compilation path
|
|
3291
|
+
${formatDegradation(d)}`);
|
|
3292
|
+
console.warn(formatDegradation(d));
|
|
3293
|
+
}
|
|
3294
|
+
var _immediate = /* @__PURE__ */ new Set();
|
|
3295
|
+
function beginCompileDegradationDrain() {
|
|
3296
|
+
if (resolveDegradationLevel() === "off" || _sinks.length > 0) return () => {
|
|
3297
|
+
};
|
|
3298
|
+
const depth = degradationCaptureDepth();
|
|
3299
|
+
beginDegradationCapture();
|
|
3300
|
+
return (report) => {
|
|
3301
|
+
const found = unwindDegradationCapture(depth);
|
|
3302
|
+
if (!report || found.length === 0) return;
|
|
3303
|
+
const fresh = found.filter((d) => {
|
|
3304
|
+
const k = degradationKey(d);
|
|
3305
|
+
if (_immediate.has(k)) return false;
|
|
3306
|
+
_immediate.add(k);
|
|
3307
|
+
return true;
|
|
3308
|
+
});
|
|
3309
|
+
if (fresh.length === 0) return;
|
|
3310
|
+
const lines = formatDegradations(fresh);
|
|
3311
|
+
if (resolveDegradationLevel() === "error") {
|
|
3312
|
+
throw new Error(`parseman: ${fresh.length} degraded compilation path(s)
|
|
3313
|
+
${lines.join("\n")}`);
|
|
3314
|
+
}
|
|
3315
|
+
for (const l of lines) console.warn(l);
|
|
3316
|
+
};
|
|
3317
|
+
}
|
|
3318
|
+
|
|
3223
3319
|
// src/compiler/build-arity.ts
|
|
3224
3320
|
function cstOutputHost(build) {
|
|
3225
3321
|
return build?._parsemanCstOutput === true;
|
|
3226
3322
|
}
|
|
3227
|
-
var
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
var CONFIRMABLE_PARAM_RE = /^[A-Za-z_$][\w$]*\s*\??\s*(?::[^,=]+)?$/;
|
|
3323
|
+
var SINGLE_IDENT_ARROW_RE = /^[A-Za-z_$][\w$]*\s*=>/;
|
|
3324
|
+
var PARAM_LIST_OPEN_RE = /^(?:function\b[^(]*)?\(/;
|
|
3325
|
+
var NATIVE_CODE_RE = /\{\s*\[native code\]\s*\}/;
|
|
3326
|
+
var PARAM_HEAD_RE = /^[A-Za-z_$][\w$]*\s*\??\s*/;
|
|
3232
3327
|
function confirmedBuildArity(src) {
|
|
3233
3328
|
const s = src.trim();
|
|
3234
|
-
|
|
3235
|
-
if (
|
|
3236
|
-
if (
|
|
3237
|
-
const inner = (
|
|
3238
|
-
if (inner ===
|
|
3239
|
-
|
|
3329
|
+
if (NATIVE_CODE_RE.test(s)) return null;
|
|
3330
|
+
if (/\barguments\b/.test(s)) return null;
|
|
3331
|
+
if (SINGLE_IDENT_ARROW_RE.test(s)) return 1;
|
|
3332
|
+
const inner = paramListText(s);
|
|
3333
|
+
if (inner === null) return null;
|
|
3334
|
+
if (inner.trim() === "") return 0;
|
|
3335
|
+
const parts = splitTopLevel(inner);
|
|
3336
|
+
if (parts === null) return null;
|
|
3240
3337
|
for (const part of parts) {
|
|
3241
|
-
if (!
|
|
3338
|
+
if (!isConfirmableParam(part.trim())) return null;
|
|
3242
3339
|
}
|
|
3243
|
-
if (/\barguments\b/.test(s)) return null;
|
|
3244
3340
|
return parts.length;
|
|
3245
3341
|
}
|
|
3342
|
+
function paramListText(s) {
|
|
3343
|
+
const open = PARAM_LIST_OPEN_RE.exec(s);
|
|
3344
|
+
if (!open) return null;
|
|
3345
|
+
const start = open[0].length;
|
|
3346
|
+
const end = matchingParen(s, start);
|
|
3347
|
+
if (end === null) return null;
|
|
3348
|
+
if (!s.startsWith("function") && !/^\s*=>/.test(s.slice(end + 1))) return null;
|
|
3349
|
+
return s.slice(start, end);
|
|
3350
|
+
}
|
|
3351
|
+
function matchingParen(s, start) {
|
|
3352
|
+
let depth = 0;
|
|
3353
|
+
for (let i = start; i < s.length; i++) {
|
|
3354
|
+
const c = s[i];
|
|
3355
|
+
if (c === '"' || c === "'" || c === "`") {
|
|
3356
|
+
const close = skipString(s, i);
|
|
3357
|
+
if (close === null) return null;
|
|
3358
|
+
i = close;
|
|
3359
|
+
continue;
|
|
3360
|
+
}
|
|
3361
|
+
if (c === "(" || c === "[" || c === "{") depth++;
|
|
3362
|
+
else if (c === "]" || c === "}") {
|
|
3363
|
+
if (--depth < 0) return null;
|
|
3364
|
+
} else if (c === ")") {
|
|
3365
|
+
if (depth === 0) return i;
|
|
3366
|
+
depth--;
|
|
3367
|
+
}
|
|
3368
|
+
}
|
|
3369
|
+
return null;
|
|
3370
|
+
}
|
|
3371
|
+
function skipString(s, open) {
|
|
3372
|
+
const quote = s[open];
|
|
3373
|
+
for (let i = open + 1; i < s.length; i++) {
|
|
3374
|
+
if (s[i] === "\\") {
|
|
3375
|
+
i++;
|
|
3376
|
+
continue;
|
|
3377
|
+
}
|
|
3378
|
+
if (s[i] === quote) return i;
|
|
3379
|
+
}
|
|
3380
|
+
return null;
|
|
3381
|
+
}
|
|
3382
|
+
function splitTopLevel(inner) {
|
|
3383
|
+
const parts = [];
|
|
3384
|
+
let depth = 0;
|
|
3385
|
+
let angle = 0;
|
|
3386
|
+
let last = 0;
|
|
3387
|
+
for (let i = 0; i < inner.length; i++) {
|
|
3388
|
+
const c = inner[i];
|
|
3389
|
+
if (c === "=" && inner[i + 1] === ">") {
|
|
3390
|
+
i++;
|
|
3391
|
+
continue;
|
|
3392
|
+
}
|
|
3393
|
+
if (c === '"' || c === "'" || c === "`") {
|
|
3394
|
+
const close = skipString(inner, i);
|
|
3395
|
+
if (close === null) return null;
|
|
3396
|
+
i = close;
|
|
3397
|
+
continue;
|
|
3398
|
+
}
|
|
3399
|
+
if (c === "(" || c === "[" || c === "{") depth++;
|
|
3400
|
+
else if (c === ")" || c === "]" || c === "}") {
|
|
3401
|
+
if (--depth < 0) return null;
|
|
3402
|
+
} else if (c === "<") angle++;
|
|
3403
|
+
else if (c === ">") {
|
|
3404
|
+
if (--angle < 0) return null;
|
|
3405
|
+
} else if (c === "," && depth === 0 && angle === 0) {
|
|
3406
|
+
parts.push(inner.slice(last, i));
|
|
3407
|
+
last = i + 1;
|
|
3408
|
+
}
|
|
3409
|
+
}
|
|
3410
|
+
if (depth !== 0 || angle !== 0) return null;
|
|
3411
|
+
parts.push(inner.slice(last));
|
|
3412
|
+
return parts;
|
|
3413
|
+
}
|
|
3414
|
+
function isConfirmableParam(part) {
|
|
3415
|
+
const head = PARAM_HEAD_RE.exec(part);
|
|
3416
|
+
if (!head) return false;
|
|
3417
|
+
const rest = part.slice(head[0].length);
|
|
3418
|
+
if (rest === "") return true;
|
|
3419
|
+
if (rest[0] !== ":") return false;
|
|
3420
|
+
return !hasDefaultAssign(rest.slice(1));
|
|
3421
|
+
}
|
|
3422
|
+
function hasDefaultAssign(annotation) {
|
|
3423
|
+
for (let i = 0; i < annotation.length; i++) {
|
|
3424
|
+
if (annotation[i] !== "=") continue;
|
|
3425
|
+
if (annotation[i + 1] === ">" || annotation[i + 1] === "=") {
|
|
3426
|
+
i++;
|
|
3427
|
+
continue;
|
|
3428
|
+
}
|
|
3429
|
+
const prev = annotation[i - 1];
|
|
3430
|
+
if (prev === "<" || prev === ">" || prev === "!" || prev === "=") continue;
|
|
3431
|
+
return true;
|
|
3432
|
+
}
|
|
3433
|
+
return false;
|
|
3434
|
+
}
|
|
3435
|
+
function buildAnalysisSrc(def) {
|
|
3436
|
+
return def.buildSigSrc ?? def.buildSrc ?? def.build.toString();
|
|
3437
|
+
}
|
|
3438
|
+
var RESOLVER_REASONS = {
|
|
3439
|
+
"rest-parameter": "its parameter list uses a rest parameter, so the declared arity is unbounded",
|
|
3440
|
+
"arguments": "its body references `arguments`",
|
|
3441
|
+
"reassigned": "the binding it names is reassigned, so the function read here is not decidable",
|
|
3442
|
+
"not-a-function": "the binding it names is not a function declaration",
|
|
3443
|
+
"unresolved-import": "its module could not be resolved or parsed",
|
|
3444
|
+
"not-found": "the name did not resolve to any binding",
|
|
3445
|
+
"computed": "it is a computed expression",
|
|
3446
|
+
"foreign-source": "it is named inside an imported factory, whose offsets the entry-file resolver cannot index"
|
|
3447
|
+
};
|
|
3448
|
+
function unconfirmableReason(def, src) {
|
|
3449
|
+
const declared = def.buildArityUnresolved;
|
|
3450
|
+
if (declared !== void 0 && RESOLVER_REASONS[declared]) return RESOLVER_REASONS[declared];
|
|
3451
|
+
const s = src.trim();
|
|
3452
|
+
const params = s.slice(0, s.indexOf(")") + 1);
|
|
3453
|
+
if (params.includes("...")) return RESOLVER_REASONS["rest-parameter"];
|
|
3454
|
+
if (/\barguments\b/.test(s)) return RESOLVER_REASONS["arguments"];
|
|
3455
|
+
if (/^[A-Za-z_$][\w$]*(\s*\.\s*[A-Za-z_$][\w$]*)?$/.test(s)) {
|
|
3456
|
+
return "it names a binding this build could not resolve to a function declaration";
|
|
3457
|
+
}
|
|
3458
|
+
return "its parameter list could not be parsed";
|
|
3459
|
+
}
|
|
3460
|
+
function confirmedArityForDef(def) {
|
|
3461
|
+
if (def.buildArity !== void 0) return def.buildArity;
|
|
3462
|
+
const src = buildAnalysisSrc(def);
|
|
3463
|
+
const arity = confirmedBuildArity(src);
|
|
3464
|
+
if (arity !== null) return arity;
|
|
3465
|
+
const subject = `build reducer \`${(def.buildSrc ?? "<runtime fn>").trim().split("\n")[0].slice(0, 60)}\``;
|
|
3466
|
+
recordDegradation({
|
|
3467
|
+
code: "build-arity-unconfirmed",
|
|
3468
|
+
severity: "warn",
|
|
3469
|
+
where: `node("${def.type ?? "<inferred>"}")`,
|
|
3470
|
+
subject,
|
|
3471
|
+
fellBackTo: `could not confirm its declared arity \u2014 ${unconfirmableReason(def, src)} \u2014 so this node captures children, fields and raw children, logs trivia, and clones \`_ctx.state\` on every match`,
|
|
3472
|
+
otherwise: "only the tiers the reducer actually declares would be captured (arity >= 1 children, >= 2 fields, >= 4 raw, >= 5 trivia, >= 6 state). Declare it with `node(..., { buildArity: n })` if it cannot be derived"
|
|
3473
|
+
});
|
|
3474
|
+
return null;
|
|
3475
|
+
}
|
|
3246
3476
|
function buildReadsChildren(def) {
|
|
3247
3477
|
if (!def.build) return true;
|
|
3248
|
-
const
|
|
3249
|
-
const arity = confirmedBuildArity(src);
|
|
3478
|
+
const arity = confirmedArityForDef(def);
|
|
3250
3479
|
if (arity === null) return true;
|
|
3251
3480
|
return arity >= 1;
|
|
3252
3481
|
}
|
|
3253
3482
|
function buildReadsRaw(def) {
|
|
3254
3483
|
if (!def.build) return true;
|
|
3255
|
-
const
|
|
3256
|
-
const arity = confirmedBuildArity(src);
|
|
3484
|
+
const arity = confirmedArityForDef(def);
|
|
3257
3485
|
if (arity === null) return true;
|
|
3258
3486
|
return arity >= 4;
|
|
3259
3487
|
}
|
|
3260
3488
|
function buildReadsTrivia(def) {
|
|
3261
3489
|
if (!def.build) return true;
|
|
3262
|
-
const
|
|
3263
|
-
const arity = confirmedBuildArity(src);
|
|
3490
|
+
const arity = confirmedArityForDef(def);
|
|
3264
3491
|
if (arity === null) return true;
|
|
3265
3492
|
return arity >= 5;
|
|
3266
3493
|
}
|
|
3267
3494
|
function buildReadsState(def) {
|
|
3268
3495
|
if (!def.build) return true;
|
|
3269
|
-
const
|
|
3270
|
-
const arity = confirmedBuildArity(src);
|
|
3496
|
+
const arity = confirmedArityForDef(def);
|
|
3271
3497
|
if (arity === null) return true;
|
|
3272
3498
|
return arity >= 6;
|
|
3273
3499
|
}
|
|
@@ -3275,8 +3501,7 @@ function buildReadsState(def) {
|
|
|
3275
3501
|
// src/compiler/fields.ts
|
|
3276
3502
|
function buildReadsFields(def) {
|
|
3277
3503
|
if (!def.build) return true;
|
|
3278
|
-
const
|
|
3279
|
-
const arity = confirmedBuildArity(src);
|
|
3504
|
+
const arity = confirmedArityForDef(def);
|
|
3280
3505
|
if (arity === null) return true;
|
|
3281
3506
|
return arity >= 2;
|
|
3282
3507
|
}
|
|
@@ -3457,6 +3682,13 @@ function isCstChild(value) {
|
|
|
3457
3682
|
function missingInferredType() {
|
|
3458
3683
|
throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
|
|
3459
3684
|
}
|
|
3685
|
+
function normalizeBuildArity(arity) {
|
|
3686
|
+
if (arity === void 0) return void 0;
|
|
3687
|
+
if (!Number.isInteger(arity) || arity < 0 || arity > 6) {
|
|
3688
|
+
throw new Error("node() buildArity must be an integer 0..6 (children, fields, span, rawChildren, triviaLog, state)");
|
|
3689
|
+
}
|
|
3690
|
+
return arity;
|
|
3691
|
+
}
|
|
3460
3692
|
function normalizeProject(project) {
|
|
3461
3693
|
if (project === void 0) return void 0;
|
|
3462
3694
|
if (!Number.isInteger(project) || project < 0) {
|
|
@@ -3492,13 +3724,14 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
|
3492
3724
|
const captureTrivia = opts?.captureTrivia === true;
|
|
3493
3725
|
const trailingTrivia = opts?.trailingTrivia === true;
|
|
3494
3726
|
const tags = opts?.tags;
|
|
3727
|
+
const buildArity = normalizeBuildArity(opts?.buildArity);
|
|
3495
3728
|
if (unwrap && collapse) {
|
|
3496
3729
|
throw new Error("node() options cannot set both unwrap and collapse");
|
|
3497
3730
|
}
|
|
3498
3731
|
if (project !== void 0 && (unwrap || collapse)) {
|
|
3499
3732
|
throw new Error("node() options cannot combine project with unwrap or collapse");
|
|
3500
3733
|
}
|
|
3501
|
-
const def = unwrap || collapse || project !== void 0 || captureTrivia || trailingTrivia || tags !== void 0 && tags.length > 0 ? { ...baseDef, ...unwrap ? { unwrap: true } : {}, ...collapse ? { collapse: true } : {}, ...project !== void 0 ? { project } : {}, ...captureTrivia ? { captureTrivia: true } : {}, ...trailingTrivia ? { trailingTrivia: true } : {}, ...tags !== void 0 && tags.length > 0 ? { tags } : {} } : baseDef;
|
|
3734
|
+
const def = unwrap || collapse || project !== void 0 || captureTrivia || trailingTrivia || buildArity !== void 0 || tags !== void 0 && tags.length > 0 ? { ...baseDef, ...unwrap ? { unwrap: true } : {}, ...collapse ? { collapse: true } : {}, ...project !== void 0 ? { project } : {}, ...captureTrivia ? { captureTrivia: true } : {}, ...trailingTrivia ? { trailingTrivia: true } : {}, ...buildArity !== void 0 ? { buildArity } : {}, ...tags !== void 0 && tags.length > 0 ? { tags } : {} } : baseDef;
|
|
3502
3735
|
const capturesTrivia = captureTrivia || trailingTrivia || (build ? buildReadsTrivia(def) : project === void 0);
|
|
3503
3736
|
const clonesState = build ? buildReadsState(def) : project === void 0;
|
|
3504
3737
|
const hasOwnFields = parserHasOwnFields(combinator);
|
|
@@ -3544,7 +3777,7 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
|
3544
3777
|
const cstOutput = cstOutputHost(ctx.build);
|
|
3545
3778
|
const span = ctx.trackLines ? annotateSpanFromLineContext(r.span, ctx) : r.span;
|
|
3546
3779
|
const hostState = clonesState ? st : ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
|
|
3547
|
-
const built = unwrap && children2.length === 1 ? unwrapChild(children2[0]) : collapse && children2.length === 1 ? children2[0] : !build && project === void 0 && ctx.build?._parsemanCstCollapse && children2.length === 1 && rawChildren.length === 1 && ctx.build._parsemanCstCollapse(nodeType, children2[0], children2, rawChildren) ? children2[0] : project !== void 0 ? cstOutput && ctx.build ? ctx.build(nodeType, children2, fields, span, rawChildren, triviaLog, hostState, tags) : projectChild(children2, project, nodeType) : build ? cstOutput && ctx.build ? ctx.build(nodeType, children2, fields, span, rawChildren, triviaLog, hostState, tags) : build(children2, fields, span, rawChildren, triviaLog, st) : ctx.build ? ctx.build(nodeType, children2, fields, span, rawChildren, triviaLog, st, tags) : { _tag: "node", type: nodeType, span: ctx.trackLines ? { ...span } : { start: r.span.start, end: r.span.end }, state: st ?? null, children: children2 };
|
|
3780
|
+
const built = unwrap && children2.length === 1 ? unwrapChild(children2[0]) : collapse && children2.length === 1 ? children2[0] : (cstOutput || !build && project === void 0) && ctx.build?._parsemanCstCollapse && children2.length === 1 && rawChildren.length === 1 && ctx.build._parsemanCstCollapse(nodeType, children2[0], children2, rawChildren) ? children2[0] : project !== void 0 ? cstOutput && ctx.build ? ctx.build(nodeType, children2, fields, span, rawChildren, triviaLog, hostState, tags) : projectChild(children2, project, nodeType) : build ? cstOutput && ctx.build ? ctx.build(nodeType, children2, fields, span, rawChildren, triviaLog, hostState, tags) : build(children2, fields, span, rawChildren, triviaLog, st) : ctx.build ? ctx.build(nodeType, children2, fields, span, rawChildren, triviaLog, st, tags) : { _tag: "node", type: nodeType, span: ctx.trackLines ? { ...span } : { start: r.span.start, end: r.span.end }, state: st ?? null, children: children2 };
|
|
3548
3781
|
const rawEntry = isCstChild(built) ? built : { _tag: "leaf", value: typeof built === "string" ? built : typeof built === "object" && built !== null ? input.slice(r.span.start, r.span.end) : "", span };
|
|
3549
3782
|
if (saved.buf !== void 0 || saved.ch !== void 0) {
|
|
3550
3783
|
pushCstChild(ctx, built, rawEntry);
|
|
@@ -3739,7 +3972,7 @@ function leaf(root, fn) {
|
|
|
3739
3972
|
}
|
|
3740
3973
|
|
|
3741
3974
|
// src/version.ts
|
|
3742
|
-
var PARSEMAN_VERSION = "0.
|
|
3975
|
+
var PARSEMAN_VERSION = "0.45.0";
|
|
3743
3976
|
|
|
3744
3977
|
// src/cst/host-mode.ts
|
|
3745
3978
|
var FUSED_HOST_MODE = /* @__PURE__ */ Symbol.for("parseman.fusedHostMode");
|
|
@@ -4614,7 +4847,7 @@ function findDivergentSlot(members, shapeOf) {
|
|
|
4614
4847
|
const path = [];
|
|
4615
4848
|
const defs = [];
|
|
4616
4849
|
let cur = [...members];
|
|
4617
|
-
for (let
|
|
4850
|
+
for (let guard = 0; guard < 64; guard++) {
|
|
4618
4851
|
const d0 = cur[0]._def;
|
|
4619
4852
|
const kidLists = cur.map((c) => childrenOf2(c._def));
|
|
4620
4853
|
const arity = kidLists[0].length;
|
|
@@ -5573,7 +5806,15 @@ function children(def, winners) {
|
|
|
5573
5806
|
let resolved;
|
|
5574
5807
|
try {
|
|
5575
5808
|
resolved = def.thunk();
|
|
5576
|
-
} catch {
|
|
5809
|
+
} catch (e) {
|
|
5810
|
+
recordDegradation({
|
|
5811
|
+
code: "coverage-definitions-unavailable",
|
|
5812
|
+
severity: "warn",
|
|
5813
|
+
where: "<lazy rule reference>",
|
|
5814
|
+
subject: `unresolvable reference (${e.message})`,
|
|
5815
|
+
fellBackTo: "the coverage walk stopped at this reference, so every definition below it is ABSENT from the denominator \u2014 which raises the reported ratio rather than lowering it",
|
|
5816
|
+
otherwise: "the referenced rule and its whole subtree would contribute definitions"
|
|
5817
|
+
});
|
|
5577
5818
|
return [];
|
|
5578
5819
|
}
|
|
5579
5820
|
const name = resolved._ruleName;
|
|
@@ -7074,27 +7315,53 @@ function emitScannableTerminal(shape, c) {
|
|
|
7074
7315
|
}
|
|
7075
7316
|
|
|
7076
7317
|
// src/compiler/inline-build.ts
|
|
7077
|
-
var
|
|
7318
|
+
var ANN = String.raw`\s*\??\s*(?::[^,)=]+)?`;
|
|
7319
|
+
var ANY_P = String.raw`\w+${ANN}`;
|
|
7320
|
+
var MK_BUILD_RE = new RegExp(
|
|
7321
|
+
String.raw`^\(\s*(\w+)${ANN}\s*,\s*${ANY_P}\s*,\s*(\w+)${ANN}\s*,\s*(\w+)${ANN}\s*,\s*(\w+)${ANN}\s*\)\s*=>\s*mk\s*\(\s*(['"])([^'"]+)\5\s*,\s*\1\s*,\s*\3\s*,\s*\2\s*,\s*\4\s*\)\s*$`
|
|
7322
|
+
);
|
|
7078
7323
|
function escapeRegExp(s) {
|
|
7079
7324
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
7080
7325
|
}
|
|
7326
|
+
function identMkBuildRe(typeIdent) {
|
|
7327
|
+
return new RegExp(
|
|
7328
|
+
String.raw`^\(\s*(\w+)${ANN}\s*,\s*${ANY_P}\s*,\s*(\w+)${ANN}\s*,\s*(\w+)${ANN}\s*,\s*(\w+)${ANN}\s*\)\s*=>\s*(?:[\w$.]*\.)?mk\s*\(\s*${escapeRegExp(typeIdent)}\s*,\s*\1\s*,\s*\3\s*,\s*\2\s*,\s*\4\s*\)\s*$`
|
|
7329
|
+
);
|
|
7330
|
+
}
|
|
7081
7331
|
function looseMkBuildRe(type) {
|
|
7082
7332
|
return new RegExp(
|
|
7083
|
-
String.raw`^\(\s*(\w+)\s*,\s
|
|
7333
|
+
String.raw`^\(\s*(\w+)${ANN}\s*,\s*${ANY_P}\s*,\s*(\w+)${ANN}\s*,\s*(\w+)${ANN}\s*,\s*(\w+)${ANN}\s*\)\s*=>\s*.+\(\s*(['"])${escapeRegExp(type)}\5\s*,\s*\1\s*,\s*\3\s*,\s*\2\s*,\s*\4\s*\)\s*$`
|
|
7084
7334
|
);
|
|
7085
7335
|
}
|
|
7336
|
+
var LOOKS_LIKE_MK_RE = /=>\s*(?:[\w$.]*\.)?mk\s*\(/;
|
|
7086
7337
|
function analyzeMkInlineBuild(def) {
|
|
7087
7338
|
if (!def.build) return null;
|
|
7088
7339
|
if (def.type === void 0) return null;
|
|
7089
|
-
const src = (def
|
|
7340
|
+
const src = buildAnalysisSrc(def).trim();
|
|
7090
7341
|
const strict = src.match(MK_BUILD_RE);
|
|
7091
7342
|
if (strict) {
|
|
7092
7343
|
const mkType = strict[6];
|
|
7093
|
-
|
|
7344
|
+
if (mkType === def.type) return def.type;
|
|
7345
|
+
reportMkMiss(def.type, src, `it builds a "${mkType}" node, not "${def.type}"`);
|
|
7346
|
+
return null;
|
|
7094
7347
|
}
|
|
7095
7348
|
if (looseMkBuildRe(def.type).test(src)) return def.type;
|
|
7349
|
+
if (def.typeSrc !== void 0 && identMkBuildRe(def.typeSrc).test(src)) return def.type;
|
|
7350
|
+
if (LOOKS_LIKE_MK_RE.test(src)) {
|
|
7351
|
+
reportMkMiss(def.type, src, "its parameter list or argument order does not match `(children, fields, span, rawChildren, triviaLog) => mk(type, children, rawChildren, span, triviaLog)`");
|
|
7352
|
+
}
|
|
7096
7353
|
return null;
|
|
7097
7354
|
}
|
|
7355
|
+
function reportMkMiss(type, src, why) {
|
|
7356
|
+
recordDegradation({
|
|
7357
|
+
code: "mk-inline-missed",
|
|
7358
|
+
severity: "warn",
|
|
7359
|
+
where: `node("${type}")`,
|
|
7360
|
+
subject: `build reducer \`${src.split("\n")[0].slice(0, 80)}\``,
|
|
7361
|
+
fellBackTo: `looks like an inline-\`mk\` builder but ${why}, so every match pays a \`_build[n](...)\` call instead of an inlined object literal`,
|
|
7362
|
+
otherwise: "the node object would be constructed at the call site with no call frame"
|
|
7363
|
+
});
|
|
7364
|
+
}
|
|
7098
7365
|
function emitInlineMkNodeExpr(type, chV, rawV, spanExpr, tlV) {
|
|
7099
7366
|
return `{ _tag: 'node', type: ${JSON.stringify(type)}, span: ${spanExpr}, children: ${chV}, rawCount: ${rawV}.length, localTriviaLen: ${tlV}.length }`;
|
|
7100
7367
|
}
|
|
@@ -7277,10 +7544,34 @@ function leadingFirstSetRecipe(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
7277
7544
|
seen.delete(p);
|
|
7278
7545
|
}
|
|
7279
7546
|
}
|
|
7547
|
+
function tern(cond, whenTrue, whenFalse) {
|
|
7548
|
+
if (cond === "false") return whenFalse;
|
|
7549
|
+
if (cond === "true") return whenTrue;
|
|
7550
|
+
return `${cond} ? ${whenTrue} : ${whenFalse}`;
|
|
7551
|
+
}
|
|
7552
|
+
function notGate(cond) {
|
|
7553
|
+
if (cond === "false") return "true";
|
|
7554
|
+
if (cond === "true") return "false";
|
|
7555
|
+
return `!(${cond})`;
|
|
7556
|
+
}
|
|
7557
|
+
function orGate(a, b) {
|
|
7558
|
+
if (a === "false") return b;
|
|
7559
|
+
if (b === "false") return a;
|
|
7560
|
+
if (a === "true" || b === "true") return "true";
|
|
7561
|
+
return `${a} || ${b}`;
|
|
7562
|
+
}
|
|
7563
|
+
function andGate(a, b) {
|
|
7564
|
+
if (a === "false" || b === "false") return "false";
|
|
7565
|
+
if (a === "true") return b;
|
|
7566
|
+
if (b === "true") return a;
|
|
7567
|
+
return `${a} && ${b}`;
|
|
7568
|
+
}
|
|
7280
7569
|
var HOST_READS_DECL = "const _hostReads = (b, n) => { if (b === undefined) return false; let s; try { s = Function.prototype.toString.call(b) } catch (e) { return true } if (/\\barguments\\b/.test(s)) return true; const m = /^[^(]*\\(([\\s\\S]*?)\\)/.exec(s); if (m && /\\.\\.\\.|=/.test(m[1])) return true; return b.length > n }";
|
|
7570
|
+
var RAW_ENTRY_DECL = "const _rawEntry = (v, input, s, e, span) => (typeof v === 'object' && v !== null && (v._tag === 'node' || v._tag === 'leaf' || v._tag === 'parseError')) ? v : { _tag: 'leaf', value: typeof v === 'string' ? v : (typeof v === 'object' && v !== null ? input.slice(s, e) : ''), span: span ?? { start: s, end: e } }";
|
|
7281
7571
|
var LINE_TRACK_DECL = "const _trackLines = (_ctx, input, start, end) => { const from = _ctx._lineScannedTo ?? 0; if (end <= from) return; for (let i = from; i < end; i++) if (input.charCodeAt(i) === 10) _ctx._lineStarts.push(i + 1); _ctx._lineScannedTo = end }";
|
|
7282
7572
|
var LINE_SPAN_DECL = "const _lineCol = (_ctx, offset) => { const starts = _ctx._lineStarts; let lo = 0, hi = starts.length - 1; while (lo < hi) { const mid = (lo + hi + 1) >> 1; if (starts[mid] <= offset) lo = mid; else hi = mid - 1 } return [lo + 1, offset - starts[lo] + 1] }\nconst _spanLines = (_ctx, start, end) => { const s = _lineCol(_ctx, start), e = _lineCol(_ctx, end); return { start, end, startLine: s[0], startColumn: s[1], endLine: e[0], endColumn: e[1] } }";
|
|
7283
7573
|
var _loweringSink = null;
|
|
7574
|
+
var _inlineCapSink = null;
|
|
7284
7575
|
function hasSelectedRootTrivia(ctx) {
|
|
7285
7576
|
return ctx.rootTriviaClassified === true;
|
|
7286
7577
|
}
|
|
@@ -8029,9 +8320,11 @@ function emitSeqValues(def, ctx, pos) {
|
|
|
8029
8320
|
const markLog = v(ctx, "_mklg");
|
|
8030
8321
|
const markRootLog = hasSelectedRootTrivia(ctx) ? v(ctx, "_mkrlg") : null;
|
|
8031
8322
|
const scanEndV = v(ctx, "_sne");
|
|
8032
|
-
const
|
|
8323
|
+
const logV = v(ctx, "_tlg");
|
|
8324
|
+
const capArg = ctx.noHoist ? "0" : hasSelectedRootTrivia(ctx) ? `(${logV} !== undefined || _ctx._rootTriviaLog !== undefined) ? 2 : 0` : `${logV} !== undefined ? 2 : 0`;
|
|
8033
8325
|
stmts.push(
|
|
8034
|
-
`${ind(ctx)}const ${
|
|
8326
|
+
`${ind(ctx)}const ${logV} = _ctx._triviaLog`,
|
|
8327
|
+
`${ind(ctx)}const ${markLog} = ${logV} !== undefined ? ${logV}.length : 0`,
|
|
8035
8328
|
...markRootLog ? [`${ind(ctx)}const ${markRootLog} = _ctx._rootTriviaLog ? _ctx._rootTriviaLog.length : 0`] : [],
|
|
8036
8329
|
`${ind(ctx)}const ${scanEndV} = ${trivFn}(input, ${curV}, _ctx, ${capArg})`,
|
|
8037
8330
|
...emitLineTrack(ctx, curV, scanEndV)
|
|
@@ -8041,7 +8334,7 @@ function emitSeqValues(def, ctx, pos) {
|
|
|
8041
8334
|
const endAfterV = v(ctx, "_sea");
|
|
8042
8335
|
stmts.push(
|
|
8043
8336
|
`${ind(ctx)}const ${endAfterV} = ${r2.endVar}`,
|
|
8044
|
-
`${ind(ctx)}if (${endAfterV} > ${scanEndV}) ${curV} = ${endAfterV}; else { if (
|
|
8337
|
+
`${ind(ctx)}if (${endAfterV} > ${scanEndV}) ${curV} = ${endAfterV}; else { if (${logV} !== undefined && ${logV}.length !== ${markLog}) ${logV}.length = ${markLog};${markRootLog ? ` if (_ctx._rootTriviaLog && _ctx._rootTriviaLog.length !== ${markRootLog}) _ctx._rootTriviaLog.length = ${markRootLog};` : ""} }`
|
|
8045
8338
|
);
|
|
8046
8339
|
valueVars.push(r2.valueVar);
|
|
8047
8340
|
continue;
|
|
@@ -9113,9 +9406,18 @@ function emitPeek(def, ctx, pos) {
|
|
|
9113
9406
|
endVar: pos
|
|
9114
9407
|
};
|
|
9115
9408
|
}
|
|
9116
|
-
function emitRouted(ctx, pos) {
|
|
9409
|
+
function emitRouted(ctx, pos, def) {
|
|
9117
9410
|
const local = ctx.routedLocal;
|
|
9411
|
+
const fallback = def.fallback;
|
|
9118
9412
|
if (local !== void 0) {
|
|
9413
|
+
if (fallback !== void 0 && local.startVar !== pos) {
|
|
9414
|
+
return emitRoutedWithFallback(ctx, pos, fallback, {
|
|
9415
|
+
test: `${local.startVar} === ${pos}`,
|
|
9416
|
+
valExpr: local.valueVar,
|
|
9417
|
+
startExpr: local.startVar,
|
|
9418
|
+
endExpr: local.endVar
|
|
9419
|
+
});
|
|
9420
|
+
}
|
|
9119
9421
|
return {
|
|
9120
9422
|
stmts: [
|
|
9121
9423
|
...emitIfFail(ctx, `${local.startVar} !== ${pos}`, failBody(ctx, '"routed()"', pos)),
|
|
@@ -9126,9 +9428,19 @@ function emitRouted(ctx, pos) {
|
|
|
9126
9428
|
};
|
|
9127
9429
|
}
|
|
9128
9430
|
const item = v(ctx, "_rt");
|
|
9431
|
+
const read = `${ind(ctx)}const ${item} = _ctx._routed`;
|
|
9432
|
+
if (fallback !== void 0) {
|
|
9433
|
+
const r = emitRoutedWithFallback(ctx, pos, fallback, {
|
|
9434
|
+
test: `${item} !== undefined && ${item}.span.start === ${pos}`,
|
|
9435
|
+
valExpr: `${item}.value`,
|
|
9436
|
+
startExpr: `${item}.span.start`,
|
|
9437
|
+
endExpr: `${item}.span.end`
|
|
9438
|
+
});
|
|
9439
|
+
return { ...r, stmts: [read, ...r.stmts] };
|
|
9440
|
+
}
|
|
9129
9441
|
return {
|
|
9130
9442
|
stmts: [
|
|
9131
|
-
|
|
9443
|
+
read,
|
|
9132
9444
|
...emitIfFail(ctx, `${item} === undefined || ${item}.span.start !== ${pos}`, failBody(ctx, '"routed()"', pos)),
|
|
9133
9445
|
...emitLeafCapture(ctx, `${item}.value`, `${item}.span.start`, `${item}.span.end`)
|
|
9134
9446
|
],
|
|
@@ -9136,6 +9448,30 @@ function emitRouted(ctx, pos) {
|
|
|
9136
9448
|
endVar: `${item}.span.end`
|
|
9137
9449
|
};
|
|
9138
9450
|
}
|
|
9451
|
+
function emitRoutedWithFallback(ctx, pos, fallback, routed2) {
|
|
9452
|
+
const valV = v(ctx, "_rtv");
|
|
9453
|
+
const endV = v(ctx, "_rte");
|
|
9454
|
+
const i = ind(ctx);
|
|
9455
|
+
ctx.indent++;
|
|
9456
|
+
const capture = emitLeafCapture(ctx, routed2.valExpr, routed2.startExpr, routed2.endExpr);
|
|
9457
|
+
const fb = emit(fallback, ctx, pos);
|
|
9458
|
+
const inner = ind(ctx);
|
|
9459
|
+
ctx.indent--;
|
|
9460
|
+
return {
|
|
9461
|
+
stmts: [
|
|
9462
|
+
`${i}let ${valV}, ${endV}`,
|
|
9463
|
+
`${i}if (${routed2.test}) {`,
|
|
9464
|
+
...capture,
|
|
9465
|
+
`${inner}${valV} = ${routed2.valExpr}; ${endV} = ${routed2.endExpr}`,
|
|
9466
|
+
`${i}} else {`,
|
|
9467
|
+
...fb.stmts,
|
|
9468
|
+
`${inner}${valV} = ${fb.valueVar}; ${endV} = ${fb.endVar}`,
|
|
9469
|
+
`${i}}`
|
|
9470
|
+
],
|
|
9471
|
+
valueVar: valV,
|
|
9472
|
+
endVar: endV
|
|
9473
|
+
};
|
|
9474
|
+
}
|
|
9139
9475
|
function escapeTokenLiteral(value) {
|
|
9140
9476
|
return value.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&");
|
|
9141
9477
|
}
|
|
@@ -9317,22 +9653,16 @@ function emitNode(def, ctx, pos) {
|
|
|
9317
9653
|
const smk = structural ? v(ctx, "_smk") : null;
|
|
9318
9654
|
if (structural) ctx.needsHostReads = true;
|
|
9319
9655
|
const hostTriviaGate = `_ctx.build !== undefined && (_ctx.build._parsemanCaptureTrivia !== undefined ? _ctx.build._parsemanCaptureTrivia(${JSON.stringify(def.type)}) : (_ctx._pmCapTL ??= _hostReads(_ctx.build, 5)))`;
|
|
9320
|
-
const
|
|
9321
|
-
const
|
|
9322
|
-
const profileRecognizer = recV;
|
|
9323
|
-
const profileCapture = capV;
|
|
9324
|
-
const cstMode = ctx.hostMode === "cst";
|
|
9325
|
-
const directCstV = !structural && !cstMode && (!capturesChildren || !capturesRaw) ? v(ctx, "_dcst") : null;
|
|
9326
|
-
const directCstGate = directCstV === null ? "false" : profileCapture;
|
|
9656
|
+
const profileRecognizer = "false";
|
|
9657
|
+
const profileCapture = "false";
|
|
9327
9658
|
const structuralCapturesTrivia = structural && (def.captureTrivia === true || def.trailingTrivia === true);
|
|
9328
9659
|
const chNeededExpr = def.unwrap || def.collapse ? "true" : `(_ctx._pmReadsCh ??= (_ctx.build === undefined || _ctx.build._parsemanReadsChildren !== false || _ctx.build._parsemanCstCollapse !== undefined))`;
|
|
9329
|
-
const chAlloc = def.unwrap || def.collapse ?
|
|
9330
|
-
const
|
|
9331
|
-
|
|
9332
|
-
|
|
9333
|
-
` : ""}${i}const ${chV} = ${profileRecognizer} ? undefined : ${capturesChildren ? "[]" : `${directCstV} ? [] : undefined`}, ${rawV} = ${profileRecognizer} ? undefined : ${capturesRaw ? "[]" : `${directCstV} ? [] : undefined`}`;
|
|
9660
|
+
const chAlloc = def.unwrap || def.collapse ? tern(profileRecognizer, "undefined", "[]") : tern(profileRecognizer, "undefined", `${tern(orGate(profileCapture, chNeededExpr), "[]", "undefined")}`);
|
|
9661
|
+
const dcstAlloc = "undefined";
|
|
9662
|
+
const allocStmt = structural ? `${i}const ${capTLv} = ${andGate(notGate(profileRecognizer), orGate(profileCapture, structuralCapturesTrivia ? "true" : hostTriviaGate))}, ${capSTv} = ${andGate(notGate(orGate(profileRecognizer, profileCapture)), "(_ctx._pmCapST ??= (_ctx.build === undefined || _hostReads(_ctx.build, 6)))")}${capFv ? `, ${capFv} = ${andGate(notGate(profileRecognizer), orGate(profileCapture, "(_ctx.build !== undefined && _hostReads(_ctx.build, 2))"))}` : ""}
|
|
9663
|
+
${i}const ${chV} = ${chAlloc}, ${rawV} = ${tern(profileRecognizer, "undefined", "[]")}, ${tlV} = ${tern(profileRecognizer, "undefined", innerEnablesTriviaCapture ? "[]" : `${capTLv} ? [] : _EMPTY_TL`)}` : capturesTrivia ? `${i}const ${capTLv} = ${notGate(profileRecognizer)}, ${chV} = ${tern(profileRecognizer, "undefined", capturesChildren ? "[]" : dcstAlloc)}, ${rawV} = ${tern(profileRecognizer, "undefined", capturesRaw ? "[]" : dcstAlloc)}, ${tlV} = ${tern(profileRecognizer, "undefined", "[]")}` : `${i}const ${chV} = ${tern(profileRecognizer, "undefined", capturesChildren ? "[]" : dcstAlloc)}, ${rawV} = ${tern(profileRecognizer, "undefined", capturesRaw ? "[]" : dcstAlloc)}`;
|
|
9334
9664
|
const innerTl = structural || capturesTrivia ? structural && !innerEnablesTriviaCapture ? `${capTLv} ? ${tlV} : undefined` : tlV : "undefined";
|
|
9335
|
-
const fieldsOn = structural ? capFv ?? "false" :
|
|
9665
|
+
const fieldsOn = structural ? capFv ?? "false" : tern(profileRecognizer, "false", capturesFields ? "true" : "false");
|
|
9336
9666
|
const sf = hasFields ? v(ctx, "_sf") : null;
|
|
9337
9667
|
const fArr = hasFields ? v(ctx, "_fa") : null;
|
|
9338
9668
|
const fObj = hasFields ? v(ctx, "_fields") : "undefined";
|
|
@@ -9341,7 +9671,7 @@ ${i}const ${chV} = ${chAlloc}, ${rawV} = ${profileRecognizer} ? undefined : [],
|
|
|
9341
9671
|
const installTrivia = needsTriviaFrame ? `; _ctx.captureTrivia = ${capTLv ?? "false"}; _ctx._cstTriviaLog = ${innerTl}${smk ? `; _ctx._triviaCaptureMask = ${capTLv} && _ctx.build !== undefined && _ctx.build._parsemanTriviaKinds !== undefined ? _ctx.build._parsemanTriviaKinds(${JSON.stringify(def.type)}) : ${smk}` : ""}` : "";
|
|
9342
9672
|
const restoreTrivia = needsTriviaFrame ? `; _ctx.captureTrivia = ${st}; _ctx._cstTriviaLog = ${stl}${smk ? `; _ctx._triviaCaptureMask = ${smk}` : ""}` : "";
|
|
9343
9673
|
const preGuard = [];
|
|
9344
|
-
if (!ctx.recovery && !ctx.coverage &&
|
|
9674
|
+
if (!ctx.recovery && !ctx.coverage && needsFirstSetGuard(def.parser)) {
|
|
9345
9675
|
const gcV = v(ctx, "_ngc");
|
|
9346
9676
|
const gExp = armStaticExpected(ctx, def.parser);
|
|
9347
9677
|
const gFail = ctx.failLabel ? ctx.recordFail ? `{ _ctx._fe = ${pos}; _ctx._fx = ${gExp}; break ${ctx.failLabel} }` : `break ${ctx.failLabel}` : failReturnArr(ctx, gExp, pos);
|
|
@@ -9352,7 +9682,6 @@ ${i}const ${chV} = ${chAlloc}, ${rawV} = ${profileRecognizer} ? undefined : [],
|
|
|
9352
9682
|
}
|
|
9353
9683
|
const stmts = [
|
|
9354
9684
|
...preGuard,
|
|
9355
|
-
profHoist,
|
|
9356
9685
|
allocStmt,
|
|
9357
9686
|
`${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren${saveTrivia}${sf ? `, ${sf} = _ctx._fields` : ""}`,
|
|
9358
9687
|
`${i}_ctx._cstChildren = ${chV}; _ctx._cstLeaves = ${chV}; _ctx._cstRawChildren = ${rawV}${installTrivia}${sf ? `; _ctx._fields = ${fieldsOn} ? [] : undefined` : ""}`
|
|
@@ -9369,21 +9698,13 @@ ${i}const ${chV} = ${chAlloc}, ${rawV} = ${profileRecognizer} ? undefined : [],
|
|
|
9369
9698
|
}
|
|
9370
9699
|
stmts.push(`${i}_ctx._cstChildren = ${sc}; _ctx._cstLeaves = ${sl}; _ctx._cstRawChildren = ${sr}${restoreTrivia}${sf ? `; _ctx._fields = ${sf}` : ""}`);
|
|
9371
9700
|
stmts.push(...emitIfFail(ctx, `!${okVar}`, propagateFailBody(ctx)));
|
|
9372
|
-
stmts.push(
|
|
9373
|
-
`${i}if (_ctx._pmProfile) {`,
|
|
9374
|
-
`${i} _ctx._pmProfile.nodes++`,
|
|
9375
|
-
`${i} if (${profileCapture}) {`,
|
|
9376
|
-
`${i} _ctx._pmProfile.childSlots += ${chV}.length; _ctx._pmProfile.rawSlots += ${rawV}.length; _ctx._pmProfile.triviaSlots += ${tlV}.length${fArr ? `; _ctx._pmProfile.fieldSlots += ${fArr} ? ${fArr}.length : 0` : ""}`,
|
|
9377
|
-
`${i} }`,
|
|
9378
|
-
`${i}}`
|
|
9379
|
-
);
|
|
9380
9701
|
let stV = "undefined";
|
|
9381
9702
|
if (structural) {
|
|
9382
9703
|
stV = v(ctx, "_nst");
|
|
9383
9704
|
stmts.push(`${i}const ${stV} = ${capSTv} && _ctx.state !== undefined ? Object.assign({}, _ctx.state) : undefined`);
|
|
9384
9705
|
} else if (clonesState) {
|
|
9385
9706
|
stV = v(ctx, "_nst");
|
|
9386
|
-
stmts.push(`${i}const ${stV} =
|
|
9707
|
+
stmts.push(`${i}const ${stV} = ${andGate(notGate(orGate(profileRecognizer, profileCapture)), "_ctx.state !== undefined")} ? Object.assign({}, _ctx.state) : undefined`);
|
|
9387
9708
|
}
|
|
9388
9709
|
if (sf && fArr) {
|
|
9389
9710
|
const fe = v(ctx, "_fe");
|
|
@@ -9407,19 +9728,22 @@ ${i}const ${chV} = ${chAlloc}, ${rawV} = ${profileRecognizer} ? undefined : [],
|
|
|
9407
9728
|
if (ctx.lineTracking) stmts.push(`${i}const ${nodeSpanV} = ${nodeSpanExpr}`);
|
|
9408
9729
|
const buildExpr = structural ? `{ _tag: 'node', type: ${JSON.stringify(def.type)}, span: ${nodeSpanV}, state: ${stV} ?? null, children: ${chV} }` : mkType ? emitInlineMkNodeExpr(mkType, chV, rawV, nodeSpanV, tlV) : def.project !== void 0 ? emitNodeProjectExpr(def.type, def.project, chV) : `${buildRef(ctx)}[${buildIdx}](${chV}, ${fObj}, ${nodeSpanV}, ${rawV}, ${tlV}, ${stV})`;
|
|
9409
9730
|
const hostBuildArgs = `${JSON.stringify(def.type)}, ${chV}, ${fObj}, ${nodeSpanV}, ${rawV}, ${tlV}, ${stV}${def.tags !== void 0 && def.tags.length > 0 ? `, ${JSON.stringify(def.tags)}` : ""}`;
|
|
9410
|
-
const hostBuildExpr = `_ctx.
|
|
9731
|
+
const hostBuildExpr = `_ctx.build(${hostBuildArgs})`;
|
|
9411
9732
|
const ndExpr = structural ? `_ctx.build !== undefined ? (${hostBuildExpr}) : (${buildExpr})` : cstOut ? hostBuildExpr : buildExpr;
|
|
9412
|
-
const
|
|
9733
|
+
const hostCollapses = structural || cstOut;
|
|
9734
|
+
const hostCollapseExpr = hostCollapses ? `_ctx.build !== undefined && _ctx.build._parsemanCstCollapse !== undefined && ${chV}.length === 1 && ${rawV}.length === 1 && _ctx.build._parsemanCstCollapse(${JSON.stringify(def.type)}, ${chV}[0], ${chV}, ${rawV}) ? ${chV}[0] : (${ndExpr})` : ndExpr;
|
|
9413
9735
|
const unwrapExpr = `${chV}.length === 1 ? (${chV}[0] !== null && typeof ${chV}[0] === 'object' && ${chV}[0]._tag === 'leaf' ? ${chV}[0].value : ${chV}[0]) : (${ndExpr})`;
|
|
9414
9736
|
const collapseExpr = `${chV}.length === 1 ? ${chV}[0] : (${ndExpr})`;
|
|
9415
9737
|
const finalExpr = def.unwrap ? unwrapExpr : def.collapse ? collapseExpr : hostCollapseExpr;
|
|
9416
|
-
|
|
9417
|
-
|
|
9418
|
-
|
|
9419
|
-
|
|
9420
|
-
|
|
9421
|
-
|
|
9422
|
-
);
|
|
9738
|
+
const ndGate = orGate(profileRecognizer, profileCapture);
|
|
9739
|
+
const recGate = notGate(profileRecognizer);
|
|
9740
|
+
const pushIndent = recGate === "true" ? i : `${i} `;
|
|
9741
|
+
const pushCh = `${pushIndent}if (${sc}) ${sc}.push(${ndV})`;
|
|
9742
|
+
ctx.needsRawEntry = true;
|
|
9743
|
+
const pushRaw = `${pushIndent}if (${sr}) ${sr}.push(_rawEntry(${ndV}, input, ${pos}, ${endVar}${ctx.lineTracking ? `, ${nodeSpanV}` : ""}))`;
|
|
9744
|
+
stmts.push(`${i}const ${ndV} = ${tern(ndGate, "undefined", `(${finalExpr})`)}`);
|
|
9745
|
+
if (recGate === "true") stmts.push(pushCh, pushRaw);
|
|
9746
|
+
else stmts.push(`${i}if (${recGate}) {`, pushCh, pushRaw, `${i}}`);
|
|
9423
9747
|
return { stmts, valueVar: ndV, endVar };
|
|
9424
9748
|
}
|
|
9425
9749
|
function emitRuntimeFallback(parser2, ctx, pos) {
|
|
@@ -9448,7 +9772,12 @@ function emitLazy(p, def, ctx, pos) {
|
|
|
9448
9772
|
} catch {
|
|
9449
9773
|
return emitRuntimeFallback(p, ctx, pos);
|
|
9450
9774
|
}
|
|
9451
|
-
|
|
9775
|
+
const cost = usage.sizes.get(resolved) ?? 1;
|
|
9776
|
+
if (cost <= ctx.inlineLeft) {
|
|
9777
|
+
ctx.inlineLeft -= cost;
|
|
9778
|
+
return emit(resolved, ctx, pos);
|
|
9779
|
+
}
|
|
9780
|
+
_inlineCapSink?.push({ fn: ctx.currentFnName ?? "<root>", nodes: cost });
|
|
9452
9781
|
}
|
|
9453
9782
|
if (!ctx.namedParsers.has(p)) {
|
|
9454
9783
|
const fnName2 = canonical2 ?? `${nsp(ctx)}_pf${ctx.namedParsers.size}`;
|
|
@@ -9463,6 +9792,9 @@ function emitLazy(p, def, ctx, pos) {
|
|
|
9463
9792
|
const savedIndent = ctx.indent;
|
|
9464
9793
|
const savedFailLabel = ctx.failLabel;
|
|
9465
9794
|
const savedRecord = ctx.recordFail;
|
|
9795
|
+
const savedInlineLeft = ctx.inlineLeft, savedFnName = ctx.currentFnName;
|
|
9796
|
+
ctx.inlineLeft = ctx.inlineMax;
|
|
9797
|
+
ctx.currentFnName = fnName2;
|
|
9466
9798
|
const failureRuleId = p === ctx.coverage?.entry ? void 0 : ctx.coverage?.plan.rules.get(p) ?? ctx.coverage?.plan.rules.get(resolved);
|
|
9467
9799
|
const savedActiveRule = ctx.activeCoverageRuleId;
|
|
9468
9800
|
const savedSuppressFailure = ctx.suppressCoverageFailure;
|
|
@@ -9477,6 +9809,8 @@ function emitLazy(p, def, ctx, pos) {
|
|
|
9477
9809
|
ctx.indent = savedIndent;
|
|
9478
9810
|
ctx.failLabel = savedFailLabel;
|
|
9479
9811
|
ctx.recordFail = savedRecord;
|
|
9812
|
+
ctx.inlineLeft = savedInlineLeft;
|
|
9813
|
+
ctx.currentFnName = savedFnName;
|
|
9480
9814
|
ctx.activeCoverageRuleId = savedActiveRule;
|
|
9481
9815
|
ctx.suppressCoverageFailure = savedSuppressFailure;
|
|
9482
9816
|
pushNamedFnDecl(ctx, fnName2, r.stmts, r.valueVar, r.endVar, failureRuleId);
|
|
@@ -9571,6 +9905,9 @@ function emit(p, ctx, pos) {
|
|
|
9571
9905
|
const savedIndent = ctx.indent;
|
|
9572
9906
|
const savedFailLabel = ctx.failLabel;
|
|
9573
9907
|
const savedRecord = ctx.recordFail;
|
|
9908
|
+
const savedInlineLeft = ctx.inlineLeft, savedFnName = ctx.currentFnName;
|
|
9909
|
+
ctx.inlineLeft = ctx.inlineMax;
|
|
9910
|
+
ctx.currentFnName = fnName;
|
|
9574
9911
|
ctx.indent = 1;
|
|
9575
9912
|
ctx.failLabel = "_pfail";
|
|
9576
9913
|
ctx.recordFail = true;
|
|
@@ -9578,6 +9915,8 @@ function emit(p, ctx, pos) {
|
|
|
9578
9915
|
ctx.indent = savedIndent;
|
|
9579
9916
|
ctx.failLabel = savedFailLabel;
|
|
9580
9917
|
ctx.recordFail = savedRecord;
|
|
9918
|
+
ctx.inlineLeft = savedInlineLeft;
|
|
9919
|
+
ctx.currentFnName = savedFnName;
|
|
9581
9920
|
pushNamedFnDecl(ctx, fnName, r.stmts, r.valueVar, r.endVar);
|
|
9582
9921
|
return instrument(emitNamedFnCall(ctx, fnName, pos));
|
|
9583
9922
|
}
|
|
@@ -9771,7 +10110,7 @@ function emitDispatch(p, ctx, pos) {
|
|
|
9771
10110
|
case "peek":
|
|
9772
10111
|
return emitPeek(def, ctx, pos);
|
|
9773
10112
|
case "routed":
|
|
9774
|
-
return emitRouted(ctx, pos);
|
|
10113
|
+
return emitRouted(ctx, pos, def);
|
|
9775
10114
|
case "node":
|
|
9776
10115
|
return emitNode(def, ctx, pos);
|
|
9777
10116
|
case "scanTo":
|
|
@@ -9806,6 +10145,9 @@ function emitDispatch(p, ctx, pos) {
|
|
|
9806
10145
|
const savedIndent = ctx.indent;
|
|
9807
10146
|
const savedFailLabel = ctx.failLabel;
|
|
9808
10147
|
const savedRecord = ctx.recordFail;
|
|
10148
|
+
const savedInlineLeft = ctx.inlineLeft, savedFnName = ctx.currentFnName;
|
|
10149
|
+
ctx.inlineLeft = ctx.inlineMax;
|
|
10150
|
+
ctx.currentFnName = fnName;
|
|
9809
10151
|
ctx.indent = 1;
|
|
9810
10152
|
ctx.failLabel = "_pfail";
|
|
9811
10153
|
ctx.recordFail = true;
|
|
@@ -9813,6 +10155,8 @@ function emitDispatch(p, ctx, pos) {
|
|
|
9813
10155
|
ctx.indent = savedIndent;
|
|
9814
10156
|
ctx.failLabel = savedFailLabel;
|
|
9815
10157
|
ctx.recordFail = savedRecord;
|
|
10158
|
+
ctx.inlineLeft = savedInlineLeft;
|
|
10159
|
+
ctx.currentFnName = savedFnName;
|
|
9816
10160
|
pushNamedFnDecl(ctx, fnName, innerR.stmts, innerR.valueVar, innerR.endVar);
|
|
9817
10161
|
}
|
|
9818
10162
|
const fn = ctx.namedParsers.get(innerParser);
|
|
@@ -9971,12 +10315,16 @@ function childrenOf3(def) {
|
|
|
9971
10315
|
return [def.parser, def.sentinel];
|
|
9972
10316
|
case "scanTo":
|
|
9973
10317
|
return [def.sentinel, ...def.skip];
|
|
10318
|
+
// A `routed()` fallback IS emitted at this site (emitRouted), so the usage
|
|
10319
|
+
// analysis must see the edge — otherwise a fallback shared by several routed()
|
|
10320
|
+
// sites is miscounted as single-use and inlined at each.
|
|
10321
|
+
case "routed":
|
|
10322
|
+
return def.fallback ? [def.fallback] : [];
|
|
9974
10323
|
case "lazy":
|
|
9975
10324
|
case "literal":
|
|
9976
10325
|
case "regex":
|
|
9977
10326
|
case "keywords":
|
|
9978
10327
|
case "guard":
|
|
9979
|
-
case "routed":
|
|
9980
10328
|
case "unknown":
|
|
9981
10329
|
return [];
|
|
9982
10330
|
}
|
|
@@ -9997,6 +10345,17 @@ function isHoistableTag(tag) {
|
|
|
9997
10345
|
return HOISTABLE_TAGS.has(tag);
|
|
9998
10346
|
}
|
|
9999
10347
|
var HOIST_MIN_SUBTREE = 3;
|
|
10348
|
+
var INLINE_MAX_NODES = 1e3;
|
|
10349
|
+
function resolveInlineMax(explicit) {
|
|
10350
|
+
if (explicit !== void 0) return explicit;
|
|
10351
|
+
const env = typeof process !== "undefined" ? process.env?.PARSEMAN_MAX_INLINE : void 0;
|
|
10352
|
+
if (env !== void 0 && env !== "") {
|
|
10353
|
+
if (env === "off" || env === "infinity") return Infinity;
|
|
10354
|
+
const n = Number(env);
|
|
10355
|
+
if (Number.isFinite(n) && n >= 0) return n;
|
|
10356
|
+
}
|
|
10357
|
+
return INLINE_MAX_NODES;
|
|
10358
|
+
}
|
|
10000
10359
|
function analyzeLazyUsage(root) {
|
|
10001
10360
|
return analyzeLazyUsageMulti([root]);
|
|
10002
10361
|
}
|
|
@@ -10102,102 +10461,6 @@ function ruleDependencies(ruleMap) {
|
|
|
10102
10461
|
}
|
|
10103
10462
|
return deps;
|
|
10104
10463
|
}
|
|
10105
|
-
function resolveGatingLevel(opt) {
|
|
10106
|
-
const explicit = typeof opt === "string" ? opt : opt?.level;
|
|
10107
|
-
if (explicit !== void 0) return explicit;
|
|
10108
|
-
const env = typeof process !== "undefined" ? process.env?.PARSEMAN_GATING : void 0;
|
|
10109
|
-
if (env === "off" || env === "warn" || env === "error") return env;
|
|
10110
|
-
return "warn";
|
|
10111
|
-
}
|
|
10112
|
-
function runGatingDiagnostic(combinator, opt) {
|
|
10113
|
-
return reportGating(opt, (o) => analyzeGating(combinator, o));
|
|
10114
|
-
}
|
|
10115
|
-
function runGatingDiagnosticRules(ruleMap, opt) {
|
|
10116
|
-
return reportGating(opt, (o) => analyzeGatingRules(ruleMap, o));
|
|
10117
|
-
}
|
|
10118
|
-
function runFusedGatingDiagnostic(getRuleMaps, opt, getOpaque) {
|
|
10119
|
-
if (resolveGatingLevel(opt) === "off") return void 0;
|
|
10120
|
-
const ruleMaps = getRuleMaps();
|
|
10121
|
-
const opaque = getOpaque?.() ?? [];
|
|
10122
|
-
const opaqueFindings = opaque.map((o) => ({
|
|
10123
|
-
rule: o.ruleNames.length > 0 ? o.ruleNames.join(", ") : `<artifact ${o.ns}>`,
|
|
10124
|
-
kind: "opaque-artifact",
|
|
10125
|
-
reason: `precompiled artifact "${o.ns}" carries compiled rule functions, not re-lowerable IR \u2014 its choices were not examined at this fuse.`
|
|
10126
|
-
}));
|
|
10127
|
-
if (!ruleMaps.some((map) => hasExternalRuleRef(map))) {
|
|
10128
|
-
if (opaqueFindings.length === 0) return void 0;
|
|
10129
|
-
return reportGating(opt, () => ({
|
|
10130
|
-
totalChoices: 0,
|
|
10131
|
-
gated: 0,
|
|
10132
|
-
recoverable: 0,
|
|
10133
|
-
unanalysable: opaqueFindings,
|
|
10134
|
-
ungated: [],
|
|
10135
|
-
accepted: [],
|
|
10136
|
-
deferred: [],
|
|
10137
|
-
acceptedUnused: [],
|
|
10138
|
-
choices: [],
|
|
10139
|
-
antiPatterns: []
|
|
10140
|
-
}));
|
|
10141
|
-
}
|
|
10142
|
-
const winners = /* @__PURE__ */ new Map();
|
|
10143
|
-
for (const map of ruleMaps) for (const [name, rule] of map) {
|
|
10144
|
-
if (rule._def.tag === "lazy") {
|
|
10145
|
-
try {
|
|
10146
|
-
rule._def.thunk();
|
|
10147
|
-
} catch {
|
|
10148
|
-
continue;
|
|
10149
|
-
}
|
|
10150
|
-
}
|
|
10151
|
-
winners.set(name, rule);
|
|
10152
|
-
}
|
|
10153
|
-
const entries = [...winners];
|
|
10154
|
-
return reportGating(opt, (o) => {
|
|
10155
|
-
const deferredHere = new Set(analyzeGatingRules(entries, o).deferred.map((c) => c.id));
|
|
10156
|
-
const fused = analyzeGatingRules(entries, { ...o, resolveRef: (name) => winners.get(name) });
|
|
10157
|
-
return {
|
|
10158
|
-
...fused,
|
|
10159
|
-
ungated: fused.ungated.filter((c) => deferredHere.has(c.id)),
|
|
10160
|
-
antiPatterns: [],
|
|
10161
|
-
unanalysable: [...fused.unanalysable, ...opaqueFindings]
|
|
10162
|
-
};
|
|
10163
|
-
});
|
|
10164
|
-
}
|
|
10165
|
-
function reportGating(opt, analyze) {
|
|
10166
|
-
const level = resolveGatingLevel(opt);
|
|
10167
|
-
if (level === "off") return void 0;
|
|
10168
|
-
const obj = opt !== null && typeof opt === "object" ? opt : void 0;
|
|
10169
|
-
const analyzeOpts = obj?.accept !== void 0 || obj?.entryName !== void 0 ? { ...obj.accept !== void 0 ? { accept: obj.accept } : {}, ...obj.entryName !== void 0 ? { entryName: obj.entryName } : {} } : void 0;
|
|
10170
|
-
let report;
|
|
10171
|
-
try {
|
|
10172
|
-
report = analyze(analyzeOpts);
|
|
10173
|
-
} catch (e) {
|
|
10174
|
-
const reason = e instanceof Error ? `${e.name}: ${e.message}` : String(e);
|
|
10175
|
-
const failed = {
|
|
10176
|
-
totalChoices: 0,
|
|
10177
|
-
gated: 0,
|
|
10178
|
-
recoverable: 0,
|
|
10179
|
-
unanalysable: [{ rule: "<whole grammar>", kind: "not-a-combinator", reason: `gating analysis threw \u2014 ${reason}` }],
|
|
10180
|
-
ungated: [],
|
|
10181
|
-
accepted: [],
|
|
10182
|
-
deferred: [],
|
|
10183
|
-
acceptedUnused: [],
|
|
10184
|
-
choices: [],
|
|
10185
|
-
antiPatterns: []
|
|
10186
|
-
};
|
|
10187
|
-
const failLines = formatGatingWarnings(failed);
|
|
10188
|
-
if (level === "error") throw new Error(`parseman: gating analysis FAILED (no verdict available)
|
|
10189
|
-
${failLines.join("\n")}`);
|
|
10190
|
-
for (const l of failLines) console.warn(l);
|
|
10191
|
-
return failed;
|
|
10192
|
-
}
|
|
10193
|
-
const lines = formatGatingWarnings(report);
|
|
10194
|
-
if (lines.length > 0) {
|
|
10195
|
-
if (level === "error") throw new Error(`parseman: ${report.ungated.length} ungated hot choice(s) / ${report.antiPatterns.length} anti-pattern(s) / ${report.unanalysable.length} unanalysable rule(s)
|
|
10196
|
-
${lines.join("\n")}`);
|
|
10197
|
-
for (const l of lines) console.warn(l);
|
|
10198
|
-
}
|
|
10199
|
-
return report;
|
|
10200
|
-
}
|
|
10201
10464
|
function resolveDuplicationLevel(opt) {
|
|
10202
10465
|
const explicit = typeof opt === "string" ? opt : opt?.level;
|
|
10203
10466
|
if (explicit !== void 0) return explicit;
|
|
@@ -10240,7 +10503,17 @@ function runDuplicationDiagnosticRules(ruleMap, opt) {
|
|
|
10240
10503
|
return reportDuplication(opt, (o) => analyzeDuplicationRules(ruleMap, o));
|
|
10241
10504
|
}
|
|
10242
10505
|
function compile(combinator, mapFnSources, opts) {
|
|
10243
|
-
const
|
|
10506
|
+
const drain = beginCompileDegradationDrain();
|
|
10507
|
+
let completed = false;
|
|
10508
|
+
try {
|
|
10509
|
+
const compiled = compileImpl(combinator, mapFnSources, opts);
|
|
10510
|
+
completed = true;
|
|
10511
|
+
return compiled;
|
|
10512
|
+
} finally {
|
|
10513
|
+
drain(completed);
|
|
10514
|
+
}
|
|
10515
|
+
}
|
|
10516
|
+
function compileImpl(combinator, mapFnSources, opts) {
|
|
10244
10517
|
runDuplicationDiagnostic(combinator, opts?.duplication);
|
|
10245
10518
|
markUnusedValues(combinator);
|
|
10246
10519
|
const grammarTrivia = combinator._meta.grammarTrivia;
|
|
@@ -10248,9 +10521,12 @@ function compile(combinator, mapFnSources, opts) {
|
|
|
10248
10521
|
const grammarScanSkip = combinator._meta.grammarScanSkip;
|
|
10249
10522
|
const grammarHostMode = combinator._meta.grammarHostMode;
|
|
10250
10523
|
const grammarTrackLines = combinator._meta.grammarTrackLines;
|
|
10524
|
+
const _inlineMax = resolveInlineMax(opts?.maxInline);
|
|
10251
10525
|
const ctx = {
|
|
10252
10526
|
vars: 0,
|
|
10253
10527
|
indent: 1,
|
|
10528
|
+
inlineMax: _inlineMax,
|
|
10529
|
+
inlineLeft: _inlineMax,
|
|
10254
10530
|
regexDecls: [],
|
|
10255
10531
|
regexMap: /* @__PURE__ */ new Map(),
|
|
10256
10532
|
expectedDecls: [],
|
|
@@ -10296,11 +10572,13 @@ function compile(combinator, mapFnSources, opts) {
|
|
|
10296
10572
|
const namedPrelude = ctx.namedFnDecls.length > 0 ? [...namedFnPrelude(), ""] : [];
|
|
10297
10573
|
const emptyTlDecls = ctx.needsEmptyTl ? ["const _EMPTY_TL = Object.freeze([])"] : [];
|
|
10298
10574
|
const hostReadsDecls = ctx.needsHostReads ? [HOST_READS_DECL] : [];
|
|
10575
|
+
const rawEntryDecls = ctx.needsRawEntry ? [RAW_ENTRY_DECL] : [];
|
|
10299
10576
|
const lineTrackDecls = ctx.needsLineTrack ? [LINE_TRACK_DECL] : [];
|
|
10300
10577
|
const lineSpanDecls = ctx.needsLineSpan ? [LINE_SPAN_DECL] : [];
|
|
10301
10578
|
const source = [
|
|
10302
10579
|
...emptyTlDecls,
|
|
10303
10580
|
...hostReadsDecls,
|
|
10581
|
+
...rawEntryDecls,
|
|
10304
10582
|
...lineTrackDecls,
|
|
10305
10583
|
...lineSpanDecls,
|
|
10306
10584
|
...ctx.regexDecls,
|
|
@@ -10315,6 +10593,7 @@ function compile(combinator, mapFnSources, opts) {
|
|
|
10315
10593
|
const fn = new Function("input", "_pos", "_rp", "_mf", "_build", "_ctx", [
|
|
10316
10594
|
...emptyTlDecls,
|
|
10317
10595
|
...hostReadsDecls,
|
|
10596
|
+
...rawEntryDecls,
|
|
10318
10597
|
...lineTrackDecls,
|
|
10319
10598
|
...lineSpanDecls,
|
|
10320
10599
|
...ctx.regexDecls,
|
|
@@ -10364,8 +10643,7 @@ function compile(combinator, mapFnSources, opts) {
|
|
|
10364
10643
|
const compiledMeta = {
|
|
10365
10644
|
source,
|
|
10366
10645
|
inlineExpression,
|
|
10367
|
-
...ctx.coverage === void 0 ? {} : { coverageDefinitions: ctx.coverage.plan.definitions }
|
|
10368
|
-
...gatingReport === void 0 ? {} : { gating: gatingReport }
|
|
10646
|
+
...ctx.coverage === void 0 ? {} : { coverageDefinitions: ctx.coverage.plan.definitions }
|
|
10369
10647
|
};
|
|
10370
10648
|
if (!ctx.lineTracking) {
|
|
10371
10649
|
return {
|
|
@@ -10431,7 +10709,6 @@ function publicRuleWrapperSource(rule, fnSource, ambientTriviaKindLabels, ambien
|
|
|
10431
10709
|
}
|
|
10432
10710
|
function compileLinkable(ruleMapArg, ns, opts) {
|
|
10433
10711
|
if (!ns) throw new Error("compileLinkable: ns must be a non-empty namespace");
|
|
10434
|
-
if (opts?.gating !== void 0) runGatingDiagnosticRules(ruleMapArg, opts.gating);
|
|
10435
10712
|
if (opts?.duplication !== void 0) runDuplicationDiagnosticRules(ruleMapArg, opts.duplication);
|
|
10436
10713
|
for (const [, rule] of ruleMapArg) markUnusedValues(rule);
|
|
10437
10714
|
const grammarTrivia = opts?.trivia ?? ruleMapArg.map(([, r]) => r._meta.grammarTrivia).find(Boolean);
|
|
@@ -10450,9 +10727,12 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
10450
10727
|
}
|
|
10451
10728
|
});
|
|
10452
10729
|
const nodeMeta = new Map(ruleMap.map(([name, rule]) => [name, collectGrammarReflection([[name, rule]], { followLazy: false })]));
|
|
10730
|
+
const _inlineMax = resolveInlineMax(opts?.maxInline);
|
|
10453
10731
|
const ctx = {
|
|
10454
10732
|
vars: 0,
|
|
10455
10733
|
indent: 1,
|
|
10734
|
+
inlineMax: _inlineMax,
|
|
10735
|
+
inlineLeft: _inlineMax,
|
|
10456
10736
|
regexDecls: [],
|
|
10457
10737
|
regexMap: /* @__PURE__ */ new Map(),
|
|
10458
10738
|
expectedDecls: [],
|
|
@@ -10548,6 +10828,9 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
10548
10828
|
}
|
|
10549
10829
|
}
|
|
10550
10830
|
const savedIndent = ctx.indent, savedFail = ctx.failLabel, savedRec = ctx.recordFail;
|
|
10831
|
+
const savedInlineLeft = ctx.inlineLeft, savedFnName = ctx.currentFnName;
|
|
10832
|
+
ctx.inlineLeft = ctx.inlineMax;
|
|
10833
|
+
ctx.currentFnName = fn;
|
|
10551
10834
|
ctx.indent = 1;
|
|
10552
10835
|
ctx.failLabel = "_pfail";
|
|
10553
10836
|
ctx.recordFail = true;
|
|
@@ -10563,6 +10846,8 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
10563
10846
|
ctx.indent = savedIndent;
|
|
10564
10847
|
ctx.failLabel = savedFail;
|
|
10565
10848
|
ctx.recordFail = savedRec;
|
|
10849
|
+
ctx.inlineLeft = savedInlineLeft;
|
|
10850
|
+
ctx.currentFnName = savedFnName;
|
|
10566
10851
|
const ruleId = ctx.coverage?.plan.rules.get(rule);
|
|
10567
10852
|
const stmts = ruleId === void 0 ? body.stmts : [
|
|
10568
10853
|
`${ind(ctx)}_ctx._grammarCoverage?.(${JSON.stringify(ruleId)})`,
|
|
@@ -10647,6 +10932,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
10647
10932
|
deps: ruleDependencies(ruleMap),
|
|
10648
10933
|
needsEmptyTl: !!ctx.needsEmptyTl,
|
|
10649
10934
|
needsHostReads: !!ctx.needsHostReads,
|
|
10935
|
+
needsRawEntry: !!ctx.needsRawEntry,
|
|
10650
10936
|
hostMode: ctx.hostMode ?? "ast",
|
|
10651
10937
|
hostBranchElided: !!ctx.hostBranchElided,
|
|
10652
10938
|
hasDirectBuilders: ruleMap.some(([, rule]) => hasDirectBuildDef(rule)),
|
|
@@ -10656,26 +10942,6 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
10656
10942
|
buildFns: buildSrcs ? [] : ctx.buildFns
|
|
10657
10943
|
};
|
|
10658
10944
|
}
|
|
10659
|
-
function hasExternalRuleRef(ruleMap) {
|
|
10660
|
-
const seen = /* @__PURE__ */ new Set();
|
|
10661
|
-
const visit = (p) => {
|
|
10662
|
-
if (seen.has(p)) return false;
|
|
10663
|
-
seen.add(p);
|
|
10664
|
-
const def = p._def;
|
|
10665
|
-
if (def.tag === "lazy") {
|
|
10666
|
-
let resolved;
|
|
10667
|
-
try {
|
|
10668
|
-
resolved = def.thunk();
|
|
10669
|
-
} catch {
|
|
10670
|
-
resolved = void 0;
|
|
10671
|
-
}
|
|
10672
|
-
if (resolved === void 0) return p._ruleName !== void 0;
|
|
10673
|
-
return visit(resolved);
|
|
10674
|
-
}
|
|
10675
|
-
return childrenOf3(def).some(visit);
|
|
10676
|
-
};
|
|
10677
|
-
return ruleMap.some(([, rule]) => visit(rule));
|
|
10678
|
-
}
|
|
10679
10945
|
function hasSemanticReduction(roots, externalRefs) {
|
|
10680
10946
|
const seen = /* @__PURE__ */ new Set();
|
|
10681
10947
|
const visit = (parser2) => {
|
|
@@ -10721,14 +10987,16 @@ function buildInlineExpression(ctx, r, mapFnSources, buildSources, coverageRootR
|
|
|
10721
10987
|
const buildDecl = buildSources?.length ? ` const _build = [${buildSources.join(", ")}]` : "";
|
|
10722
10988
|
const emptyTlDecl = ctx.needsEmptyTl ? ` const _EMPTY_TL = Object.freeze([])` : "";
|
|
10723
10989
|
const hostReadsDecl = ctx.needsHostReads ? ` ${HOST_READS_DECL}` : "";
|
|
10990
|
+
const rawEntryDecl = ctx.needsRawEntry ? ` ${RAW_ENTRY_DECL}` : "";
|
|
10724
10991
|
const lineTrackDecl = ctx.needsLineTrack ? ` ${LINE_TRACK_DECL}` : "";
|
|
10725
10992
|
const lineSpanDecl = ctx.needsLineSpan ? ` ${LINE_SPAN_DECL}` : "";
|
|
10726
|
-
const needsWrapper = ctx.regexDecls.length > 0 || ctx.expectedDecls.length > 0 || ctx.namedFnDecls.length > 0 || !!mfDecl || !!buildDecl || !!emptyTlDecl || !!hostReadsDecl || !!lineTrackDecl || !!lineSpanDecl;
|
|
10993
|
+
const needsWrapper = ctx.regexDecls.length > 0 || ctx.expectedDecls.length > 0 || ctx.namedFnDecls.length > 0 || !!mfDecl || !!buildDecl || !!emptyTlDecl || !!hostReadsDecl || !!rawEntryDecl || !!lineTrackDecl || !!lineSpanDecl;
|
|
10727
10994
|
if (!needsWrapper) return innerFn;
|
|
10728
10995
|
const namedPrelude = ctx.namedFnDecls.length > 0 ? namedFnPrelude() : [];
|
|
10729
10996
|
const hoistedDecls = [
|
|
10730
10997
|
emptyTlDecl,
|
|
10731
10998
|
hostReadsDecl,
|
|
10999
|
+
rawEntryDecl,
|
|
10732
11000
|
lineTrackDecl,
|
|
10733
11001
|
lineSpanDecl,
|
|
10734
11002
|
...ctx.regexDecls.map((d) => ` ${d}`),
|
|
@@ -10798,11 +11066,12 @@ function childrenOf4(def) {
|
|
|
10798
11066
|
return [def.main, def.skipped];
|
|
10799
11067
|
case "scanTo":
|
|
10800
11068
|
return [def.sentinel, ...def.skip];
|
|
11069
|
+
case "routed":
|
|
11070
|
+
return def.fallback ? [def.fallback] : [];
|
|
10801
11071
|
case "lazy":
|
|
10802
11072
|
case "literal":
|
|
10803
11073
|
case "regex":
|
|
10804
11074
|
case "keywords":
|
|
10805
|
-
case "routed":
|
|
10806
11075
|
case "guard":
|
|
10807
11076
|
case "recover":
|
|
10808
11077
|
case "unknown":
|
|
@@ -10884,7 +11153,7 @@ function evalRuleMapIR(ir) {
|
|
|
10884
11153
|
l._def.fnSrc = src;
|
|
10885
11154
|
return l;
|
|
10886
11155
|
};
|
|
10887
|
-
const _nd = (type, child, src, opts, staticError) => {
|
|
11156
|
+
const _nd = (type, child, src, opts, staticError, sigSrc) => {
|
|
10888
11157
|
if (staticError !== void 0 && staticError.length > 0) {
|
|
10889
11158
|
throw new Error(`IR direct node builder for ${type} must be macro-static and self-contained; unsupported binding(s): ${staticError.join(", ")}`);
|
|
10890
11159
|
}
|
|
@@ -10893,6 +11162,7 @@ function evalRuleMapIR(ir) {
|
|
|
10893
11162
|
}), opts);
|
|
10894
11163
|
n._def.buildSrc = src;
|
|
10895
11164
|
if (staticError !== void 0) n._def.buildStaticError = staticError;
|
|
11165
|
+
if (sigSrc !== void 0) n._def.buildSigSrc = sigSrc;
|
|
10896
11166
|
return n;
|
|
10897
11167
|
};
|
|
10898
11168
|
const _gch = (items) => {
|
|
@@ -11205,7 +11475,7 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
11205
11475
|
case "peek":
|
|
11206
11476
|
return `peek(${kid(def.parser)})`;
|
|
11207
11477
|
case "routed":
|
|
11208
|
-
return "routed()"
|
|
11478
|
+
return def.fallback === void 0 ? "routed()" : `routed(${kid(def.fallback)})`;
|
|
11209
11479
|
case "trivia":
|
|
11210
11480
|
return `trivia(${kid(def.parser)})`;
|
|
11211
11481
|
case "token":
|
|
@@ -11238,6 +11508,9 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
11238
11508
|
...projectEntry === void 0 ? [] : [projectEntry],
|
|
11239
11509
|
...def.captureTrivia ? ["captureTrivia: true"] : [],
|
|
11240
11510
|
...def.trailingTrivia ? ["trailingTrivia: true"] : [],
|
|
11511
|
+
// Declared or resolved arity. Carried so a re-lowered composed artifact does
|
|
11512
|
+
// not silently re-acquire the fail-open capture cost this module resolved away.
|
|
11513
|
+
...def.buildArity === void 0 ? [] : [`buildArity: ${def.buildArity}`],
|
|
11241
11514
|
...tagEntry === void 0 ? [] : [tagEntry]
|
|
11242
11515
|
];
|
|
11243
11516
|
const opts = optEntries.length > 0 ? `, { ${optEntries.join(", ")} }` : "";
|
|
@@ -11246,8 +11519,14 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
11246
11519
|
return opts ? `node(${kid(def.parser)}, undefined${opts})` : `node(${kid(def.parser)})`;
|
|
11247
11520
|
}
|
|
11248
11521
|
if (def.buildSrc !== void 0) {
|
|
11249
|
-
const
|
|
11250
|
-
|
|
11522
|
+
const tail = [];
|
|
11523
|
+
if (def.buildStaticError !== void 0 || def.buildSigSrc !== void 0) {
|
|
11524
|
+
if (!opts) tail.push("undefined");
|
|
11525
|
+
tail.push(def.buildStaticError === void 0 ? "undefined" : JSON.stringify(def.buildStaticError));
|
|
11526
|
+
}
|
|
11527
|
+
if (def.buildSigSrc !== void 0) tail.push(JSON.stringify(def.buildSigSrc));
|
|
11528
|
+
const trailing = tail.length > 0 ? `, ${tail.join(", ")}` : "";
|
|
11529
|
+
return `_nd(${JSON.stringify(def.type)}, ${kid(def.parser)}, ${JSON.stringify(def.buildSrc)}${opts}${trailing})`;
|
|
11251
11530
|
}
|
|
11252
11531
|
return opts ? `node(${JSON.stringify(def.type)}, ${kid(def.parser)}, undefined${opts})` : `node(${JSON.stringify(def.type)}, ${kid(def.parser)})`;
|
|
11253
11532
|
}
|
|
@@ -11328,12 +11607,14 @@ function fusedBody(pieces) {
|
|
|
11328
11607
|
const contributingPieces = [...contributing];
|
|
11329
11608
|
const needsEmptyTl = contributingPieces.some((p) => p.needsEmptyTl);
|
|
11330
11609
|
const needsHostReads = contributingPieces.some((p) => p.needsHostReads);
|
|
11610
|
+
const needsRawEntry = contributingPieces.some((p) => p.needsRawEntry);
|
|
11331
11611
|
const lines = [
|
|
11332
11612
|
// Shared sentinel protocol (must match NAMED_FN_FAIL / NAMED_FN_END in codegen).
|
|
11333
11613
|
"const _pfFail = {}",
|
|
11334
11614
|
"let _pfEnd",
|
|
11335
11615
|
...needsEmptyTl ? ["const _EMPTY_TL = Object.freeze([])"] : [],
|
|
11336
11616
|
...needsHostReads ? [HOST_READS_DECL] : [],
|
|
11617
|
+
...needsRawEntry ? [RAW_ENTRY_DECL] : [],
|
|
11337
11618
|
// Each contributing artifact's namespaced private prelude (regexes, _pf, …).
|
|
11338
11619
|
...new Set(contributingPieces.flatMap((p) => p.prelude)),
|
|
11339
11620
|
// The winning `_r_<Name>` function for each rule (one per name → no redeclare).
|
|
@@ -11449,17 +11730,6 @@ var COMPOSED_COVERAGE_RULES = /* @__PURE__ */ Symbol.for("parseman.composedCover
|
|
|
11449
11730
|
function isIRPiece(p) {
|
|
11450
11731
|
return !!p && typeof p === "object" && typeof p.ir === "string" && typeof p.ns === "string" && !("ruleFns" in p);
|
|
11451
11732
|
}
|
|
11452
|
-
function once(fn) {
|
|
11453
|
-
let done = false;
|
|
11454
|
-
let value;
|
|
11455
|
-
return () => {
|
|
11456
|
-
if (!done) {
|
|
11457
|
-
value = fn();
|
|
11458
|
-
done = true;
|
|
11459
|
-
}
|
|
11460
|
-
return value;
|
|
11461
|
-
};
|
|
11462
|
-
}
|
|
11463
11733
|
function carriedRuleMapsDetailed(carried) {
|
|
11464
11734
|
const maps = [];
|
|
11465
11735
|
const opaque = [];
|
|
@@ -11576,12 +11846,6 @@ function compose(items, opts) {
|
|
|
11576
11846
|
const used = /* @__PURE__ */ new Set();
|
|
11577
11847
|
const trivia2 = composingTriviaOf(items);
|
|
11578
11848
|
const carried = items.flatMap((item) => itemCarried(item, used, trivia2, opts?.hostMode));
|
|
11579
|
-
const detailed = once(() => carriedRuleMapsDetailed(carried));
|
|
11580
|
-
runFusedGatingDiagnostic(
|
|
11581
|
-
() => detailed().maps,
|
|
11582
|
-
void 0,
|
|
11583
|
-
() => detailed().opaque
|
|
11584
|
-
);
|
|
11585
11849
|
const pieces = carried.map((p) => materializePiece(p, trivia2, false, opts?.hostMode));
|
|
11586
11850
|
const map = fuseRules(pieces);
|
|
11587
11851
|
Object.defineProperty(map, COMPOSED_PIECES, { value: carried, enumerable: false });
|
|
@@ -11608,9 +11872,175 @@ function analyzeGrammarGating(grammar, opts) {
|
|
|
11608
11872
|
kind: "opaque-artifact",
|
|
11609
11873
|
reason: `precompiled artifact "${o.ns}" carries compiled rule functions, not re-lowerable IR \u2014 its choices cannot be examined. Recompile the contributing grammar so it carries IR (the macro emits IR by default) to bring it back into analysis.`
|
|
11610
11874
|
}));
|
|
11875
|
+
for (const o of opaque) {
|
|
11876
|
+
recordDegradation({
|
|
11877
|
+
code: "opaque-artifact",
|
|
11878
|
+
// `info`, not `warn`: the artifact is usually someone else's package, so the author
|
|
11879
|
+
// of THIS grammar has nothing to act on — but the blind spot still has to be counted.
|
|
11880
|
+
severity: "info",
|
|
11881
|
+
where: o.ruleNames.length > 0 ? o.ruleNames.join(", ") : `<artifact ${o.ns}>`,
|
|
11882
|
+
subject: `precompiled artifact "${o.ns}"`,
|
|
11883
|
+
fellBackTo: `it carries compiled rule functions rather than re-lowerable IR, so its ${o.ruleNames.length > 0 ? `${o.ruleNames.length} rule(s)` : "rules"} were NOT analysed and a clean gating report must not be read as a pass`,
|
|
11884
|
+
otherwise: "its choices would be walked like any other rule. Recompile the contributing grammar so it carries IR (the macro emits IR by default)"
|
|
11885
|
+
});
|
|
11886
|
+
}
|
|
11611
11887
|
return fromOpaque.length === 0 ? report : { ...report, unanalysable: [...report.unanalysable, ...fromOpaque] };
|
|
11612
11888
|
}
|
|
11613
11889
|
|
|
11890
|
+
// src/analysis/diagnose.ts
|
|
11891
|
+
var isCombinator = (g) => typeof g === "object" && g !== null && "_def" in g;
|
|
11892
|
+
var isRuleEntries = (g) => Array.isArray(g);
|
|
11893
|
+
function diagnoseGrammar(grammar, opts) {
|
|
11894
|
+
const depth = degradationCaptureDepth();
|
|
11895
|
+
beginDegradationCapture();
|
|
11896
|
+
let report;
|
|
11897
|
+
let degradations;
|
|
11898
|
+
try {
|
|
11899
|
+
report = runAnalysis(grammar, opts);
|
|
11900
|
+
} catch (e) {
|
|
11901
|
+
const reason = e instanceof Error ? `${e.name}: ${e.message}` : String(e);
|
|
11902
|
+
report = emptyReport(`gating analysis threw \u2014 ${reason}`);
|
|
11903
|
+
} finally {
|
|
11904
|
+
degradations = unwindDegradationCapture(depth);
|
|
11905
|
+
}
|
|
11906
|
+
return assemble(report, degradations);
|
|
11907
|
+
}
|
|
11908
|
+
function formatGrammarDiagnosis(d) {
|
|
11909
|
+
const s = d.summary;
|
|
11910
|
+
const lines = [];
|
|
11911
|
+
lines.push(
|
|
11912
|
+
d.ok ? `parseman: grammar OK \u2014 ${s.gated}/${s.totalChoices} choice(s) gate on first char${s.recoverable > 0 ? `, ${s.recoverable} recoverable` : ""}${s.accepted > 0 ? `, ${s.accepted} accepted` : ""}${s.deferred > 0 ? `, ${s.deferred} deferred to the fusing artifact` : ""}.` : `parseman: grammar NOT OK \u2014 ${blockingOf(d).length} blocking finding(s) over ${s.totalChoices} examined choice(s).`
|
|
11913
|
+
);
|
|
11914
|
+
if (s.unanalysable > 0) {
|
|
11915
|
+
lines.push(
|
|
11916
|
+
` ${s.unanalysable} rule(s) UNANALYSABLE \u2014 THIS REPORT IS PARTIAL. An empty finding list below does NOT mean the grammar is clean.`
|
|
11917
|
+
);
|
|
11918
|
+
}
|
|
11919
|
+
for (const f of d.findings) {
|
|
11920
|
+
lines.push(`${f.severity === "blocking" ? "\u2717" : "\xB7"} [${f.code}] ${f.id}: ${f.message}`);
|
|
11921
|
+
for (const detail of f.details) lines.push(` ${detail.replace(/\n/g, "\n ")}`);
|
|
11922
|
+
if (f.acceptKey !== void 0) {
|
|
11923
|
+
lines.push(` intentional? add to the gating snapshot: { accept: ['${f.acceptKey}'] }`);
|
|
11924
|
+
}
|
|
11925
|
+
}
|
|
11926
|
+
if (!d.ok && d.acceptSnapshot.length > 0) {
|
|
11927
|
+
lines.push(` accept-all snapshot: { accept: [${d.acceptSnapshot.map((i) => `'${i}'`).join(", ")}] }`);
|
|
11928
|
+
}
|
|
11929
|
+
return lines;
|
|
11930
|
+
}
|
|
11931
|
+
function runAnalysis(grammar, opts) {
|
|
11932
|
+
if (isCombinator(grammar)) return analyzeGating(grammar, opts);
|
|
11933
|
+
if (isRuleEntries(grammar)) return analyzeGatingRules(grammar, opts);
|
|
11934
|
+
return analyzeGrammarGating(grammar, opts);
|
|
11935
|
+
}
|
|
11936
|
+
function emptyReport(reason) {
|
|
11937
|
+
return {
|
|
11938
|
+
totalChoices: 0,
|
|
11939
|
+
gated: 0,
|
|
11940
|
+
recoverable: 0,
|
|
11941
|
+
unanalysable: [{ rule: "<whole grammar>", kind: "not-a-combinator", reason }],
|
|
11942
|
+
ungated: [],
|
|
11943
|
+
accepted: [],
|
|
11944
|
+
deferred: [],
|
|
11945
|
+
acceptedUnused: [],
|
|
11946
|
+
choices: [],
|
|
11947
|
+
antiPatterns: []
|
|
11948
|
+
};
|
|
11949
|
+
}
|
|
11950
|
+
var blockingOf = (d) => d.findings.filter((f) => f.severity === "blocking");
|
|
11951
|
+
var SEVERITY_RANK = { blocking: 0, advisory: 1 };
|
|
11952
|
+
var CODE_RANK = {
|
|
11953
|
+
unanalysable: 0,
|
|
11954
|
+
"ungated-choice": 1,
|
|
11955
|
+
"anti-pattern": 2,
|
|
11956
|
+
degraded: 3,
|
|
11957
|
+
"stale-accept": 4
|
|
11958
|
+
};
|
|
11959
|
+
function assemble(report, degradations) {
|
|
11960
|
+
const findings = [];
|
|
11961
|
+
for (const u of report.unanalysable) {
|
|
11962
|
+
findings.push({
|
|
11963
|
+
id: u.rule,
|
|
11964
|
+
code: "unanalysable",
|
|
11965
|
+
severity: "blocking",
|
|
11966
|
+
rule: u.rule,
|
|
11967
|
+
message: `could not be examined [${u.kind}] \u2014 no verdict about it is available`,
|
|
11968
|
+
details: [u.reason]
|
|
11969
|
+
});
|
|
11970
|
+
}
|
|
11971
|
+
for (const c of report.ungated) {
|
|
11972
|
+
findings.push({
|
|
11973
|
+
id: c.id,
|
|
11974
|
+
code: "ungated-choice",
|
|
11975
|
+
severity: "blocking",
|
|
11976
|
+
rule: c.rule,
|
|
11977
|
+
message: `choice is UNGATED [${c.strategy}] \u2014 no first-char dispatch; every position speculatively enters doomed arms`,
|
|
11978
|
+
details: [
|
|
11979
|
+
...c.anyArms.map((a) => `arm[${a.index}] first-set ANY (${a.cause}): ${a.detail}
|
|
11980
|
+
fix: ${a.suggestion}`),
|
|
11981
|
+
...c.overlaps.map((o) => `arm[${o.a}] \u2229 arm[${o.b}] overlap on ${firstSetToString(o.on)}
|
|
11982
|
+
fix: ${o.suggestion}`)
|
|
11983
|
+
],
|
|
11984
|
+
acceptKey: c.id
|
|
11985
|
+
});
|
|
11986
|
+
}
|
|
11987
|
+
for (const ap of report.antiPatterns) {
|
|
11988
|
+
findings.push({
|
|
11989
|
+
id: `${ap.rule}#arm${ap.armIndex}`,
|
|
11990
|
+
code: "anti-pattern",
|
|
11991
|
+
severity: "blocking",
|
|
11992
|
+
rule: ap.rule,
|
|
11993
|
+
message: `[${ap.kind}] ${ap.message}`,
|
|
11994
|
+
details: []
|
|
11995
|
+
});
|
|
11996
|
+
}
|
|
11997
|
+
for (const d of degradations) {
|
|
11998
|
+
findings.push({
|
|
11999
|
+
// `where` + `code` is the degradation channel's own identity; reuse it so the two
|
|
12000
|
+
// surfaces name the same thing the same way.
|
|
12001
|
+
id: `${d.code}@${d.where}`,
|
|
12002
|
+
code: "degraded",
|
|
12003
|
+
// Mirrors `DegradationSeverity`: 'warn' is a real cost the author can remove,
|
|
12004
|
+
// 'info' is a fact they cannot act on (someone else's package).
|
|
12005
|
+
severity: d.severity === "warn" ? "blocking" : "advisory",
|
|
12006
|
+
rule: d.where,
|
|
12007
|
+
message: formatDegradation(d),
|
|
12008
|
+
details: []
|
|
12009
|
+
});
|
|
12010
|
+
}
|
|
12011
|
+
for (const id of report.acceptedUnused) {
|
|
12012
|
+
findings.push({
|
|
12013
|
+
id,
|
|
12014
|
+
code: "stale-accept",
|
|
12015
|
+
severity: "advisory",
|
|
12016
|
+
rule: id,
|
|
12017
|
+
message: "accept entry matched no ungated choice \u2014 the grammar was fixed; prune this line",
|
|
12018
|
+
details: []
|
|
12019
|
+
});
|
|
12020
|
+
}
|
|
12021
|
+
findings.sort((a, b) => SEVERITY_RANK[a.severity] - SEVERITY_RANK[b.severity] || CODE_RANK[a.code] - CODE_RANK[b.code] || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
|
|
12022
|
+
return {
|
|
12023
|
+
schema: "parseman.diagnosis/1",
|
|
12024
|
+
ok: !findings.some((f) => f.severity === "blocking"),
|
|
12025
|
+
summary: {
|
|
12026
|
+
totalChoices: report.totalChoices,
|
|
12027
|
+
gated: report.gated,
|
|
12028
|
+
recoverable: report.recoverable,
|
|
12029
|
+
ungated: report.ungated.length,
|
|
12030
|
+
accepted: report.accepted.length,
|
|
12031
|
+
deferred: report.deferred.length,
|
|
12032
|
+
antiPatterns: report.antiPatterns.length,
|
|
12033
|
+
unanalysable: report.unanalysable.length,
|
|
12034
|
+
degraded: degradations.length,
|
|
12035
|
+
staleAccepts: report.acceptedUnused.length
|
|
12036
|
+
},
|
|
12037
|
+
findings,
|
|
12038
|
+
acceptSnapshot: report.ungated.map((c) => c.id).sort(),
|
|
12039
|
+
gating: report,
|
|
12040
|
+
degradations
|
|
12041
|
+
};
|
|
12042
|
+
}
|
|
12043
|
+
|
|
11614
12044
|
// src/combinators/gate.ts
|
|
11615
12045
|
function gate(predicate) {
|
|
11616
12046
|
const meta = {
|
|
@@ -11630,9 +12060,6 @@ function gate(predicate) {
|
|
|
11630
12060
|
};
|
|
11631
12061
|
}
|
|
11632
12062
|
|
|
11633
|
-
// src/combinators/guard.ts
|
|
11634
|
-
var guard = gate;
|
|
11635
|
-
|
|
11636
12063
|
// src/combinators/completions.ts
|
|
11637
12064
|
function completionsAt(target, input, offset, options = {}) {
|
|
11638
12065
|
const probe = { offset, best: null };
|
|
@@ -11859,9 +12286,9 @@ function parseMiddle(input, reStart, reEnd, cStart, ruleFn, separator, build, to
|
|
|
11859
12286
|
const ctx = mkCtx(null, build, tolerant);
|
|
11860
12287
|
const out = [];
|
|
11861
12288
|
let pos = reStart;
|
|
11862
|
-
let
|
|
12289
|
+
let guard = 0;
|
|
11863
12290
|
while (pos < reEnd) {
|
|
11864
|
-
if (++
|
|
12291
|
+
if (++guard > reEnd - reStart + 2) return null;
|
|
11865
12292
|
if (separator && out.length > 0 && out[out.length - 1]._tag === "node") {
|
|
11866
12293
|
if (pos + separator.length > reEnd || !input.startsWith(separator, pos)) return null;
|
|
11867
12294
|
out.push({ _tag: "leaf", value: separator, span: { start: pos - cStart, end: pos + separator.length - cStart } });
|
|
@@ -12154,6 +12581,35 @@ function parseDoc(registry, rootRule, input, opts = {}) {
|
|
|
12154
12581
|
}
|
|
12155
12582
|
|
|
12156
12583
|
// src/functional/run.ts
|
|
12584
|
+
var SELECT_EXAMPLE = "run(entry, input, { rootTrivia: { select: ['blockComment', 'lineComment'] } })";
|
|
12585
|
+
var REMOVED_RUN_RESULT_FIELDS = [
|
|
12586
|
+
[
|
|
12587
|
+
"triviaMap",
|
|
12588
|
+
`It was a dense root-trivia index built on every parse; root trivia is now an OPT-IN sparse capture, because most grammars paid for an index they never read. Migration: name the trivia labels your grammar defines \u2014 ${SELECT_EXAMPLE} \u2014 and read \`RunResult.rootTrivia\`, whose \`.index\` carries the labels and gap lookups \`triviaMap\` exposed.`
|
|
12589
|
+
],
|
|
12590
|
+
[
|
|
12591
|
+
"triviaLog",
|
|
12592
|
+
`It was the flat \`start, end[, kindIndex]\` log every other trivia view was derived from, and it is no longer allocated at all \u2014 not empty, absent. Migration: request the labels you need \u2014 ${SELECT_EXAMPLE} \u2014 and read \`RunResult.rootTrivia.rows\`. Do NOT reuse a stride-2/3 reader: rows are a different width and a different unit (one row per SELECTED marker, not one per trivia chunk), so an old loop reads confidently wrong offsets rather than failing.`
|
|
12593
|
+
],
|
|
12594
|
+
[
|
|
12595
|
+
"triviaKindLabels",
|
|
12596
|
+
`It was already optional, so nothing ever flagged its disappearance \u2014 and \`triviaKindMask(undefined, \u2026)\` means "capture everything", so reading it now silently WIDENS capture instead of erroring. Migration: request labels \u2014 ${SELECT_EXAMPLE} \u2014 then the set you asked for is \`RunResult.rootTrivia.select\` and the resolved table is \`RunResult.rootTrivia.index.labels\`.`
|
|
12597
|
+
]
|
|
12598
|
+
];
|
|
12599
|
+
function guardRemovedFields(result) {
|
|
12600
|
+
for (const [name, detail] of REMOVED_RUN_RESULT_FIELDS) {
|
|
12601
|
+
Object.defineProperty(result, name, {
|
|
12602
|
+
configurable: true,
|
|
12603
|
+
enumerable: false,
|
|
12604
|
+
get() {
|
|
12605
|
+
throw new TypeError(
|
|
12606
|
+
`RunResult.${name} was REMOVED in parseman 0.44.0 and has no default replacement. ${detail}`
|
|
12607
|
+
);
|
|
12608
|
+
}
|
|
12609
|
+
});
|
|
12610
|
+
}
|
|
12611
|
+
return result;
|
|
12612
|
+
}
|
|
12157
12613
|
var invoke = (r, input, pos, ctx) => typeof r === "function" ? r(input, pos, ctx) : r.parse(input, pos, ctx);
|
|
12158
12614
|
function triviaKindLabelsFromRunnable(r) {
|
|
12159
12615
|
if (!r) return void 0;
|
|
@@ -12256,37 +12712,11 @@ function runOnce(entry, input, options, phase, profileState) {
|
|
|
12256
12712
|
unconsumedFrom
|
|
12257
12713
|
};
|
|
12258
12714
|
}
|
|
12259
|
-
function clonePassState(state) {
|
|
12260
|
-
if (state === null || typeof state !== "object") return state;
|
|
12261
|
-
return Array.isArray(state) ? [...state] : { ...state };
|
|
12262
|
-
}
|
|
12263
|
-
function profilePass(entry, input, options, phase) {
|
|
12264
|
-
const state = { phase, nodes: 0, childSlots: 0, rawSlots: 0, triviaSlots: 0, fieldSlots: 0, hostCalls: 0 };
|
|
12265
|
-
const passOptions = options.state === void 0 ? options : { ...options, state: clonePassState(options.state) };
|
|
12266
|
-
const start = performance.now();
|
|
12267
|
-
const result = runOnce(entry, input, passOptions, phase, state);
|
|
12268
|
-
const { phase: _phase, ...counts } = state;
|
|
12269
|
-
return { result, profile: { ms: performance.now() - start, ...counts } };
|
|
12270
|
-
}
|
|
12271
12715
|
function run(entry, input, options = {}) {
|
|
12272
|
-
if (!options.profile) return runOnce(entry, input, options);
|
|
12273
|
-
|
|
12274
|
-
|
|
12275
|
-
|
|
12276
|
-
const recognizer = profilePass(entry, input, options, "recognizer");
|
|
12277
|
-
const capture = profilePass(entry, input, options, "capture");
|
|
12278
|
-
const host = profilePass(entry, input, options, "host");
|
|
12279
|
-
if (recognizer.result.ok !== host.result.ok || capture.result.ok !== host.result.ok || recognizer.result.unconsumedFrom !== host.result.unconsumedFrom || capture.result.unconsumedFrom !== host.result.unconsumedFrom) {
|
|
12280
|
-
throw new Error("run({ profile: true }) changed recognition; the grammar is not profile-safe");
|
|
12281
|
-
}
|
|
12282
|
-
return {
|
|
12283
|
-
...host.result,
|
|
12284
|
-
profile: {
|
|
12285
|
-
recognizer: recognizer.profile,
|
|
12286
|
-
structuralCapture: capture.profile,
|
|
12287
|
-
hostConstruction: host.profile
|
|
12288
|
-
}
|
|
12289
|
-
};
|
|
12716
|
+
if (!options.profile) return guardRemovedFields(runOnce(entry, input, options));
|
|
12717
|
+
throw new TypeError(
|
|
12718
|
+
"run({ profile: true }) is unavailable: profiling counters are no longer compiled into parser artifacts, and the interpreter does not implement them yet. Profiling is moving to interpreted mode."
|
|
12719
|
+
);
|
|
12290
12720
|
}
|
|
12291
12721
|
|
|
12292
12722
|
// src/coverage.ts
|
|
@@ -12303,7 +12733,7 @@ function dispatchMatcher(entry) {
|
|
|
12303
12733
|
var GRAMMAR_COVERAGE_DEFINITIONS = /* @__PURE__ */ Symbol.for("parseman.grammarCoverageDefinitions");
|
|
12304
12734
|
function compiledGrammarCoverageDefinitions(grammar) {
|
|
12305
12735
|
const definitions = grammar[GRAMMAR_COVERAGE_DEFINITIONS];
|
|
12306
|
-
if (!Array.isArray(definitions) || !definitions.every((definition) => typeof definition === "object" && definition !== null && typeof definition.id === "string" && (definition.kind === "rule" || definition.kind === "choice-arm" || definition.kind === "dispatch-arm" || definition.kind === "label"))) {
|
|
12736
|
+
if (!Array.isArray(definitions) || definitions.length === 0 || !definitions.every((definition) => typeof definition === "object" && definition !== null && typeof definition.id === "string" && (definition.kind === "rule" || definition.kind === "choice-arm" || definition.kind === "dispatch-arm" || definition.kind === "label"))) {
|
|
12307
12737
|
throw new TypeError("grammar has no coverage definitions; enable grammarCoverage for this macro build");
|
|
12308
12738
|
}
|
|
12309
12739
|
return definitions;
|
|
@@ -12357,7 +12787,13 @@ function createGrammarCoverageCollector(definitions) {
|
|
|
12357
12787
|
snapshot() {
|
|
12358
12788
|
const hitList = [...hits].sort();
|
|
12359
12789
|
const unhit = ordered.map((definition) => definition.id).filter((id) => !hits.has(id));
|
|
12360
|
-
return {
|
|
12790
|
+
return {
|
|
12791
|
+
definitions: ordered,
|
|
12792
|
+
hits: hitList,
|
|
12793
|
+
unhit,
|
|
12794
|
+
ratio: hitList.length / ordered.length,
|
|
12795
|
+
measurable: ordered.length > 0
|
|
12796
|
+
};
|
|
12361
12797
|
},
|
|
12362
12798
|
reset() {
|
|
12363
12799
|
hits.clear();
|
|
@@ -12677,13 +13113,13 @@ function buildTriviaIndex(root, input = "", opts) {
|
|
|
12677
13113
|
}
|
|
12678
13114
|
|
|
12679
13115
|
// src/cst/walk.ts
|
|
12680
|
-
function
|
|
13116
|
+
function isCombinator2(value) {
|
|
12681
13117
|
return !!value && typeof value === "object" && "_def" in value && "_meta" in value && typeof value.parse === "function";
|
|
12682
13118
|
}
|
|
12683
13119
|
function reflectionFor(grammar) {
|
|
12684
13120
|
const stamped = grammarReflectionOf(grammar);
|
|
12685
13121
|
if (stamped) return stamped;
|
|
12686
|
-
const entries = Object.entries(grammar).filter((entry) =>
|
|
13122
|
+
const entries = Object.entries(grammar).filter((entry) => isCombinator2(entry[1]));
|
|
12687
13123
|
return collectGrammarReflection(entries);
|
|
12688
13124
|
}
|
|
12689
13125
|
function createVisitor(grammar, spec) {
|
|
@@ -12721,201 +13157,10 @@ function createVisitor(grammar, spec) {
|
|
|
12721
13157
|
};
|
|
12722
13158
|
}
|
|
12723
13159
|
|
|
12724
|
-
// src/cst/offset-model.ts
|
|
12725
|
-
var { isFinite } = Number;
|
|
12726
|
-
function floorIndex(arr, len, x) {
|
|
12727
|
-
let lo = 0;
|
|
12728
|
-
let hi = len - 1;
|
|
12729
|
-
let ans = -1;
|
|
12730
|
-
while (lo <= hi) {
|
|
12731
|
-
const mid = lo + hi >>> 1;
|
|
12732
|
-
if (arr[mid] <= x) {
|
|
12733
|
-
ans = mid;
|
|
12734
|
-
lo = mid + 1;
|
|
12735
|
-
} else {
|
|
12736
|
-
hi = mid - 1;
|
|
12737
|
-
}
|
|
12738
|
-
}
|
|
12739
|
-
return ans;
|
|
12740
|
-
}
|
|
12741
|
-
var OffsetIndex = class {
|
|
12742
|
-
/** Slot starts, sorted ascending. Parallel to `_ends`. */
|
|
12743
|
-
_starts;
|
|
12744
|
-
_ends;
|
|
12745
|
-
count;
|
|
12746
|
-
docStart;
|
|
12747
|
-
docEnd;
|
|
12748
|
-
constructor(slots, docStart = 0, docEnd) {
|
|
12749
|
-
const sorted = [...slots].sort((a, b) => a.start - b.start);
|
|
12750
|
-
const starts = [];
|
|
12751
|
-
const ends = [];
|
|
12752
|
-
let prevEnd = docStart;
|
|
12753
|
-
for (const s of sorted) {
|
|
12754
|
-
if (!isFinite(s.start) || !isFinite(s.end) || s.end < s.start) {
|
|
12755
|
-
throw new RangeError(`OffsetIndex: invalid slot [${s.start}, ${s.end}]`);
|
|
12756
|
-
}
|
|
12757
|
-
if (s.start < prevEnd) {
|
|
12758
|
-
throw new RangeError(`OffsetIndex: overlapping/out-of-order slot [${s.start}, ${s.end}] after end ${prevEnd}`);
|
|
12759
|
-
}
|
|
12760
|
-
starts.push(s.start);
|
|
12761
|
-
ends.push(s.end);
|
|
12762
|
-
prevEnd = s.end;
|
|
12763
|
-
}
|
|
12764
|
-
this._starts = starts;
|
|
12765
|
-
this._ends = ends;
|
|
12766
|
-
this.count = starts.length;
|
|
12767
|
-
this.docStart = docStart;
|
|
12768
|
-
this.docEnd = docEnd ?? (this.count ? Math.max(prevEnd, ends[ends.length - 1]) : docStart);
|
|
12769
|
-
}
|
|
12770
|
-
/** The slot at index `i` (0-based, source order), or undefined. */
|
|
12771
|
-
slot(i) {
|
|
12772
|
-
if (i < 0 || i >= this.count) return void 0;
|
|
12773
|
-
return { start: this._starts[i], end: this._ends[i] };
|
|
12774
|
-
}
|
|
12775
|
-
/**
|
|
12776
|
-
* Index of the gap that CONTAINS `offset`, in `[0, count]`. Gap `i` spans
|
|
12777
|
-
* `[endOf(i-1), startOf(i))` where `endOf(-1)=docStart` and `startOf(count)=docEnd`.
|
|
12778
|
-
* An offset that lands inside a slot returns that slot's TRAILING gap index
|
|
12779
|
-
* (i.e. the gap after it) — callers querying at slot boundaries get the
|
|
12780
|
-
* intuitive answer via `gapBefore`/`gapAfter`.
|
|
12781
|
-
*/
|
|
12782
|
-
gapIndexAt(offset) {
|
|
12783
|
-
const i = floorIndex(this._starts, this.count, offset);
|
|
12784
|
-
if (i < 0) return 0;
|
|
12785
|
-
if (offset < this._ends[i]) return i + 1;
|
|
12786
|
-
return i + 1;
|
|
12787
|
-
}
|
|
12788
|
-
/** The gap at index `i` in `[0, count]`. */
|
|
12789
|
-
gap(i) {
|
|
12790
|
-
if (i < 0 || i > this.count) return void 0;
|
|
12791
|
-
const start = i === 0 ? this.docStart : this._ends[i - 1];
|
|
12792
|
-
const end = i === this.count ? this.docEnd : this._starts[i];
|
|
12793
|
-
return { start, end };
|
|
12794
|
-
}
|
|
12795
|
-
/**
|
|
12796
|
-
* The trivia gap immediately BEFORE `offset` (`[prevSlotEnd, offset)`), where
|
|
12797
|
-
* `prevSlotEnd` is the end of the last slot ending at or before `offset` (or
|
|
12798
|
-
* `docStart`). For a real slot start this is the gap preceding that slot; for an
|
|
12799
|
-
* adjacent slot the gap is empty and agrees with `gapAfter` on the same seam.
|
|
12800
|
-
*/
|
|
12801
|
-
gapBefore(offset) {
|
|
12802
|
-
const e = floorIndex(this._ends, this.count, offset);
|
|
12803
|
-
const start = e >= 0 ? this._ends[e] : this.docStart;
|
|
12804
|
-
return { start, end: offset };
|
|
12805
|
-
}
|
|
12806
|
-
/**
|
|
12807
|
-
* The trivia gap immediately AFTER `offset` (`[offset, nextSlotStart)`), where
|
|
12808
|
-
* `nextSlotStart` is the least slot start at or after `offset` (or `docEnd`).
|
|
12809
|
-
*/
|
|
12810
|
-
gapAfter(offset) {
|
|
12811
|
-
return { start: offset, end: this._ceilStart(offset) };
|
|
12812
|
-
}
|
|
12813
|
-
/** Least slot start `>= offset`, else `docEnd`. */
|
|
12814
|
-
_ceilStart(offset) {
|
|
12815
|
-
let lo = 0;
|
|
12816
|
-
let hi = this.count - 1;
|
|
12817
|
-
let ans = this.docEnd;
|
|
12818
|
-
while (lo <= hi) {
|
|
12819
|
-
const mid = lo + hi >>> 1;
|
|
12820
|
-
if (this._starts[mid] >= offset) {
|
|
12821
|
-
ans = this._starts[mid];
|
|
12822
|
-
hi = mid - 1;
|
|
12823
|
-
} else {
|
|
12824
|
-
lo = mid + 1;
|
|
12825
|
-
}
|
|
12826
|
-
}
|
|
12827
|
-
return ans;
|
|
12828
|
-
}
|
|
12829
|
-
/** Is this gap empty (adjacent slots, no trivia)? */
|
|
12830
|
-
isEmpty(gap) {
|
|
12831
|
-
return gap.end <= gap.start;
|
|
12832
|
-
}
|
|
12833
|
-
};
|
|
12834
|
-
var NL = 10;
|
|
12835
|
-
var CR = 13;
|
|
12836
|
-
var SP = 32;
|
|
12837
|
-
var TAB = 9;
|
|
12838
|
-
function gapText(source, gap) {
|
|
12839
|
-
return gap.end > gap.start ? source.slice(gap.start, gap.end) : "";
|
|
12840
|
-
}
|
|
12841
|
-
function lineBreaksIn(source, gap) {
|
|
12842
|
-
let n = 0;
|
|
12843
|
-
for (let i = gap.start; i < gap.end; i++) {
|
|
12844
|
-
const c = source.charCodeAt(i);
|
|
12845
|
-
if (c === NL) n++;
|
|
12846
|
-
else if (c === CR && source.charCodeAt(i + 1) !== NL) n++;
|
|
12847
|
-
}
|
|
12848
|
-
return n;
|
|
12849
|
-
}
|
|
12850
|
-
function blankLinesIn(source, gap) {
|
|
12851
|
-
return Math.max(0, lineBreaksIn(source, gap) - 1);
|
|
12852
|
-
}
|
|
12853
|
-
function lineStartWithin(source, gap) {
|
|
12854
|
-
for (let i = gap.end - 1; i >= gap.start; i--) {
|
|
12855
|
-
const c = source.charCodeAt(i);
|
|
12856
|
-
if (c === NL || c === CR) return i + 1;
|
|
12857
|
-
}
|
|
12858
|
-
return gap.start;
|
|
12859
|
-
}
|
|
12860
|
-
function indentWidth(source, gap) {
|
|
12861
|
-
const ls = lineStartWithin(source, gap);
|
|
12862
|
-
if (ls === gap.start) return 0;
|
|
12863
|
-
return gap.end - ls;
|
|
12864
|
-
}
|
|
12865
|
-
function indentMixed(source, gap) {
|
|
12866
|
-
const ls = lineStartWithin(source, gap);
|
|
12867
|
-
let sawSpace = false;
|
|
12868
|
-
let sawTab = false;
|
|
12869
|
-
for (let i = ls; i < gap.end; i++) {
|
|
12870
|
-
const c = source.charCodeAt(i);
|
|
12871
|
-
if (c === SP) sawSpace = true;
|
|
12872
|
-
else if (c === TAB) sawTab = true;
|
|
12873
|
-
}
|
|
12874
|
-
return sawSpace && sawTab;
|
|
12875
|
-
}
|
|
12876
|
-
function commentsIn(source, gap, comment) {
|
|
12877
|
-
const re = new RegExp(comment.source, comment.flags.replace(/[gy]/g, "") + "g");
|
|
12878
|
-
re.lastIndex = gap.start;
|
|
12879
|
-
const out = [];
|
|
12880
|
-
let m;
|
|
12881
|
-
while ((m = re.exec(source)) && m.index < gap.end) {
|
|
12882
|
-
if (m[0].length === 0) {
|
|
12883
|
-
re.lastIndex++;
|
|
12884
|
-
continue;
|
|
12885
|
-
}
|
|
12886
|
-
if (m.index + m[0].length > gap.end) break;
|
|
12887
|
-
out.push({ start: m.index, end: m.index + m[0].length });
|
|
12888
|
-
}
|
|
12889
|
-
return out;
|
|
12890
|
-
}
|
|
12891
|
-
function gapIsSignificant(source, gap, comment) {
|
|
12892
|
-
if (gap.end <= gap.start) return false;
|
|
12893
|
-
if (lineBreaksIn(source, gap) > 0) return true;
|
|
12894
|
-
if (comment && commentsIn(source, gap, comment).length > 0) return true;
|
|
12895
|
-
return false;
|
|
12896
|
-
}
|
|
12897
|
-
function collectLeafSlots(root) {
|
|
12898
|
-
const slots = [];
|
|
12899
|
-
const visit = (n) => {
|
|
12900
|
-
const kids = n.children;
|
|
12901
|
-
if (kids && kids.length) {
|
|
12902
|
-
for (const c of kids) visit(c);
|
|
12903
|
-
} else if (n.span) {
|
|
12904
|
-
slots.push({ start: n.span.start, end: n.span.end });
|
|
12905
|
-
}
|
|
12906
|
-
};
|
|
12907
|
-
if (root) visit(root);
|
|
12908
|
-
return slots;
|
|
12909
|
-
}
|
|
12910
|
-
function buildOffsetIndex(root, input = "") {
|
|
12911
|
-
return new OffsetIndex(collectLeafSlots(root), 0, input.length);
|
|
12912
|
-
}
|
|
12913
|
-
|
|
12914
13160
|
// src/index.ts
|
|
12915
13161
|
registerRegexAnalyzer(firstSetFromRegex);
|
|
12916
13162
|
export {
|
|
12917
13163
|
GRAMMAR_COVERAGE_DEFINITIONS,
|
|
12918
|
-
OffsetIndex,
|
|
12919
13164
|
absoluteSpanAt,
|
|
12920
13165
|
absoluteSpanCST,
|
|
12921
13166
|
absolutize,
|
|
@@ -12931,16 +13176,12 @@ export {
|
|
|
12931
13176
|
applyEdit,
|
|
12932
13177
|
attempt,
|
|
12933
13178
|
balanced,
|
|
12934
|
-
blankLinesIn,
|
|
12935
13179
|
buildLineIndex,
|
|
12936
|
-
buildOffsetIndex,
|
|
12937
13180
|
buildRootTriviaIndex,
|
|
12938
13181
|
buildTriviaIndex,
|
|
12939
13182
|
charClassMembers,
|
|
12940
13183
|
choice,
|
|
12941
13184
|
classifiedTrivia,
|
|
12942
|
-
collectLeafSlots,
|
|
12943
|
-
commentsIn,
|
|
12944
13185
|
compile,
|
|
12945
13186
|
compiledGrammarCoverageDefinitions,
|
|
12946
13187
|
completionsAt,
|
|
@@ -12953,6 +13194,7 @@ export {
|
|
|
12953
13194
|
createLineIndex,
|
|
12954
13195
|
createVisitor,
|
|
12955
13196
|
cstBuildHost,
|
|
13197
|
+
diagnoseGrammar,
|
|
12956
13198
|
dispatch,
|
|
12957
13199
|
duplicationFindingCount,
|
|
12958
13200
|
endsWith,
|
|
@@ -12962,21 +13204,15 @@ export {
|
|
|
12962
13204
|
firstSetToString,
|
|
12963
13205
|
formatDuplicationFindings,
|
|
12964
13206
|
formatGatingWarnings,
|
|
12965
|
-
|
|
12966
|
-
gapText,
|
|
13207
|
+
formatGrammarDiagnosis,
|
|
12967
13208
|
gate,
|
|
12968
13209
|
grammarCoverageDefinitions,
|
|
12969
|
-
guard,
|
|
12970
|
-
indentMixed,
|
|
12971
|
-
indentWidth,
|
|
12972
13210
|
isParseError,
|
|
12973
13211
|
keywordAlternationHazards,
|
|
12974
13212
|
keywordRegexShape,
|
|
12975
13213
|
keywords,
|
|
12976
13214
|
label,
|
|
12977
13215
|
leaf,
|
|
12978
|
-
lineBreaksIn,
|
|
12979
|
-
lineStartWithin,
|
|
12980
13216
|
literal,
|
|
12981
13217
|
makeWhen,
|
|
12982
13218
|
makeWord,
|