UNPKG

prsc

Version:

Tiny parser combinators library

1 lines 34.7 kB
{"version":3,"file":"prsc.umd.cjs","sources":["../src/parser-combinators.ts","../src/streaming.ts"],"sourcesContent":["/**\n * The result of parsing - either success (with an offset at which to resume parsing the next thing)\n * or failure. If a failure is fatal, parsing should not continue to try alternative options.\n *\n * A ParseResult may contain a value that represents the parsed input.\n *\n * @public\n */\nexport type ParseResult<T> =\n\t| { success: true; offset: number; value: T }\n\t| { success: false; offset: number; expected: string[]; fatal: boolean };\n\n/**\n * A parser is a function that tries to match whatever it expects at the given offset in the input\n * string. Returns a ParseResult.\n *\n * @public\n */\nexport type Parser<T> = (input: string, offset: number) => ParseResult<T>;\n\n/**\n * Creates a successful ParseResult containing the given value.\n *\n * @public\n *\n * @param offset - The offset in the input at which to continue parsing\n * @param value - The value resulting from applying the parser\n */\nexport function okWithValue<T>(offset: number, value: T): ParseResult<T> {\n\treturn { success: true, offset, value };\n}\n\n/**\n * Creates a successful ParseResult with an undefined value. Use this to signal success in cases\n * where no value is required.\n *\n * @public\n *\n * @param offset - The offset in the input at which to continue parsing\n */\nexport function ok(offset: number): ParseResult<undefined> {\n\treturn okWithValue(offset, undefined);\n}\n\n/**\n * Creates an unsuccessful ParseResult (parse error) at the given offset.\n *\n * @public\n *\n * @param offset - The offset in the input at which matching failed\n * @param expected - An array of strings indicating things that were expected at offset\n * @param fatal - If true, no other branches should be tried as a result of this error\n */\nexport function error<T>(\n\toffset: number,\n\texpected: string[],\n\tfatal: boolean = false\n): ParseResult<T> {\n\treturn { success: false, offset, expected, fatal };\n}\n\n/**\n * Creates a Parser that matches the given string.\n *\n * @public\n *\n * @param token - The expected string\n */\nexport function token(token: string): Parser<string> {\n\treturn (input, offset) => {\n\t\tconst offsetAfter = offset + token.length;\n\t\tif (input.slice(offset, offsetAfter) === token) {\n\t\t\treturn okWithValue(offsetAfter, token);\n\t\t}\n\t\treturn error(offset, [token]);\n\t};\n}\n\nfunction lengthFromCodePoint(cp: number): number {\n\treturn cp > 0xffff ? 2 : 1;\n}\n\n/**\n * Creates a Parser that skips the next code point if the given predicate returns true.\n *\n * This counts in unicode characters (code points), not UTF-16 code units.\n *\n * To match a sequence of code points, consider using `codepoints` instead.\n *\n * @public\n *\n * @param isMatch - callback called with the next codepoint, should return whether that matches\n * @param expected - expected strings to return if the codepoint does not match\n */\nexport function codepoint(\n\tisMatch: (codepoint: number) => boolean,\n\texpected: string[]\n): Parser<void> {\n\treturn (input: string, offset: number) => {\n\t\tconst cp = input.codePointAt(offset);\n\t\tif (cp === undefined || !isMatch(cp)) {\n\t\t\treturn error(offset, expected);\n\t\t}\n\t\treturn ok(offset + lengthFromCodePoint(cp));\n\t};\n}\n\n/**\n * Creates a Parser that skips code points while the given predicate returns true.\n *\n * This counts in unicode characters (code points), not UTF-16 code units.\n *\n * This acts like `starConsumed(codepoint(isMatch, []))` if expected is not set, or as\n * `plusConsumed(codepoint(isMatch, expected))` if it is, but is much more efficient than either of\n * those combinations.\n *\n * @public\n *\n * @param isMatch - callback called for each codepoint, should return whether that matches\n * @param expected - expected strings to return if the first codepoint does not match\n */\nexport function codepoints(\n\tisMatch: (codepoint: number) => boolean,\n\texpected?: string[]\n): Parser<void> {\n\treturn (input: string, offset: number) => {\n\t\tconst startOffset = offset;\n\t\twhile (true) {\n\t\t\tconst cp = input.codePointAt(offset);\n\t\t\tif (cp === undefined) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (!isMatch(cp)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\toffset += cp > 0xffff ? 2 : 1;\n\t\t}\n\t\tif (expected !== undefined && offset === startOffset) {\n\t\t\treturn error(offset, expected);\n\t\t}\n\t\treturn ok(offset);\n\t};\n}\n\n/**\n * Creates a Parser that matches a single character from a range of codepoints.\n *\n * Use `recognize` if you need the character that was matched.\n *\n * @public\n *\n * @param firstCodePoint - The first code point to accept\n * @param lastCodePoint - The last code point to accept (inclusive)\n */\nexport function range(\n\tfirstCodePoint: number,\n\tlastCodePoint: number,\n\texpected?: string[]\n): Parser<void> {\n\treturn codepoint(\n\t\t(cp) => firstCodePoint <= cp && cp <= lastCodePoint,\n\t\texpected || [\n\t\t\t`${String.fromCodePoint(firstCodePoint)}-${String.fromCodePoint(lastCodePoint)}`,\n\t\t]\n\t);\n}\n\n/**\n * Creates a Parser that skips the given number of characters.\n *\n * This counts in unicode characters (code points), not UTF-16 code units.\n *\n * @public\n *\n * @param nCodepoints - number of characters to skip\n */\nexport function skipChars(nCodepoints: number): Parser<void> {\n\treturn (input: string, offset: number) => {\n\t\tlet i = nCodepoints;\n\t\twhile (i > 0) {\n\t\t\tconst cp = input.codePointAt(offset);\n\t\t\tif (cp === undefined) {\n\t\t\t\treturn error(offset, ['any character']);\n\t\t\t}\n\t\t\toffset += lengthFromCodePoint(cp);\n\t\t\ti -= 1;\n\t\t}\n\t\treturn ok(offset);\n\t};\n}\n\n/**\n * Creates a Parser that applies the given function to each value generated by the given parser.\n *\n * @public\n *\n * @param parser - Parser to map over\n * @param map - Function to transform values generated by parser\n */\nexport function map<T, U>(parser: Parser<T>, map: (v: T) => U): Parser<U> {\n\treturn (input, offset) => {\n\t\tconst res = parser(input, offset);\n\t\tif (!res.success) {\n\t\t\treturn res;\n\t\t}\n\t\treturn okWithValue(res.offset, map(res.value));\n\t};\n}\n\n/**\n * Creates a Parser that applies the given parser but discards the resulting value.\n *\n * @public\n *\n * @param parser - Parser to apply\n */\nexport function consume<T>(parser: Parser<T>): Parser<void> {\n\treturn map(parser, () => undefined);\n}\n\n/**\n * Creates a Parser that uses the given filter predicate to check values generated by the given\n * parser. Values that pass the predicate are passed through, those that don't return a parse error\n * instead.\n *\n * @public\n *\n * @param parser - Parser to filter\n * @param filter - Predicate function over the inner parser's values\n * @param expected - Expected values for parse errors generated when the filter rejects a value\n * @param fatal - Whether the error returned when the filter rejects should be fatal\n */\nexport function filter<T>(\n\tparser: Parser<T>,\n\tfilter: (v: T) => boolean,\n\texpected: string[],\n\tfatal?: boolean\n): Parser<T> {\n\treturn (input, offset) => {\n\t\tconst res = parser(input, offset);\n\t\tif (!res.success) {\n\t\t\treturn res;\n\t\t}\n\t\tif (!filter(res.value)) {\n\t\t\treturn error(offset, expected, fatal);\n\t\t}\n\t\treturn res;\n\t};\n}\n\n/**\n * Creates a Parser that applies each of the given parsers in turn until one matches, then returns\n * that parser's result. If no parser matches, an error is returned reflecting the furthest offset\n * reached in the input string. If any parser returns a fatal error, no further branches are tried.\n *\n * @public\n *\n * @param parsers - Parsers to attempt to apply\n * @param expected - Overrides the expected value used if none of the inner parsers match\n */\nexport function or<T>(parsers: Parser<T>[], expected?: string[]): Parser<T> {\n\treturn (input, offset) => {\n\t\tlet lastError: ParseResult<T> | null = null;\n\t\tfor (const parser of parsers) {\n\t\t\tconst res = parser(input, offset);\n\t\t\tif (res.success) {\n\t\t\t\treturn res;\n\t\t\t}\n\n\t\t\tif (lastError === null || res.offset > lastError.offset) {\n\t\t\t\tlastError = res;\n\t\t\t} else if (res.offset === lastError.offset && expected === undefined) {\n\t\t\t\tlastError.expected = lastError.expected.concat(res.expected);\n\t\t\t}\n\t\t\tif (res.fatal) {\n\t\t\t\treturn res;\n\t\t\t}\n\t\t}\n\t\texpected = expected || lastError?.expected || [];\n\t\tif (lastError) {\n\t\t\tlastError.expected = expected;\n\t\t}\n\t\treturn lastError || error(offset, expected);\n\t};\n}\n\n/**\n * Creates a Parser that tries to apply the given parser optionally. It returns the inner parser's\n * result if succesful, and otherwise indicates success at the starting offset with a `null` value.\n *\n * If the inner parser returns a fatal failure, the error is returned as-is.\n *\n * @public\n *\n * @param parser - Parser to attempt to apply\n */\nexport function optional<T>(parser: Parser<T>): Parser<T | null> {\n\treturn (input, offset) => {\n\t\tconst res = parser(input, offset);\n\t\tif (!res.success && !res.fatal) {\n\t\t\treturn okWithValue(offset, null);\n\t\t}\n\n\t\treturn res;\n\t};\n}\n\n/**\n * Creates a Parser that tries to apply the given parser zero or more times in sequence. Values for\n * successful matches are collected in an array. Once the inner parser no longer matches, success is\n * returned at the offset reached with the accumulated values.\n *\n * If the inner parser returns a fatal failure, the error is returned as-is.\n *\n * @public\n *\n * @param parser - Parser to apply repeatedly\n */\nexport function star<T>(parser: Parser<T>): Parser<T[]> {\n\treturn (input, offset) => {\n\t\tlet ts: T[] = [];\n\t\tlet nextOffset = offset;\n\t\twhile (true) {\n\t\t\tconst res = parser(input, nextOffset);\n\t\t\tif (!res.success) {\n\t\t\t\tif (res.fatal) {\n\t\t\t\t\treturn res;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tts.push(res.value);\n\t\t\tif (res.offset === nextOffset) {\n\t\t\t\t// Did not advance\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tnextOffset = res.offset;\n\t\t}\n\n\t\treturn okWithValue(nextOffset, ts);\n\t};\n}\n\n/**\n * Creates a Parser that tries to apply the given parser zero or more times in sequence. Values for\n * successful matches are discarded. Once the inner parser no longer matches, success is returned at\n * the offset reached.\n *\n * If the inner parser returns a fatal failure, the error is returned as-is.\n *\n * @public\n *\n * @param parser - Parser to apply repeatedly\n */\nexport function starConsumed<T>(parser: Parser<T>): Parser<void> {\n\treturn (input, offset) => {\n\t\tlet nextOffset = offset;\n\t\twhile (true) {\n\t\t\tconst res = parser(input, nextOffset);\n\t\t\tif (!res.success) {\n\t\t\t\tif (res.fatal) {\n\t\t\t\t\treturn res;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (res.offset === nextOffset) {\n\t\t\t\t// Did not advance\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tnextOffset = res.offset;\n\t\t}\n\n\t\treturn ok(nextOffset);\n\t};\n}\n\n/**\n * Creates a parser that discards undefined values from the array produced by the\n * given parser.\n *\n * Useful in combination with `star`, `or` and `consume`:\n *\n * ```\n * const a: Parser<string> = token('a');\n * const b: Parser<void> = consume(token('b'));\n * const abs: Parser<(string | void)[]> = star(or<string | void>([a, b]));\n * const as: Parser<string[]> = filterUndefined(abs);\n * ```\n *\n * @public\n *\n * @param parser - Parser to apply, should produce an array that may contain undefined entries.\n */\nexport function filterUndefined<T>(parser: Parser<(T | void)[]>): Parser<T[]> {\n\treturn map(parser, (vs) => vs.filter((v) => v !== undefined) as T[]);\n}\n\n/**\n * Creates a Parser that applies the given two parsers in sequence, returning success only if both\n * succeed. The given join function is used to combine the values from both parsers into the single\n * value to return. If either parser fails, the failure is returned as-is.\n *\n * @public\n *\n * @param parser1 - First parser to apply\n * @param parser2 - Parser to apply after the first one is successful\n * @param join - Function used to combine the values of both parsers\n */\nexport function then<T1, T2, T>(\n\tparser1: Parser<T1>,\n\tparser2: Parser<T2>,\n\tjoin: (value1: T1, value2: T2) => T\n): Parser<T> {\n\treturn (input, offset) => {\n\t\tconst r1 = parser1(input, offset);\n\t\tif (!r1.success) {\n\t\t\treturn r1;\n\t\t}\n\t\tconst r2 = parser2(input, r1.offset);\n\t\tif (!r2.success) {\n\t\t\treturn r2;\n\t\t}\n\t\treturn okWithValue(r2.offset, join(r1.value, r2.value));\n\t};\n}\n\n/**\n * Creates a parser that applies the given parsers in sequence, returning a tuple of the\n * corresponding values if all of them accept.\n *\n * This can be slightly less efficient than nesting `then` and its variations, but may be a lot more\n * readable. If you don't care about any of the values produced, consider using `sequenceConsumed`\n * instead.\n *\n * @public\n *\n * @param parsers - Parsers to apply one after the other\n */\nexport function sequence<Ts extends unknown[]>(\n\t...parsers: { [key in keyof Ts]: Parser<Ts[key]> }\n): Parser<Ts> {\n\treturn (input, offset) => {\n\t\tconst values: Ts = [] as unknown[] as Ts;\n\t\tfor (const parser of parsers) {\n\t\t\tconst res = parser(input, offset);\n\t\t\tif (!res.success) {\n\t\t\t\treturn res;\n\t\t\t}\n\t\t\toffset = res.offset;\n\t\t\tvalues.push(res.value);\n\t\t}\n\t\treturn okWithValue(offset, values);\n\t};\n}\n\n/**\n * Creates a parser that applies the given parsers in sequence, discarding all of the values\n * produced.\n *\n * @public\n *\n * @param parsers - Parsers to apply one after the other\n */\nexport function sequenceConsumed(...parsers: Parser<unknown>[]): Parser<void> {\n\treturn (input, offset) => {\n\t\tfor (const parser of parsers) {\n\t\t\tconst res = parser(input, offset);\n\t\t\tif (!res.success) {\n\t\t\t\treturn res;\n\t\t\t}\n\t\t\toffset = res.offset;\n\t\t}\n\t\treturn ok(offset);\n\t};\n}\n\n/**\n * Creates a Parser that tries to apply the given parser one or more times in sequence. Values for\n * successful matches are collected in an array. Once the inner parser no longer matches, success is\n * returned at the offset reached with the accumulated values. The parser is required to match at\n * least once, so an initial failure is returned as-is.\n *\n * If the inner parser returns a fatal failure, the error is returned as-is.\n *\n * @public\n *\n * @param parser - The parser to apply repeatedly\n */\nexport function plus<T>(parser: Parser<T>): Parser<T[]> {\n\treturn then(parser, star(parser), (v, vs) => [v].concat(vs));\n}\n\n/**\n * Returns the first of the given two arguments. Useful as a `join` function for `then`. See also\n * `followed`.\n *\n * @public\n *\n * @param x - Argument to return\n * @param y - Argument to ignore\n */\nexport function first<T1, T2>(x: T1, y: T2): T1 {\n\treturn x;\n}\n\n/**\n * Returns the second of the given two arguments. Useful as a `join` function for `then`. See also\n * `preceded`.\n *\n * @public\n *\n * @param x - Argument to ignore\n * @param y - Argument to return\n */\nexport function second<T1, T2>(x: T1, y: T2): T2 {\n\treturn y;\n}\n\n/**\n * Creates a Parser that tries to apply the given parser one or more times in sequence. Values for\n * successful matches are discarded. Once the inner parser no longer matches, success is returned at\n * the offset reached. The parser is required to match at least once, so an initial failure is\n * returned as-is.\n *\n * If the inner parser returns a fatal failure, the error is returned as-is.\n *\n * @public\n *\n * @param parser - The parser to apply repeatedly\n */\nexport function plusConsumed<T>(parser: Parser<T>): Parser<void> {\n\treturn then(parser, starConsumed(parser), second);\n}\n\n/**\n * Creates a Parser that applies the given two parsers in sequence, returning the result of the\n * second if the first succeeds.\n *\n * Equivalent to `then(before, parser, second)`.\n *\n * @public\n *\n * @param before - First parser to apply, value is discarded\n * @param parser - Second parser to apply, value is kept\n */\nexport function preceded<TBefore, T>(before: Parser<TBefore>, parser: Parser<T>): Parser<T> {\n\treturn then(before, parser, second);\n}\n\n/**\n * Creates a Parser that applies the given two parsers in sequence, returning the result value of\n * the first at the offset of the second if both succeed. If either parser fails the error is\n * returned as-is.\n *\n * Equivalent to `then(parser, after, first)`.\n *\n * @public\n *\n * @param parser - First parser to apply, value is kept\n * @param before - Second parser to apply, value is discarded\n */\nexport function followed<T, TAfter>(parser: Parser<T>, after: Parser<TAfter>): Parser<T> {\n\treturn then(parser, after, first);\n}\n\n/**\n * Creates a Parser that applies the given parsers in sequence, returning the result value of the\n * middle parser at the offset of the third if all are successful. If any parser fails, the error is\n * returned as-is.\n *\n * Optionally makes errors by the second and third parsers fatal if `cutAfterOpen` is `true`.\n *\n * @public\n *\n * @param open - First parser to apply, value is discarded\n * @param inner - Second parser to apply, value is kept\n * @param close - Third parser to apply, value is discarded\n * @param cutAfterOpen - If `true`, errors returned by the second and third parsers are considered\n * fatal, causing parsers using this to stop trying other branches.\n */\nexport function delimited<TOpen, T, TClose>(\n\topen: Parser<TOpen>,\n\tinner: Parser<T>,\n\tclose: Parser<TClose>,\n\tcutAfterOpen: boolean = false\n): Parser<T> {\n\tconst rest = cutAfterOpen ? cut(followed(inner, close)) : followed(inner, close);\n\treturn preceded(open, rest);\n}\n\n/**\n * Creates a Parser that applies the given parser. If successful, the inner parser's value is\n * discarded and the substring that was consumed from the input is returned as value instead. Errors\n * are returned as-is.\n *\n * When using this in combination with `star` or `plus`, consider using `starConsumed` or\n * `plusConsumed` instead for efficiency.\n *\n * @public\n *\n * @param parser - The parser to apply, value is discarded and replaced by the consumed input.\n */\nexport function recognize<T>(parser: Parser<T>): Parser<string> {\n\treturn (input, offset) => {\n\t\tconst res = parser(input, offset);\n\t\tif (!res.success) {\n\t\t\treturn res;\n\t\t}\n\t\treturn okWithValue(res.offset, input.slice(offset, res.offset));\n\t};\n}\n\n/**\n * Creates a Parser that applies the given parser without consuming any input. That is, if the inner\n * parser is successful, success is returned (with the resulting value) at the starting offset,\n * effectively making the parser consume no input.\n *\n * Errors returned by the inner parser are returned as-is.\n *\n * @public\n *\n * @param parser - The parser to apply, value is discarded and any progress made in input is reset.\n */\nexport function peek<T>(parser: Parser<T>): Parser<T> {\n\treturn (input, offset) => {\n\t\tconst res = parser(input, offset);\n\t\tif (!res.success) {\n\t\t\treturn res;\n\t\t}\n\t\treturn okWithValue(offset, res.value);\n\t};\n}\n\n/**\n * Creates a Parser that succeeds at the starting offset if the given parser fails and vice-versa.\n *\n * @public\n *\n * @param parser - The parser to apply\n * @param expected - Expected values for parse errors generated when the inner parser succeeds\n */\nexport function not<T>(parser: Parser<T>, expected: string[]): Parser<void> {\n\treturn (input, offset) => {\n\t\tconst res = parser(input, offset);\n\t\tif (!res.success) {\n\t\t\treturn ok(offset);\n\t\t}\n\t\treturn error(offset, expected);\n\t};\n}\n\n/**\n * Creates a Parser that matches only if the first Parser matches input at the starting position,\n * but the second Parser does not.\n *\n * @public\n *\n * @param match - Parser that should match\n * @param except - Parser that should not match\n * @param expected - Expected values for parse errors generated when the except parser succeeds\n */\nexport function except<T, U>(match: Parser<T>, except: Parser<U>, expected: string[]): Parser<T> {\n\treturn preceded(not(except, expected), match);\n}\n\n/**\n * Creates a parser that looks at a single codepoint to determine which parser to invoke. Can be\n * used as an alternative to large `or` parsers if looking ahead can narrow down the options.\n *\n * Can optionally look ahead further than the current codepoint, which is useful when nesting\n * several `dispatch` parsers.\n *\n * @public\n *\n * @param mapping - Object mapping code points to parsers\n * @param otherwise - Parser to use when the code point is not found in the mapping, or undefined\n * to reject in that situation.\n * @param extraOffset - How far ahead to look for the codepoint, defaults to 0\n * @param expected - Expected values for parse errors generated when there is no codepoint or\n * when the codepoint is not in the mapping and there is no `otherwise` parser\n */\nexport function dispatch<T>(\n\tmapping: { [codepoint: number]: Parser<T> },\n\totherwise: Parser<T> | undefined,\n\textraOffset: number = 0,\n\texpected: string[] = []\n): Parser<T> {\n\treturn (input, offset) => {\n\t\tconst cp = input.codePointAt(offset + extraOffset);\n\t\tif (cp === undefined) {\n\t\t\treturn error(offset, expected);\n\t\t}\n\t\tconst parser = mapping[cp];\n\t\tif (parser === undefined) {\n\t\t\tif (otherwise === undefined) {\n\t\t\t\treturn error(offset, expected);\n\t\t\t}\n\t\t\treturn otherwise(input, offset);\n\t\t}\n\t\treturn parser(input, offset);\n\t};\n}\n\n/**\n * Creates a Parser that turns errors returned by the inner parser into fatal errors. Parsers such\n * as `or` and `star` will not continue to attempt additional matches if a parser returns a fatal\n * error, and will usually return the error instead.\n *\n * @public\n *\n * @param parser - The parser to wrap\n */\nexport function cut<T>(parser: Parser<T>): Parser<T> {\n\treturn (input, offset) => {\n\t\tconst res = parser(input, offset);\n\t\tif (!res.success) {\n\t\t\treturn error(res.offset, res.expected, true);\n\t\t}\n\t\treturn res;\n\t};\n}\n\n/**\n * A parser that only succeeds at the start of the input string.\n *\n * @public\n *\n * @param input - The input to match in\n * @param offset - The offset in `input` at which to start matching\n */\nexport const start: Parser<void> = (_input, offset) =>\n\toffset === 0 ? ok(offset) : error(offset, ['start of input']);\n\n/**\n * A parser that only succeeds if the end of the input string is reached.\n *\n * @public\n *\n * @param input - The input to match in\n * @param offset - The offset in `input` at which to start matching\n */\nexport const end: Parser<void> = (input, offset) =>\n\tinput.length === offset ? ok(offset) : error(offset, ['end of input']);\n\n/**\n * Creates a Parser that applies the given parser and only succeeds (returning the inner parser's\n * result) if parsing concludes at the end of the input string.\n *\n * @public\n *\n * @param parser - The parser to wrap\n */\nexport function complete<T>(parser: Parser<T>): Parser<T> {\n\treturn then(parser, end, first);\n}\n","import { end, ok, Parser, ParseResult } from './parser-combinators';\n\n/**\n * Helper to collect both the yielded values and the returned value from a generator.\n *\n * @public\n *\n * @param gen - Generator to collect from\n */\nexport function collect<T, R>(gen: Generator<T, R>): [T[], R] {\n\tconst values: T[] = [];\n\tlet it = gen.next();\n\twhile (!it.done) {\n\t\tvalues.push(it.value);\n\t\tit = gen.next();\n\t}\n\treturn [values, it.value];\n}\n\n/**\n * A StreamingParser is similar to a Parser, but instead of returning a value when parsing is\n * complete it can parse incrementally and yield values as they are produced. The generator returns\n * a ParseResult when iteration is done which indicates whether parsing was successful.\n *\n * @public\n */\nexport type StreamingParser<T> = (\n\tinput: string,\n\toffset: number\n) => Generator<T, ParseResult<unknown>>;\n\n/**\n * Creates a StreamingParser which applies the given Parser and yields the value produced if it\n * matches.\n *\n * @public\n *\n * @param parser - The Parser to apply\n */\nexport function streaming<T>(parser: Parser<T>): StreamingParser<T> {\n\treturn function* (input: string, offset: number) {\n\t\tconst res = parser(input, offset);\n\t\tif (res.success) {\n\t\t\tyield res.value;\n\t\t}\n\t\treturn res;\n\t};\n}\n\n/**\n * Creates a StreamingParser which applies the given two StreamingParsers in sequence.\n *\n * Unlike `then`, this does not combine values using a function, but instead simply yields the\n * values produced by both parsers as they produce them.\n *\n * @public\n *\n * @param parser1 - First StreamingParser to apply\n * @param parser2 - StreamingParser to apply if the first one is successful\n */\nexport function streamingThen<T, U>(\n\tparser1: StreamingParser<T>,\n\tparser2: StreamingParser<U>\n): StreamingParser<T | U> {\n\treturn function* (input: string, offset: number) {\n\t\tconst res1 = yield* parser1(input, offset);\n\t\tif (!res1.success) {\n\t\t\treturn res1;\n\t\t}\n\t\treturn yield* parser2(input, res1.offset);\n\t};\n}\n\n/**\n * Creates a StreamingParser which discards undefined values yielded by the given StreamingParser.\n *\n * @public\n *\n * @param parser - The StreamingParser to filter\n */\nexport function streamingFilterUndefined<T>(parser: StreamingParser<T | void>): StreamingParser<T> {\n\treturn function* (input: string, offset: number) {\n\t\tconst gen = parser(input, offset);\n\t\tlet it = gen.next();\n\t\twhile (!it.done) {\n\t\t\tconst value = it.value;\n\t\t\tif (value !== undefined) {\n\t\t\t\tyield value;\n\t\t\t}\n\t\t\tit = gen.next();\n\t\t}\n\t\treturn it.value;\n\t};\n}\n\n/**\n * Creates a StreamingParser that tries to apply the given StreamingParser zero or more times in\n * sequence. Values produced during each iteration are only yielded whenever the inner parser\n * matches successfully.\n *\n * @public\n *\n * @param parser - StreamingParser to apply repeatedly\n */\nexport function streamingStar<T>(parser: StreamingParser<T>): StreamingParser<T> {\n\treturn function* (input: string, offset: number) {\n\t\twhile (true) {\n\t\t\tconst [values, result] = collect(parser(input, offset));\n\t\t\tif (!result.success) {\n\t\t\t\tif (result.fatal) {\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\t\t\t\treturn ok(offset);\n\t\t\t}\n\n\t\t\tyield* values;\n\n\t\t\tif (offset === result.offset) {\n\t\t\t\t// Did not advance\n\t\t\t\treturn ok(offset);\n\t\t\t}\n\t\t\toffset = result.offset;\n\t\t}\n\t};\n}\n\n/**\n * Creates a StreamingParser that tries to apply the given parser optionally. It only yields the\n * values produced by the inner parser if it matches successfully, and does not yield anything\n * otherwise.\n *\n * @public\n *\n * @param parser - StreamingParser to attempt to apply\n */\nexport function streamingOptional<T>(parser: StreamingParser<T>): StreamingParser<T> {\n\treturn function* (input: string, offset: number) {\n\t\tconst [values, result] = collect(parser(input, offset));\n\t\tif (!result.success) {\n\t\t\tif (result.fatal) {\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\treturn ok(offset);\n\t\t}\n\n\t\tyield* values;\n\n\t\treturn result;\n\t};\n}\n\n/**\n * Creates a StreamingParser that applies the given parser and directly yields values produced by\n * it, and then only succeeds if parsing concludes at the end of the input string.\n *\n * @public\n *\n * @param parser - StreamingParser to apply\n */\nexport function streamingComplete<T>(parser: StreamingParser<T>): StreamingParser<T> {\n\treturn function* (input: string, offset: number) {\n\t\tconst res = yield* parser(input, offset);\n\t\tif (!res.success) {\n\t\t\treturn res;\n\t\t}\n\t\treturn end(input, res.offset);\n\t};\n}\n"],"names":["okWithValue","offset","value","success","ok","undefined","error","expected","fatal","lengthFromCodePoint","cp","codepoint","isMatch","input","codePointAt","map","parser","res","star","ts","nextOffset","push","starConsumed","then","parser1","parser2","join","r1","r2","first","x","y","second","preceded","before","followed","after","not","cut","end","length","collect","gen","values","it","next","done","startOffset","open","inner","close","cutAfterOpen","mapping","otherwise","extraOffset","match","except","filter","vs","v","parsers","lastError","concat","firstCodePoint","lastCodePoint","String","fromCodePoint","slice","nCodepoints","i","_input","result","res1","token","offsetAfter"],"mappings":"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"}