@thomasfosterau/effect-parse 0.5.0 → 0.6.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.
Files changed (99) hide show
  1. package/CHANGELOG.md +202 -0
  2. package/README.md +19 -1
  3. package/dist/Ascii.d.ts.map +1 -1
  4. package/dist/Ascii.js +5 -3
  5. package/dist/Ascii.js.map +1 -1
  6. package/dist/Binary.d.ts +5 -2
  7. package/dist/Binary.d.ts.map +1 -1
  8. package/dist/Binary.js +20 -3
  9. package/dist/Binary.js.map +1 -1
  10. package/dist/Bits.d.ts.map +1 -1
  11. package/dist/Bits.js +4 -0
  12. package/dist/Bits.js.map +1 -1
  13. package/dist/Input.d.ts +21 -3
  14. package/dist/Input.d.ts.map +1 -1
  15. package/dist/Input.js +31 -4
  16. package/dist/Input.js.map +1 -1
  17. package/dist/Nom.d.ts.map +1 -1
  18. package/dist/ParseError.d.ts +69 -11
  19. package/dist/ParseError.d.ts.map +1 -1
  20. package/dist/ParseError.js +129 -28
  21. package/dist/ParseError.js.map +1 -1
  22. package/dist/Parser.d.ts +10 -4
  23. package/dist/Parser.d.ts.map +1 -1
  24. package/dist/Parser.js +10 -24
  25. package/dist/Parser.js.map +1 -1
  26. package/dist/ParserSchema.d.ts.map +1 -1
  27. package/dist/ParserSchema.js +1 -2
  28. package/dist/ParserSchema.js.map +1 -1
  29. package/dist/ParserStream.d.ts +119 -12
  30. package/dist/ParserStream.d.ts.map +1 -1
  31. package/dist/ParserStream.js +282 -55
  32. package/dist/ParserStream.js.map +1 -1
  33. package/dist/Syntax.js +1 -1
  34. package/dist/Text.d.ts.map +1 -1
  35. package/dist/Text.js +13 -7
  36. package/dist/Text.js.map +1 -1
  37. package/dist/Token.d.ts +10 -1
  38. package/dist/Token.d.ts.map +1 -1
  39. package/dist/Token.js +14 -5
  40. package/dist/Token.js.map +1 -1
  41. package/dist/internal/compiler/closure.d.ts +1 -1
  42. package/dist/internal/compiler/closure.d.ts.map +1 -1
  43. package/dist/internal/compiler/closure.js +7 -17
  44. package/dist/internal/compiler/closure.js.map +1 -1
  45. package/dist/internal/compiler/first.d.ts.map +1 -1
  46. package/dist/internal/compiler/first.js +2 -1
  47. package/dist/internal/compiler/first.js.map +1 -1
  48. package/dist/internal/compiler/graph.d.ts +23 -1
  49. package/dist/internal/compiler/graph.d.ts.map +1 -1
  50. package/dist/internal/compiler/graph.js +27 -5
  51. package/dist/internal/compiler/graph.js.map +1 -1
  52. package/dist/internal/compiler/jit.d.ts.map +1 -1
  53. package/dist/internal/compiler/jit.js +26 -13
  54. package/dist/internal/compiler/jit.js.map +1 -1
  55. package/dist/internal/compiler/registry.d.ts +1 -1
  56. package/dist/internal/compiler/wasm.d.ts.map +1 -1
  57. package/dist/internal/compiler/wasm.js +105 -34
  58. package/dist/internal/compiler/wasm.js.map +1 -1
  59. package/dist/internal/node.d.ts +19 -1
  60. package/dist/internal/node.d.ts.map +1 -1
  61. package/dist/internal/node.js +42 -8
  62. package/dist/internal/node.js.map +1 -1
  63. package/dist/internal/run.d.ts +3 -1
  64. package/dist/internal/run.d.ts.map +1 -1
  65. package/dist/internal/run.js +4 -2
  66. package/dist/internal/run.js.map +1 -1
  67. package/dist/internal/stack.d.ts +8 -0
  68. package/dist/internal/stack.d.ts.map +1 -1
  69. package/dist/internal/stack.js +17 -1
  70. package/dist/internal/stack.js.map +1 -1
  71. package/dist/internal/tokens.d.ts +10 -3
  72. package/dist/internal/tokens.d.ts.map +1 -1
  73. package/dist/internal/tokens.js +22 -9
  74. package/dist/internal/tokens.js.map +1 -1
  75. package/dist/internal/tuple.d.ts +6 -0
  76. package/dist/internal/tuple.d.ts.map +1 -0
  77. package/dist/internal/tuple.js +170 -0
  78. package/dist/internal/tuple.js.map +1 -0
  79. package/package.json +17 -10
  80. package/src/Ascii.ts +5 -3
  81. package/src/Binary.ts +24 -3
  82. package/src/Bits.ts +4 -0
  83. package/src/Input.ts +37 -4
  84. package/src/ParseError.ts +206 -52
  85. package/src/Parser.ts +19 -29
  86. package/src/ParserSchema.ts +1 -2
  87. package/src/ParserStream.ts +336 -62
  88. package/src/Text.ts +16 -12
  89. package/src/Token.ts +14 -5
  90. package/src/internal/compiler/closure.ts +9 -18
  91. package/src/internal/compiler/first.ts +6 -0
  92. package/src/internal/compiler/graph.ts +32 -4
  93. package/src/internal/compiler/jit.ts +37 -17
  94. package/src/internal/compiler/wasm.ts +141 -68
  95. package/src/internal/node.ts +49 -3
  96. package/src/internal/run.ts +4 -2
  97. package/src/internal/stack.ts +17 -0
  98. package/src/internal/tokens.ts +20 -10
  99. package/src/internal/tuple.ts +141 -0
@@ -1 +1 @@
1
- {"version":3,"file":"first.js","names":[],"sources":["../../../src/internal/compiler/first.ts"],"sourcesContent":["/**\n * First sets: which input units can start a match of a parser.\n *\n * A first set has a mode:\n *\n * - `Strict`: when the next unit is not in `units` (or the input has\n * ended), the parser fails with `Backtrack`.\n * - `Optional`: in that case, the parser either fails with `Backtrack` or\n * succeeds without consuming input.\n * - `Unknown`: no guarantee.\n *\n * Units are UTF-16 code units for strings and bytes for byte inputs; units\n * from `TableSize` up are summarized by `high`. Array inputs have no units.\n *\n * Skipping a parser that is certain to fail also skips the callbacks it\n * would have run before failing, which is why callbacks must be pure.\n */\nimport * as Arr from \"effect/Array\"\nimport * as Predicate from \"effect/Predicate\"\nimport type { Encoding } from \"../../Encoding.js\"\nimport type { Node, ParserLike } from \"../node.js\"\nimport { nodeOf } from \"../node.js\"\nimport { fastLimit, isEmptyUnits } from \"../text.js\"\nimport type { CharSet } from \"./sets.js\"\nimport { kindOfEncoding, reachesAbove, TableSize, textSet, tokenSet } from \"./sets.js\"\n\nexport const Strict = 0\nconst Optional = 1\nconst Unknown = 2\n\nexport interface First {\n readonly mode: 0 | 1 | 2\n readonly units: Uint8Array\n readonly high: boolean\n}\n\nconst none = /*#__PURE__*/ new Uint8Array(TableSize)\nconst all = /*#__PURE__*/ new Uint8Array(TableSize).fill(1)\n\nconst unknown: First = { mode: Unknown, units: all, high: true }\nconst emptyOptional: First = { mode: Optional, units: none, high: false }\nconst failing: First = { mode: Strict, units: none, high: false }\nconst anyUnit: First = { mode: Strict, units: all, high: true }\n\nconst union = (a: First, b: First, mode: 0 | 1 | 2): First => {\n const units = new Uint8Array(TableSize)\n for (let i = 0; i < TableSize; i++) units[i] = a.units[i] | b.units[i]\n return { mode, units, high: a.high || b.high }\n}\n\nconst withMode = (f: First, mode: 0 | 1 | 2): First => (f.mode === mode ? f : { ...f, mode })\n\nconst lowerAscii = (c: number): number => (c >= 65 && c <= 90 ? c + 32 : c)\nconst upperAscii = (c: number): number => (c >= 97 && c <= 122 ? c - 32 : c)\n\nconst ofUnits = (codes: ReadonlyArray<number>, mode: 0 | 1 | 2 = Strict): First => {\n const units = new Uint8Array(TableSize)\n let high = false\n for (const c of codes) {\n if (c < TableSize) units[c] = 1\n else high = true\n }\n return { mode, units, high }\n}\n\nexport class FirstSets {\n private readonly memo = new Map<ParserLike, First | undefined>()\n constructor(readonly kind: 0 | 1 | 2) {}\n\n of(p: ParserLike): First {\n if (this.kind === 2) return unknown\n if (this.memo.has(p)) return this.memo.get(p) ?? unknown // in progress: a cycle\n this.memo.set(p, undefined)\n const f = this.compute(nodeOf(p))\n this.memo.set(p, f)\n return f\n }\n\n /** Units of the code points of a set, as an encoding (or `Token`) reads them. */\n private setUnits(set: CharSet, enc: Encoding<any> | undefined, mode: 0 | 1): First | undefined {\n if (enc === undefined || kindOfEncoding(enc) === 0) {\n if (this.kind === 1) return { mode, units: set.table, high: false }\n return { mode, units: set.table, high: reachesAbove(set, TableSize) }\n }\n if (enc.unit !== 1) return undefined\n const fast = fastLimit(enc)\n if (fast === 0) return undefined\n const units = set.table.slice()\n // Multi-unit sequences start with a unit at or above `fast`\n if (fast < TableSize) units.fill(reachesAbove(set, fast) ? 1 : 0, fast)\n return { mode, units, high: false }\n }\n\n private compute(node: Node): First {\n // SAFETY: `compute` is only called from `of`, which returns before it when `kind` is 2\n const kind = this.kind as 0 | 1\n switch (node._tag) {\n case \"Succeed\":\n case \"Sync\":\n case \"Location\":\n case \"RestLen\":\n case \"Eof\":\n return emptyOptional\n case \"Fail\":\n return node.mode === \"Backtrack\" ? failing : unknown\n case \"Any\":\n return node.encoding !== undefined && kindOfEncoding(node.encoding) !== kind ? unknown : anyUnit\n case \"Take\":\n return node.count === 0 ? emptyOptional : anyUnit\n case \"Literal\": {\n const lit = node.literal\n if (node.encoding !== undefined) {\n if (kindOfEncoding(node.encoding) !== kind) return unknown\n if (node.caseless) return isEmptyUnits(lit) ? unknown : anyUnit\n // SAFETY: a `Literal` with an encoding is a `Text` literal, which records the string it encodes\n const encoded = node.encoding.encode(lit as string)\n if (isEmptyUnits(encoded)) return emptyOptional\n return ofUnits([Predicate.isString(encoded) ? encoded.charCodeAt(0) : encoded[0]])\n }\n if (isEmptyUnits(lit)) return emptyOptional\n let first: number\n if (Predicate.isString(lit)) {\n first = kind === 0 ? lit.charCodeAt(0) : new TextEncoder().encode(lit)[0]\n } else if (lit instanceof Uint8Array && kind === 1) {\n first = lit[0]\n } else {\n return unknown\n }\n return ofUnits(node.caseless ? [first, lowerAscii(first), upperAscii(first)] : [first])\n }\n case \"OneOf\":\n case \"TakeWhile\": {\n if (node.encoding !== undefined && kindOfEncoding(node.encoding) !== kind) return unknown\n const min = Predicate.isTagged(node, \"OneOf\") ? 1 : node.min\n if (Predicate.isTagged(node, \"TakeWhile\") && node.max === 0) return emptyOptional\n const mode = min > 0 ? Strict : Optional\n if (node.negate) return mode === Strict ? anyUnit : withMode(anyUnit, Optional)\n const set = node.encoding === undefined ? tokenSet(node.set, kind) : textSet(node.set)\n return this.setUnits(set, node.encoding, mode) ?? (mode === Strict ? anyUnit : unknown)\n }\n case \"Map\":\n case \"As\":\n case \"Tap\":\n case \"TryMap\":\n case \"FilterMap\":\n case \"MapOrFail\":\n case \"Filter\":\n case \"Taken\":\n case \"WithTaken\":\n case \"Span\":\n case \"WithSpan\":\n case \"MapSpan\":\n case \"Context\":\n case \"Expected\":\n case \"Quiet\":\n // A fast path accepts what its grammar accepts (`Parser.withFastPath`)\n case \"FastPath\":\n case \"MapError\":\n case \"OrFail\":\n case \"Peek\":\n case \"Trace\":\n case \"Syntax\":\n case \"ResumeAfter\":\n case \"RetryAfter\":\n return this.of(node.self)\n case \"FlatMap\":\n case \"SeparatedFold\":\n case \"Dispatch\": {\n const f = this.of(Predicate.isTagged(node, \"Dispatch\") ? node.selector : node.self)\n return f.mode === Strict ? f : unknown\n }\n case \"Mode\": {\n const f = this.of(node.self)\n return node.from === \"Backtrack\" ? (f.mode === Unknown ? f : unknown) : f\n }\n case \"Opt\":\n case \"OrElseSucceed\": {\n const f = this.of(node.self)\n return f.mode === Unknown ? f : withMode(f, Optional)\n }\n case \"Seq\":\n case \"Struct\":\n case \"SeqWith\":\n return this.sequence(node.parsers)\n case \"ZipWith\":\n return this.sequence([node.self, node.that])\n case \"Alt\": {\n if (Arr.isReadonlyArrayEmpty(node.parsers)) return failing\n let acc: First | undefined\n let mode: 0 | 1 | 2 = Strict\n for (const p of node.parsers) {\n const f = this.of(p)\n if (f.mode === Unknown) return unknown\n if (f.mode === Optional) mode = Optional\n acc = acc === undefined ? f : union(acc, f, mode)\n }\n return acc === undefined ? failing : withMode(acc, mode)\n }\n case \"Repeat\":\n case \"Fold\":\n case \"Separated\": {\n if (node.max === 0) return emptyOptional\n const f = this.of(node.self)\n if (f.mode !== Strict) return unknown\n return node.min === 0 ? withMode(f, Optional) : f\n }\n case \"Suspend\":\n return this.of(node.resolve())\n case \"Fixed\":\n return kind !== 1 ? unknown : node.size === 0 ? emptyOptional : anyUnit\n default:\n return unknown\n }\n }\n\n private sequence(parsers: ReadonlyArray<ParserLike>): First {\n let acc: First | undefined\n for (const p of parsers) {\n const f = this.of(p)\n if (f.mode === Unknown) return unknown\n acc = acc === undefined ? f : union(acc, f, f.mode)\n if (f.mode === Strict) return acc\n }\n return acc ?? emptyOptional\n }\n}\n\n/**\n * For an `Alt`: the branches worth trying for each next unit, each next\n * high unit, and at the end of the input, or `undefined` when pruning\n * would never skip a branch.\n */\nexport interface AltPlan {\n /** Indexed by unit: indexes into `lists`. */\n readonly byUnit: Uint8Array\n readonly high: number\n readonly end: number\n readonly lists: ReadonlyArray<ReadonlyArray<number>>\n}\n\nexport const planAlt = (firsts: ReadonlyArray<First>): AltPlan | undefined => {\n const n = firsts.length\n if (n < 2 || n > 64) return undefined\n const lists: Array<ReadonlyArray<number>> = []\n const index = new Map<string, number>()\n const listOf = (keep: (f: First) => boolean): number => {\n const list: Array<number> = []\n for (let i = 0; i < n; i++) if (keep(firsts[i])) list.push(i)\n const key = list.join(\",\")\n let k = index.get(key)\n if (k === undefined) {\n k = lists.length\n lists.push(list)\n index.set(key, k)\n }\n return k\n }\n const byUnit = new Uint8Array(TableSize)\n for (let u = 0; u < TableSize; u++) byUnit[u] = listOf((f) => f.mode !== Strict || f.units[u] === 1)\n const high = listOf((f) => f.mode !== Strict || f.high)\n const end = listOf((f) => f.mode !== Strict)\n if (lists.length === 1 && lists[0].length === n) return undefined\n if (lists.length > 255) return undefined\n return { byUnit, high, end, lists }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"first.js","names":[],"sources":["../../../src/internal/compiler/first.ts"],"sourcesContent":["/**\n * First sets: which input units can start a match of a parser.\n *\n * A first set has a mode:\n *\n * - `Strict`: when the next unit is not in `units` (or the input has\n * ended), the parser fails with `Backtrack`.\n * - `Optional`: in that case, the parser either fails with `Backtrack` or\n * succeeds without consuming input.\n * - `Unknown`: no guarantee.\n *\n * Units are UTF-16 code units for strings and bytes for byte inputs; units\n * from `TableSize` up are summarized by `high`. Array inputs have no units.\n *\n * Skipping a parser that is certain to fail also skips the callbacks it\n * would have run before failing, which is why callbacks must be pure.\n */\nimport * as Arr from \"effect/Array\"\nimport * as Predicate from \"effect/Predicate\"\nimport type { Encoding } from \"../../Encoding.js\"\nimport type { Node, ParserLike } from \"../node.js\"\nimport { nodeOf } from \"../node.js\"\nimport { fastLimit, isEmptyUnits } from \"../text.js\"\nimport type { CharSet } from \"./sets.js\"\nimport { kindOfEncoding, reachesAbove, TableSize, textSet, tokenSet } from \"./sets.js\"\n\nexport const Strict = 0\nconst Optional = 1\nconst Unknown = 2\n\nexport interface First {\n readonly mode: 0 | 1 | 2\n readonly units: Uint8Array\n readonly high: boolean\n}\n\nconst none = /*#__PURE__*/ new Uint8Array(TableSize)\nconst all = /*#__PURE__*/ new Uint8Array(TableSize).fill(1)\n\nconst unknown: First = { mode: Unknown, units: all, high: true }\nconst emptyOptional: First = { mode: Optional, units: none, high: false }\nconst failing: First = { mode: Strict, units: none, high: false }\nconst anyUnit: First = { mode: Strict, units: all, high: true }\n\nconst union = (a: First, b: First, mode: 0 | 1 | 2): First => {\n const units = new Uint8Array(TableSize)\n for (let i = 0; i < TableSize; i++) units[i] = a.units[i] | b.units[i]\n return { mode, units, high: a.high || b.high }\n}\n\nconst withMode = (f: First, mode: 0 | 1 | 2): First => (f.mode === mode ? f : { ...f, mode })\n\nconst lowerAscii = (c: number): number => (c >= 65 && c <= 90 ? c + 32 : c)\nconst upperAscii = (c: number): number => (c >= 97 && c <= 122 ? c - 32 : c)\n\nconst ofUnits = (codes: ReadonlyArray<number>, mode: 0 | 1 | 2 = Strict): First => {\n const units = new Uint8Array(TableSize)\n let high = false\n for (const c of codes) {\n if (c < TableSize) units[c] = 1\n else high = true\n }\n return { mode, units, high }\n}\n\nexport class FirstSets {\n private readonly memo = new Map<ParserLike, First | undefined>()\n constructor(readonly kind: 0 | 1 | 2) {}\n\n of(p: ParserLike): First {\n if (this.kind === 2) return unknown\n if (this.memo.has(p)) return this.memo.get(p) ?? unknown // in progress: a cycle\n this.memo.set(p, undefined)\n const f = this.compute(nodeOf(p))\n this.memo.set(p, f)\n return f\n }\n\n /** Units of the code points of a set, as an encoding (or `Token`) reads them. */\n private setUnits(set: CharSet, enc: Encoding<any> | undefined, mode: 0 | 1): First | undefined {\n if (enc === undefined || kindOfEncoding(enc) === 0) {\n if (this.kind === 1) return { mode, units: set.table, high: false }\n return { mode, units: set.table, high: reachesAbove(set, TableSize) }\n }\n if (enc.unit !== 1) return undefined\n const fast = fastLimit(enc)\n if (fast === 0) return undefined\n const units = set.table.slice()\n // Multi-unit sequences start with a unit at or above `fast`\n if (fast < TableSize) units.fill(reachesAbove(set, fast) ? 1 : 0, fast)\n return { mode, units, high: false }\n }\n\n private compute(node: Node): First {\n // SAFETY: `compute` is only called from `of`, which returns before it when `kind` is 2\n const kind = this.kind as 0 | 1\n switch (node._tag) {\n case \"Succeed\":\n case \"Sync\":\n case \"Location\":\n case \"RestLen\":\n case \"Eof\":\n return emptyOptional\n case \"Fail\":\n return node.mode === \"Backtrack\" ? failing : unknown\n case \"Any\":\n return node.encoding !== undefined && kindOfEncoding(node.encoding) !== kind ? unknown : anyUnit\n case \"Take\":\n return node.count === 0 ? emptyOptional : anyUnit\n case \"Literal\": {\n const lit = node.literal\n if (node.encoding !== undefined) {\n if (kindOfEncoding(node.encoding) !== kind) return unknown\n if (node.caseless) return isEmptyUnits(lit) ? unknown : anyUnit\n // SAFETY: a `Literal` with an encoding is a `Text` literal, which records the string it encodes\n const encoded = node.encoding.encode(lit as string)\n if (isEmptyUnits(encoded)) return emptyOptional\n return ofUnits([Predicate.isString(encoded) ? encoded.charCodeAt(0) : encoded[0]])\n }\n if (isEmptyUnits(lit)) return emptyOptional\n let first: number\n if (Predicate.isString(lit)) {\n first = kind === 0 ? lit.charCodeAt(0) : new TextEncoder().encode(lit)[0]\n } else if (lit instanceof Uint8Array && kind === 1) {\n first = lit[0]\n } else {\n return unknown\n }\n return ofUnits(node.caseless ? [first, lowerAscii(first), upperAscii(first)] : [first])\n }\n case \"OneOf\":\n case \"TakeWhile\": {\n if (node.encoding !== undefined && kindOfEncoding(node.encoding) !== kind) return unknown\n const min = Predicate.isTagged(node, \"OneOf\") ? 1 : node.min\n if (Predicate.isTagged(node, \"TakeWhile\") && node.max === 0) return emptyOptional\n const mode = min > 0 ? Strict : Optional\n if (node.negate) return mode === Strict ? anyUnit : withMode(anyUnit, Optional)\n const set = node.encoding === undefined ? tokenSet(node.set, kind) : textSet(node.set)\n return this.setUnits(set, node.encoding, mode) ?? (mode === Strict ? anyUnit : unknown)\n }\n case \"Map\":\n case \"As\":\n case \"Tap\":\n case \"TryMap\":\n case \"FilterMap\":\n case \"MapOrFail\":\n case \"Filter\":\n case \"Taken\":\n case \"WithTaken\":\n case \"Span\":\n case \"WithSpan\":\n case \"MapSpan\":\n case \"Context\":\n case \"Expected\":\n case \"Quiet\":\n // A fast path accepts what its grammar accepts (`Parser.withFastPath`)\n case \"FastPath\":\n case \"MapError\":\n case \"OrFail\":\n case \"Peek\":\n case \"Trace\":\n case \"Syntax\":\n case \"ResumeAfter\":\n case \"RetryAfter\":\n return this.of(node.self)\n case \"FlatMap\":\n case \"SeparatedFold\":\n case \"Dispatch\": {\n const f = this.of(Predicate.isTagged(node, \"Dispatch\") ? node.selector : node.self)\n return f.mode === Strict ? f : unknown\n }\n case \"Mode\": {\n const f = this.of(node.self)\n return node.from === \"Backtrack\" ? (f.mode === Unknown ? f : unknown) : f\n }\n // `not(p)` consumes nothing. Where `p`'s first set rules a unit out, `p`\n // backtracks there, so `not(p)` succeeds without consuming: Optional\n // over `p`'s units. On a unit in that set it may also fail, Cut\n // included, which Optional leaves open. So `seq(not(p), q)` starts\n // with `p`'s units and `q`'s, and an `alt` can skip it on any other (#84)\n case \"Not\":\n case \"Opt\":\n case \"OrElseSucceed\": {\n const f = this.of(node.self)\n return f.mode === Unknown ? f : withMode(f, Optional)\n }\n case \"Seq\":\n case \"Struct\":\n case \"SeqWith\":\n return this.sequence(node.parsers)\n case \"ZipWith\":\n return this.sequence([node.self, node.that])\n case \"Alt\": {\n if (Arr.isReadonlyArrayEmpty(node.parsers)) return failing\n let acc: First | undefined\n let mode: 0 | 1 | 2 = Strict\n for (const p of node.parsers) {\n const f = this.of(p)\n if (f.mode === Unknown) return unknown\n if (f.mode === Optional) mode = Optional\n acc = acc === undefined ? f : union(acc, f, mode)\n }\n return acc === undefined ? failing : withMode(acc, mode)\n }\n case \"Repeat\":\n case \"Fold\":\n case \"Separated\": {\n if (node.max === 0) return emptyOptional\n const f = this.of(node.self)\n if (f.mode !== Strict) return unknown\n return node.min === 0 ? withMode(f, Optional) : f\n }\n case \"Suspend\":\n return this.of(node.resolve())\n case \"Fixed\":\n return kind !== 1 ? unknown : node.size === 0 ? emptyOptional : anyUnit\n default:\n return unknown\n }\n }\n\n private sequence(parsers: ReadonlyArray<ParserLike>): First {\n let acc: First | undefined\n for (const p of parsers) {\n const f = this.of(p)\n if (f.mode === Unknown) return unknown\n acc = acc === undefined ? f : union(acc, f, f.mode)\n if (f.mode === Strict) return acc\n }\n return acc ?? emptyOptional\n }\n}\n\n/**\n * For an `Alt`: the branches worth trying for each next unit, each next\n * high unit, and at the end of the input, or `undefined` when pruning\n * would never skip a branch.\n */\nexport interface AltPlan {\n /** Indexed by unit: indexes into `lists`. */\n readonly byUnit: Uint8Array\n readonly high: number\n readonly end: number\n readonly lists: ReadonlyArray<ReadonlyArray<number>>\n}\n\nexport const planAlt = (firsts: ReadonlyArray<First>): AltPlan | undefined => {\n const n = firsts.length\n if (n < 2 || n > 64) return undefined\n const lists: Array<ReadonlyArray<number>> = []\n const index = new Map<string, number>()\n const listOf = (keep: (f: First) => boolean): number => {\n const list: Array<number> = []\n for (let i = 0; i < n; i++) if (keep(firsts[i])) list.push(i)\n const key = list.join(\",\")\n let k = index.get(key)\n if (k === undefined) {\n k = lists.length\n lists.push(list)\n index.set(key, k)\n }\n return k\n }\n const byUnit = new Uint8Array(TableSize)\n for (let u = 0; u < TableSize; u++) byUnit[u] = listOf((f) => f.mode !== Strict || f.units[u] === 1)\n const high = listOf((f) => f.mode !== Strict || f.high)\n const end = listOf((f) => f.mode !== Strict)\n if (lists.length === 1 && lists[0].length === n) return undefined\n if (lists.length > 255) return undefined\n return { byUnit, high, end, lists }\n}\n"],"mappings":"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"}
@@ -1,8 +1,30 @@
1
1
  import { Node, ParserLike } from "../node.js";
2
2
  /** Whether a node is a token or a constant, always generated inline. */
3
3
  export declare const isLeaf: (node: Node) => boolean;
4
- /** The number of distinct parents of each parser reachable from `root`. */
4
+ /**
5
+ * How many times each parser reachable from `root` is used: one for every
6
+ * place a parent mentions it. A parser used twice is generated once, as a
7
+ * rule the two places call (unless it is small, see {@link isSmall}).
8
+ *
9
+ * Uses are counted, not distinct parents: `seq(p, p)` uses `p` twice. When
10
+ * only parents were counted, such a `p` was inlined at both places, and a
11
+ * grammar that does it at every level (`p = seq(p, p)`, twenty times over)
12
+ * compiled to 2^20 copies: 160 MB of source from twenty lines (#122).
13
+ */
5
14
  export declare const countRefs: (root: ParserLike) => WeakMap<ParserLike, number>;
15
+ /**
16
+ * The most parsers a code-generating compiler inlines for one root. Sharing
17
+ * is what keeps generated code proportional to the grammar; a grammar that
18
+ * is itself enormous (a tree of distinct parsers built by a loop, a derived
19
+ * schema) would still take minutes and gigabytes to generate, so past this
20
+ * many the compiler gives up and the next one down takes over (the JIT for
21
+ * WebAssembly, the closure compiler for the JIT), which costs a closure per
22
+ * parser instead of source text. The largest grammars in this repository
23
+ * and the libraries built on it inline a few thousand.
24
+ */
25
+ export declare const MaxInlined = 100000;
26
+ /** Counts a parser a compiler is about to inline, failing the compilation past {@link MaxInlined}. */
27
+ export declare const countInlined: (inlined: number) => number;
6
28
  /** Whether a parser is small enough to inline wherever it is used. */
7
29
  export declare const isSmall: (p: ParserLike) => boolean;
8
30
  /** The node a `dispatch` selects on, and whether it is looked at with `peek`. */
@@ -1 +1 @@
1
- {"version":3,"file":"graph.d.ts","names":[],"sources":["../../../src/internal/compiler/graph.ts"],"mappings":";;qBAUa,SAAU,MAAM;;qBAYhB,YAAa,MAAM,eAAa,QAAQ;;qBAmBxC,UAAW,GAAG;;qBAiBd,aAAc,UAAU;WAAwB,MAAM;WAAe;;;qBAMrE,aAAc;;qBAGd,WAAY"}
1
+ {"version":3,"file":"graph.d.ts","names":[],"sources":["../../../src/internal/compiler/graph.ts"],"mappings":";;qBAUa,SAAU,MAAM;;;;;;;;;;;qBAqBhB,YAAa,MAAM,eAAa,QAAQ;;;;;;;;;;;qBAyBxC;;qBAGA,eAAgB;;qBAUhB,UAAW,GAAG;;qBAiBd,aAAc,UAAU;WAAwB,MAAM;WAAe;;;qBAMrE,aAAc;;qBAGd,WAAY"}
@@ -8,7 +8,16 @@ import { children, nodeOf } from "../node.js";
8
8
  */
9
9
  /** Whether a node is a token or a constant, always generated inline. */
10
10
  const isLeaf = (node) => Predicate.isTagged(node, "Succeed") || Predicate.isTagged(node, "Fail") || Predicate.isTagged(node, "Eof") || Predicate.isTagged(node, "Location") || Predicate.isTagged(node, "RestLen") || Predicate.isTagged(node, "Any") || Predicate.isTagged(node, "Literal") || Predicate.isTagged(node, "OneOf") || Predicate.isTagged(node, "TakeWhile");
11
- /** The number of distinct parents of each parser reachable from `root`. */
11
+ /**
12
+ * How many times each parser reachable from `root` is used: one for every
13
+ * place a parent mentions it. A parser used twice is generated once, as a
14
+ * rule the two places call (unless it is small, see {@link isSmall}).
15
+ *
16
+ * Uses are counted, not distinct parents: `seq(p, p)` uses `p` twice. When
17
+ * only parents were counted, such a `p` was inlined at both places, and a
18
+ * grammar that does it at every level (`p = seq(p, p)`, twenty times over)
19
+ * compiled to 2^20 copies: 160 MB of source from twenty lines (#122).
20
+ */
12
21
  const countRefs = (root) => {
13
22
  const refs = /* @__PURE__ */ new WeakMap();
14
23
  const seen = /* @__PURE__ */ new WeakSet();
@@ -16,16 +25,29 @@ const countRefs = (root) => {
16
25
  for (let p = stack.pop(); p !== void 0; p = stack.pop()) {
17
26
  if (seen.has(p)) continue;
18
27
  seen.add(p);
19
- const counted = /* @__PURE__ */ new WeakSet();
20
28
  for (const c of children(nodeOf(p))) {
21
- if (counted.has(c)) continue;
22
- counted.add(c);
23
29
  refs.set(c, (refs.get(c) ?? 0) + 1);
24
30
  stack.push(c);
25
31
  }
26
32
  }
27
33
  return refs;
28
34
  };
35
+ /**
36
+ * The most parsers a code-generating compiler inlines for one root. Sharing
37
+ * is what keeps generated code proportional to the grammar; a grammar that
38
+ * is itself enormous (a tree of distinct parsers built by a loop, a derived
39
+ * schema) would still take minutes and gigabytes to generate, so past this
40
+ * many the compiler gives up and the next one down takes over (the JIT for
41
+ * WebAssembly, the closure compiler for the JIT), which costs a closure per
42
+ * parser instead of source text. The largest grammars in this repository
43
+ * and the libraries built on it inline a few thousand.
44
+ */
45
+ const MaxInlined = 1e5;
46
+ /** Counts a parser a compiler is about to inline, failing the compilation past {@link MaxInlined}. */
47
+ const countInlined = (inlined) => {
48
+ if (inlined >= 1e5) throw new RangeError(`effect-parse: the grammar is too large to generate code for (over ${MaxInlined} parsers inlined)`);
49
+ return inlined + 1;
50
+ };
29
51
  /** Whether a parser is small enough to inline wherever it is used. */
30
52
  const isSmall = (p) => {
31
53
  let budget = 6;
@@ -51,6 +73,6 @@ const selectorOf = (selector) => {
51
73
  const lowerAscii = (c) => c >= 65 && c <= 90 ? c + 32 : c;
52
74
  /** Whether a code is an ASCII letter. */
53
75
  const isLetter = (c) => c >= 65 && c <= 90 || c >= 97 && c <= 122;
54
- export { countRefs, isLeaf, isLetter, isSmall, lowerAscii, selectorOf };
76
+ export { MaxInlined, countInlined, countRefs, isLeaf, isLetter, isSmall, lowerAscii, selectorOf };
55
77
 
56
78
  //# sourceMappingURL=graph.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"graph.js","names":[],"sources":["../../../src/internal/compiler/graph.ts"],"sourcesContent":["/**\n * The shape of a grammar, as the code-generating compilers (the JIT and the\n * WebAssembly compiler) see it: which parsers are leaves, which are shared\n * and which are small enough to inline everywhere.\n */\nimport * as Predicate from \"effect/Predicate\"\nimport type { Node, ParserLike } from \"../node.js\"\nimport { children, nodeOf } from \"../node.js\"\n\n/** Whether a node is a token or a constant, always generated inline. */\nexport const isLeaf = (node: Node): boolean =>\n Predicate.isTagged(node, \"Succeed\") ||\n Predicate.isTagged(node, \"Fail\") ||\n Predicate.isTagged(node, \"Eof\") ||\n Predicate.isTagged(node, \"Location\") ||\n Predicate.isTagged(node, \"RestLen\") ||\n Predicate.isTagged(node, \"Any\") ||\n Predicate.isTagged(node, \"Literal\") ||\n Predicate.isTagged(node, \"OneOf\") ||\n Predicate.isTagged(node, \"TakeWhile\")\n\n/** The number of distinct parents of each parser reachable from `root`. */\nexport const countRefs = (root: ParserLike): WeakMap<ParserLike, number> => {\n const refs = new WeakMap<ParserLike, number>()\n const seen = new WeakSet<ParserLike>()\n const stack = [root]\n for (let p = stack.pop(); p !== undefined; p = stack.pop()) {\n if (seen.has(p)) continue\n seen.add(p)\n const counted = new WeakSet<ParserLike>()\n for (const c of children(nodeOf(p))) {\n if (counted.has(c)) continue\n counted.add(c)\n refs.set(c, (refs.get(c) ?? 0) + 1)\n stack.push(c)\n }\n }\n return refs\n}\n\n/** Whether a parser is small enough to inline wherever it is used. */\nexport const isSmall = (p: ParserLike): boolean => {\n let budget = 6\n const visit = (q: ParserLike): boolean => {\n const node = nodeOf(q)\n if (\n --budget < 0 ||\n Predicate.isTagged(node, \"Suspend\") ||\n Predicate.isTagged(node, \"Escaped\") ||\n Predicate.isTagged(node, \"Dispatch\")\n )\n return false\n return children(node).every(visit)\n }\n return visit(p)\n}\n\n/** The node a `dispatch` selects on, and whether it is looked at with `peek`. */\nexport const selectorOf = (selector: ParserLike): { readonly node: Node; readonly peek: boolean } => {\n const node = nodeOf(selector)\n return Predicate.isTagged(node, \"Peek\") ? { node: nodeOf(node.self), peek: true } : { node, peek: false }\n}\n\n/** ASCII lower case. */\nexport const lowerAscii = (c: number): number => (c >= 65 && c <= 90 ? c + 32 : c)\n\n/** Whether a code is an ASCII letter. */\nexport const isLetter = (c: number): boolean => (c >= 65 && c <= 90) || (c >= 97 && c <= 122)\n"],"mappings":";;;;;;;;;AAUA,MAAa,UAAU,SACrB,UAAU,SAAS,MAAM,SAAS,KAClC,UAAU,SAAS,MAAM,MAAM,KAC/B,UAAU,SAAS,MAAM,KAAK,KAC9B,UAAU,SAAS,MAAM,UAAU,KACnC,UAAU,SAAS,MAAM,SAAS,KAClC,UAAU,SAAS,MAAM,KAAK,KAC9B,UAAU,SAAS,MAAM,SAAS,KAClC,UAAU,SAAS,MAAM,OAAO,KAChC,UAAU,SAAS,MAAM,WAAW;;AAGtC,MAAa,aAAa,SAAkD;CAC1E,MAAM,uBAAO,IAAI,QAA4B;CAC7C,MAAM,uBAAO,IAAI,QAAoB;CACrC,MAAM,QAAQ,CAAC,IAAI;CACnB,KAAK,IAAI,IAAI,MAAM,IAAI,GAAG,MAAM,KAAA,GAAW,IAAI,MAAM,IAAI,GAAG;EAC1D,IAAI,KAAK,IAAI,CAAC,GAAG;EACjB,KAAK,IAAI,CAAC;EACV,MAAM,0BAAU,IAAI,QAAoB;EACxC,KAAK,MAAM,KAAK,SAAS,OAAO,CAAC,CAAC,GAAG;GACnC,IAAI,QAAQ,IAAI,CAAC,GAAG;GACpB,QAAQ,IAAI,CAAC;GACb,KAAK,IAAI,IAAI,KAAK,IAAI,CAAC,KAAK,KAAK,CAAC;GAClC,MAAM,KAAK,CAAC;EACd;CACF;CACA,OAAO;AACT;;AAGA,MAAa,WAAW,MAA2B;CACjD,IAAI,SAAS;CACb,MAAM,SAAS,MAA2B;EACxC,MAAM,OAAO,OAAO,CAAC;EACrB,IACE,EAAE,SAAS,KACX,UAAU,SAAS,MAAM,SAAS,KAClC,UAAU,SAAS,MAAM,SAAS,KAClC,UAAU,SAAS,MAAM,UAAU,GAEnC,OAAO;EACT,OAAO,SAAS,IAAI,CAAC,CAAC,MAAM,KAAK;CACnC;CACA,OAAO,MAAM,CAAC;AAChB;;AAGA,MAAa,cAAc,aAA0E;CACnG,MAAM,OAAO,OAAO,QAAQ;CAC5B,OAAO,UAAU,SAAS,MAAM,MAAM,IAAI;EAAE,MAAM,OAAO,KAAK,IAAI;EAAG,MAAM;CAAK,IAAI;EAAE;EAAM,MAAM;CAAM;AAC1G;;AAGA,MAAa,cAAc,MAAuB,KAAK,MAAM,KAAK,KAAK,IAAI,KAAK;;AAGhF,MAAa,YAAY,MAAwB,KAAK,MAAM,KAAK,MAAQ,KAAK,MAAM,KAAK"}
1
+ {"version":3,"file":"graph.js","names":[],"sources":["../../../src/internal/compiler/graph.ts"],"sourcesContent":["/**\n * The shape of a grammar, as the code-generating compilers (the JIT and the\n * WebAssembly compiler) see it: which parsers are leaves, which are shared\n * and which are small enough to inline everywhere.\n */\nimport * as Predicate from \"effect/Predicate\"\nimport type { Node, ParserLike } from \"../node.js\"\nimport { children, nodeOf } from \"../node.js\"\n\n/** Whether a node is a token or a constant, always generated inline. */\nexport const isLeaf = (node: Node): boolean =>\n Predicate.isTagged(node, \"Succeed\") ||\n Predicate.isTagged(node, \"Fail\") ||\n Predicate.isTagged(node, \"Eof\") ||\n Predicate.isTagged(node, \"Location\") ||\n Predicate.isTagged(node, \"RestLen\") ||\n Predicate.isTagged(node, \"Any\") ||\n Predicate.isTagged(node, \"Literal\") ||\n Predicate.isTagged(node, \"OneOf\") ||\n Predicate.isTagged(node, \"TakeWhile\")\n\n/**\n * How many times each parser reachable from `root` is used: one for every\n * place a parent mentions it. A parser used twice is generated once, as a\n * rule the two places call (unless it is small, see {@link isSmall}).\n *\n * Uses are counted, not distinct parents: `seq(p, p)` uses `p` twice. When\n * only parents were counted, such a `p` was inlined at both places, and a\n * grammar that does it at every level (`p = seq(p, p)`, twenty times over)\n * compiled to 2^20 copies: 160 MB of source from twenty lines (#122).\n */\nexport const countRefs = (root: ParserLike): WeakMap<ParserLike, number> => {\n const refs = new WeakMap<ParserLike, number>()\n const seen = new WeakSet<ParserLike>()\n const stack = [root]\n for (let p = stack.pop(); p !== undefined; p = stack.pop()) {\n if (seen.has(p)) continue\n seen.add(p)\n for (const c of children(nodeOf(p))) {\n refs.set(c, (refs.get(c) ?? 0) + 1)\n stack.push(c)\n }\n }\n return refs\n}\n\n/**\n * The most parsers a code-generating compiler inlines for one root. Sharing\n * is what keeps generated code proportional to the grammar; a grammar that\n * is itself enormous (a tree of distinct parsers built by a loop, a derived\n * schema) would still take minutes and gigabytes to generate, so past this\n * many the compiler gives up and the next one down takes over (the JIT for\n * WebAssembly, the closure compiler for the JIT), which costs a closure per\n * parser instead of source text. The largest grammars in this repository\n * and the libraries built on it inline a few thousand.\n */\nexport const MaxInlined = 100_000\n\n/** Counts a parser a compiler is about to inline, failing the compilation past {@link MaxInlined}. */\nexport const countInlined = (inlined: number): number => {\n if (inlined >= MaxInlined) {\n throw new RangeError(\n `effect-parse: the grammar is too large to generate code for (over ${MaxInlined} parsers inlined)`\n )\n }\n return inlined + 1\n}\n\n/** Whether a parser is small enough to inline wherever it is used. */\nexport const isSmall = (p: ParserLike): boolean => {\n let budget = 6\n const visit = (q: ParserLike): boolean => {\n const node = nodeOf(q)\n if (\n --budget < 0 ||\n Predicate.isTagged(node, \"Suspend\") ||\n Predicate.isTagged(node, \"Escaped\") ||\n Predicate.isTagged(node, \"Dispatch\")\n )\n return false\n return children(node).every(visit)\n }\n return visit(p)\n}\n\n/** The node a `dispatch` selects on, and whether it is looked at with `peek`. */\nexport const selectorOf = (selector: ParserLike): { readonly node: Node; readonly peek: boolean } => {\n const node = nodeOf(selector)\n return Predicate.isTagged(node, \"Peek\") ? { node: nodeOf(node.self), peek: true } : { node, peek: false }\n}\n\n/** ASCII lower case. */\nexport const lowerAscii = (c: number): number => (c >= 65 && c <= 90 ? c + 32 : c)\n\n/** Whether a code is an ASCII letter. */\nexport const isLetter = (c: number): boolean => (c >= 65 && c <= 90) || (c >= 97 && c <= 122)\n"],"mappings":";;;;;;;;;AAUA,MAAa,UAAU,SACrB,UAAU,SAAS,MAAM,SAAS,KAClC,UAAU,SAAS,MAAM,MAAM,KAC/B,UAAU,SAAS,MAAM,KAAK,KAC9B,UAAU,SAAS,MAAM,UAAU,KACnC,UAAU,SAAS,MAAM,SAAS,KAClC,UAAU,SAAS,MAAM,KAAK,KAC9B,UAAU,SAAS,MAAM,SAAS,KAClC,UAAU,SAAS,MAAM,OAAO,KAChC,UAAU,SAAS,MAAM,WAAW;;;;;;;;;;;AAYtC,MAAa,aAAa,SAAkD;CAC1E,MAAM,uBAAO,IAAI,QAA4B;CAC7C,MAAM,uBAAO,IAAI,QAAoB;CACrC,MAAM,QAAQ,CAAC,IAAI;CACnB,KAAK,IAAI,IAAI,MAAM,IAAI,GAAG,MAAM,KAAA,GAAW,IAAI,MAAM,IAAI,GAAG;EAC1D,IAAI,KAAK,IAAI,CAAC,GAAG;EACjB,KAAK,IAAI,CAAC;EACV,KAAK,MAAM,KAAK,SAAS,OAAO,CAAC,CAAC,GAAG;GACnC,KAAK,IAAI,IAAI,KAAK,IAAI,CAAC,KAAK,KAAK,CAAC;GAClC,MAAM,KAAK,CAAC;EACd;CACF;CACA,OAAO;AACT;;;;;;;;;;;AAYA,MAAa,aAAa;;AAG1B,MAAa,gBAAgB,YAA4B;CACvD,IAAI,WAAA,KACF,MAAM,IAAI,WACR,qEAAqE,WAAW,kBAClF;CAEF,OAAO,UAAU;AACnB;;AAGA,MAAa,WAAW,MAA2B;CACjD,IAAI,SAAS;CACb,MAAM,SAAS,MAA2B;EACxC,MAAM,OAAO,OAAO,CAAC;EACrB,IACE,EAAE,SAAS,KACX,UAAU,SAAS,MAAM,SAAS,KAClC,UAAU,SAAS,MAAM,SAAS,KAClC,UAAU,SAAS,MAAM,UAAU,GAEnC,OAAO;EACT,OAAO,SAAS,IAAI,CAAC,CAAC,MAAM,KAAK;CACnC;CACA,OAAO,MAAM,CAAC;AAChB;;AAGA,MAAa,cAAc,aAA0E;CACnG,MAAM,OAAO,OAAO,QAAQ;CAC5B,OAAO,UAAU,SAAS,MAAM,MAAM,IAAI;EAAE,MAAM,OAAO,KAAK,IAAI;EAAG,MAAM;CAAK,IAAI;EAAE;EAAM,MAAM;CAAM;AAC1G;;AAGA,MAAa,cAAc,MAAuB,KAAK,MAAM,KAAK,KAAK,IAAI,KAAK;;AAGhF,MAAa,YAAY,MAAwB,KAAK,MAAM,KAAK,MAAQ,KAAK,MAAM,KAAK"}
@@ -1 +1 @@
1
- {"version":3,"file":"jit.d.ts","names":[],"sources":["../../../src/internal/compiler/jit.ts"],"mappings":";;;;;qBAmGa;;;;;qBA8yCA,SAAS"}
1
+ {"version":3,"file":"jit.d.ts","names":[],"sources":["../../../src/internal/compiler/jit.ts"],"mappings":";;;;;qBAmGa;;;;;qBAk0CA,SAAS"}
@@ -3,6 +3,7 @@ import * as Result from "effect/Result";
3
3
  import { Fail } from "../../Input.js";
4
4
  import { floatScan, floatTexts, scanFloatBytes, scanFloatString, toFloat } from "../numbers.js";
5
5
  import { Key } from "../key.js";
6
+ import { Defer, NodeId, nodeOf, scansFloat } from "../node.js";
6
7
  import * as Resume from "../resume.js";
7
8
  import { compileAny } from "../tokens.js";
8
9
  import { backend as backend$1, createClosureCompiler } from "./closure.js";
@@ -11,12 +12,11 @@ import { ShortText, charOf, fastLimit, latin1, string, textIn, utf16be, utf16le,
11
12
  import * as Arr from "effect/Array";
12
13
  import { addEntry, flushEntries, fromEntries, isPlainKey } from "../entries.js";
13
14
  import * as Stack from "../stack.js";
14
- import { Defer, NodeId, nodeOf, scansFloat } from "../node.js";
15
15
  import { buildsEntries, pairOf } from "./entries.js";
16
16
  import { Strict, planAlt } from "./first.js";
17
17
  import { SearchHead, StopCache, nextStop, stopChars } from "./search.js";
18
18
  import { TableSize, acceptTable, kindOfEncoding, reachesAbove, textSet, tokenSet } from "./sets.js";
19
- import { countRefs, isLeaf, isLetter, isSmall, lowerAscii, selectorOf } from "./graph.js";
19
+ import { countInlined, countRefs, isLeaf, isLetter, isSmall, lowerAscii, selectorOf } from "./graph.js";
20
20
  // src/internal/compiler/jit.ts
21
21
  /**
22
22
  * The JIT: emits JavaScript source for a parser's description and builds
@@ -153,6 +153,8 @@ var Emitter = class {
153
153
  functions = [];
154
154
  rules = [/* @__PURE__ */ new Map(), /* @__PURE__ */ new Map()];
155
155
  refs;
156
+ /** How many parsers have been inlined (see `countInlined`). */
157
+ inlined = 0;
156
158
  closure;
157
159
  next = 0;
158
160
  constructor(root, kind, resumable = false) {
@@ -179,6 +181,16 @@ var Emitter = class {
179
181
  const text = `${this.const(enc.text)}(I,${start},p)`;
180
182
  return enc === utf8 ? `(p-${start}>${ShortText}?R.utf8Text($S,${start},p):${text})` : text;
181
183
  }
184
+ /**
185
+ * A count or bound as source text. Every number a description contributes
186
+ * to the generated source is written here, so nothing but a non-negative
187
+ * integer can reach it: a bound is a `number` only in the types, and a
188
+ * string written as given would run as code (#121).
189
+ */
190
+ num(n) {
191
+ if (!Number.isSafeInteger(n) || n < 0) throw new TypeError("effect-parse: a compiled bound must be a non-negative integer");
192
+ return String(n);
193
+ }
182
194
  /** A JavaScript literal for simple values, otherwise a constant. */
183
195
  lit(value) {
184
196
  if (value === void 0) return "void 0";
@@ -290,12 +302,12 @@ var Emitter = class {
290
302
  return `if(p>=E){${BT}${fail}}${out === null ? "" : `${out}=I[p];`}p++;`;
291
303
  }
292
304
  arrayOneOf(node, out, fail) {
293
- return `if(p>=E||${this.const(compileAny(node.set).forCode.token)}(I[p])===${node.negate}){${BT}${fail}}${out === null ? "" : `${out}=I[p];`}p++;`;
305
+ return `if(p>=E||${this.const(compileAny(node.set).forCode.token)}(I[p])===${node.negate === true}){${BT}${fail}}${out === null ? "" : `${out}=I[p];`}p++;`;
294
306
  }
295
307
  arrayTakeWhile(node, out, fail, fn) {
296
308
  const m = this.const(compileAny(node.set).forCode.token);
297
309
  const st = this.v(fn);
298
- return `${st}=p;while(p<E${node.max === Infinity ? "" : `&&p-${st}<${node.max}`}&&${m}(I[p])!==${node.negate})p++;` + (node.min > 0 ? `if(p-${st}<${node.min}){${BT}${fail}}` : "") + (out === null ? "" : `${out}=I.slice(${st},p);`);
310
+ return `${st}=p;while(p<E${node.max === Infinity ? "" : `&&p-${st}<${this.num(node.max)}`}&&${m}(I[p])!==${node.negate === true})p++;` + (node.min > 0 ? `if(p-${st}<${this.num(node.min)}){${BT}${fail}}` : "") + (out === null ? "" : `${out}=I.slice(${st},p);`);
299
311
  }
300
312
  call(name, out, fail) {
301
313
  if (out === null) return `if(${name}(p)===F){${fail}}p=P;`;
@@ -311,6 +323,7 @@ var Emitter = class {
311
323
  return enc === void 0 ? this.kind !== 2 : kindOfEncoding(enc) === this.kind;
312
324
  }
313
325
  inline(p, used, out, fail, fn, depth) {
326
+ this.inlined = countInlined(this.inlined);
314
327
  const node = nodeOf(p);
315
328
  const set = (value) => out === null ? "" : `${out}=${value};`;
316
329
  const d = depth + 1;
@@ -469,7 +482,7 @@ var Emitter = class {
469
482
  case "Fixed": {
470
483
  if (this.kind !== 1) return this.delegate(p, used, out, fail, fn);
471
484
  const read = used ? `${out ?? this.v(fn)}=${this.const(node.read)}(I,p,$S);` : "";
472
- return `if(E-p>=${node.size}){${read}p+=${node.size}}else{${this.delegate(p, used, out, fail, fn)}}`;
485
+ return `if(E-p>=${this.num(node.size)}){${read}p+=${this.num(node.size)}}else{${this.delegate(p, used, out, fail, fn)}}`;
473
486
  }
474
487
  default: return this.delegate(p, used, out, fail, fn);
475
488
  }
@@ -651,13 +664,13 @@ var Emitter = class {
651
664
  add = `${acc}.push(${x});`;
652
665
  }
653
666
  }
654
- const check = max === Infinity ? `if(p===${st}){$S.mode="Cut";${fail}}` : "";
655
- const bound = max === Infinity ? "" : `${n}<${max}`;
667
+ const check = `if(p===${st}){$S.mode="Cut";${fail}}`;
668
+ const bound = max === Infinity ? "" : `${n}<${this.num(max)}`;
656
669
  const r = this.resumable ? this.resumePoint(fn) : void 0;
657
670
  const held = collect?.value ?? acc;
658
671
  const save = r === void 0 ? "" : `if($S.mode==="Incomplete"&&$S.resume!==void 0)R.save($S,${r.key},${r.entry},{acc:${held},${collect?.saved ?? ""}count:${n},pos:${st}});`;
659
672
  const element = collect === void 0 ? `${this.gen(node.self, tracked, x, `break ${bad};`, fn, d)}${check}${add}` : collect.element(`break ${bad};`, check);
660
- const body = `${loop}:for(;${bound};${n}++){${cond === void 0 ? "" : `if(${min > 0 ? `${n}>=${min}&&` : ""}!${this.const(cond)}(${acc}))break ${loop};`}${st}=p;${bad}:{${element}continue ${loop};}${save}if($S.mode!=="Backtrack"${min > 0 ? `||${n}<${min}` : ""}){${fail}}p=${st};break ${loop};}`;
673
+ const body = `${loop}:for(;${bound};${n}++){${cond === void 0 ? "" : `if(${min > 0 ? `${n}>=${this.num(min)}&&` : ""}!${this.const(cond)}(${acc}))break ${loop};`}${st}=p;${bad}:{${element}continue ${loop};}${save}if($S.mode!=="Backtrack"${min > 0 ? `||${n}<${this.num(min)}` : ""}){${fail}}p=${st};break ${loop};}`;
661
674
  if (r === void 0) return `${init}${n}=0;${body}${collect?.finish ?? ""}`;
662
675
  return r.wrap(held, `${held}=cp.acc;${collect?.restore ?? ""}${n}=cp.count;p=cp.pos;`, `${init}${n}=0;`, `${body}${collect?.finish ?? ""}`);
663
676
  }
@@ -699,9 +712,9 @@ var Emitter = class {
699
712
  };
700
713
  const self = (f) => collect === void 0 ? this.gen(node.self, keep, x, f, fn, d) : collect.element(f, "");
701
714
  const sep = (f) => this.gen(node.separator, false, null, f, fn, d);
702
- const check = max === Infinity ? `if(p===${st}){$S.mode="Cut";${fail}}` : "";
715
+ const check = `if(p===${st}){$S.mode="Cut";${fail}}`;
703
716
  const first = `${collect?.init ?? (keep ? `${acc}=[];` : "")}${n}=0;${st}=p;` + attempt(self, `${push}${n}++;`, min > 0 ? "||true" : "", "");
704
- const rest = `${loop}:while(${max === Infinity ? "true" : `${n}<${max}`}){${st}=p;` + attempt(sep, "", `||${n}<${min}`, save) + check + attempt(self, `${push}${n}++;continue ${loop};`, `||${n}<${min}`, save) + `}`;
717
+ const rest = `${loop}:while(${max === Infinity ? "true" : `${n}<${this.num(max)}`}){${st}=p;` + attempt(sep, "", `||${n}<${this.num(min)}`, save) + check + attempt(self, `${push}${n}++;continue ${loop};`, `||${n}<${this.num(min)}`, save) + `}`;
705
718
  if (r === void 0) return `${done}:{${first}${rest}}${collect?.finish ?? ""}`;
706
719
  return r.wrap(held, `${held}=cp.acc;${collect?.restore ?? ""}${n}=cp.count;p=cp.pos;`, "", `${done}:{if(!${r.resumed}){${first}}${rest}}${collect?.finish ?? ""}`);
707
720
  }
@@ -854,9 +867,9 @@ var Emitter = class {
854
867
  const loop = this.label();
855
868
  const counted = max !== Infinity || min > 1;
856
869
  const count = counted ? `${n}++;` : "";
857
- const bound = max !== Infinity ? `&&${n}<${max}` : "";
870
+ const bound = max !== Infinity ? `&&${n}<${this.num(max)}` : "";
858
871
  const slice = enc !== void 0 ? this.text(enc, st) : kind === 0 ? `I.slice(${st},p)` : `I.subarray(${st},p)`;
859
- const finish = (min > 0 ? `if(${counted ? n : `p-${st}`}<${min}){${BT}${fail}}` : "") + (out === null ? "" : `${out}=${slice};`);
872
+ const finish = (min > 0 ? `if(${counted ? n : `p-${st}`}<${this.num(min)}){${BT}${fail}}` : "") + (out === null ? "" : `${out}=${slice};`);
860
873
  const head = `${st}=p;${counted ? `${n}=0;` : ""}${loop}:while(p<E${bound}){${c}=${this.unit("p")};`;
861
874
  const member = this.member(accept, c);
862
875
  if (kind === 1 && (enc === void 0 || fastLimit(enc) >= TableSize)) return `${head}if(!(${member}))break;p++;${count}}${finish}`;
@@ -915,7 +928,7 @@ var Emitter = class {
915
928
  const escape = this.gen(node.escape, !raw, x, `${save(b)}${fail}`, fn, d);
916
929
  const onNormal = raw ? `if(p===${b}){$S.mode="Cut";${fail}}continue ${loop};` : `if(p!==${b}){${acc}+=${x};continue ${loop}}`;
917
930
  const slice = enc !== void 0 ? this.text(enc, st) : this.kind === 0 ? `I.slice(${st},p)` : `I.subarray(${st},p)`;
918
- const ctrlTest = rd === void 0 ? `p<E&&${this.unit("p")}===${ctrl}` : `${rd.guard("p")}&&${rd.unit("p")}===${ctrl}`;
931
+ const ctrlTest = rd === void 0 ? `p<E&&${this.unit("p")}===${this.num(ctrl)}` : `${rd.guard("p")}&&${rd.unit("p")}===${this.num(ctrl)}`;
919
932
  const stop = r === void 0 ? loop : this.label();
920
933
  const loopCode = `${loop}:while(p<E){${b}=p;${okv}=false;${bad}:{${normal}${okv}=true;}if(${okv}){${onNormal}}else{if($S.mode!=="Backtrack"){${save(b)}${fail}}p=${b}}if(${ctrlTest}){p+=${rd?.width ?? 1};${escape}${raw ? "" : `${acc}+=${x};`}}else break ${stop};}`;
921
934
  const body = r === void 0 ? loopCode : `${stop}:{${loopCode}if($S.partial){$S.incomplete(0);${save("p")}${fail}}}`;