@thomasfosterau/effect-parse 0.4.0 → 0.5.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 (148) hide show
  1. package/README.md +40 -14
  2. package/dist/Ascii.d.ts +11 -4
  3. package/dist/Ascii.d.ts.map +1 -1
  4. package/dist/Ascii.js +7 -1
  5. package/dist/Ascii.js.map +1 -1
  6. package/dist/Binary.d.ts.map +1 -1
  7. package/dist/Binary.js +64 -35
  8. package/dist/Binary.js.map +1 -1
  9. package/dist/Bits.d.ts.map +1 -1
  10. package/dist/Bits.js +7 -4
  11. package/dist/Bits.js.map +1 -1
  12. package/dist/Compiler.d.ts +74 -2
  13. package/dist/Compiler.d.ts.map +1 -1
  14. package/dist/Compiler.js +78 -1
  15. package/dist/Compiler.js.map +1 -1
  16. package/dist/Expression.d.ts.map +1 -1
  17. package/dist/Expression.js +86 -74
  18. package/dist/Expression.js.map +1 -1
  19. package/dist/Input.d.ts +37 -4
  20. package/dist/Input.d.ts.map +1 -1
  21. package/dist/Input.js +42 -0
  22. package/dist/Input.js.map +1 -1
  23. package/dist/Nom.d.ts +5 -15
  24. package/dist/Nom.d.ts.map +1 -1
  25. package/dist/Nom.js.map +1 -1
  26. package/dist/ParseError.d.ts +2 -2
  27. package/dist/ParseError.d.ts.map +1 -1
  28. package/dist/ParseError.js +1 -1
  29. package/dist/ParseError.js.map +1 -1
  30. package/dist/Parser.d.ts +370 -28
  31. package/dist/Parser.d.ts.map +1 -1
  32. package/dist/Parser.js +390 -19
  33. package/dist/Parser.js.map +1 -1
  34. package/dist/ParserSchema.js +2 -2
  35. package/dist/ParserSchema.js.map +1 -1
  36. package/dist/ParserStream.d.ts +3 -2
  37. package/dist/ParserStream.d.ts.map +1 -1
  38. package/dist/ParserStream.js +15 -10
  39. package/dist/ParserStream.js.map +1 -1
  40. package/dist/Syntax.d.ts +23 -5
  41. package/dist/Syntax.d.ts.map +1 -1
  42. package/dist/Syntax.js.map +1 -1
  43. package/dist/Text.d.ts.map +1 -1
  44. package/dist/Text.js +9 -9
  45. package/dist/Text.js.map +1 -1
  46. package/dist/Token.d.ts +55 -10
  47. package/dist/Token.d.ts.map +1 -1
  48. package/dist/Token.js +59 -21
  49. package/dist/Token.js.map +1 -1
  50. package/dist/internal/compiler/closure.d.ts.map +1 -1
  51. package/dist/internal/compiler/closure.js +257 -97
  52. package/dist/internal/compiler/closure.js.map +1 -1
  53. package/dist/internal/compiler/entries.d.ts +3 -1
  54. package/dist/internal/compiler/entries.d.ts.map +1 -1
  55. package/dist/internal/compiler/entries.js +3 -2
  56. package/dist/internal/compiler/entries.js.map +1 -1
  57. package/dist/internal/compiler/first.d.ts.map +1 -1
  58. package/dist/internal/compiler/first.js +7 -1
  59. package/dist/internal/compiler/first.js.map +1 -1
  60. package/dist/internal/compiler/graph.d.ts +17 -0
  61. package/dist/internal/compiler/graph.d.ts.map +1 -0
  62. package/dist/internal/compiler/graph.js +56 -0
  63. package/dist/internal/compiler/graph.js.map +1 -0
  64. package/dist/internal/compiler/jit.d.ts +5 -0
  65. package/dist/internal/compiler/jit.d.ts.map +1 -1
  66. package/dist/internal/compiler/jit.js +185 -96
  67. package/dist/internal/compiler/jit.js.map +1 -1
  68. package/dist/internal/compiler/registry.d.ts +10 -2
  69. package/dist/internal/compiler/registry.d.ts.map +1 -1
  70. package/dist/internal/compiler/registry.js.map +1 -1
  71. package/dist/internal/compiler/search.d.ts +32 -0
  72. package/dist/internal/compiler/search.d.ts.map +1 -0
  73. package/dist/internal/compiler/search.js +68 -0
  74. package/dist/internal/compiler/search.js.map +1 -0
  75. package/dist/internal/compiler/sets.d.ts.map +1 -1
  76. package/dist/internal/compiler/sets.js +1 -1
  77. package/dist/internal/compiler/sets.js.map +1 -1
  78. package/dist/internal/compiler/wasm.d.ts +8 -0
  79. package/dist/internal/compiler/wasm.d.ts.map +1 -0
  80. package/dist/internal/compiler/wasm.js +2769 -0
  81. package/dist/internal/compiler/wasm.js.map +1 -0
  82. package/dist/internal/compiler/wasmAsm.d.ts +199 -0
  83. package/dist/internal/compiler/wasmAsm.d.ts.map +1 -0
  84. package/dist/internal/compiler/wasmAsm.js +427 -0
  85. package/dist/internal/compiler/wasmAsm.js.map +1 -0
  86. package/dist/internal/entries.d.ts +3 -1
  87. package/dist/internal/entries.d.ts.map +1 -1
  88. package/dist/internal/entries.js +1 -2
  89. package/dist/internal/entries.js.map +1 -1
  90. package/dist/internal/node.d.ts +58 -2
  91. package/dist/internal/node.d.ts.map +1 -1
  92. package/dist/internal/node.js +13 -3
  93. package/dist/internal/node.js.map +1 -1
  94. package/dist/internal/numbers.d.ts.map +1 -1
  95. package/dist/internal/numbers.js.map +1 -1
  96. package/dist/internal/run.d.ts +12 -0
  97. package/dist/internal/run.d.ts.map +1 -1
  98. package/dist/internal/run.js +51 -11
  99. package/dist/internal/run.js.map +1 -1
  100. package/dist/internal/stack.d.ts +6 -0
  101. package/dist/internal/stack.d.ts.map +1 -1
  102. package/dist/internal/stack.js +8 -2
  103. package/dist/internal/stack.js.map +1 -1
  104. package/dist/internal/syntax.d.ts +4 -4
  105. package/dist/internal/syntax.d.ts.map +1 -1
  106. package/dist/internal/syntax.js +18 -10
  107. package/dist/internal/syntax.js.map +1 -1
  108. package/dist/internal/text.d.ts +32 -0
  109. package/dist/internal/text.d.ts.map +1 -1
  110. package/dist/internal/text.js +68 -14
  111. package/dist/internal/text.js.map +1 -1
  112. package/dist/internal/tokens.d.ts +13 -0
  113. package/dist/internal/tokens.d.ts.map +1 -1
  114. package/dist/internal/tokens.js +59 -39
  115. package/dist/internal/tokens.js.map +1 -1
  116. package/package.json +5 -4
  117. package/src/Ascii.ts +42 -9
  118. package/src/Binary.ts +151 -71
  119. package/src/Bits.ts +12 -6
  120. package/src/Compiler.ts +101 -10
  121. package/src/Expression.ts +94 -81
  122. package/src/Input.ts +65 -6
  123. package/src/Nom.ts +15 -5
  124. package/src/ParseError.ts +9 -4
  125. package/src/Parser.ts +682 -129
  126. package/src/ParserSchema.ts +1 -1
  127. package/src/ParserStream.ts +40 -19
  128. package/src/Syntax.ts +60 -36
  129. package/src/Text.ts +16 -15
  130. package/src/Token.ts +138 -29
  131. package/src/internal/compiler/closure.ts +362 -135
  132. package/src/internal/compiler/entries.ts +4 -2
  133. package/src/internal/compiler/first.ts +10 -0
  134. package/src/internal/compiler/graph.ts +68 -0
  135. package/src/internal/compiler/jit.ts +284 -154
  136. package/src/internal/compiler/registry.ts +10 -2
  137. package/src/internal/compiler/search.ts +68 -0
  138. package/src/internal/compiler/sets.ts +7 -3
  139. package/src/internal/compiler/wasm.ts +3203 -0
  140. package/src/internal/compiler/wasmAsm.ts +484 -0
  141. package/src/internal/entries.ts +10 -4
  142. package/src/internal/node.ts +54 -4
  143. package/src/internal/numbers.ts +3 -1
  144. package/src/internal/run.ts +71 -12
  145. package/src/internal/stack.ts +8 -1
  146. package/src/internal/syntax.ts +39 -18
  147. package/src/internal/text.ts +97 -9
  148. package/src/internal/tokens.ts +96 -14
@@ -1 +1 @@
1
- {"version":3,"file":"ParseError.js","names":[],"sources":["../src/ParseError.ts"],"sourcesContent":["/**\n * The error type produced when running a parser.\n *\n * `ParseError` merges winnow's `ContextError`/`ParseError` and nom's\n * `VerboseError`. It records where parsing failed, what was expected there,\n * the context labels that were active, and an optional typed `cause`\n * produced by `Parser.fail`, `Parser.tryMap` and friends. Its `message`\n * shows the failing position in the input:\n *\n * ```text\n * Parse error at line 1, column 4:\n * 1 | [1,,2]\n * | ^\n * expected digit\n * ```\n *\n * `ParseError` is a `Data.TaggedError`, so it can be yielded directly inside\n * `Effect.gen`.\n *\n * @since 0.1.0\n */\nimport * as Arr from \"effect/Array\"\nimport * as Predicate from \"effect/Predicate\"\nimport * as Data from \"effect/Data\"\nimport * as Option from \"effect/Option\"\nimport * as Result from \"effect/Result\"\nimport type { Encoding } from \"./Encoding.js\"\nimport type { ErrMode, Failure, Input } from \"./Input.js\"\nimport * as text from \"./internal/text.js\"\n\n/**\n * The kind of parser that produced an error, in the spirit of nom's\n * `ErrorKind`.\n *\n * `\"TooDeep\"` is not produced by a parser: the runners report it when\n * deeply nested input exhausts the call stack (see `Parser.suspend`).\n *\n * @since 0.1.0\n * @category models\n */\nexport type ErrorKind =\n | \"Alpha\"\n | \"AlphaNumeric\"\n | \"Alt\"\n | \"Assert\"\n | \"Bits\"\n | \"Complete\"\n | \"CrLf\"\n | \"Digit\"\n | \"Dispatch\"\n | \"Eof\"\n | \"Escaped\"\n | \"Fail\"\n | \"Float\"\n | \"HexDigit\"\n | \"Incomplete\"\n | \"LineEnding\"\n | \"Literal\"\n | \"Many\"\n | \"MultiSpace\"\n | \"NoneOf\"\n | \"Not\"\n | \"OctDigit\"\n | \"OneOf\"\n | \"Permutation\"\n | \"Separated\"\n | \"Slice\"\n | \"Space\"\n | \"Take\"\n | \"TakeUntil\"\n | \"TakeWhile\"\n | \"Token\"\n | \"TooDeep\"\n | \"Verify\"\n\n/**\n * @since 0.1.0\n * @category type ids\n */\nexport const TypeId = \"~effect-parse/ParseError\" as const\n\n/**\n * An error produced by running a parser.\n *\n * @since 0.1.0\n * @category models\n */\nexport class ParseError<out E = never>\n extends /*#__PURE__*/ Data.TaggedError(\"ParseError\")<{\n /** The input that was being parsed. */\n readonly input: Input\n /** The offset of the failure in the input. */\n readonly offset: number\n /** The kind of parser that failed. */\n readonly kind: ErrorKind\n /** How the error propagated before parsing stopped. */\n readonly mode: ErrMode\n /** Descriptions of what was expected at `offset`. */\n readonly expected: ReadonlyArray<string>\n /** Context labels (`Parser.context`), innermost first. */\n readonly context: ReadonlyArray<string>\n /** The user supplied cause, if any. */\n readonly cause: E | undefined\n /** An optional free-form description. */\n readonly description: string | undefined\n /**\n * For byte inputs parsed by `Text` parsers, the text encoding. Errors\n * then show the input as text, with line and column numbers.\n */\n readonly encoding?: Encoding<Uint8Array> | undefined\n }>\n{\n /**\n * @since 0.1.0\n */\n readonly [TypeId]: typeof TypeId = TypeId\n\n /**\n * The 1-based line and column of the failure (for strings and encoded\n * text; for other inputs the line is 1 and the column is `offset + 1`).\n *\n * @since 0.1.0\n */\n get position(): LineColumn {\n return lineColumn(this.input, this.offset, this.encoding)\n }\n\n /**\n * The rendered, human-readable error message.\n *\n * @since 0.1.0\n */\n override get message(): string {\n return render(this)\n }\n\n /**\n * @since 0.1.0\n */\n override toString(): string {\n return `ParseError: ${this.message}`\n }\n}\n\n/**\n * @since 0.1.0\n * @category guards\n */\nexport const isParseError = (u: unknown): u is ParseError<unknown> => Predicate.isObjectOrArray(u) && TypeId in u\n\n/**\n * Builds a `ParseError` from the failure details recorded while parsing.\n *\n * @since 0.1.0\n * @category constructors\n */\nexport const fromFailure = <E = never>(\n input: Input,\n failure: Failure,\n mode: ErrMode,\n encoding?: Encoding<any> | undefined\n): ParseError<E> =>\n new ParseError<E>({\n input,\n offset: failure.offset,\n kind: failure.kind,\n mode,\n expected: failure.expected,\n context: failure.context,\n cause: failure.hasCause ? (failure.cause as E) : undefined,\n description: failure.message,\n encoding: input instanceof Uint8Array ? encoding : undefined\n })\n\n/**\n * The user supplied cause of an error, if any.\n *\n * @since 0.1.0\n * @category getters\n */\nexport const getCause = <E>(self: ParseError<E>): Option.Option<E> =>\n self.cause === undefined ? Option.none() : Option.some(self.cause)\n\n/**\n * A 1-based line/column position.\n *\n * @since 0.1.0\n * @category models\n */\nexport interface LineColumn {\n readonly line: number\n readonly column: number\n}\n\n/**\n * Computes the 1-based line and column (in code points) of an offset. Lines\n * are separated by `\\n`. Byte inputs are read as text when an `encoding`\n * is given. For other inputs the line is always 1 and the column is\n * `offset + 1`.\n *\n * @since 0.1.0\n * @category utils\n */\nexport const lineColumn = (input: Input, offset: number, encoding?: Encoding<any> | undefined): LineColumn => {\n if (encoding !== undefined && input instanceof Uint8Array) {\n let line = 1\n let column = 1\n text.walk(encoding, input, 0, Math.min(offset, input.length), (cp) => {\n if (cp === 10) {\n line++\n column = 1\n } else {\n column++\n }\n })\n return { line, column }\n }\n if (!Predicate.isString(input)) return { line: 1, column: offset + 1 }\n let line = 1\n let lineStart = 0\n for (let i = 0; i < offset && i < input.length; i++) {\n if (input.charCodeAt(i) === 10) {\n line++\n lineStart = i + 1\n }\n }\n return { line, column: codePointCount(input, lineStart, Math.min(offset, input.length)) + 1 }\n}\n\nconst codePointCount = (s: string, start: number, end: number): number => {\n let n = 0\n for (let i = start; i < end; i++) {\n const c = s.charCodeAt(i)\n if (c >= 0xd800 && c <= 0xdbff && i + 1 < end) {\n const d = s.charCodeAt(i + 1)\n if (d >= 0xdc00 && d <= 0xdfff) i++\n }\n n++\n }\n return n\n}\n\n/**\n * Formats a list of expectations: `a`, `a or b`, `a, b or c`.\n *\n * @since 0.1.0\n * @category utils\n */\nexport const formatExpected = (expected: ReadonlyArray<string>): string => {\n if (Arr.isReadonlyArrayEmpty(expected)) return \"\"\n if (expected.length === 1) return expected[0]\n return `${expected.slice(0, -1).join(\", \")} or ${expected[expected.length - 1]}`\n}\n\nconst hexBytes = (bytes: Uint8Array): string =>\n Array.from(bytes, (b) => `0x${b.toString(16).padStart(2, \"0\")}`).join(\" \")\n\nconst describeFound = (input: Input, offset: number, encoding: Encoding<any> | undefined): string => {\n if (offset >= input.length) return \"end of input\"\n if (encoding !== undefined && input instanceof Uint8Array) {\n const cp = encoding.decode(input, offset, input.length)\n if (cp >= 0) return JSON.stringify(String.fromCodePoint(cp))\n const bad = input.subarray(offset, Math.min(input.length, offset + Math.max(encoding.unit, 1)))\n return cp === text.Truncated\n ? `incomplete ${encoding.name} sequence ${hexBytes(input.subarray(offset))}`\n : `invalid ${encoding.name} ${hexBytes(bad)}`\n }\n if (Predicate.isString(input)) {\n const cp = input.codePointAt(offset) ?? Number.NaN\n return JSON.stringify(String.fromCodePoint(cp))\n }\n if (input instanceof Uint8Array) {\n return `0x${input[offset].toString(16).padStart(2, \"0\")}`\n }\n return inspectToken(input[offset])\n}\n\n/** @internal */\nexport const inspectToken = (u: unknown): string => {\n if (Predicate.isString(u)) return JSON.stringify(u)\n if (Predicate.isObjectOrArray(u)) {\n // `JSON.stringify` throws on cycles and `BigInt`s\n return Result.getOrElse(\n Result.try(() => JSON.stringify(u)),\n () => String(u)\n )\n }\n return String(u)\n}\n\nconst causeMessage = (cause: unknown): string | undefined => {\n if (cause === undefined) return undefined\n if (Predicate.isString(cause)) return cause\n // An `Error`'s message, or any other object's string `message`\n if (Predicate.isObjectOrArray(cause) && \"message\" in cause && Predicate.isString(cause.message)) {\n return cause.message\n }\n return inspectToken(cause)\n}\n\nconst renderSnippet = (input: Input, offset: number, encoding: Encoding<any> | undefined): Array<string> => {\n if (encoding !== undefined && input instanceof Uint8Array) {\n // Find the line containing `offset`, then decode it\n let lineStart = 0\n let end = input.length\n let column = 1\n text.walk(encoding, input, 0, input.length, (cp, i, w) => {\n if (i >= offset && cp === 10) {\n end = i\n return false\n }\n if (i < offset) {\n if (cp === 10) {\n lineStart = i + w\n column = 1\n } else {\n column++\n }\n }\n })\n let line = text.lenientText(encoding, input, lineStart, end)\n if (line.endsWith(\"\\r\")) line = line.slice(0, -1)\n const gutter = String(lineColumn(input, offset, encoding).line)\n const pad = \" \".repeat(gutter.length)\n return [`${gutter} | ${line}`, `${pad} | ${\" \".repeat(column - 1)}^`]\n }\n if (Predicate.isString(input)) {\n const { column, line } = lineColumn(input, offset)\n let start = offset\n while (start > 0 && input.charCodeAt(start - 1) !== 10) start--\n let end = offset\n while (end < input.length && input.charCodeAt(end) !== 10) end++\n let text = input.slice(start, end)\n if (text.endsWith(\"\\r\")) text = text.slice(0, -1)\n const gutter = String(line)\n const pad = \" \".repeat(gutter.length)\n return [`${gutter} | ${text}`, `${pad} | ${\" \".repeat(column - 1)}^`]\n }\n if (input instanceof Uint8Array) {\n const start = Math.max(0, offset - 8)\n const end = Math.min(input.length, offset + 8)\n const bytes: Array<string> = []\n for (let i = start; i < end; i++) bytes.push(input[i].toString(16).padStart(2, \"0\"))\n const caret = (offset - start) * 3\n return [`${start.toString(16).padStart(8, \"0\")} | ${bytes.join(\" \")}`, `${\" \".repeat(8)} | ${\" \".repeat(caret)}^`]\n }\n return []\n}\n\nconst render = (error: ParseError<unknown>): string => {\n const { encoding, input, offset } = error\n const lines: Array<string> = []\n if (Predicate.isString(input)) {\n const { column, line } = lineColumn(input, offset)\n lines.push(`Parse error at line ${line}, column ${column}:`)\n } else if (encoding !== undefined) {\n const { column, line } = lineColumn(input, offset, encoding)\n lines.push(`Parse error at line ${line}, column ${column} (byte ${offset}):`)\n } else {\n lines.push(`Parse error at offset ${offset}:`)\n }\n lines.push(...renderSnippet(input, offset, encoding))\n for (let i = error.context.length - 1; i >= 0; i--) {\n lines.push(`while parsing ${error.context[i]}`)\n }\n const cause = causeMessage(error.cause)\n if (cause !== undefined) lines.push(cause)\n if (error.description !== undefined) lines.push(error.description)\n if (error.mode === \"Incomplete\") {\n lines.push(\"unexpected end of input (incomplete)\")\n } else if (Arr.isReadonlyArrayNonEmpty(error.expected)) {\n lines.push(`expected ${formatExpected(error.expected)}, found ${describeFound(input, offset, encoding)}`)\n } else if (cause === undefined && error.description === undefined) {\n lines.push(`unexpected ${describeFound(input, offset, encoding)} (${error.kind})`)\n }\n return lines.join(\"\\n\")\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ParseError.js","names":[],"sources":["../src/ParseError.ts"],"sourcesContent":["/**\n * The error type produced when running a parser.\n *\n * `ParseError` merges winnow's `ContextError`/`ParseError` and nom's\n * `VerboseError`. It records where parsing failed, what was expected there,\n * the context labels that were active, and an optional typed `cause`\n * produced by `Parser.fail`, `Parser.tryMap` and friends. Its `message`\n * shows the failing position in the input:\n *\n * ```text\n * Parse error at line 1, column 4:\n * 1 | [1,,2]\n * | ^\n * expected digit\n * ```\n *\n * `ParseError` is a `Data.TaggedError`, so it can be yielded directly inside\n * `Effect.gen`.\n *\n * @since 0.1.0\n */\nimport * as Arr from \"effect/Array\"\nimport * as Predicate from \"effect/Predicate\"\nimport * as Data from \"effect/Data\"\nimport * as Option from \"effect/Option\"\nimport * as Result from \"effect/Result\"\nimport type { Encoding } from \"./Encoding.js\"\nimport type { ErrMode, Failure, Input } from \"./Input.js\"\nimport * as text from \"./internal/text.js\"\n\n/**\n * The kind of parser that produced an error, in the spirit of nom's\n * `ErrorKind`.\n *\n * `\"TooDeep\"` is not produced by a parser: the runners report it when\n * deeply nested input exhausts the call stack (see `Parser.suspend`).\n *\n * @since 0.1.0\n * @category models\n */\nexport type ErrorKind =\n | \"Alpha\"\n | \"AlphaNumeric\"\n | \"Alt\"\n | \"Assert\"\n | \"Bits\"\n | \"Complete\"\n | \"CrLf\"\n | \"Digit\"\n | \"Dispatch\"\n | \"Eof\"\n | \"Escaped\"\n | \"Fail\"\n | \"Float\"\n | \"HexDigit\"\n | \"Incomplete\"\n | \"LineEnding\"\n | \"Literal\"\n | \"Many\"\n | \"MultiSpace\"\n | \"NoneOf\"\n | \"Not\"\n | \"OctDigit\"\n | \"OneOf\"\n | \"Permutation\"\n | \"Separated\"\n | \"Slice\"\n | \"Space\"\n | \"Take\"\n | \"TakeUntil\"\n | \"TakeWhile\"\n | \"Token\"\n | \"TooDeep\"\n | \"Verify\"\n\n/**\n * @since 0.1.0\n * @category type ids\n */\nexport const TypeId = \"~effect-parse/ParseError\" as const\n\n/**\n * An error produced by running a parser.\n *\n * @since 0.1.0\n * @category models\n */\nexport class ParseError<out E = never>\n extends /*#__PURE__*/ Data.TaggedError(\"ParseError\")<{\n /** The input that was being parsed. */\n readonly input: Input\n /** The offset of the failure in the input. */\n readonly offset: number\n /** The kind of parser that failed. */\n readonly kind: ErrorKind\n /** How the error propagated before parsing stopped. */\n readonly mode: ErrMode\n /** Descriptions of what was expected at `offset`. */\n readonly expected: ReadonlyArray<string>\n /** Context labels (`Parser.context`), innermost first. */\n readonly context: ReadonlyArray<string>\n /** The user supplied cause, if any. */\n readonly cause: E | undefined\n /** An optional free-form description. */\n readonly description: string | undefined\n /**\n * For byte inputs parsed by `Text` parsers, the text encoding. Errors\n * then show the input as text, with line and column numbers.\n */\n readonly encoding?: Encoding<Uint8Array> | undefined\n }>\n{\n /**\n * @since 0.1.0\n */\n readonly [TypeId]: typeof TypeId = TypeId\n\n /**\n * The 1-based line and column of the failure (for strings and encoded\n * text; for other inputs the line is 1 and the column is `offset + 1`).\n *\n * @since 0.1.0\n */\n get position(): LineColumn {\n return lineColumn(this.input, this.offset, this.encoding)\n }\n\n /**\n * The rendered, human-readable error message.\n *\n * @since 0.1.0\n */\n override get message(): string {\n return render(this)\n }\n\n /**\n * @since 0.1.0\n */\n override toString(): string {\n return `ParseError: ${this.message}`\n }\n}\n\n/**\n * @since 0.1.0\n * @category guards\n */\nexport const isParseError = (u: unknown): u is ParseError<unknown> => Predicate.isObjectOrArray(u) && TypeId in u\n\n/**\n * Builds a `ParseError` from the failure details recorded while parsing.\n *\n * @since 0.1.0\n * @category constructors\n */\nexport const fromFailure = <E = never>(\n input: Input,\n failure: Failure,\n mode: ErrMode,\n encoding?: Encoding<any>\n): ParseError<E> =>\n new ParseError<E>({\n input,\n offset: failure.offset,\n kind: failure.kind,\n mode,\n expected: failure.expected,\n context: failure.context,\n // SAFETY: `E` is the user error type of the parser whose run recorded\n // `failure`; a failure with `hasCause` carries a cause raised by that\n // parser's `fail` / `mapError`\n cause: failure.hasCause ? (failure.cause as E) : undefined,\n description: failure.message,\n encoding: input instanceof Uint8Array ? encoding : undefined\n })\n\n/**\n * The user supplied cause of an error, if any.\n *\n * @since 0.1.0\n * @category getters\n */\nexport const getCause = <E>(self: ParseError<E>): Option.Option<E> =>\n self.cause === undefined ? Option.none() : Option.some(self.cause)\n\n/**\n * A 1-based line/column position.\n *\n * @since 0.1.0\n * @category models\n */\nexport interface LineColumn {\n readonly line: number\n readonly column: number\n}\n\n/**\n * Computes the 1-based line and column (in code points) of an offset. Lines\n * are separated by `\\n`. Byte inputs are read as text when an `encoding`\n * is given. For other inputs the line is always 1 and the column is\n * `offset + 1`.\n *\n * @since 0.1.0\n * @category utils\n */\nexport const lineColumn = (input: Input, offset: number, encoding?: Encoding<any>): LineColumn => {\n if (encoding !== undefined && input instanceof Uint8Array) {\n let line = 1\n let column = 1\n text.walk(encoding, input, 0, Math.min(offset, input.length), (cp) => {\n if (cp === 10) {\n line++\n column = 1\n } else {\n column++\n }\n })\n return { line, column }\n }\n if (!Predicate.isString(input)) return { line: 1, column: offset + 1 }\n let line = 1\n let lineStart = 0\n for (let i = 0; i < offset && i < input.length; i++) {\n if (input.charCodeAt(i) === 10) {\n line++\n lineStart = i + 1\n }\n }\n return { line, column: codePointCount(input, lineStart, Math.min(offset, input.length)) + 1 }\n}\n\nconst codePointCount = (s: string, start: number, end: number): number => {\n let n = 0\n for (let i = start; i < end; i++) {\n const c = s.charCodeAt(i)\n if (c >= 0xd800 && c <= 0xdbff && i + 1 < end) {\n const d = s.charCodeAt(i + 1)\n if (d >= 0xdc00 && d <= 0xdfff) i++\n }\n n++\n }\n return n\n}\n\n/**\n * Formats a list of expectations: `a`, `a or b`, `a, b or c`.\n *\n * @since 0.1.0\n * @category utils\n */\nexport const formatExpected = (expected: ReadonlyArray<string>): string => {\n if (Arr.isReadonlyArrayEmpty(expected)) return \"\"\n if (expected.length === 1) return expected[0]\n return `${expected.slice(0, -1).join(\", \")} or ${expected[expected.length - 1]}`\n}\n\nconst hexBytes = (bytes: Uint8Array): string =>\n Array.from(bytes, (b) => `0x${b.toString(16).padStart(2, \"0\")}`).join(\" \")\n\nconst describeFound = (input: Input, offset: number, encoding: Encoding<any> | undefined): string => {\n if (offset >= input.length) return \"end of input\"\n if (encoding !== undefined && input instanceof Uint8Array) {\n const cp = encoding.decode(input, offset, input.length)\n if (cp >= 0) return JSON.stringify(String.fromCodePoint(cp))\n const bad = input.subarray(offset, Math.min(input.length, offset + Math.max(encoding.unit, 1)))\n return cp === text.Truncated\n ? `incomplete ${encoding.name} sequence ${hexBytes(input.subarray(offset))}`\n : `invalid ${encoding.name} ${hexBytes(bad)}`\n }\n if (Predicate.isString(input)) {\n const cp = input.codePointAt(offset) ?? Number.NaN\n return JSON.stringify(String.fromCodePoint(cp))\n }\n if (input instanceof Uint8Array) {\n return `0x${input[offset].toString(16).padStart(2, \"0\")}`\n }\n return inspectToken(input[offset])\n}\n\n/** @internal */\nexport const inspectToken = (u: unknown): string => {\n if (Predicate.isString(u)) return JSON.stringify(u)\n if (Predicate.isObjectOrArray(u)) {\n // `JSON.stringify` throws on cycles and `BigInt`s. Fall back to what\n // `String` gives an array (its elements joined) or an object's tag\n // (`[object Map]`), never a user `toString` that might throw in turn.\n return Result.getOrElse(\n Result.try(() => JSON.stringify(u)),\n () => (Array.isArray(u) ? u.join(\",\") : Object.prototype.toString.call(u))\n )\n }\n return String(u)\n}\n\nconst causeMessage = (cause: unknown): string | undefined => {\n if (cause === undefined) return undefined\n if (Predicate.isString(cause)) return cause\n // An `Error`'s message, or any other object's string `message`\n if (Predicate.isObjectOrArray(cause) && \"message\" in cause && Predicate.isString(cause.message)) {\n return cause.message\n }\n return inspectToken(cause)\n}\n\nconst renderSnippet = (input: Input, offset: number, encoding: Encoding<any> | undefined): Array<string> => {\n if (encoding !== undefined && input instanceof Uint8Array) {\n // Find the line containing `offset`, then decode it\n let lineStart = 0\n let end = input.length\n let column = 1\n text.walk(encoding, input, 0, input.length, (cp, i, w) => {\n if (i >= offset && cp === 10) {\n end = i\n return false\n }\n if (i < offset) {\n if (cp === 10) {\n lineStart = i + w\n column = 1\n } else {\n column++\n }\n }\n })\n let line = text.lenientText(encoding, input, lineStart, end)\n if (line.endsWith(\"\\r\")) line = line.slice(0, -1)\n const gutter = String(lineColumn(input, offset, encoding).line)\n const pad = \" \".repeat(gutter.length)\n return [`${gutter} | ${line}`, `${pad} | ${\" \".repeat(column - 1)}^`]\n }\n if (Predicate.isString(input)) {\n const { column, line } = lineColumn(input, offset)\n let start = offset\n while (start > 0 && input.charCodeAt(start - 1) !== 10) start--\n let end = offset\n while (end < input.length && input.charCodeAt(end) !== 10) end++\n let text = input.slice(start, end)\n if (text.endsWith(\"\\r\")) text = text.slice(0, -1)\n const gutter = String(line)\n const pad = \" \".repeat(gutter.length)\n return [`${gutter} | ${text}`, `${pad} | ${\" \".repeat(column - 1)}^`]\n }\n if (input instanceof Uint8Array) {\n const start = Math.max(0, offset - 8)\n const end = Math.min(input.length, offset + 8)\n const bytes: Array<string> = []\n for (let i = start; i < end; i++) bytes.push(input[i].toString(16).padStart(2, \"0\"))\n const caret = (offset - start) * 3\n return [`${start.toString(16).padStart(8, \"0\")} | ${bytes.join(\" \")}`, `${\" \".repeat(8)} | ${\" \".repeat(caret)}^`]\n }\n return []\n}\n\nconst render = (error: ParseError<unknown>): string => {\n const { encoding, input, offset } = error\n const lines: Array<string> = []\n if (Predicate.isString(input)) {\n const { column, line } = lineColumn(input, offset)\n lines.push(`Parse error at line ${line}, column ${column}:`)\n } else if (encoding !== undefined) {\n const { column, line } = lineColumn(input, offset, encoding)\n lines.push(`Parse error at line ${line}, column ${column} (byte ${offset}):`)\n } else {\n lines.push(`Parse error at offset ${offset}:`)\n }\n lines.push(...renderSnippet(input, offset, encoding))\n for (let i = error.context.length - 1; i >= 0; i--) {\n lines.push(`while parsing ${error.context[i]}`)\n }\n const cause = causeMessage(error.cause)\n if (cause !== undefined) lines.push(cause)\n if (error.description !== undefined) lines.push(error.description)\n if (error.mode === \"Incomplete\") {\n lines.push(\"unexpected end of input (incomplete)\")\n } else if (Arr.isReadonlyArrayNonEmpty(error.expected)) {\n lines.push(`expected ${formatExpected(error.expected)}, found ${describeFound(input, offset, encoding)}`)\n } else if (cause === undefined && error.description === undefined) {\n lines.push(`unexpected ${describeFound(input, offset, encoding)} (${error.kind})`)\n }\n return lines.join(\"\\n\")\n}\n"],"mappings":"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"}
package/dist/Parser.d.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  import * as Result from "effect/Result";
2
- import { Fail, Input, Slice, Source, State, TraceEvent } from "./Input.js";
2
+ import { ErrMode, Fail, Input, Slice, Source, State, TraceEvent } from "./Input.js";
3
3
  import * as Option from "effect/Option";
4
4
  import * as Context from "effect/Context";
5
5
  import * as Effect from "effect/Effect";
6
6
  import { Pipeable } from "effect/Pipeable";
7
7
  import * as ParseError from "./ParseError.js";
8
8
  import { ErrorKind } from "./ParseError.js";
9
- import { Node } from "./internal/node.js";
9
+ import { Defer as Defer$1, Node } from "./internal/node.js";
10
10
  import { Contravariant, Covariant, Simplify } from "effect/Types";
11
11
  /**
12
12
  * @since 0.1.0
@@ -33,6 +33,8 @@ export interface Parser<out A, out E = never, out R = never, in I extends Input
33
33
  /** A human-readable name, used by `toString` and tracing. */
34
34
  readonly name: string | undefined;
35
35
  [Symbol.iterator](): ParserIterator<Parser<A, E, R, I>>;
36
+ /** Describes the parser: `Parser(<name>)`, or `Parser` when it has no name. */
37
+ toString(): string;
36
38
  }
37
39
  /**
38
40
  * The iterator used by `yield*` inside {@link gen}.
@@ -88,6 +90,13 @@ export declare namespace Parser {
88
90
  * @since 0.1.0
89
91
  */
90
92
  type InputOf<P> = [P] extends [never] ? Input : [P] extends [Parser<infer _A, infer _E, infer _R, infer I>] ? I : never;
93
+ /**
94
+ * The steps {@link combinator}'s `build` receives: one per parser, in
95
+ * order, each returning its parser's output or `Fail`.
96
+ *
97
+ * @since 0.5.0
98
+ */
99
+ type Steps<Ps extends ReadonlyArray<Any>> = { readonly [K in keyof Ps]: (state: State<InputOf<Ps[number]>>) => Success<Ps[K]> | Fail; };
91
100
  }
92
101
  /**
93
102
  * A repetition range, in the spirit of winnow's `impl Into<Range>`:
@@ -169,6 +178,51 @@ export declare const make: <A, E = never, R = never, I extends Input = string>(s
169
178
  * @internal
170
179
  */
171
180
  export declare const described: <A, E = never, R = never, I extends Input = string>(step: (state: State<I>) => A | Fail, name: string | undefined, node: Node) => Parser<A, E, R, I>;
181
+ /**
182
+ * Creates a combinator over `parsers` that compiles: `build` makes the
183
+ * combinator's step from the parsers' steps. Write combinators with it
184
+ * rather than with {@link make} when they run other parsers: a `make`
185
+ * parser is opaque to the compilers, so in a compiled grammar it runs
186
+ * interpreted, and so does every parser it runs. Interpreted, `build`
187
+ * receives the parsers' own steps; compiled (see the `Compiler` module), it
188
+ * receives their compiled steps, so the parsers inside compile with the
189
+ * grammar.
190
+ *
191
+ * Each step runs its parser on the state it is given, as `Parser.run` does,
192
+ * and returns the parser's output or `Fail`. The steps must run on the
193
+ * combinator's own state (they are compiled for its input kind): a
194
+ * combinator that runs a parser on another input, as {@link mapParser}
195
+ * does, is written with `make`. `build` may be called more than once (once
196
+ * interpreted, and once for each compiled build), so state its step shares
197
+ * between calls belongs inside `build`.
198
+ *
199
+ * @example
200
+ * ```ts
201
+ * import { Ascii, Input, Parser, Token } from "@thomasfosterau/effect-parse"
202
+ *
203
+ * // One or more `item`s separated by `sep`, returning their count
204
+ * const count = <A, B>(item: Parser.Parser<A>, sep: Parser.Parser<B>) =>
205
+ * Parser.combinator([item, sep], ([itemStep, sepStep]) => (state) => {
206
+ * if (itemStep(state) === Input.Fail) return Input.Fail
207
+ * let n = 1
208
+ * while (true) {
209
+ * const start = state.pos
210
+ * if (sepStep(state) === Input.Fail || itemStep(state) === Input.Fail) {
211
+ * if (state.mode !== "Backtrack") return Input.Fail
212
+ * state.rewind(start)
213
+ * return n
214
+ * }
215
+ * n++
216
+ * }
217
+ * })
218
+ *
219
+ * Parser.parse(count(Ascii.digit1, Token.literal(",")), "1,22,333") // Result.succeed(3)
220
+ * ```
221
+ *
222
+ * @since 0.5.0
223
+ * @category constructors
224
+ */
225
+ export declare const combinator: <const Ps extends ReadonlyArray<Parser.Any>, A, E = never>(parsers: Ps, build: (steps: Parser.Steps<Ps>) => (state: State<Parser.InputOf<Ps[number]>>) => A | Fail, name?: string) => Parser<A, E | Parser.Error<Ps[number]>, Parser.Services<Ps[number]>, Parser.InputOf<Ps[number]>>;
172
226
  /**
173
227
  * Gives a parser a name, used by `toString`.
174
228
  *
@@ -216,6 +270,34 @@ export declare const void_: Parser<void, never, never, Input>;
216
270
  * @category constructors
217
271
  */
218
272
  export declare const fail: <E>(error: E) => Parser<never, E, never, Input>;
273
+ /**
274
+ * A parser that fails (backtracks) with the given user error, reporting it
275
+ * at `offset` rather than where the parser runs. Use it for a check that
276
+ * can only run once a whole construct has parsed but should point at the
277
+ * part at fault: return it from a {@link flatMap} continuation, with an
278
+ * offset taken from {@link location} or {@link withSpan}. Like any failure,
279
+ * one at a later offset is preferred over the failures of other
280
+ * alternatives (the furthest failure wins). The offset is clamped to the
281
+ * input.
282
+ *
283
+ * @example
284
+ * ```ts
285
+ * import { Ascii, Parser, Token } from "@thomasfosterau/effect-parse"
286
+ *
287
+ * const tag = (open: string) => Parser.delimited(Token.literal(open), Ascii.alpha1, Token.literal(">"))
288
+ * const element = Parser.seq(tag("<"), Parser.location, tag("</")).pipe(
289
+ * Parser.flatMap(([start, at, end]) =>
290
+ * start === end ? Parser.succeed(start) : Parser.failAt(at, `expected </${start}>`)
291
+ * )
292
+ * )
293
+ * // The error points at the end tag (offset 3), not at the start of the element
294
+ * Parser.parse(element, "<a></b>")
295
+ * ```
296
+ *
297
+ * @since 0.5.0
298
+ * @category constructors
299
+ */
300
+ export declare const failAt: <E>(offset: number, error: E) => Parser<never, E, never, Input>;
219
301
  /**
220
302
  * A parser that always fails (backtracks) without a cause. This is winnow's
221
303
  * `fail` and nom's `fail()`.
@@ -396,6 +478,40 @@ export declare const tryMap: {
396
478
  <A, B, E2>(f: (a: A) => Result.Result<B, E2>): <E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<B, E | E2, R, I>;
397
479
  <A, E, R, I extends Input, B, E2>(self: Parser<A, E, R, I>, f: (a: A) => Result.Result<B, E2>): Parser<B, E | E2, R, I>;
398
480
  };
481
+ /**
482
+ * Transforms the output of a parser with a function that returns
483
+ * `Input.Fail` to reject it: the allocation-free form of {@link tryMap} and
484
+ * {@link filterMap}, for checks that run on nearly every token. Compiled
485
+ * code compares the result with the sentinel instead of allocating and
486
+ * unwrapping a `Result` or an `Option` on every success.
487
+ *
488
+ * On failure the parser backtracks to where it started. With `orFailWith`,
489
+ * the user error it builds (only on failure) becomes the `cause` of the
490
+ * `ParseError`, as with `tryMap`; without, the failure has no cause, as
491
+ * with `filterMap`.
492
+ *
493
+ * @example
494
+ * ```ts
495
+ * import { Ascii, Input, Parser } from "@thomasfosterau/effect-parse"
496
+ *
497
+ * const byte = Ascii.decUint.pipe(
498
+ * Parser.mapOrFail(
499
+ * (n) => (n < 256 ? n : Input.Fail),
500
+ * (n) => `${n} is not a byte`
501
+ * )
502
+ * )
503
+ * Parser.parse(byte, "300") // fails with the cause "300 is not a byte"
504
+ * ```
505
+ *
506
+ * @since 0.5.0
507
+ * @category mapping
508
+ */
509
+ export declare const mapOrFail: {
510
+ <A, B>(f: (a: A) => B | Fail): <E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<Exclude<B, Fail>, E, R, I>;
511
+ <A, B, E2>(f: (a: A) => B | Fail, orFailWith: (a: A) => E2): <E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<Exclude<B, Fail>, E | E2, R, I>;
512
+ <A, E, R, I extends Input, B>(self: Parser<A, E, R, I>, f: (a: A) => B | Fail): Parser<Exclude<B, Fail>, E, R, I>;
513
+ <A, E, R, I extends Input, B, E2>(self: Parser<A, E, R, I>, f: (a: A) => B | Fail, orFailWith: (a: A) => E2): Parser<Exclude<B, Fail>, E | E2, R, I>;
514
+ };
399
515
  /**
400
516
  * Like {@link tryMap}, but the function may throw. Thrown values become the
401
517
  * `cause` of the error.
@@ -404,8 +520,8 @@ export declare const tryMap: {
404
520
  * @category mapping
405
521
  */
406
522
  export declare const tryMapUnknown: {
407
- <A, B>(f: (a: A) => B): <E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<B, E | unknown, R, I>;
408
- <A, E, R, I extends Input, B>(self: Parser<A, E, R, I>, f: (a: A) => B): Parser<B, E | unknown, R, I>;
523
+ <A, B>(f: (a: A) => B): <E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<B, unknown, R, I>;
524
+ <A, E, R, I extends Input, B>(self: Parser<A, E, R, I>, f: (a: A) => B): Parser<B, unknown, R, I>;
409
525
  };
410
526
  /**
411
527
  * Transforms the output of a parser with a function returning an `Option`;
@@ -477,6 +593,28 @@ export declare const span: <A, E, R, I extends Input>(self: Parser<A, E, R, I>)
477
593
  * @category consumed input
478
594
  */
479
595
  export declare const withSpan: <A, E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<[output: A, span: Span], E, R, I>;
596
+ /**
597
+ * Transforms the output of a parser together with the offsets it consumed,
598
+ * `[start, end)`: the allocation-free spelling of
599
+ * `map(withSpan(p), ([a, span]) => f(a, span.start, span.end))`, which
600
+ * builds a tuple and a span object on every success. Compiled code passes
601
+ * the offsets to `f` directly.
602
+ *
603
+ * @example
604
+ * ```ts
605
+ * import { Ascii, Parser } from "@thomasfosterau/effect-parse"
606
+ *
607
+ * const name = Ascii.alpha1.pipe(Parser.mapSpan((text, start, end) => ({ text, start, end })))
608
+ * Parser.parse(name, "abc") // Result.succeed({ text: "abc", start: 0, end: 3 })
609
+ * ```
610
+ *
611
+ * @since 0.5.0
612
+ * @category consumed input
613
+ */
614
+ export declare const mapSpan: {
615
+ <A, B>(f: (a: A, start: number, end: number) => B): <E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<B, E, R, I>;
616
+ <A, E, R, I extends Input, B>(self: Parser<A, E, R, I>, f: (a: A, start: number, end: number) => B): Parser<B, E, R, I>;
617
+ };
480
618
  /**
481
619
  * Commits to the current branch: recoverable failures of the parser become
482
620
  * unrecoverable, so enclosing `alt`, `opt`, `repeat`, ... do not try
@@ -535,6 +673,146 @@ export declare const expected: {
535
673
  (description: string): <A, E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<A, E, R, I>;
536
674
  <A, E, R, I extends Input>(self: Parser<A, E, R, I>, description: string): Parser<A, E, R, I>;
537
675
  };
676
+ /**
677
+ * Runs a parser without letting it add to the expectations of later errors
678
+ * (chumsky's `quiet`). Use it on skippers, such as whitespace and comments,
679
+ * that may appear between any two tokens: they stop by failing, and without
680
+ * `quiet` what they would have accepted (`" "`, `"(:"`, ...) is listed in
681
+ * every error raised after them.
682
+ *
683
+ * When the parser succeeds, the hints and the furthest failure it recorded
684
+ * are forgotten, as after a lookahead that succeeded. When it fails
685
+ * recoverably without consuming input, its failure expects nothing, so an
686
+ * enclosing `alt` or `opt` reports only the other alternatives. A failure
687
+ * after consuming input (an unterminated comment) or an unrecoverable one
688
+ * is kept as it is. `Parser.expected` cannot do this: it relabels a failure,
689
+ * and a skipper that matches zero or more times never fails.
690
+ *
691
+ * @example
692
+ * ```ts
693
+ * import { Ascii, Parser, Token } from "@thomasfosterau/effect-parse"
694
+ *
695
+ * const comment = Parser.delimited(Token.literal("(:"), Token.takeTill(":"), Token.literal(":)"))
696
+ * const skip = Parser.quiet(Parser.repeat(Parser.alt(Ascii.multispace1, comment)))
697
+ * const number = Parser.preceded(skip, Ascii.digit1)
698
+ * // Fails expecting only a digit: without `quiet`, also whitespace and "(:"
699
+ * Parser.parse(number, " (: one :) x")
700
+ * ```
701
+ *
702
+ * @since 0.5.0
703
+ * @category error management
704
+ */
705
+ export declare const quiet: <A, E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<A, E, R, I>;
706
+ /**
707
+ * What a fast path (see {@link withFastPath}) returns to leave the input at
708
+ * the current offset to its grammar.
709
+ *
710
+ * @since 0.5.0
711
+ * @category fast paths
712
+ */
713
+ export declare const Defer: typeof Defer$1;
714
+ /**
715
+ * The type of {@link Defer}.
716
+ *
717
+ * @since 0.5.0
718
+ * @category fast paths
719
+ */
720
+ export type Defer = typeof Defer$1;
721
+ /**
722
+ * Puts a hand-written fast path in front of a grammar, which stays the
723
+ * specification: `fast` runs on the state, at the offset where the grammar
724
+ * would, and either returns the value the grammar would return, with
725
+ * `state.pos` where the grammar would stop, or returns {@link Defer}, and
726
+ * the grammar runs from that offset instead. Use it where a scanner written
727
+ * by hand (`indexOf`, a lookup table, interned names) beats compiled code on
728
+ * the tokens that dominate an input, and let the grammar handle everything
729
+ * else.
730
+ *
731
+ * The fast path runs in compiled code only (see the `Compiler` module).
732
+ * Interpreted runs, and so every error, every `Syntax` tree and every trace,
733
+ * come from the grammar alone, so they are exactly the grammar's. It must
734
+ * defer wherever it would not return exactly what the grammar returns, and
735
+ * on partial input wherever the grammar might report `Incomplete`; check it
736
+ * against the grammar with {@link verifyFastPath}.
737
+ *
738
+ * @example
739
+ * ```ts
740
+ * import { Compiler, Parser, Token } from "@thomasfosterau/effect-parse"
741
+ *
742
+ * const text = Token.takeTill("<", { min: 1 })
743
+ * // The same run, found with `indexOf`; anything else (an empty run, the end of a partial input) defers
744
+ * const fastText = Compiler.jit(
745
+ * Parser.withFastPath(text, (state) => {
746
+ * const end = state.input.indexOf("<", state.pos)
747
+ * if (end <= state.pos || end > state.end) return Parser.Defer
748
+ * const value = state.input.slice(state.pos, end)
749
+ * state.pos = end
750
+ * return value
751
+ * })
752
+ * )
753
+ * ```
754
+ *
755
+ * @since 0.5.0
756
+ * @category fast paths
757
+ */
758
+ export declare const withFastPath: {
759
+ <A, I extends Input>(fast: (state: State<I>) => A | Defer): <E, R>(grammar: Parser<A, E, R, I>) => Parser<A, E, R, I>;
760
+ <A, E, R, I extends Input>(grammar: Parser<A, E, R, I>, fast: (state: State<I>) => A | Defer): Parser<A, E, R, I>;
761
+ };
762
+ /**
763
+ * A place where a fast path disagrees with its grammar (see
764
+ * {@link verifyFastPath}).
765
+ *
766
+ * @since 0.5.0
767
+ * @category fast paths
768
+ */
769
+ export interface FastPathMismatch<A, I extends Input> {
770
+ readonly input: I;
771
+ readonly offset: number;
772
+ readonly partial: boolean;
773
+ /** What the fast path returned, and where it stopped. */
774
+ readonly fast: {
775
+ readonly value: A;
776
+ readonly end: number;
777
+ };
778
+ /** What the grammar returned, and where it stopped, or how it failed. */
779
+ readonly grammar: {
780
+ readonly value: A;
781
+ readonly end: number;
782
+ } | {
783
+ readonly failed: ErrMode;
784
+ };
785
+ }
786
+ /**
787
+ * Checks a fast path against its grammar (see {@link withFastPath}): on
788
+ * every input, at every offset, on complete and on partial input, wherever
789
+ * `fast` returns a value, the grammar (run interpreted) must return an
790
+ * equal value (by `Equal.equals`, or `options.equivalence`) and stop at the
791
+ * same offset. Returns every place where it doesn't, so a test asserts that
792
+ * the result is empty; generated inputs, mutated and truncated, find the
793
+ * most. Grammars that use services are not supported.
794
+ *
795
+ * @example
796
+ * ```ts
797
+ * import { Input, Parser, Token } from "@thomasfosterau/effect-parse"
798
+ *
799
+ * const text = Token.takeTill("<", { min: 1 })
800
+ * const fast = (state: Input.State<string>) => {
801
+ * const end = state.input.indexOf("<", state.pos)
802
+ * if (end <= state.pos || end > state.end) return Parser.Defer
803
+ * const value = state.input.slice(state.pos, end)
804
+ * state.pos = end
805
+ * return value
806
+ * }
807
+ * Parser.verifyFastPath(text, fast, ["a<b", "<", "abc"]) // []
808
+ * ```
809
+ *
810
+ * @since 0.5.0
811
+ * @category fast paths
812
+ */
813
+ export declare const verifyFastPath: <A, E, I extends Input>(grammar: Parser<A, E, never, I>, fast: (state: State<I>) => A | Defer, inputs: Iterable<I>, options?: {
814
+ readonly equivalence?: ((a: A, b: A) => boolean) | undefined;
815
+ }) => ReadonlyArray<FastPathMismatch<A, I>>;
538
816
  /**
539
817
  * Transforms the user error (cause) of a parser's failures.
540
818
  *
@@ -631,6 +909,28 @@ export declare const allConsuming: <A, E, R, I extends Input>(self: Parser<A, E,
631
909
  * @category sequencing
632
910
  */
633
911
  export declare const seq: <const Ps extends ReadonlyArray<Parser.Any>>(...parsers: Ps) => Parser<{ -readonly [K in keyof Ps]: Parser.Success<Ps[K]>; }, Parser.Error<Ps[number]>, Parser.Services<Ps[number]>, Parser.InputOf<Ps[number]>>;
912
+ /**
913
+ * Runs parsers in sequence and combines their outputs with `f`, which
914
+ * receives one argument per parser: the allocation-free spelling of
915
+ * `map(seq(...parsers), ([a, b, ...]) => f(a, b, ...))`, which builds a
916
+ * tuple on every success. Compiled code calls `f` with the values directly.
917
+ * {@link zipWith} is the two-parser, pipeable form.
918
+ *
919
+ * @example
920
+ * ```ts
921
+ * import { Ascii, Parser, Token } from "@thomasfosterau/effect-parse"
922
+ *
923
+ * const point = Parser.seqWith(
924
+ * [Ascii.decInt, Token.literal(","), Ascii.decInt],
925
+ * (x, _, y) => ({ x, y })
926
+ * )
927
+ * Parser.parse(point, "3,-4") // Result.succeed({ x: 3, y: -4 })
928
+ * ```
929
+ *
930
+ * @since 0.5.0
931
+ * @category sequencing
932
+ */
933
+ export declare const seqWith: <const Ps extends ReadonlyArray<Parser.Any>, B>(parsers: Ps, f: (...values: { -readonly [K in keyof Ps]: Parser.Success<Ps[K]>; }) => B) => Parser<B, Parser.Error<Ps[number]>, Parser.Services<Ps[number]>, Parser.InputOf<Ps[number]>>;
634
934
  /**
635
935
  * Runs a record of parsers in sequence (in key order), collecting their
636
936
  * outputs in a record. This is the Effect counterpart to winnow's
@@ -804,6 +1104,16 @@ declare const let_: {
804
1104
  * @category choice
805
1105
  */
806
1106
  export declare const alt: <const Ps extends ReadonlyArray<Parser.Any>>(...parsers: Ps) => Parser<Parser.Success<Ps[number]>, Parser.Error<Ps[number]>, Parser.Services<Ps[number]>, Parser.InputOf<Ps[number]>>;
1107
+ /**
1108
+ * The overloads of {@link dispatch}.
1109
+ *
1110
+ * @since 0.5.0
1111
+ * @category choice
1112
+ */
1113
+ export interface DispatchFn {
1114
+ <K, E, R, I extends Input, P extends Parser.Any>(selector: Parser<K, E, R, I>, cases: (key: K) => P | undefined): Parser<Parser.Success<P>, E | Parser.Error<P>, R | Parser.Services<P>, I & Parser.InputOf<P>>;
1115
+ <K extends PropertyKey, E, R, I extends Input, const Cases extends { readonly [key in K]?: Parser.Any; }, Otherwise extends Parser.Any = never>(selector: Parser<K, E, R, I>, cases: Cases, otherwise?: Otherwise): Parser<Parser.Success<NonNullable<Cases[keyof Cases]> | Otherwise>, E | Parser.Error<NonNullable<Cases[keyof Cases]> | Otherwise>, R | Parser.Services<NonNullable<Cases[keyof Cases]> | Otherwise>, I & Parser.InputOf<NonNullable<Cases[keyof Cases]> | Otherwise>>;
1116
+ }
807
1117
  /**
808
1118
  * Selects the parser to run next based on the output of `selector`, like a
809
1119
  * `match` over the input (winnow's `dispatch!`). If no case matches, the
@@ -838,10 +1148,7 @@ export declare const alt: <const Ps extends ReadonlyArray<Parser.Any>>(...parser
838
1148
  * @since 0.1.0
839
1149
  * @category choice
840
1150
  */
841
- export declare const dispatch: {
842
- <K, E, R, I extends Input, P extends Parser.Any>(selector: Parser<K, E, R, I>, cases: (key: K) => P | undefined): Parser<Parser.Success<P>, E | Parser.Error<P>, R | Parser.Services<P>, I & Parser.InputOf<P>>;
843
- <K extends PropertyKey, E, R, I extends Input, const Cases extends { readonly [key in K]?: Parser.Any; }, Otherwise extends Parser.Any = never>(selector: Parser<K, E, R, I>, cases: Cases, otherwise?: Otherwise): Parser<Parser.Success<NonNullable<Cases[keyof Cases]> | Otherwise>, E | Parser.Error<NonNullable<Cases[keyof Cases]> | Otherwise>, R | Parser.Services<NonNullable<Cases[keyof Cases]> | Otherwise>, I & Parser.InputOf<NonNullable<Cases[keyof Cases]> | Otherwise>>;
844
- };
1151
+ export declare const dispatch: DispatchFn;
845
1152
  /**
846
1153
  * Applies every parser exactly once, in whatever order they match, and
847
1154
  * returns their outputs in the order the parsers were given (winnow's and
@@ -1130,6 +1437,16 @@ export interface ParseOptions {
1130
1437
  export interface ParseOptionsWithContext<R> extends ParseOptions {
1131
1438
  readonly context: Context.Context<R>;
1132
1439
  }
1440
+ /**
1441
+ * The overloads of {@link parse}.
1442
+ *
1443
+ * @since 0.5.0
1444
+ * @category running
1445
+ */
1446
+ export interface ParseFn {
1447
+ <A, E, I extends Input>(self: Parser<A, E, never, I>, input: NoInfer<Source<I>>, options?: ParseOptions): Result.Result<A, ParseError.ParseError<E>>;
1448
+ <A, E, R, I extends Input>(self: Parser<A, E, R, I>, input: NoInfer<Source<I>>, options: ParseOptionsWithContext<R>): Result.Result<A, ParseError.ParseError<E>>;
1449
+ }
1133
1450
  /**
1134
1451
  * Runs a parser against a complete input, requiring the whole input to be
1135
1452
  * consumed (winnow's `Parser::parse`).
@@ -1146,20 +1463,34 @@ export interface ParseOptionsWithContext<R> extends ParseOptions {
1146
1463
  * @since 0.1.0
1147
1464
  * @category running
1148
1465
  */
1149
- export declare const parse: {
1150
- <A, E, I extends Input>(self: Parser<A, E, never, I>, input: NoInfer<Source<I>>, options?: ParseOptions): Result.Result<A, ParseError.ParseError<E>>;
1151
- <A, E, R, I extends Input>(self: Parser<A, E, R, I>, input: NoInfer<Source<I>>, options: ParseOptionsWithContext<R>): Result.Result<A, ParseError.ParseError<E>>;
1152
- };
1466
+ export declare const parse: ParseFn;
1153
1467
  /**
1154
- * Like {@link parse}, but throws the `ParseError` on failure.
1468
+ * The overloads of {@link parseSync}.
1155
1469
  *
1156
- * @since 0.1.0
1470
+ * @since 0.5.0
1157
1471
  * @category running
1158
1472
  */
1159
- export declare const parseSync: {
1473
+ export interface ParseSyncFn {
1160
1474
  <A, E, I extends Input>(self: Parser<A, E, never, I>, input: NoInfer<Source<I>>, options?: ParseOptions): A;
1161
1475
  <A, E, R, I extends Input>(self: Parser<A, E, R, I>, input: NoInfer<Source<I>>, options: ParseOptionsWithContext<R>): A;
1162
- };
1476
+ }
1477
+ /**
1478
+ * Like {@link parse}, but throws the `ParseError` on failure.
1479
+ *
1480
+ * @since 0.1.0
1481
+ * @category running
1482
+ */
1483
+ export declare const parseSync: ParseSyncFn;
1484
+ /**
1485
+ * The overloads of {@link parsePeek}.
1486
+ *
1487
+ * @since 0.5.0
1488
+ * @category running
1489
+ */
1490
+ export interface ParsePeekFn {
1491
+ <A, E, I extends Input>(self: Parser<A, E, never, I>, input: NoInfer<Source<I>>, options?: ParseOptions): Result.Result<[remaining: Slice<I>, output: A], ParseError.ParseError<E>>;
1492
+ <A, E, R, I extends Input>(self: Parser<A, E, R, I>, input: NoInfer<Source<I>>, options: ParseOptionsWithContext<R>): Result.Result<[remaining: Slice<I>, output: A], ParseError.ParseError<E>>;
1493
+ }
1163
1494
  /**
1164
1495
  * Runs a parser against the start of an input, returning the remaining
1165
1496
  * input along with the output, nom-style (winnow's `parse_peek`, nom's
@@ -1172,10 +1503,7 @@ export declare const parseSync: {
1172
1503
  * @since 0.1.0
1173
1504
  * @category running
1174
1505
  */
1175
- export declare const parsePeek: {
1176
- <A, E, I extends Input>(self: Parser<A, E, never, I>, input: NoInfer<Source<I>>, options?: ParseOptions): Result.Result<[remaining: Slice<I>, output: A], ParseError.ParseError<E>>;
1177
- <A, E, R, I extends Input>(self: Parser<A, E, R, I>, input: NoInfer<Source<I>>, options: ParseOptionsWithContext<R>): Result.Result<[remaining: Slice<I>, output: A], ParseError.ParseError<E>>;
1178
- };
1506
+ export declare const parsePeek: ParsePeekFn;
1179
1507
  /**
1180
1508
  * The outcome of parsing a partial (streaming) input.
1181
1509
  *
@@ -1193,6 +1521,16 @@ export type PartialResult<A> = {
1193
1521
  readonly _tag: "Incomplete";
1194
1522
  readonly needed: Option.Option<number>;
1195
1523
  };
1524
+ /**
1525
+ * The overloads of {@link parsePartial}.
1526
+ *
1527
+ * @since 0.5.0
1528
+ * @category running
1529
+ */
1530
+ export interface ParsePartialFn {
1531
+ <A, E, I extends Input>(self: Parser<A, E, never, I>, input: NoInfer<Source<I>>, options?: ParseOptions): Result.Result<PartialResult<A>, ParseError.ParseError<E>>;
1532
+ <A, E, R, I extends Input>(self: Parser<A, E, R, I>, input: NoInfer<Source<I>>, options: ParseOptionsWithContext<R>): Result.Result<PartialResult<A>, ParseError.ParseError<E>>;
1533
+ }
1196
1534
  /**
1197
1535
  * Runs a parser against a *partial* input, i.e. a chunk of a stream that may
1198
1536
  * be followed by more data (winnow's `Partial`, nom's `streaming` parsers).
@@ -1222,10 +1560,7 @@ export type PartialResult<A> = {
1222
1560
  * @since 0.1.0
1223
1561
  * @category running
1224
1562
  */
1225
- export declare const parsePartial: {
1226
- <A, E, I extends Input>(self: Parser<A, E, never, I>, input: NoInfer<Source<I>>, options?: ParseOptions): Result.Result<PartialResult<A>, ParseError.ParseError<E>>;
1227
- <A, E, R, I extends Input>(self: Parser<A, E, R, I>, input: NoInfer<Source<I>>, options: ParseOptionsWithContext<R>): Result.Result<PartialResult<A>, ParseError.ParseError<E>>;
1228
- };
1563
+ export declare const parsePartial: ParsePartialFn;
1229
1564
  /**
1230
1565
  * Runs a parser against a complete input as an `Effect`. Services required
1231
1566
  * by the parser are taken from the Effect's context.
@@ -1328,6 +1663,16 @@ export interface RecoverableResult<A, E> {
1328
1663
  /** Every error encountered: recovered ones, then the fatal one (if any). */
1329
1664
  readonly errors: ReadonlyArray<ParseError.ParseError<E>>;
1330
1665
  }
1666
+ /**
1667
+ * The overloads of {@link parseRecoverable}.
1668
+ *
1669
+ * @since 0.5.0
1670
+ * @category running
1671
+ */
1672
+ export interface ParseRecoverableFn {
1673
+ <A, E, I extends Input>(self: Parser<A, E, never, I>, input: NoInfer<Source<I>>, options?: ParseOptions): RecoverableResult<A, E>;
1674
+ <A, E, R, I extends Input>(self: Parser<A, E, R, I>, input: NoInfer<Source<I>>, options: ParseOptionsWithContext<R>): RecoverableResult<A, E>;
1675
+ }
1331
1676
  /**
1332
1677
  * Runs a parser with error recovery enabled (winnow's `Recoverable`
1333
1678
  * stream). Failures handled by {@link resumeAfter} and {@link retryAfter}
@@ -1336,9 +1681,6 @@ export interface RecoverableResult<A, E> {
1336
1681
  * @since 0.1.0
1337
1682
  * @category running
1338
1683
  */
1339
- export declare const parseRecoverable: {
1340
- <A, E, I extends Input>(self: Parser<A, E, never, I>, input: NoInfer<Source<I>>, options?: ParseOptions): RecoverableResult<A, E>;
1341
- <A, E, R, I extends Input>(self: Parser<A, E, R, I>, input: NoInfer<Source<I>>, options: ParseOptionsWithContext<R>): RecoverableResult<A, E>;
1342
- };
1684
+ export declare const parseRecoverable: ParseRecoverableFn;
1343
1685
  export { type ErrorKind, let_ as let, void_ as void };
1344
1686
  //# sourceMappingURL=Parser.d.ts.map