parseman 0.61.5 → 0.61.7
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/diagnostics.js +109 -29
- package/dist/analysis/diagnostics.js.map +2 -2
- package/dist/cli/index.js +109 -29
- package/dist/cli/index.js.map +2 -2
- package/dist/combinators/expect.d.ts.map +1 -1
- package/dist/combinators/first-set.d.ts +3 -1
- package/dist/combinators/first-set.d.ts.map +1 -1
- package/dist/compiler/token-capability.js +14 -10
- package/dist/compiler/token-capability.js.map +1 -1
- package/dist/index.js +166 -45
- package/dist/index.js.map +2 -2
- package/dist/plugin/entry-supercompiler.d.ts +15 -0
- package/dist/plugin/entry-supercompiler.d.ts.map +1 -1
- package/dist/plugin/index.js +256 -46
- package/dist/plugin/index.js.map +2 -2
- package/dist/table/assemble.d.ts.map +1 -1
- package/dist/table/emit-assembly.d.ts.map +1 -1
- package/dist/table/hold-gap.d.ts +3 -1
- package/dist/table/hold-gap.d.ts.map +1 -1
- package/dist/table/index.js +166 -45
- package/dist/table/index.js.map +2 -2
- package/dist/table/select-hot.d.ts +9 -0
- package/dist/table/select-hot.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/combinators/expect.ts +3 -2
- package/src/combinators/first-set.ts +14 -7
- package/src/combinators/sequence.ts +1 -1
- package/src/plugin/entry-supercompiler.ts +110 -1
- package/src/table/assemble.ts +38 -0
- package/src/table/emit-assembly.ts +42 -5
- package/src/table/encode.ts +1 -1
- package/src/table/hold-gap.ts +22 -13
- package/src/table/select-hot.ts +96 -24
- package/src/version.ts +1 -1
|
@@ -36,6 +36,21 @@ export type EntrySupercompileResult = EmitResult & {
|
|
|
36
36
|
* externally-addressable scan roots passed to the canonical emitter.
|
|
37
37
|
*/
|
|
38
38
|
export declare function supercompileEntryAssembly(prog: TableProgram, cfg: EntrySupercompileCfg, extraIps?: readonly number[]): EntrySupercompileResult;
|
|
39
|
+
/**
|
|
40
|
+
* Functions that read the same are one function: `optional(x)` written in 25 places
|
|
41
|
+
* is 25 rows and one body, and a trivia skip can be pooled under two labels that
|
|
42
|
+
* lower alike. This runs after the join, so a site with one caller has
|
|
43
|
+
* already gone into it, the selection is untouched and every call a parse makes is
|
|
44
|
+
* still made. Each pass can make the callers of a merged function read alike, so it
|
|
45
|
+
* repeats until nothing merges.
|
|
46
|
+
*
|
|
47
|
+
* Only identifiers are compared or renamed: a grammar's own text reaches this source
|
|
48
|
+
* as strings and regexes, and they count as written. A temporary is local by the
|
|
49
|
+
* emitter's contract and is numbered per assembly, so one this function binds is
|
|
50
|
+
* compared in order of use. A site name that's also bound somewhere, or abbreviated
|
|
51
|
+
* in `{_pf1}`, can't be renamed by name, so that source stays as it is.
|
|
52
|
+
*/
|
|
53
|
+
export declare function mergeSameBodies(source: string): string;
|
|
39
54
|
/**
|
|
40
55
|
* Plugin-only final splice for an ordinary macro replacement. The table
|
|
41
56
|
* compiler emits its canonical callback-free public artifact first; this pass
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entry-supercompiler.d.ts","sourceRoot":"","sources":["../../src/plugin/entry-supercompiler.ts"],"names":[],"mappings":"AAYA,OAAO,EAAsB,KAAK,UAAU,EAAE,MAAM,2BAA2B,CAAA;AAE/E,OAAO,EAAkC,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAKvF,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,iBAAiB,CAAC,EAAE,OAAO,CAAA;IACpC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,SAAS,CAAA;IACpE,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAA;IAC5B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;IAC1B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;IAC1B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CACxB,CAAA;AAED,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;IAChC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;IAC/B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAA;IACjC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;IAChC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAA;IACpC,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAA;IACjC,QAAQ,CAAC,eAAe,EAAE,QAAQ,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACvF,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;CACpD,CAAA;AAED,MAAM,MAAM,uBAAuB,GAAG,UAAU,GAAG;IAAE,QAAQ,CAAC,YAAY,EAAE,sBAAsB,CAAA;CAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"entry-supercompiler.d.ts","sourceRoot":"","sources":["../../src/plugin/entry-supercompiler.ts"],"names":[],"mappings":"AAYA,OAAO,EAAsB,KAAK,UAAU,EAAE,MAAM,2BAA2B,CAAA;AAE/E,OAAO,EAAkC,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAKvF,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,iBAAiB,CAAC,EAAE,OAAO,CAAA;IACpC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,SAAS,CAAA;IACpE,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAA;IAC5B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;IAC1B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;IAC1B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CACxB,CAAA;AAED,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;IAChC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;IAC/B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAA;IACjC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;IAChC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAA;IACpC,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAA;IACjC,QAAQ,CAAC,eAAe,EAAE,QAAQ,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACvF,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;CACpD,CAAA;AAED,MAAM,MAAM,uBAAuB,GAAG,UAAU,GAAG;IAAE,QAAQ,CAAC,YAAY,EAAE,sBAAsB,CAAA;CAAE,CAAA;AA2KpG;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,YAAY,EAClB,GAAG,EAAE,oBAAoB,EACzB,QAAQ,GAAE,SAAS,MAAM,EAAO,GAC/B,uBAAuB,CAGzB;AAgCD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CA6DtD;AAED;;;;;GAKG;AACH,wBAAgB,8BAA8B,CAC5C,IAAI,EAAE,YAAY,EAClB,WAAW,EAAE,MAAM,EACnB,MAAM,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,GAC3B,MAAM,CA0CR;AAED,8EAA8E;AAC9E,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,YAAY,EAClB,IAAI,EAAE,oBAAoB,EAC1B,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,OAAO,EAAE,UAAU,GAClB,uBAAuB,CAwRzB"}
|
package/dist/plugin/index.js
CHANGED
|
@@ -206,8 +206,9 @@ function matchesEmptyBody(p, seen, resolve3) {
|
|
|
206
206
|
case "optional":
|
|
207
207
|
case "not":
|
|
208
208
|
case "peek":
|
|
209
|
+
case "expect":
|
|
209
210
|
return true;
|
|
210
|
-
// zero repetitions / absent / lookahead
|
|
211
|
+
// zero repetitions / absent / lookahead / recovered
|
|
211
212
|
// Default `sepBy` is `(item (sep item)*)?` — it MATCHES THE EMPTY STRING.
|
|
212
213
|
// Any `min >= 1` requires that many ITEMS, so it is nullable only when the
|
|
213
214
|
// item is. (Keying this off `min === 1` reported every `{ min: 2 }` list as
|
|
@@ -228,7 +229,6 @@ function matchesEmptyBody(p, seen, resolve3) {
|
|
|
228
229
|
case "trivia":
|
|
229
230
|
case "token":
|
|
230
231
|
case "leaf":
|
|
231
|
-
case "expect":
|
|
232
232
|
case "withCtx":
|
|
233
233
|
case "node":
|
|
234
234
|
case "grammar":
|
|
@@ -298,17 +298,17 @@ function sequenceSet(parsers, fs3, empties, trivia2, consuming = true) {
|
|
|
298
298
|
function sequenceFirstSet(parsers) {
|
|
299
299
|
return sequenceSet(parsers, (p) => p._meta.firstSet, matchesEmpty, void 0, false);
|
|
300
300
|
}
|
|
301
|
-
function firstSetOf(p, seen = /* @__PURE__ */ new Set(), resolve3, activeTrivia, consuming = true) {
|
|
301
|
+
function firstSetOf(p, seen = /* @__PURE__ */ new Set(), resolve3, activeTrivia, consuming = true, follow = false) {
|
|
302
302
|
if (seen.has(p)) return any();
|
|
303
303
|
seen.add(p);
|
|
304
304
|
try {
|
|
305
|
-
return firstSetBody(p, seen, resolve3, activeTrivia, consuming);
|
|
305
|
+
return firstSetBody(p, seen, resolve3, activeTrivia, consuming, follow);
|
|
306
306
|
} finally {
|
|
307
307
|
seen.delete(p);
|
|
308
308
|
}
|
|
309
309
|
}
|
|
310
|
-
function firstSetBody(p, seen, resolve3, activeTrivia, consuming) {
|
|
311
|
-
const fs3 = (c) => firstSetOf(c, seen, resolve3, activeTrivia, consuming);
|
|
310
|
+
function firstSetBody(p, seen, resolve3, activeTrivia, consuming, follow) {
|
|
311
|
+
const fs3 = (c) => firstSetOf(c, seen, resolve3, activeTrivia, consuming, follow);
|
|
312
312
|
const empties = (c) => matchesEmpty(c, /* @__PURE__ */ new Set(), resolve3);
|
|
313
313
|
const d = p._def;
|
|
314
314
|
switch (d.tag) {
|
|
@@ -329,7 +329,7 @@ function firstSetBody(p, seen, resolve3, activeTrivia, consuming) {
|
|
|
329
329
|
}
|
|
330
330
|
}
|
|
331
331
|
const through = activeTrivia === null && resolve3 !== void 0;
|
|
332
|
-
return firstSetOf(target, seen, resolve3, through ? triviaThroughRef(p, target, null) : activeTrivia, consuming);
|
|
332
|
+
return firstSetOf(target, seen, resolve3, through ? triviaThroughRef(p, target, null) : activeTrivia, consuming, follow);
|
|
333
333
|
}
|
|
334
334
|
case "choice": {
|
|
335
335
|
let out = empty();
|
|
@@ -339,6 +339,10 @@ function firstSetBody(p, seen, resolve3, activeTrivia, consuming) {
|
|
|
339
339
|
case "sequence": {
|
|
340
340
|
return sequenceSet(d.parsers, fs3, empties, activeTrivia, consuming);
|
|
341
341
|
}
|
|
342
|
+
// Runs on any character: on one its child can't start, it reports the error. A
|
|
343
|
+
// resync sentinel still stops where the child could start.
|
|
344
|
+
case "expect":
|
|
345
|
+
return follow ? fs3(d.parser) : any();
|
|
342
346
|
case "peek": {
|
|
343
347
|
const inner = d.parser;
|
|
344
348
|
return empties(inner) ? any() : fs3(inner);
|
|
@@ -352,7 +356,6 @@ function firstSetBody(p, seen, resolve3, activeTrivia, consuming) {
|
|
|
352
356
|
case "leaf":
|
|
353
357
|
case "node":
|
|
354
358
|
case "sepBy":
|
|
355
|
-
case "expect":
|
|
356
359
|
// A transaction accepts exactly what its inner accepts. Its own `_meta` is
|
|
357
360
|
// the inner's construction-time set, which reads `any` when the inner opens
|
|
358
361
|
// with a rule reference — resolve through it like any other wrapper.
|
|
@@ -360,14 +363,15 @@ function firstSetBody(p, seen, resolve3, activeTrivia, consuming) {
|
|
|
360
363
|
return fs3(d.parser);
|
|
361
364
|
// A token runs its body with trivia cleared (`token.ts`).
|
|
362
365
|
case "token":
|
|
363
|
-
return firstSetOf(d.parser, seen, resolve3, activeTrivia === void 0 ? void 0 : null, consuming);
|
|
366
|
+
return firstSetOf(d.parser, seen, resolve3, activeTrivia === void 0 ? void 0 : null, consuming, follow);
|
|
364
367
|
case "grammar":
|
|
365
368
|
return firstSetOf(
|
|
366
369
|
d.parser,
|
|
367
370
|
seen,
|
|
368
371
|
resolve3,
|
|
369
372
|
d.clearTrivia ? null : d.triviaParser ?? activeTrivia,
|
|
370
|
-
consuming
|
|
373
|
+
consuming,
|
|
374
|
+
follow
|
|
371
375
|
);
|
|
372
376
|
// A run starts with its first line's prefix; a nullable prefix starts with anything.
|
|
373
377
|
case "lines": {
|
|
@@ -3650,7 +3654,7 @@ function sequence(...parsers) {
|
|
|
3650
3654
|
if (tolerant) {
|
|
3651
3655
|
followSentinels ??= parsers.map((_, i) => firstSetSentinel(
|
|
3652
3656
|
parsers.slice(i + 1).reduce(
|
|
3653
|
-
(set, parser2) => union(set, firstSetOf(parser2, /* @__PURE__ */ new Set(), void 0, void 0, false)),
|
|
3657
|
+
(set, parser2) => union(set, firstSetOf(parser2, /* @__PURE__ */ new Set(), void 0, void 0, false, true)),
|
|
3654
3658
|
{ kind: "empty" }
|
|
3655
3659
|
)
|
|
3656
3660
|
));
|
|
@@ -3800,7 +3804,8 @@ function derive(c, seen) {
|
|
|
3800
3804
|
function expect(combinator, label2) {
|
|
3801
3805
|
const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
|
|
3802
3806
|
const meta = {
|
|
3803
|
-
|
|
3807
|
+
// It runs on any character: on one its child can't start, it reports the error.
|
|
3808
|
+
firstSet: any(),
|
|
3804
3809
|
canMatchNewline: combinator._meta.canMatchNewline,
|
|
3805
3810
|
isTrivia: false
|
|
3806
3811
|
};
|
|
@@ -5630,7 +5635,7 @@ function sourceLeaf(root, fn) {
|
|
|
5630
5635
|
}
|
|
5631
5636
|
|
|
5632
5637
|
// src/version.ts
|
|
5633
|
-
var PARSEMAN_VERSION = "0.61.
|
|
5638
|
+
var PARSEMAN_VERSION = "0.61.7";
|
|
5634
5639
|
|
|
5635
5640
|
// src/table/lex-body.ts
|
|
5636
5641
|
function buildLexBodyRecognizer(spec, constants) {
|
|
@@ -8562,7 +8567,7 @@ var Encoder = class {
|
|
|
8562
8567
|
let fs3 = { kind: "empty" };
|
|
8563
8568
|
const rr = this.refResolver();
|
|
8564
8569
|
for (let j = i + 1; j < parsers.length; j++) {
|
|
8565
|
-
fs3 = union(fs3, firstSetOf(parsers[j], /* @__PURE__ */ new Set(), rr, void 0, false));
|
|
8570
|
+
fs3 = union(fs3, firstSetOf(parsers[j], /* @__PURE__ */ new Set(), rr, void 0, false, true));
|
|
8566
8571
|
}
|
|
8567
8572
|
return this.charClass(fs3);
|
|
8568
8573
|
}
|
|
@@ -11057,17 +11062,17 @@ var WRAPPERS = /* @__PURE__ */ new Set([
|
|
|
11057
11062
|
OP_SCOPE_PLAIN,
|
|
11058
11063
|
OP_FIELD,
|
|
11059
11064
|
OP_LABEL,
|
|
11060
|
-
OP_EXPECT,
|
|
11061
11065
|
OP_WITHCTX,
|
|
11062
11066
|
OP_RULE,
|
|
11063
11067
|
OP_ATTEMPT,
|
|
11064
11068
|
OP_COV,
|
|
11065
11069
|
OP_GAPGATE
|
|
11066
11070
|
]);
|
|
11067
|
-
function rowNullable(code, k, ip, memo) {
|
|
11068
|
-
const
|
|
11071
|
+
function rowNullable(code, k, ip, memo, recovers = true) {
|
|
11072
|
+
const key = recovers ? ip : ~ip;
|
|
11073
|
+
const hit = memo.get(key);
|
|
11069
11074
|
if (hit !== void 0) return hit;
|
|
11070
|
-
memo.set(
|
|
11075
|
+
memo.set(key, true);
|
|
11071
11076
|
const op = code[ip];
|
|
11072
11077
|
const kids = [];
|
|
11073
11078
|
let out = true;
|
|
@@ -11078,20 +11083,20 @@ function rowNullable(code, k, ip, memo) {
|
|
|
11078
11083
|
out = !(re instanceof RegExp) || regexCanMatchEmpty(re.source);
|
|
11079
11084
|
} else if (op === OP_SEQ || op === OP_SEQV || op === OP_SEQX) {
|
|
11080
11085
|
childSlots(code, ip, kids);
|
|
11081
|
-
out = kids.every((c) => rowNullable(code, k, c, memo));
|
|
11086
|
+
out = kids.every((c) => rowNullable(code, k, c, memo, recovers));
|
|
11082
11087
|
} else if (op === OP_CHOICE) {
|
|
11083
11088
|
childSlots(code, ip, kids);
|
|
11084
|
-
out = kids.length === 0 || kids.some((c) => rowNullable(code, k, c, memo));
|
|
11089
|
+
out = kids.length === 0 || kids.some((c) => rowNullable(code, k, c, memo, recovers));
|
|
11085
11090
|
} else if (op === OP_REP || op === OP_REPV) {
|
|
11086
|
-
out = code[ip + 2] === 0 || rowNullable(code, k, code[ip + 1], memo);
|
|
11091
|
+
out = code[ip + 2] === 0 || rowNullable(code, k, code[ip + 1], memo, recovers);
|
|
11087
11092
|
} else if (op === OP_SEED) {
|
|
11088
|
-
out = rowNullable(code, k, code[ip + 1], memo);
|
|
11093
|
+
out = rowNullable(code, k, code[ip + 1], memo, recovers);
|
|
11089
11094
|
} else if (op === OP_CONT) {
|
|
11090
|
-
out = rowNullable(code, k, code[ip + 1], memo) && rowNullable(code, k, code[ip + 3], memo);
|
|
11091
|
-
} else if (WRAPPERS.has(op)) {
|
|
11092
|
-
if (childSlots(code, ip, kids) && kids.length === 1) out = rowNullable(code, k, kids[0], memo);
|
|
11095
|
+
out = rowNullable(code, k, code[ip + 1], memo, recovers) && rowNullable(code, k, code[ip + 3], memo, recovers);
|
|
11096
|
+
} else if (WRAPPERS.has(op) || op === OP_EXPECT && !recovers) {
|
|
11097
|
+
if (childSlots(code, ip, kids) && kids.length === 1) out = rowNullable(code, k, kids[0], memo, recovers);
|
|
11093
11098
|
}
|
|
11094
|
-
memo.set(
|
|
11099
|
+
memo.set(key, out);
|
|
11095
11100
|
return out;
|
|
11096
11101
|
}
|
|
11097
11102
|
function holdsGap(code, k, base, n, i, memo) {
|
|
@@ -11100,7 +11105,7 @@ function holdsGap(code, k, base, n, i, memo) {
|
|
|
11100
11105
|
if (code[term] !== OP_NOT && code[term] !== OP_PEEK) return false;
|
|
11101
11106
|
const next = code[base + i + 1];
|
|
11102
11107
|
if (code[next] === OP_ADJ || leadingTriviaFieldAt(code, k, next)) return false;
|
|
11103
|
-
return !rowNullable(code, k, next, memo);
|
|
11108
|
+
return !rowNullable(code, k, next, memo, false);
|
|
11104
11109
|
}
|
|
11105
11110
|
|
|
11106
11111
|
// src/table/gap-gate.ts
|
|
@@ -11422,11 +11427,35 @@ ${fast}
|
|
|
11422
11427
|
${scanned}
|
|
11423
11428
|
}`;
|
|
11424
11429
|
}
|
|
11425
|
-
|
|
11430
|
+
var TRIVIA_LOG_LENGTH = "ctx._cstBuf!==undefined?(ctx._cstBuf.tl!==undefined?ctx._cstBuf.tl.length:0):(ctx._cstTriviaLog!==undefined?ctx._cstTriviaLog.length:0)";
|
|
11431
|
+
function emitHoldTerm(callee, dst, t, l, skip, recovers) {
|
|
11426
11432
|
const fast = `const ${t}v=${callee}(input,cur,ctx)
|
|
11427
11433
|
if(${t}v===FAIL)return FAIL
|
|
11428
11434
|
${dst}=${t}v
|
|
11429
11435
|
cur=EC.e`;
|
|
11436
|
+
if (recovers) {
|
|
11437
|
+
const marked = `let ${t}c=cur,${t}s=cur,${t}tl=0,${t}stl=0,${t}lg=0,${t}slg=0,${t}rt=0,${t}srt=0`;
|
|
11438
|
+
if (l.tri === TRI_NONE) return `${marked}
|
|
11439
|
+
${fast}`;
|
|
11440
|
+
const held2 = `${t}tl=${TRIVIA_LOG_LENGTH}
|
|
11441
|
+
${t}lg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
|
|
11442
|
+
${t}rt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0
|
|
11443
|
+
${t}s=${skip}(input,cur,ctx)
|
|
11444
|
+
${t}stl=${TRIVIA_LOG_LENGTH}
|
|
11445
|
+
${t}slg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
|
|
11446
|
+
${t}srt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0
|
|
11447
|
+
const ${t}v=${callee}(input,${t}s,ctx)
|
|
11448
|
+
if(${t}v===FAIL)return FAIL
|
|
11449
|
+
${dst}=${t}v
|
|
11450
|
+
cur=${t}s`;
|
|
11451
|
+
return l.tri !== TRI_UNKNOWN ? `${marked}
|
|
11452
|
+
${held2}` : `${marked}
|
|
11453
|
+
if(ctx.trivia===undefined){
|
|
11454
|
+
${fast}
|
|
11455
|
+
}else{
|
|
11456
|
+
${held2}
|
|
11457
|
+
}`;
|
|
11458
|
+
}
|
|
11430
11459
|
if (l.tri === TRI_NONE) return fast;
|
|
11431
11460
|
const held = `const ${t}s=${skip}(input,cur,ctx)
|
|
11432
11461
|
const ${t}v=${callee}(input,${t}s,ctx)
|
|
@@ -11440,6 +11469,9 @@ ${fast}
|
|
|
11440
11469
|
${held}
|
|
11441
11470
|
}`;
|
|
11442
11471
|
}
|
|
11472
|
+
function emitHeldGapUndo(t) {
|
|
11473
|
+
return `if(cur===${t}s&&${t}s!==${t}c){rollbackScannedTriviaAt(ctx,${t}tl,${t}stl,${t}lg,${t}slg,${t}rt,${t}srt);cur=${t}c}`;
|
|
11474
|
+
}
|
|
11443
11475
|
function leadSkip(hasTrivia, leadTrivia, skip) {
|
|
11444
11476
|
if (hasTrivia === "false") return "{}";
|
|
11445
11477
|
const call = `itemStart=${skip}(input,itemStart,ctx)`;
|
|
@@ -12448,6 +12480,7 @@ return v
|
|
|
12448
12480
|
}
|
|
12449
12481
|
parts.push("let cur=EC.e");
|
|
12450
12482
|
const names = ["v0"];
|
|
12483
|
+
let heldUndo;
|
|
12451
12484
|
for (let i = 1; i < n; i++) {
|
|
12452
12485
|
const vn = `v${i}`;
|
|
12453
12486
|
parts.push(`let ${vn}`);
|
|
@@ -12464,7 +12497,16 @@ return v
|
|
|
12464
12497
|
);
|
|
12465
12498
|
} else {
|
|
12466
12499
|
const callee = leadingTriviaFieldAt(code, k, childIp) ? `(LEAD.at=cur,${kids[i]})` : kids[i];
|
|
12467
|
-
|
|
12500
|
+
if (holdsGap(code, k, base, n, i, nullable2)) {
|
|
12501
|
+
const t2 = tmp();
|
|
12502
|
+
const recovers = rowNullable(code, k, code[base + i + 1], nullable2);
|
|
12503
|
+
parts.push(emitHoldTerm(callee, vn, t2, L, skipFor(L), recovers));
|
|
12504
|
+
heldUndo = recovers ? t2 : void 0;
|
|
12505
|
+
} else {
|
|
12506
|
+
parts.push(emitTerm(callee, vn, tmp(), L, skipFor(L), L.tri >= 0 ? triviaMiss(L.tri) : void 0));
|
|
12507
|
+
if (heldUndo !== void 0) parts.push(emitHeldGapUndo(heldUndo));
|
|
12508
|
+
heldUndo = void 0;
|
|
12509
|
+
}
|
|
12468
12510
|
}
|
|
12469
12511
|
names.push(vn);
|
|
12470
12512
|
}
|
|
@@ -15965,8 +16007,46 @@ function assemble(t, prog, cfg) {
|
|
|
15965
16007
|
}
|
|
15966
16008
|
if (hasAdj) {
|
|
15967
16009
|
const first2 = linkFirst();
|
|
16010
|
+
let heldFrom = 0, heldTl = 0, heldScanTl = 0, heldLog = 0, heldScanLog = 0, heldRoot = 0, heldScanRoot = 0;
|
|
15968
16011
|
const runnerAt = (i) => {
|
|
15969
16012
|
const kidIp = code[base + i];
|
|
16013
|
+
if (i > 1 && holdsGap(code, k, base, n, i - 1, NULLABLE) && rowNullable(code, k, kidIp, NULLABLE)) {
|
|
16014
|
+
const kid = link(kidIp);
|
|
16015
|
+
return (input, cur, ctx) => {
|
|
16016
|
+
const from = heldFrom, tl = heldTl, scanTl = heldScanTl, log = heldLog;
|
|
16017
|
+
const scanLog = heldScanLog, root = heldRoot, scanRoot = heldScanRoot;
|
|
16018
|
+
const next = step(kid, input, cur, ctx);
|
|
16019
|
+
if (next !== cur || from === cur) return next;
|
|
16020
|
+
rollbackScannedTriviaAt(ctx, tl, scanTl, log, scanLog, root, scanRoot);
|
|
16021
|
+
return from;
|
|
16022
|
+
};
|
|
16023
|
+
}
|
|
16024
|
+
if (holdsGap(code, k, base, n, i, NULLABLE) && rowNullable(code, k, code[base + i + 1], NULLABLE)) {
|
|
16025
|
+
const kid = link(kidIp);
|
|
16026
|
+
return (input, cur, ctx) => {
|
|
16027
|
+
if (ctx.trivia === void 0) {
|
|
16028
|
+
const v2 = kid(input, cur, ctx);
|
|
16029
|
+
if (v2 === FAIL) return -1;
|
|
16030
|
+
TERMV = v2;
|
|
16031
|
+
heldFrom = cur;
|
|
16032
|
+
return EC.e;
|
|
16033
|
+
}
|
|
16034
|
+
const tl = cstTlLen(ctx), log = ctx._triviaLog?.length ?? 0, root = ctx._rootTriviaLog?.length ?? 0;
|
|
16035
|
+
const scanEnd = skipTrivia(input, cur, ctx);
|
|
16036
|
+
const scanTl = cstTlLen(ctx), scanLog = ctx._triviaLog?.length ?? 0, scanRoot = ctx._rootTriviaLog?.length ?? 0;
|
|
16037
|
+
const v = kid(input, scanEnd, ctx);
|
|
16038
|
+
if (v === FAIL) return -1;
|
|
16039
|
+
TERMV = v;
|
|
16040
|
+
heldFrom = cur;
|
|
16041
|
+
heldTl = tl;
|
|
16042
|
+
heldScanTl = scanTl;
|
|
16043
|
+
heldLog = log;
|
|
16044
|
+
heldScanLog = scanLog;
|
|
16045
|
+
heldRoot = root;
|
|
16046
|
+
heldScanRoot = scanRoot;
|
|
16047
|
+
return scanEnd;
|
|
16048
|
+
};
|
|
16049
|
+
}
|
|
15970
16050
|
if (holdsGap(code, k, base, n, i, NULLABLE)) {
|
|
15971
16051
|
const kid = link(kidIp);
|
|
15972
16052
|
return (input, cur, ctx) => {
|
|
@@ -19464,21 +19544,70 @@ function runDuplicationDiagnosticRules(ruleMap, opt) {
|
|
|
19464
19544
|
var LOOP = 8;
|
|
19465
19545
|
var ROUNDS = 60;
|
|
19466
19546
|
var CAP = 1e12;
|
|
19547
|
+
var CROSSING_WEIGHT = 4;
|
|
19548
|
+
var TAKEN = -1;
|
|
19467
19549
|
function selectHotSites(code, entries, siteBytes, budget, profile) {
|
|
19468
19550
|
const selected = /* @__PURE__ */ new Set();
|
|
19469
19551
|
if (budget <= 0) return selected;
|
|
19470
|
-
const weight = profile === void 0 ? staticWeights(code, entries) : void 0;
|
|
19471
|
-
const w = (ip) => (weight !== void 0 ? weight.get(ip) : profile[ip]) ?? 0;
|
|
19472
|
-
const ranked = [...siteBytes.keys()].sort((a, b) => w(b) / siteBytes.get(b) - w(a) / siteBytes.get(a) || a - b);
|
|
19473
19552
|
let spent = 0;
|
|
19474
|
-
for (const ip of
|
|
19475
|
-
if (w(ip) === 0) break;
|
|
19553
|
+
for (const ip of profile === void 0 ? staticRanking(code, entries, siteBytes) : connectedRanking(code, siteBytes, profile)) {
|
|
19476
19554
|
spent += siteBytes.get(ip);
|
|
19477
19555
|
if (spent > budget) break;
|
|
19478
19556
|
selected.add(ip);
|
|
19479
19557
|
}
|
|
19480
19558
|
return selected;
|
|
19481
19559
|
}
|
|
19560
|
+
function edgesAsLowered(code, siteBytes, ip, out) {
|
|
19561
|
+
out.length = 0;
|
|
19562
|
+
if (code[ip] !== OP_CONT) childSlots(code, ip, out);
|
|
19563
|
+
else if (siteBytes.has(ip)) out.push(code[ip + 1], code[ip + 3]);
|
|
19564
|
+
else out.push(code[ip + 2]);
|
|
19565
|
+
for (let i = 0; i < out.length; i++) {
|
|
19566
|
+
let row = out[i];
|
|
19567
|
+
for (; ; ) {
|
|
19568
|
+
const op = code[row];
|
|
19569
|
+
if (op === OP_GAPGATE || op === OP_SEED) row = code[row + 1];
|
|
19570
|
+
else if (op === OP_CONT && !siteBytes.has(row)) row = code[row + 2];
|
|
19571
|
+
else break;
|
|
19572
|
+
}
|
|
19573
|
+
out[i] = row;
|
|
19574
|
+
}
|
|
19575
|
+
}
|
|
19576
|
+
function staticRanking(code, entries, siteBytes) {
|
|
19577
|
+
const weight = staticWeights(code, entries, siteBytes);
|
|
19578
|
+
const w = (ip) => weight.get(ip) ?? 0;
|
|
19579
|
+
return [...siteBytes.keys()].filter((ip) => w(ip) > 0).sort((a, b) => w(b) / siteBytes.get(b) - w(a) / siteBytes.get(a) || a - b);
|
|
19580
|
+
}
|
|
19581
|
+
function* connectedRanking(code, siteBytes, calls) {
|
|
19582
|
+
const ran = [...siteBytes.keys()].filter((ip) => calls[ip] > 0).sort((a, b) => a - b);
|
|
19583
|
+
const slot = new Map(ran.map((ip, i) => [ip, i]));
|
|
19584
|
+
const bytes = ran.map((ip) => siteBytes.get(ip));
|
|
19585
|
+
const worth = ran.map((ip) => calls[ip]);
|
|
19586
|
+
const score = worth.map((value, i) => value / bytes[i]);
|
|
19587
|
+
const crossings = ran.map(() => []);
|
|
19588
|
+
const kids = [];
|
|
19589
|
+
ran.forEach((ip, from) => {
|
|
19590
|
+
edgesAsLowered(code, siteBytes, ip, kids);
|
|
19591
|
+
for (const callee of kids) {
|
|
19592
|
+
const to = slot.get(callee);
|
|
19593
|
+
if (to === void 0) continue;
|
|
19594
|
+
const gain = CROSSING_WEIGHT * calls[callee];
|
|
19595
|
+
crossings[from].push([to, gain]);
|
|
19596
|
+
crossings[to].push([from, gain]);
|
|
19597
|
+
}
|
|
19598
|
+
});
|
|
19599
|
+
for (let left = ran.length; left > 0; left--) {
|
|
19600
|
+
let best = 0;
|
|
19601
|
+
for (let i = 1; i < score.length; i++) if (score[i] > score[best]) best = i;
|
|
19602
|
+
score[best] = TAKEN;
|
|
19603
|
+
yield ran[best];
|
|
19604
|
+
for (const [neighbour, gain] of crossings[best]) {
|
|
19605
|
+
if (score[neighbour] === TAKEN) continue;
|
|
19606
|
+
worth[neighbour] = worth[neighbour] + gain;
|
|
19607
|
+
score[neighbour] = worth[neighbour] / bytes[neighbour];
|
|
19608
|
+
}
|
|
19609
|
+
}
|
|
19610
|
+
}
|
|
19482
19611
|
function fitHotSites(code, entries, siteBytes, fixed, ceiling, sourceBytes, profile) {
|
|
19483
19612
|
const ranked = [...selectHotSites(code, entries, siteBytes, ceiling - fixed, profile)];
|
|
19484
19613
|
for (; ranked.length > 0; ranked.pop()) {
|
|
@@ -19488,25 +19617,17 @@ function fitHotSites(code, entries, siteBytes, fixed, ceiling, sourceBytes, prof
|
|
|
19488
19617
|
}
|
|
19489
19618
|
return void 0;
|
|
19490
19619
|
}
|
|
19491
|
-
function staticWeights(code, entries) {
|
|
19620
|
+
function staticWeights(code, entries, siteBytes) {
|
|
19492
19621
|
let weight = /* @__PURE__ */ new Map();
|
|
19493
19622
|
const kids = [];
|
|
19494
19623
|
for (let round = 0; round < ROUNDS; round++) {
|
|
19495
19624
|
const next = /* @__PURE__ */ new Map();
|
|
19496
19625
|
for (const ip of entries) next.set(ip, 1);
|
|
19497
19626
|
for (const [ip, w] of weight) {
|
|
19498
|
-
|
|
19499
|
-
childSlots(code, ip, kids);
|
|
19627
|
+
edgesAsLowered(code, siteBytes, ip, kids);
|
|
19500
19628
|
const op = code[ip];
|
|
19501
|
-
if (op === OP_CONT && continuationGate(code, code[ip + 3]) !== void 0) {
|
|
19502
|
-
kids.length = 0;
|
|
19503
|
-
kids.push(code[ip + 1], code[ip + 3]);
|
|
19504
|
-
}
|
|
19505
19629
|
const scale = op === OP_REP || op === OP_REPV ? LOOP : op === OP_CHOICE || op === OP_DISPATCH ? 1 / Math.max(1, kids.length) : 1;
|
|
19506
|
-
for (const
|
|
19507
|
-
const kid = code[k] === OP_GAPGATE ? code[k + 1] : k;
|
|
19508
|
-
next.set(kid, Math.min(CAP, (next.get(kid) ?? 0) + w * scale));
|
|
19509
|
-
}
|
|
19630
|
+
for (const kid of kids) next.set(kid, Math.min(CAP, (next.get(kid) ?? 0) + w * scale));
|
|
19510
19631
|
}
|
|
19511
19632
|
weight = next;
|
|
19512
19633
|
}
|
|
@@ -22732,6 +22853,8 @@ function findFreeIdentifiers(code, filename) {
|
|
|
22732
22853
|
// src/plugin/entry-supercompiler.ts
|
|
22733
22854
|
import { parseSync as parseSync5 } from "oxc-parser";
|
|
22734
22855
|
var PIECE = /^_pf(\d+)$/;
|
|
22856
|
+
var MERGEABLE = /^_(?:pf|sk)\d+$/;
|
|
22857
|
+
var TEMP = /^_t\d+_/;
|
|
22735
22858
|
var WRAP = "function __parseman_supercompile__(){\n";
|
|
22736
22859
|
var SUFFIX = "\n}";
|
|
22737
22860
|
function ast(value) {
|
|
@@ -22865,6 +22988,93 @@ function fallback(emitted, reason, before) {
|
|
|
22865
22988
|
}
|
|
22866
22989
|
};
|
|
22867
22990
|
}
|
|
22991
|
+
function namesUnder(root, uses, bound) {
|
|
22992
|
+
let plain = true;
|
|
22993
|
+
const bind = (id) => {
|
|
22994
|
+
const name = nameOf2(id);
|
|
22995
|
+
if (name !== void 0) bound.add(name);
|
|
22996
|
+
};
|
|
22997
|
+
const walk = (node2, parent) => {
|
|
22998
|
+
if (node2.type === "VariableDeclarator") bind(ast(node2.id));
|
|
22999
|
+
else if (node2.type === "LabeledStatement") bind(ast(node2.label));
|
|
23000
|
+
else if (isFunction(node2)) {
|
|
23001
|
+
if (node2 !== root) bind(ast(node2.id));
|
|
23002
|
+
nodes(node2.params).forEach(bind);
|
|
23003
|
+
}
|
|
23004
|
+
const name = nameOf2(node2);
|
|
23005
|
+
if (name !== void 0 && (MERGEABLE.test(name) || TEMP.test(name))) {
|
|
23006
|
+
const isKey = parent?.type === "Property" && parent.key === node2 && parent.computed !== true;
|
|
23007
|
+
const isProperty = parent?.type === "MemberExpression" && parent.property === node2 && parent.computed !== true;
|
|
23008
|
+
if (parent?.type === "Property" && parent.shorthand === true) plain = false;
|
|
23009
|
+
if (!isKey && !isProperty) uses.push({ ...range(node2), name });
|
|
23010
|
+
}
|
|
23011
|
+
for (const child of children2(node2)) walk(child, node2);
|
|
23012
|
+
};
|
|
23013
|
+
walk(root, void 0);
|
|
23014
|
+
return plain;
|
|
23015
|
+
}
|
|
23016
|
+
function mergeSameBodies(source) {
|
|
23017
|
+
const parsed = parseSync5("parseman-merge-same-bodies.js", WRAP + source + SUFFIX);
|
|
23018
|
+
if (parsed.errors.length > 0) return source;
|
|
23019
|
+
const statements = nodes(ast(nodes(parsed.program.body)[0]?.body)?.body);
|
|
23020
|
+
const bodies = [];
|
|
23021
|
+
const others = [];
|
|
23022
|
+
const declared = /* @__PURE__ */ new Set();
|
|
23023
|
+
for (const statement of statements) {
|
|
23024
|
+
const name = statement.type === "FunctionDeclaration" ? nameOf2(ast(statement.id)) : void 0;
|
|
23025
|
+
const uses = [];
|
|
23026
|
+
const bound = /* @__PURE__ */ new Set();
|
|
23027
|
+
if (!namesUnder(statement, uses, bound)) return source;
|
|
23028
|
+
for (const local of bound) declared.add(local);
|
|
23029
|
+
if (name === void 0 || !MERGEABLE.test(name)) others.push(...uses);
|
|
23030
|
+
else bodies.push({ ...range(statement), name, uses: uses.sort((a, b) => a.start - b.start), local: bound });
|
|
23031
|
+
}
|
|
23032
|
+
for (const local of declared) if (MERGEABLE.test(local)) return source;
|
|
23033
|
+
const merged = /* @__PURE__ */ new Map();
|
|
23034
|
+
const current = (name) => {
|
|
23035
|
+
let at = name;
|
|
23036
|
+
for (let next = merged.get(at); next !== void 0; next = merged.get(at)) at = next;
|
|
23037
|
+
return at;
|
|
23038
|
+
};
|
|
23039
|
+
let live = bodies;
|
|
23040
|
+
for (let more = true; more; ) {
|
|
23041
|
+
more = false;
|
|
23042
|
+
const first = /* @__PURE__ */ new Map();
|
|
23043
|
+
live = live.filter((body) => {
|
|
23044
|
+
const temps = /* @__PURE__ */ new Map();
|
|
23045
|
+
const edits2 = body.uses.map((use) => {
|
|
23046
|
+
if (MERGEABLE.test(use.name)) {
|
|
23047
|
+
const site = current(use.name);
|
|
23048
|
+
return { ...use, text: site === body.name ? "#self" : site };
|
|
23049
|
+
}
|
|
23050
|
+
if (!body.local.has(use.name)) return { ...use, text: use.name };
|
|
23051
|
+
const seen = temps.get(use.name) ?? temps.size;
|
|
23052
|
+
temps.set(use.name, seen);
|
|
23053
|
+
return { ...use, text: `#t${seen}` };
|
|
23054
|
+
});
|
|
23055
|
+
const key = render2(source, body.start, body.end, edits2);
|
|
23056
|
+
const kept = first.get(key);
|
|
23057
|
+
if (kept === void 0) {
|
|
23058
|
+
first.set(key, body.name);
|
|
23059
|
+
return true;
|
|
23060
|
+
}
|
|
23061
|
+
merged.set(body.name, kept);
|
|
23062
|
+
more = true;
|
|
23063
|
+
return false;
|
|
23064
|
+
});
|
|
23065
|
+
}
|
|
23066
|
+
if (merged.size === 0) return source;
|
|
23067
|
+
const edits = [];
|
|
23068
|
+
const rename = (use) => {
|
|
23069
|
+
if (MERGEABLE.test(use.name) && merged.has(use.name)) edits.push({ ...use, text: current(use.name) });
|
|
23070
|
+
};
|
|
23071
|
+
others.forEach(rename);
|
|
23072
|
+
for (const body of bodies) {
|
|
23073
|
+
if (merged.has(body.name)) edits.push({ start: body.start, end: body.end, text: "" });
|
|
23074
|
+
else body.uses.forEach(rename);
|
|
23075
|
+
}
|
|
23076
|
+
return render2(source, 0, source.length, edits);
|
|
23077
|
+
}
|
|
22868
23078
|
function supercompileRuleMapReplacement(prog, replacement, select) {
|
|
22869
23079
|
const cfg = defaultAssemblyCfgs(prog)[0];
|
|
22870
23080
|
if (cfg === void 0) return replacement;
|
|
@@ -22899,7 +23109,7 @@ function supercompileRuleMapReplacement(prog, replacement, select) {
|
|
|
22899
23109
|
const start = body.start - prefix.length + 1;
|
|
22900
23110
|
const end = body.end - prefix.length - 1;
|
|
22901
23111
|
if (replacement.slice(start, end) !== FACTORY_ARITY_GUARD + canonical2.source + "\n") return replacement;
|
|
22902
|
-
const transformed = replacement.slice(0, start) + FACTORY_ARITY_GUARD + candidate.source + "\n" + replacement.slice(end);
|
|
23112
|
+
const transformed = replacement.slice(0, start) + FACTORY_ARITY_GUARD + mergeSameBodies(candidate.source) + "\n" + replacement.slice(end);
|
|
22903
23113
|
const checked = parseSync5("parseman-entry-supercompile-replacement-result.js", prefix + transformed);
|
|
22904
23114
|
return checked.errors.length === 0 ? transformed : replacement;
|
|
22905
23115
|
}
|