@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.
- package/README.md +40 -14
- package/dist/Ascii.d.ts +11 -4
- package/dist/Ascii.d.ts.map +1 -1
- package/dist/Ascii.js +7 -1
- package/dist/Ascii.js.map +1 -1
- package/dist/Binary.d.ts.map +1 -1
- package/dist/Binary.js +64 -35
- package/dist/Binary.js.map +1 -1
- package/dist/Bits.d.ts.map +1 -1
- package/dist/Bits.js +7 -4
- package/dist/Bits.js.map +1 -1
- package/dist/Compiler.d.ts +74 -2
- package/dist/Compiler.d.ts.map +1 -1
- package/dist/Compiler.js +78 -1
- package/dist/Compiler.js.map +1 -1
- package/dist/Expression.d.ts.map +1 -1
- package/dist/Expression.js +86 -74
- package/dist/Expression.js.map +1 -1
- package/dist/Input.d.ts +37 -4
- package/dist/Input.d.ts.map +1 -1
- package/dist/Input.js +42 -0
- package/dist/Input.js.map +1 -1
- package/dist/Nom.d.ts +5 -15
- package/dist/Nom.d.ts.map +1 -1
- package/dist/Nom.js.map +1 -1
- package/dist/ParseError.d.ts +2 -2
- package/dist/ParseError.d.ts.map +1 -1
- package/dist/ParseError.js +1 -1
- package/dist/ParseError.js.map +1 -1
- package/dist/Parser.d.ts +370 -28
- package/dist/Parser.d.ts.map +1 -1
- package/dist/Parser.js +390 -19
- package/dist/Parser.js.map +1 -1
- package/dist/ParserSchema.js +2 -2
- package/dist/ParserSchema.js.map +1 -1
- package/dist/ParserStream.d.ts +3 -2
- package/dist/ParserStream.d.ts.map +1 -1
- package/dist/ParserStream.js +15 -10
- package/dist/ParserStream.js.map +1 -1
- package/dist/Syntax.d.ts +23 -5
- package/dist/Syntax.d.ts.map +1 -1
- package/dist/Syntax.js.map +1 -1
- package/dist/Text.d.ts.map +1 -1
- package/dist/Text.js +9 -9
- package/dist/Text.js.map +1 -1
- package/dist/Token.d.ts +55 -10
- package/dist/Token.d.ts.map +1 -1
- package/dist/Token.js +59 -21
- package/dist/Token.js.map +1 -1
- package/dist/internal/compiler/closure.d.ts.map +1 -1
- package/dist/internal/compiler/closure.js +257 -97
- package/dist/internal/compiler/closure.js.map +1 -1
- package/dist/internal/compiler/entries.d.ts +3 -1
- package/dist/internal/compiler/entries.d.ts.map +1 -1
- package/dist/internal/compiler/entries.js +3 -2
- package/dist/internal/compiler/entries.js.map +1 -1
- package/dist/internal/compiler/first.d.ts.map +1 -1
- package/dist/internal/compiler/first.js +7 -1
- package/dist/internal/compiler/first.js.map +1 -1
- package/dist/internal/compiler/graph.d.ts +17 -0
- package/dist/internal/compiler/graph.d.ts.map +1 -0
- package/dist/internal/compiler/graph.js +56 -0
- package/dist/internal/compiler/graph.js.map +1 -0
- package/dist/internal/compiler/jit.d.ts +5 -0
- package/dist/internal/compiler/jit.d.ts.map +1 -1
- package/dist/internal/compiler/jit.js +185 -96
- package/dist/internal/compiler/jit.js.map +1 -1
- package/dist/internal/compiler/registry.d.ts +10 -2
- package/dist/internal/compiler/registry.d.ts.map +1 -1
- package/dist/internal/compiler/registry.js.map +1 -1
- package/dist/internal/compiler/search.d.ts +32 -0
- package/dist/internal/compiler/search.d.ts.map +1 -0
- package/dist/internal/compiler/search.js +68 -0
- package/dist/internal/compiler/search.js.map +1 -0
- package/dist/internal/compiler/sets.d.ts.map +1 -1
- package/dist/internal/compiler/sets.js +1 -1
- package/dist/internal/compiler/sets.js.map +1 -1
- package/dist/internal/compiler/wasm.d.ts +8 -0
- package/dist/internal/compiler/wasm.d.ts.map +1 -0
- package/dist/internal/compiler/wasm.js +2769 -0
- package/dist/internal/compiler/wasm.js.map +1 -0
- package/dist/internal/compiler/wasmAsm.d.ts +199 -0
- package/dist/internal/compiler/wasmAsm.d.ts.map +1 -0
- package/dist/internal/compiler/wasmAsm.js +427 -0
- package/dist/internal/compiler/wasmAsm.js.map +1 -0
- package/dist/internal/entries.d.ts +3 -1
- package/dist/internal/entries.d.ts.map +1 -1
- package/dist/internal/entries.js +1 -2
- package/dist/internal/entries.js.map +1 -1
- package/dist/internal/node.d.ts +58 -2
- package/dist/internal/node.d.ts.map +1 -1
- package/dist/internal/node.js +13 -3
- package/dist/internal/node.js.map +1 -1
- package/dist/internal/numbers.d.ts.map +1 -1
- package/dist/internal/numbers.js.map +1 -1
- package/dist/internal/run.d.ts +12 -0
- package/dist/internal/run.d.ts.map +1 -1
- package/dist/internal/run.js +51 -11
- package/dist/internal/run.js.map +1 -1
- package/dist/internal/stack.d.ts +6 -0
- package/dist/internal/stack.d.ts.map +1 -1
- package/dist/internal/stack.js +8 -2
- package/dist/internal/stack.js.map +1 -1
- package/dist/internal/syntax.d.ts +4 -4
- package/dist/internal/syntax.d.ts.map +1 -1
- package/dist/internal/syntax.js +18 -10
- package/dist/internal/syntax.js.map +1 -1
- package/dist/internal/text.d.ts +32 -0
- package/dist/internal/text.d.ts.map +1 -1
- package/dist/internal/text.js +68 -14
- package/dist/internal/text.js.map +1 -1
- package/dist/internal/tokens.d.ts +13 -0
- package/dist/internal/tokens.d.ts.map +1 -1
- package/dist/internal/tokens.js +59 -39
- package/dist/internal/tokens.js.map +1 -1
- package/package.json +5 -4
- package/src/Ascii.ts +42 -9
- package/src/Binary.ts +151 -71
- package/src/Bits.ts +12 -6
- package/src/Compiler.ts +101 -10
- package/src/Expression.ts +94 -81
- package/src/Input.ts +65 -6
- package/src/Nom.ts +15 -5
- package/src/ParseError.ts +9 -4
- package/src/Parser.ts +682 -129
- package/src/ParserSchema.ts +1 -1
- package/src/ParserStream.ts +40 -19
- package/src/Syntax.ts +60 -36
- package/src/Text.ts +16 -15
- package/src/Token.ts +138 -29
- package/src/internal/compiler/closure.ts +362 -135
- package/src/internal/compiler/entries.ts +4 -2
- package/src/internal/compiler/first.ts +10 -0
- package/src/internal/compiler/graph.ts +68 -0
- package/src/internal/compiler/jit.ts +284 -154
- package/src/internal/compiler/registry.ts +10 -2
- package/src/internal/compiler/search.ts +68 -0
- package/src/internal/compiler/sets.ts +7 -3
- package/src/internal/compiler/wasm.ts +3203 -0
- package/src/internal/compiler/wasmAsm.ts +484 -0
- package/src/internal/entries.ts +10 -4
- package/src/internal/node.ts +54 -4
- package/src/internal/numbers.ts +3 -1
- package/src/internal/run.ts +71 -12
- package/src/internal/stack.ts +8 -1
- package/src/internal/syntax.ts +39 -18
- package/src/internal/text.ts +97 -9
- package/src/internal/tokens.ts +96 -14
package/dist/ParseError.js.map
CHANGED
|
@@ -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,
|
|
408
|
-
<A, E, R, I extends Input, B>(self: Parser<A, E, R, I>, f: (a: A) => B): Parser<B,
|
|
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
|
-
*
|
|
1468
|
+
* The overloads of {@link parseSync}.
|
|
1155
1469
|
*
|
|
1156
|
-
* @since 0.
|
|
1470
|
+
* @since 0.5.0
|
|
1157
1471
|
* @category running
|
|
1158
1472
|
*/
|
|
1159
|
-
export
|
|
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
|