@thomasfosterau/effect-parse 0.1.0 → 0.2.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 +247 -230
- package/dist/Ascii.d.ts +32 -53
- package/dist/Ascii.d.ts.map +1 -1
- package/dist/Ascii.js +576 -571
- package/dist/Ascii.js.map +1 -1
- package/dist/Binary.d.ts +6 -29
- package/dist/Binary.d.ts.map +1 -1
- package/dist/Binary.js +129 -116
- package/dist/Binary.js.map +1 -1
- package/dist/Bits.d.ts +4 -2
- package/dist/Bits.d.ts.map +1 -1
- package/dist/Bits.js +121 -123
- package/dist/Bits.js.map +1 -1
- package/dist/Compiler.d.ts +39 -0
- package/dist/Compiler.d.ts.map +1 -0
- package/dist/Compiler.js +48 -0
- package/dist/Compiler.js.map +1 -0
- package/dist/Encoding.d.ts +29 -46
- package/dist/Encoding.d.ts.map +1 -1
- package/dist/Encoding.js +76 -75
- package/dist/Encoding.js.map +1 -1
- package/dist/Expression.d.ts +15 -49
- package/dist/Expression.d.ts.map +1 -1
- package/dist/Expression.js +143 -131
- package/dist/Expression.js.map +1 -1
- package/dist/Input.d.ts +206 -177
- package/dist/Input.d.ts.map +1 -1
- package/dist/Input.js +317 -299
- package/dist/Input.js.map +1 -1
- package/dist/Nom.d.ts +44 -84
- package/dist/Nom.d.ts.map +1 -1
- package/dist/Nom.js +423 -453
- package/dist/Nom.js.map +1 -1
- package/dist/ParseError.d.ts +54 -49
- package/dist/ParseError.d.ts.map +1 -1
- package/dist/ParseError.js +233 -275
- package/dist/ParseError.js.map +1 -1
- package/dist/Parser.d.ts +345 -313
- package/dist/Parser.d.ts.map +1 -1
- package/dist/Parser.js +2010 -1802
- package/dist/Parser.js.map +1 -1
- package/dist/ParserSchema.d.ts +8 -7
- package/dist/ParserSchema.d.ts.map +1 -1
- package/dist/ParserSchema.js +49 -49
- package/dist/ParserSchema.js.map +1 -1
- package/dist/ParserStream.d.ts +26 -20
- package/dist/ParserStream.d.ts.map +1 -1
- package/dist/ParserStream.js +267 -255
- package/dist/ParserStream.js.map +1 -1
- package/dist/Syntax.d.ts +401 -0
- package/dist/Syntax.d.ts.map +1 -0
- package/dist/Syntax.js +717 -0
- package/dist/Syntax.js.map +1 -0
- package/dist/Text.d.ts +98 -134
- package/dist/Text.d.ts.map +1 -1
- package/dist/Text.js +534 -496
- package/dist/Text.js.map +1 -1
- package/dist/Token.d.ts +60 -42
- package/dist/Token.d.ts.map +1 -1
- package/dist/Token.js +331 -265
- package/dist/Token.js.map +1 -1
- package/dist/index.d.ts +16 -17
- package/dist/index.js +16 -17
- package/dist/internal/compiler/closure.d.ts +14 -16
- package/dist/internal/compiler/closure.d.ts.map +1 -1
- package/dist/internal/compiler/closure.js +1458 -1637
- package/dist/internal/compiler/closure.js.map +1 -1
- package/dist/internal/compiler/entries.d.ts +11 -11
- package/dist/internal/compiler/entries.d.ts.map +1 -1
- package/dist/internal/compiler/entries.js +36 -26
- package/dist/internal/compiler/entries.js.map +1 -1
- package/dist/internal/compiler/first.d.ts +19 -19
- package/dist/internal/compiler/first.d.ts.map +1 -1
- package/dist/internal/compiler/first.js +251 -227
- package/dist/internal/compiler/first.js.map +1 -1
- package/dist/internal/compiler/jit.d.ts +6 -17
- package/dist/internal/compiler/jit.d.ts.map +1 -1
- package/dist/internal/compiler/jit.js +860 -988
- package/dist/internal/compiler/jit.js.map +1 -1
- package/dist/internal/compiler/registry.d.ts +20 -21
- package/dist/internal/compiler/registry.d.ts.map +1 -1
- package/dist/internal/compiler/registry.js +21 -41
- package/dist/internal/compiler/registry.js.map +1 -1
- package/dist/internal/compiler/sets.d.ts +9 -13
- package/dist/internal/compiler/sets.d.ts.map +1 -1
- package/dist/internal/compiler/sets.js +76 -73
- package/dist/internal/compiler/sets.js.map +1 -1
- package/dist/internal/entries.d.ts +3 -3
- package/dist/internal/entries.d.ts.map +1 -1
- package/dist/internal/entries.js +38 -30
- package/dist/internal/entries.js.map +1 -1
- package/dist/internal/node.d.ts +177 -173
- package/dist/internal/node.d.ts.map +1 -1
- package/dist/internal/node.js +77 -66
- package/dist/internal/node.js.map +1 -1
- package/dist/internal/numbers.d.ts +7 -8
- package/dist/internal/numbers.d.ts.map +1 -1
- package/dist/internal/numbers.js +246 -276
- package/dist/internal/numbers.js.map +1 -1
- package/dist/internal/resume.d.ts +6 -24
- package/dist/internal/resume.d.ts.map +1 -1
- package/dist/internal/resume.js +30 -29
- package/dist/internal/resume.js.map +1 -1
- package/dist/internal/run.d.ts +15 -0
- package/dist/internal/run.d.ts.map +1 -0
- package/dist/internal/run.js +36 -0
- package/dist/internal/run.js.map +1 -0
- package/dist/internal/stack.d.ts +16 -0
- package/dist/internal/stack.d.ts.map +1 -0
- package/dist/internal/stack.js +26 -0
- package/dist/internal/stack.js.map +1 -0
- package/dist/internal/syntax.d.ts +146 -0
- package/dist/internal/syntax.d.ts.map +1 -0
- package/dist/internal/syntax.js +305 -0
- package/dist/internal/syntax.js.map +1 -0
- package/dist/internal/text.d.ts +10 -2
- package/dist/internal/text.d.ts.map +1 -1
- package/dist/internal/text.js +295 -345
- package/dist/internal/text.js.map +1 -1
- package/dist/internal/tokens.d.ts +25 -30
- package/dist/internal/tokens.d.ts.map +1 -1
- package/dist/internal/tokens.js +369 -363
- package/dist/internal/tokens.js.map +1 -1
- package/package.json +42 -28
- package/src/Ascii.ts +278 -187
- package/src/Binary.ts +150 -44
- package/src/Bits.ts +6 -3
- package/src/Compiler.ts +98 -0
- package/src/Expression.ts +10 -5
- package/src/Input.ts +106 -28
- package/src/Nom.ts +4 -3
- package/src/ParseError.ts +48 -51
- package/src/Parser.ts +1163 -795
- package/src/ParserStream.ts +104 -80
- package/src/Syntax.ts +900 -0
- package/src/Text.ts +272 -187
- package/src/Token.ts +180 -87
- package/src/index.ts +2 -0
- package/src/internal/compiler/closure.ts +121 -88
- package/src/internal/compiler/entries.ts +21 -8
- package/src/internal/compiler/first.ts +17 -15
- package/src/internal/compiler/jit.ts +360 -157
- package/src/internal/compiler/registry.ts +12 -33
- package/src/internal/compiler/sets.ts +17 -11
- package/src/internal/entries.ts +4 -2
- package/src/internal/node.ts +51 -37
- package/src/internal/numbers.ts +22 -20
- package/src/internal/resume.ts +8 -4
- package/src/internal/run.ts +41 -0
- package/src/internal/stack.ts +36 -0
- package/src/internal/syntax.ts +421 -0
- package/src/internal/text.ts +32 -25
- package/src/internal/tokens.ts +96 -51
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
package/dist/Encoding.js
CHANGED
|
@@ -1,85 +1,86 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Text encodings for the `Text` module.
|
|
3
|
-
*
|
|
4
|
-
* An {@link Encoding} tells the `Text` parsers how to read Unicode code
|
|
5
|
-
* points out of an input. JavaScript strings are read natively, without any
|
|
6
|
-
* conversion. Byte inputs are decoded as they are parsed, so offsets stay
|
|
7
|
-
* byte offsets, slices that are kept as bytes (`Parser.taken`) are
|
|
8
|
-
* zero-copy views, and partial input that ends in the middle of a character
|
|
9
|
-
* reports `Incomplete`.
|
|
10
|
-
*
|
|
11
|
-
* ```ts
|
|
12
|
-
* import { Encoding, Text } from "@thomasfosterau/effect-parse"
|
|
13
|
-
*
|
|
14
|
-
* Text.utf8.encoding === Encoding.utf8
|
|
15
|
-
* Text.make(Encoding.latin1) // the Text parsers for any Encoding, including your own
|
|
16
|
-
* ```
|
|
17
|
-
*
|
|
18
|
-
* @since 0.1.0
|
|
19
|
-
*/
|
|
20
1
|
import * as Option from "effect/Option";
|
|
21
2
|
import * as internal from "./internal/text.js";
|
|
3
|
+
//#region src/Encoding.ts
|
|
4
|
+
/**
|
|
5
|
+
* Text encodings for the `Text` module.
|
|
6
|
+
*
|
|
7
|
+
* An {@link Encoding} tells the `Text` parsers how to read Unicode code
|
|
8
|
+
* points out of an input. JavaScript strings are read natively, without any
|
|
9
|
+
* conversion. Byte inputs are decoded as they are parsed, so offsets stay
|
|
10
|
+
* byte offsets, slices that are kept as bytes (`Parser.taken`) are
|
|
11
|
+
* zero-copy views, and partial input that ends in the middle of a character
|
|
12
|
+
* reports `Incomplete`.
|
|
13
|
+
*
|
|
14
|
+
* ```ts
|
|
15
|
+
* import { Encoding, Text } from "@thomasfosterau/effect-parse"
|
|
16
|
+
*
|
|
17
|
+
* Text.utf8.encoding === Encoding.utf8
|
|
18
|
+
* Text.make(Encoding.latin1) // the Text parsers for any Encoding, including your own
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* @since 0.1.0
|
|
22
|
+
*/
|
|
22
23
|
/**
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
24
|
+
* JavaScript strings, read as UTF-16 code units. Offsets are code-unit
|
|
25
|
+
* indices and slices are plain `String.prototype.slice`s. Unpaired
|
|
26
|
+
* surrogates are malformed.
|
|
27
|
+
*
|
|
28
|
+
* @since 0.1.0
|
|
29
|
+
* @category encodings
|
|
30
|
+
*/
|
|
31
|
+
const string = internal.string;
|
|
31
32
|
/**
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
33
|
+
* UTF-8 bytes. Overlong encodings, surrogates and code points above
|
|
34
|
+
* U+10FFFF are malformed.
|
|
35
|
+
*
|
|
36
|
+
* @since 0.1.0
|
|
37
|
+
* @category encodings
|
|
38
|
+
*/
|
|
39
|
+
const utf8 = internal.utf8;
|
|
39
40
|
/**
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
* UTF-16 bytes, little endian. Unpaired surrogates are malformed.
|
|
42
|
+
*
|
|
43
|
+
* @since 0.1.0
|
|
44
|
+
* @category encodings
|
|
45
|
+
*/
|
|
46
|
+
const utf16le = internal.utf16le;
|
|
46
47
|
/**
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
48
|
+
* UTF-16 bytes, big endian. Unpaired surrogates are malformed.
|
|
49
|
+
*
|
|
50
|
+
* @since 0.1.0
|
|
51
|
+
* @category encodings
|
|
52
|
+
*/
|
|
53
|
+
const utf16be = internal.utf16be;
|
|
53
54
|
/**
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
55
|
+
* ISO-8859-1 (Latin-1) bytes: each byte is the code point U+0000 to U+00FF
|
|
56
|
+
* of the same value.
|
|
57
|
+
*
|
|
58
|
+
* @since 0.1.0
|
|
59
|
+
* @category encodings
|
|
60
|
+
*/
|
|
61
|
+
const latin1 = internal.latin1;
|
|
61
62
|
/**
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
if (bytes[0] === 0xfe && bytes[1] === 0xff)
|
|
82
|
-
return Option.some(utf16be);
|
|
83
|
-
return Option.none();
|
|
63
|
+
* Detects the encoding of bytes from a byte order mark: UTF-8
|
|
64
|
+
* (`EF BB BF`), UTF-16LE (`FF FE`) or UTF-16BE (`FE FF`). The mark itself
|
|
65
|
+
* is not skipped; parse it with `Text.bom`.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```ts
|
|
69
|
+
* import { Encoding } from "@thomasfosterau/effect-parse"
|
|
70
|
+
*
|
|
71
|
+
* Encoding.sniff(new Uint8Array([0xff, 0xfe, 0x41, 0x00])) // Option.some(Encoding.utf16le)
|
|
72
|
+
* ```
|
|
73
|
+
*
|
|
74
|
+
* @since 0.1.0
|
|
75
|
+
* @category utils
|
|
76
|
+
*/
|
|
77
|
+
const sniff = (bytes) => {
|
|
78
|
+
if (bytes[0] === 239 && bytes[1] === 187 && bytes[2] === 191) return Option.some(utf8);
|
|
79
|
+
if (bytes[0] === 255 && bytes[1] === 254) return Option.some(utf16le);
|
|
80
|
+
if (bytes[0] === 254 && bytes[1] === 255) return Option.some(utf16be);
|
|
81
|
+
return Option.none();
|
|
84
82
|
};
|
|
83
|
+
//#endregion
|
|
84
|
+
export { latin1, sniff, string, utf16be, utf16le, utf8 };
|
|
85
|
+
|
|
85
86
|
//# sourceMappingURL=Encoding.js.map
|
package/dist/Encoding.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Encoding.js","
|
|
1
|
+
{"version":3,"file":"Encoding.js","names":[],"sources":["../src/Encoding.ts"],"sourcesContent":["/**\n * Text encodings for the `Text` module.\n *\n * An {@link Encoding} tells the `Text` parsers how to read Unicode code\n * points out of an input. JavaScript strings are read natively, without any\n * conversion. Byte inputs are decoded as they are parsed, so offsets stay\n * byte offsets, slices that are kept as bytes (`Parser.taken`) are\n * zero-copy views, and partial input that ends in the middle of a character\n * reports `Incomplete`.\n *\n * ```ts\n * import { Encoding, Text } from \"@thomasfosterau/effect-parse\"\n *\n * Text.utf8.encoding === Encoding.utf8\n * Text.make(Encoding.latin1) // the Text parsers for any Encoding, including your own\n * ```\n *\n * @since 0.1.0\n */\nimport * as Option from \"effect/Option\"\nimport * as internal from \"./internal/text.js\"\n\n/**\n * A text encoding: how to read Unicode code points out of an input. The\n * `Text` module is generic over encodings, so one grammar can parse\n * JavaScript strings, UTF-8 bytes, UTF-16 bytes and so on.\n *\n * Decoding is strict: malformed sequences (invalid UTF-8, unpaired UTF-16\n * surrogates) are reported as invalid, never replaced.\n *\n * @since 0.1.0\n * @category models\n */\nexport interface Encoding<I extends string | Uint8Array = string | Uint8Array> {\n /** The name of the encoding, e.g. `\"UTF-8\"`. Used in error messages. */\n readonly name: string\n /**\n * The size of a code unit, in input units: 1 for strings, UTF-8 and\n * Latin-1, 2 for UTF-16 bytes. Code points start at multiples of it.\n */\n readonly unit: number\n /**\n * Whether every input unit below `0x80` encodes the ASCII character with\n * that value, and is never part of a longer sequence. Enables fast paths.\n */\n readonly asciiCompatible: boolean\n /**\n * Decodes the code point starting at `offset` (with `offset < end`).\n * Returns the code point, `-1` if the input is malformed there, or `-2` if\n * the input ends inside a sequence (more input could complete it).\n */\n readonly decode: (input: I, offset: number, end: number) => number\n /** The number of input units that encode a code point. */\n readonly width: (codePoint: number) => number\n /** Encodes a string. Throws if the string can't be represented. */\n readonly encode: (text: string) => I\n /**\n * Decodes the units `[start, end)` to a string. The parsers only call it\n * on ranges they have checked are well formed.\n */\n readonly text: (input: I, start: number, end: number) => string\n}\n\n/**\n * JavaScript strings, read as UTF-16 code units. Offsets are code-unit\n * indices and slices are plain `String.prototype.slice`s. Unpaired\n * surrogates are malformed.\n *\n * @since 0.1.0\n * @category encodings\n */\nexport const string: Encoding<string> = internal.string\n\n/**\n * UTF-8 bytes. Overlong encodings, surrogates and code points above\n * U+10FFFF are malformed.\n *\n * @since 0.1.0\n * @category encodings\n */\nexport const utf8: Encoding<Uint8Array> = internal.utf8\n\n/**\n * UTF-16 bytes, little endian. Unpaired surrogates are malformed.\n *\n * @since 0.1.0\n * @category encodings\n */\nexport const utf16le: Encoding<Uint8Array> = internal.utf16le\n\n/**\n * UTF-16 bytes, big endian. Unpaired surrogates are malformed.\n *\n * @since 0.1.0\n * @category encodings\n */\nexport const utf16be: Encoding<Uint8Array> = internal.utf16be\n\n/**\n * ISO-8859-1 (Latin-1) bytes: each byte is the code point U+0000 to U+00FF\n * of the same value.\n *\n * @since 0.1.0\n * @category encodings\n */\nexport const latin1: Encoding<Uint8Array> = internal.latin1\n\n/**\n * Detects the encoding of bytes from a byte order mark: UTF-8\n * (`EF BB BF`), UTF-16LE (`FF FE`) or UTF-16BE (`FE FF`). The mark itself\n * is not skipped; parse it with `Text.bom`.\n *\n * @example\n * ```ts\n * import { Encoding } from \"@thomasfosterau/effect-parse\"\n *\n * Encoding.sniff(new Uint8Array([0xff, 0xfe, 0x41, 0x00])) // Option.some(Encoding.utf16le)\n * ```\n *\n * @since 0.1.0\n * @category utils\n */\nexport const sniff = (bytes: Uint8Array): Option.Option<Encoding<Uint8Array>> => {\n if (bytes[0] === 0xef && bytes[1] === 0xbb && bytes[2] === 0xbf) return Option.some(utf8)\n if (bytes[0] === 0xff && bytes[1] === 0xfe) return Option.some(utf16le)\n if (bytes[0] === 0xfe && bytes[1] === 0xff) return Option.some(utf16be)\n return Option.none()\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuEA,MAAa,SAA2B,SAAS;;;;;;;;AASjD,MAAa,OAA6B,SAAS;;;;;;;AAQnD,MAAa,UAAgC,SAAS;;;;;;;AAQtD,MAAa,UAAgC,SAAS;;;;;;;;AAStD,MAAa,SAA+B,SAAS;;;;;;;;;;;;;;;;AAiBrD,MAAa,SAAS,UAA2D;CAC/E,IAAI,MAAM,OAAO,OAAQ,MAAM,OAAO,OAAQ,MAAM,OAAO,KAAM,OAAO,OAAO,KAAK,IAAI;CACxF,IAAI,MAAM,OAAO,OAAQ,MAAM,OAAO,KAAM,OAAO,OAAO,KAAK,OAAO;CACtE,IAAI,MAAM,OAAO,OAAQ,MAAM,OAAO,KAAM,OAAO,OAAO,KAAK,OAAO;CACtE,OAAO,OAAO,KAAK;AACrB"}
|
package/dist/Expression.d.ts
CHANGED
|
@@ -1,41 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
*
|
|
5
|
-
* Describe the operand parser and a table of prefix, postfix and infix
|
|
6
|
-
* operators with their precedence (higher binds tighter) and associativity.
|
|
7
|
-
* Each operator carries a function that folds its operands into a result.
|
|
8
|
-
*
|
|
9
|
-
* @example
|
|
10
|
-
* ```ts
|
|
11
|
-
* import { Ascii, Expression, Parser, Token } from "@thomasfosterau/effect-parse"
|
|
12
|
-
*
|
|
13
|
-
* const op = (s: string) => Parser.delimited(Ascii.space0, Token.literal(s), Ascii.space0)
|
|
14
|
-
*
|
|
15
|
-
* const arithmetic: Parser.Parser<number, string> = Expression.make({
|
|
16
|
-
* operand: Parser.alt(
|
|
17
|
-
* Ascii.decInt,
|
|
18
|
-
* Parser.delimited(op("("), Parser.suspend(() => arithmetic), op(")"))
|
|
19
|
-
* ),
|
|
20
|
-
* operators: [
|
|
21
|
-
* Expression.prefix(op("-"), 4, (_, x) => -x),
|
|
22
|
-
* Expression.postfix(op("!"), 5, (x) => factorial(x)),
|
|
23
|
-
* Expression.infixRight(op("^"), 3, (l, _, r) => l ** r),
|
|
24
|
-
* Expression.infixLeft(op("*"), 2, (l, _, r) => l * r),
|
|
25
|
-
* Expression.infixLeft(op("/"), 2, (l, _, r) => l / r),
|
|
26
|
-
* Expression.infixLeft(op("+"), 1, (l, _, r) => l + r),
|
|
27
|
-
* Expression.infixLeft(op("-"), 1, (l, _, r) => l - r)
|
|
28
|
-
* ]
|
|
29
|
-
* })
|
|
30
|
-
*
|
|
31
|
-
* declare const factorial: (n: number) => number
|
|
32
|
-
* Parser.parse(arithmetic, "1 + 2 * 3 ^ 2") // Result.succeed(19)
|
|
33
|
-
* ```
|
|
34
|
-
*
|
|
35
|
-
* @since 0.1.0
|
|
36
|
-
*/
|
|
37
|
-
import type { Input } from "./Input.js";
|
|
38
|
-
import type { Parser } from "./Parser.js";
|
|
1
|
+
import { Input } from "./Input.js";
|
|
2
|
+
import { Parser } from "./Parser.js";
|
|
3
|
+
//#region src/Expression.d.ts
|
|
39
4
|
/**
|
|
40
5
|
* An operator in an expression grammar.
|
|
41
6
|
*
|
|
@@ -44,33 +9,33 @@ import type { Parser } from "./Parser.js";
|
|
|
44
9
|
*/
|
|
45
10
|
export type Operator<A, E = never, R = never, I extends Input = string> = Prefix<A, E, R, I> | Postfix<A, E, R, I> | Infix<A, E, R, I>;
|
|
46
11
|
interface OperatorBase<E, R, I extends Input> {
|
|
47
|
-
|
|
48
|
-
|
|
12
|
+
readonly parser: Parser<unknown, E, R, I>;
|
|
13
|
+
readonly precedence: number;
|
|
49
14
|
}
|
|
50
15
|
/**
|
|
51
16
|
* @since 0.1.0
|
|
52
17
|
* @category models
|
|
53
18
|
*/
|
|
54
19
|
export interface Prefix<A, E = never, R = never, I extends Input = string> extends OperatorBase<E, R, I> {
|
|
55
|
-
|
|
56
|
-
|
|
20
|
+
readonly _tag: "Prefix";
|
|
21
|
+
readonly fold: (op: any, operand: A) => A;
|
|
57
22
|
}
|
|
58
23
|
/**
|
|
59
24
|
* @since 0.1.0
|
|
60
25
|
* @category models
|
|
61
26
|
*/
|
|
62
27
|
export interface Postfix<A, E = never, R = never, I extends Input = string> extends OperatorBase<E, R, I> {
|
|
63
|
-
|
|
64
|
-
|
|
28
|
+
readonly _tag: "Postfix";
|
|
29
|
+
readonly fold: (operand: A, op: any) => A;
|
|
65
30
|
}
|
|
66
31
|
/**
|
|
67
32
|
* @since 0.1.0
|
|
68
33
|
* @category models
|
|
69
34
|
*/
|
|
70
35
|
export interface Infix<A, E = never, R = never, I extends Input = string> extends OperatorBase<E, R, I> {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
36
|
+
readonly _tag: "Infix";
|
|
37
|
+
readonly associativity: "left" | "right";
|
|
38
|
+
readonly fold: (left: A, op: any, right: A) => A;
|
|
74
39
|
}
|
|
75
40
|
/**
|
|
76
41
|
* A prefix operator, e.g. unary minus.
|
|
@@ -117,8 +82,9 @@ type OpInput<Op> = [Op] extends [never] ? Input : [Op] extends [OperatorBase<inf
|
|
|
117
82
|
* @category constructors
|
|
118
83
|
*/
|
|
119
84
|
export declare const make: <A, E, R, I extends Input, const Ops extends ReadonlyArray<Operator<A, any, any, any>>>(options: {
|
|
120
|
-
|
|
121
|
-
|
|
85
|
+
readonly operand: Parser<A, E, R, I>;
|
|
86
|
+
readonly operators: Ops;
|
|
122
87
|
}) => Parser<A, E | OpError<Ops[number]>, R | OpServices<Ops[number]>, I & OpInput<Ops[number]>>;
|
|
88
|
+
//#endregion
|
|
123
89
|
export {};
|
|
124
90
|
//# sourceMappingURL=Expression.d.ts.map
|
package/dist/Expression.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Expression.d.ts","
|
|
1
|
+
{"version":3,"file":"Expression.d.ts","names":[],"sources":["../src/Expression.ts"],"mappings":";;;;;;;;;YAgDY,SAAS,GAAG,WAAW,WAAW,UAAU,kBACpD,OAAO,GAAG,GAAG,GAAG,KAChB,QAAQ,GAAG,GAAG,GAAG,KACjB,MAAM,GAAG,GAAG,GAAG;UAET,aAAa,GAAG,GAAG,UAAU;WAC5B,QAAQ,gBAAgB,GAAG,GAAG;WAC9B;;;;;;iBAOM,OAAO,GAAG,WAAW,WAAW,UAAU,wBAAwB,aAAa,GAAG,GAAG;WAC3F;WACA,OAAO,SAAS,SAAS,MAAM;;;;;;iBAOzB,QAAQ,GAAG,WAAW,WAAW,UAAU,wBAAwB,aAAa,GAAG,GAAG;WAC5F;WACA,OAAO,SAAS,GAAG,YAAY;;;;;;iBAOzB,MAAM,GAAG,WAAW,WAAW,UAAU,wBAAwB,aAAa,GAAG,GAAG;WAC1F;WACA;WACA,OAAO,MAAM,GAAG,SAAS,OAAO,MAAM;;;;;;;;qBASpC,SAAU,GAAG,GAAG,GAAG,UAAU,OAAO,GAC/C,QAAQ,OAAO,GAAG,GAAG,GAAG,IACxB,oBACA,OAAO,IAAI,GAAG,SAAS,MAAM,MAC5B,OAAO,GAAG,GAAG,GAAG;;;;;;;qBAQN,UAAW,GAAG,GAAG,GAAG,UAAU,OAAO,GAChD,QAAQ,OAAO,GAAG,GAAG,GAAG,IACxB,oBACA,OAAO,SAAS,GAAG,IAAI,MAAM,MAC5B,QAAQ,GAAG,GAAG,GAAG;;;;;;;qBAQP,YAAa,GAAG,GAAG,GAAG,UAAU,OAAO,GAClD,QAAQ,OAAO,GAAG,GAAG,GAAG,IACxB,oBACA,OAAO,MAAM,GAAG,IAAI,GAAG,OAAO,MAAM,MACnC,MAAM,GAAG,GAAG,GAAG;;;;;;;qBAQL,aAAc,GAAG,GAAG,GAAG,UAAU,OAAO,GACnD,QAAQ,OAAO,GAAG,GAAG,GAAG,IACxB,oBACA,OAAO,MAAM,GAAG,IAAI,GAAG,OAAO,MAAM,MACnC,MAAM,GAAG,GAAG,GAAG;KAEb,QAAQ,MAAM,WAAW,mBAAmB,SAAS,UAAU,MAAM;KACrE,WAAW,MAAM,WAAW,mBAAmB,UAAU,SAAS,MAAM;KACxE,QAAQ,OAAO,sBAAsB,SAAS,aAAa,mBAAmB,UAAU,UAAU,MAAM;;;;;;;;;;;;;;qBAehG,OAAQ,GAAG,GAAG,GAAG,UAAU,aAAa,YAAY,cAAc,SAAS,oBAAoB;WACjG,SAAS,OAAO,GAAG,GAAG,GAAG;WACzB,WAAW;MAClB,OAAO,GAAG,IAAI,QAAQ,cAAc,IAAI,WAAW,cAAc,IAAI,QAAQ"}
|
package/dist/Expression.js
CHANGED
|
@@ -1,139 +1,151 @@
|
|
|
1
1
|
import { Fail, mergeFailures } from "./Input.js";
|
|
2
|
-
import { make as
|
|
2
|
+
import { make as make$1 } from "./Parser.js";
|
|
3
|
+
//#region src/Expression.ts
|
|
3
4
|
/**
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
* A prefix operator, e.g. unary minus.
|
|
6
|
+
*
|
|
7
|
+
* @since 0.1.0
|
|
8
|
+
* @category operators
|
|
9
|
+
*/
|
|
10
|
+
const prefix = (parser, precedence, fold) => ({
|
|
11
|
+
_tag: "Prefix",
|
|
12
|
+
parser,
|
|
13
|
+
precedence,
|
|
14
|
+
fold
|
|
15
|
+
});
|
|
10
16
|
/**
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
+
* A postfix operator, e.g. factorial or a function call suffix.
|
|
18
|
+
*
|
|
19
|
+
* @since 0.1.0
|
|
20
|
+
* @category operators
|
|
21
|
+
*/
|
|
22
|
+
const postfix = (parser, precedence, fold) => ({
|
|
23
|
+
_tag: "Postfix",
|
|
24
|
+
parser,
|
|
25
|
+
precedence,
|
|
26
|
+
fold
|
|
27
|
+
});
|
|
17
28
|
/**
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
29
|
+
* A left-associative infix operator: `a - b - c` is `(a - b) - c`.
|
|
30
|
+
*
|
|
31
|
+
* @since 0.1.0
|
|
32
|
+
* @category operators
|
|
33
|
+
*/
|
|
34
|
+
const infixLeft = (parser, precedence, fold) => ({
|
|
35
|
+
_tag: "Infix",
|
|
36
|
+
associativity: "left",
|
|
37
|
+
parser,
|
|
38
|
+
precedence,
|
|
39
|
+
fold
|
|
40
|
+
});
|
|
24
41
|
/**
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
42
|
+
* A right-associative infix operator: `a ^ b ^ c` is `a ^ (b ^ c)`.
|
|
43
|
+
*
|
|
44
|
+
* @since 0.1.0
|
|
45
|
+
* @category operators
|
|
46
|
+
*/
|
|
47
|
+
const infixRight = (parser, precedence, fold) => ({
|
|
48
|
+
_tag: "Infix",
|
|
49
|
+
associativity: "right",
|
|
50
|
+
parser,
|
|
51
|
+
precedence,
|
|
52
|
+
fold
|
|
53
|
+
});
|
|
31
54
|
/**
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
const leftPower = op.precedence * 2;
|
|
125
|
-
if (leftPower < minPower) {
|
|
126
|
-
state.pos = start;
|
|
127
|
-
break;
|
|
128
|
-
}
|
|
129
|
-
const opOut = matched;
|
|
130
|
-
const rhs = expr(state, op.associativity === "left" ? leftPower + 1 : leftPower);
|
|
131
|
-
if (rhs === Fail)
|
|
132
|
-
return Fail;
|
|
133
|
-
lhs = op.fold(lhs, opOut, rhs);
|
|
134
|
-
}
|
|
135
|
-
return lhs;
|
|
136
|
-
};
|
|
137
|
-
return makeParser((state) => expr(state, 0), "expression");
|
|
55
|
+
* Builds an expression parser from an operand parser and an operator table.
|
|
56
|
+
*
|
|
57
|
+
* Precedences are compared numerically: higher binds tighter. A prefix
|
|
58
|
+
* operator applies to everything that binds tighter than it, so with `-`
|
|
59
|
+
* at precedence 4 and `^` at 3, `-2 ^ 2` parses as `(-2) ^ 2`.
|
|
60
|
+
*
|
|
61
|
+
* When several operators of the same kind match, the first one in the
|
|
62
|
+
* table wins, so list longer operators (`<=`) before their prefixes (`<`).
|
|
63
|
+
*
|
|
64
|
+
* @since 0.1.0
|
|
65
|
+
* @category constructors
|
|
66
|
+
*/
|
|
67
|
+
const make = (options) => {
|
|
68
|
+
const operand = options.operand.step;
|
|
69
|
+
const prefixes = options.operators.filter((o) => o._tag === "Prefix");
|
|
70
|
+
const postfixes = options.operators.filter((o) => o._tag === "Postfix");
|
|
71
|
+
const infixes = options.operators.filter((o) => o._tag === "Infix");
|
|
72
|
+
let matched;
|
|
73
|
+
let failure;
|
|
74
|
+
const tryOps = (state, ops, mustConsume) => {
|
|
75
|
+
const start = state.pos;
|
|
76
|
+
for (let i = 0; i < ops.length; i++) {
|
|
77
|
+
const out = ops[i].parser.step(state);
|
|
78
|
+
if (out !== Fail) {
|
|
79
|
+
if (mustConsume && state.pos === start) {
|
|
80
|
+
state.failMessage("Cut", "Assert", "prefix and postfix operators must always consume");
|
|
81
|
+
return -2;
|
|
82
|
+
}
|
|
83
|
+
matched = out;
|
|
84
|
+
return i;
|
|
85
|
+
}
|
|
86
|
+
if (state.mode !== "Backtrack") return -2;
|
|
87
|
+
failure = failure === void 0 ? state.failure : mergeFailures(failure, state.failure);
|
|
88
|
+
state.pos = start;
|
|
89
|
+
}
|
|
90
|
+
return -1;
|
|
91
|
+
};
|
|
92
|
+
const expr = (state, minPower) => {
|
|
93
|
+
let lhs;
|
|
94
|
+
failure = void 0;
|
|
95
|
+
const p = tryOps(state, prefixes, true);
|
|
96
|
+
if (p === -2) return Fail;
|
|
97
|
+
if (p >= 0) {
|
|
98
|
+
const op = prefixes[p];
|
|
99
|
+
const opOut = matched;
|
|
100
|
+
const operandValue = expr(state, op.precedence * 2);
|
|
101
|
+
if (operandValue === Fail) return Fail;
|
|
102
|
+
lhs = op.fold(opOut, operandValue);
|
|
103
|
+
} else {
|
|
104
|
+
const prefixFailure = failure;
|
|
105
|
+
lhs = operand(state);
|
|
106
|
+
if (lhs === Fail) {
|
|
107
|
+
if (prefixFailure !== void 0 && state.mode === "Backtrack") state.failWith("Backtrack", mergeFailures(prefixFailure, state.failure));
|
|
108
|
+
return Fail;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
while (true) {
|
|
112
|
+
const start = state.pos;
|
|
113
|
+
failure = void 0;
|
|
114
|
+
const q = tryOps(state, postfixes, true);
|
|
115
|
+
if (q === -2) return Fail;
|
|
116
|
+
if (q >= 0) {
|
|
117
|
+
const op = postfixes[q];
|
|
118
|
+
if (op.precedence * 2 < minPower) {
|
|
119
|
+
state.pos = start;
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
lhs = op.fold(lhs, matched);
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
const postfixFailure = failure;
|
|
126
|
+
const i = tryOps(state, infixes, false);
|
|
127
|
+
if (i === -2) return Fail;
|
|
128
|
+
if (i < 0) {
|
|
129
|
+
const f = postfixFailure === void 0 ? failure : failure === void 0 ? postfixFailure : mergeFailures(postfixFailure, failure);
|
|
130
|
+
if (f !== void 0 && f.offset === state.pos) state.setHint(f.offset, f.expected);
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
const op = infixes[i];
|
|
134
|
+
const leftPower = op.precedence * 2;
|
|
135
|
+
if (leftPower < minPower) {
|
|
136
|
+
state.pos = start;
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
const opOut = matched;
|
|
140
|
+
const rhs = expr(state, op.associativity === "left" ? leftPower + 1 : leftPower);
|
|
141
|
+
if (rhs === Fail) return Fail;
|
|
142
|
+
lhs = op.fold(lhs, opOut, rhs);
|
|
143
|
+
}
|
|
144
|
+
return lhs;
|
|
145
|
+
};
|
|
146
|
+
return make$1((state) => expr(state, 0), "expression");
|
|
138
147
|
};
|
|
148
|
+
//#endregion
|
|
149
|
+
export { infixLeft, infixRight, make, postfix, prefix };
|
|
150
|
+
|
|
139
151
|
//# sourceMappingURL=Expression.js.map
|
package/dist/Expression.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Expression.js","sourceRoot":"","sources":["../src/Expression.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Expression.js","names":["makeParser"],"sources":["../src/Expression.ts"],"sourcesContent":["/**\n * Operator-precedence expression parsing with a Pratt parser (from\n * `nom-language`'s `precedence`, and winnow's expression parser).\n *\n * Describe the operand parser and a table of prefix, postfix and infix\n * operators with their precedence (higher binds tighter) and associativity.\n * Each operator carries a function that folds its operands into a result.\n *\n * @example\n * ```ts\n * import { Ascii, Expression, Parser, Token } from \"@thomasfosterau/effect-parse\"\n *\n * const op = (s: string) => Parser.delimited(Ascii.space0, Token.literal(s), Ascii.space0)\n *\n * const arithmetic: Parser.Parser<number, string> = Expression.make({\n * operand: Parser.alt(\n * Ascii.decInt,\n * Parser.delimited(op(\"(\"), Parser.suspend(() => arithmetic), op(\")\"))\n * ),\n * operators: [\n * Expression.prefix(op(\"-\"), 4, (_, x) => -x),\n * Expression.postfix(op(\"!\"), 5, (x) => factorial(x)),\n * Expression.infixRight(op(\"^\"), 3, (l, _, r) => l ** r),\n * Expression.infixLeft(op(\"*\"), 2, (l, _, r) => l * r),\n * Expression.infixLeft(op(\"/\"), 2, (l, _, r) => l / r),\n * Expression.infixLeft(op(\"+\"), 1, (l, _, r) => l + r),\n * Expression.infixLeft(op(\"-\"), 1, (l, _, r) => l - r)\n * ]\n * })\n *\n * declare const factorial: (n: number) => number\n * Parser.parse(arithmetic, \"1 + 2 * 3 ^ 2\") // Result.succeed(19)\n * ```\n *\n * @since 0.1.0\n */\nimport type { Input, State } from \"./Input.js\"\nimport { Fail, mergeFailures } from \"./Input.js\"\nimport type { Failure } from \"./Input.js\"\nimport type { Parser } from \"./Parser.js\"\nimport { make as makeParser } from \"./Parser.js\"\n\n/**\n * An operator in an expression grammar.\n *\n * @since 0.1.0\n * @category models\n */\nexport type Operator<A, E = never, R = never, I extends Input = string> =\n | Prefix<A, E, R, I>\n | Postfix<A, E, R, I>\n | Infix<A, E, R, I>\n\ninterface OperatorBase<E, R, I extends Input> {\n readonly parser: Parser<unknown, E, R, I>\n readonly precedence: number\n}\n\n/**\n * @since 0.1.0\n * @category models\n */\nexport interface Prefix<A, E = never, R = never, I extends Input = string> extends OperatorBase<E, R, I> {\n readonly _tag: \"Prefix\"\n readonly fold: (op: any, operand: A) => A\n}\n\n/**\n * @since 0.1.0\n * @category models\n */\nexport interface Postfix<A, E = never, R = never, I extends Input = string> extends OperatorBase<E, R, I> {\n readonly _tag: \"Postfix\"\n readonly fold: (operand: A, op: any) => A\n}\n\n/**\n * @since 0.1.0\n * @category models\n */\nexport interface Infix<A, E = never, R = never, I extends Input = string> extends OperatorBase<E, R, I> {\n readonly _tag: \"Infix\"\n readonly associativity: \"left\" | \"right\"\n readonly fold: (left: A, op: any, right: A) => A\n}\n\n/**\n * A prefix operator, e.g. unary minus.\n *\n * @since 0.1.0\n * @category operators\n */\nexport const prefix = <O, E, R, I extends Input, A>(\n parser: Parser<O, E, R, I>,\n precedence: number,\n fold: (op: O, operand: A) => A\n): Prefix<A, E, R, I> => ({ _tag: \"Prefix\", parser, precedence, fold })\n\n/**\n * A postfix operator, e.g. factorial or a function call suffix.\n *\n * @since 0.1.0\n * @category operators\n */\nexport const postfix = <O, E, R, I extends Input, A>(\n parser: Parser<O, E, R, I>,\n precedence: number,\n fold: (operand: A, op: O) => A\n): Postfix<A, E, R, I> => ({ _tag: \"Postfix\", parser, precedence, fold })\n\n/**\n * A left-associative infix operator: `a - b - c` is `(a - b) - c`.\n *\n * @since 0.1.0\n * @category operators\n */\nexport const infixLeft = <O, E, R, I extends Input, A>(\n parser: Parser<O, E, R, I>,\n precedence: number,\n fold: (left: A, op: O, right: A) => A\n): Infix<A, E, R, I> => ({ _tag: \"Infix\", associativity: \"left\", parser, precedence, fold })\n\n/**\n * A right-associative infix operator: `a ^ b ^ c` is `a ^ (b ^ c)`.\n *\n * @since 0.1.0\n * @category operators\n */\nexport const infixRight = <O, E, R, I extends Input, A>(\n parser: Parser<O, E, R, I>,\n precedence: number,\n fold: (left: A, op: O, right: A) => A\n): Infix<A, E, R, I> => ({ _tag: \"Infix\", associativity: \"right\", parser, precedence, fold })\n\ntype OpError<Op> = Op extends OperatorBase<infer E, infer _R, infer _I> ? E : never\ntype OpServices<Op> = Op extends OperatorBase<infer _E, infer R, infer _I> ? R : never\ntype OpInput<Op> = [Op] extends [never] ? Input : [Op] extends [OperatorBase<infer _E, infer _R, infer I>] ? I : never\n\n/**\n * Builds an expression parser from an operand parser and an operator table.\n *\n * Precedences are compared numerically: higher binds tighter. A prefix\n * operator applies to everything that binds tighter than it, so with `-`\n * at precedence 4 and `^` at 3, `-2 ^ 2` parses as `(-2) ^ 2`.\n *\n * When several operators of the same kind match, the first one in the\n * table wins, so list longer operators (`<=`) before their prefixes (`<`).\n *\n * @since 0.1.0\n * @category constructors\n */\nexport const make = <A, E, R, I extends Input, const Ops extends ReadonlyArray<Operator<A, any, any, any>>>(options: {\n readonly operand: Parser<A, E, R, I>\n readonly operators: Ops\n}): Parser<A, E | OpError<Ops[number]>, R | OpServices<Ops[number]>, I & OpInput<Ops[number]>> => {\n const operand = options.operand.step\n const prefixes = options.operators.filter((o): o is Prefix<A, any, any, any> => o._tag === \"Prefix\")\n const postfixes = options.operators.filter((o): o is Postfix<A, any, any, any> => o._tag === \"Postfix\")\n const infixes = options.operators.filter((o): o is Infix<A, any, any, any> => o._tag === \"Infix\")\n\n // Attempts each operator in turn. Returns the index of the first match\n // (with its output in `matched`), -1 if none matched, or -2 on a fatal\n // failure. Expectations of failed attempts are accumulated in `failure`.\n let matched: unknown\n let failure: Failure | undefined\n const tryOps = (state: State<any>, ops: ReadonlyArray<OperatorBase<any, any, any>>, mustConsume: boolean): number => {\n const start = state.pos\n for (let i = 0; i < ops.length; i++) {\n const out = ops[i].parser.step(state)\n if (out !== Fail) {\n // A prefix or postfix operator matching nothing would apply forever\n if (mustConsume && state.pos === start) {\n state.failMessage(\"Cut\", \"Assert\", \"prefix and postfix operators must always consume\")\n return -2\n }\n matched = out\n return i\n }\n if (state.mode !== \"Backtrack\") return -2\n failure = failure === undefined ? state.failure : mergeFailures(failure, state.failure)\n state.pos = start\n }\n return -1\n }\n\n const expr = (state: State<any>, minPower: number): A | Fail => {\n let lhs: A | Fail\n failure = undefined\n const p = tryOps(state, prefixes, true)\n if (p === -2) return Fail\n if (p >= 0) {\n const op = prefixes[p]\n const opOut = matched\n const operandValue = expr(state, op.precedence * 2)\n if (operandValue === Fail) return Fail\n lhs = op.fold(opOut, operandValue)\n } else {\n const prefixFailure = failure\n lhs = operand(state)\n if (lhs === Fail) {\n if (prefixFailure !== undefined && state.mode === \"Backtrack\") {\n state.failWith(\"Backtrack\", mergeFailures(prefixFailure, state.failure))\n }\n return Fail\n }\n }\n\n while (true) {\n const start = state.pos\n failure = undefined\n const q = tryOps(state, postfixes, true)\n if (q === -2) return Fail\n if (q >= 0) {\n const op = postfixes[q]\n if (op.precedence * 2 < minPower) {\n state.pos = start\n break\n }\n lhs = op.fold(lhs, matched)\n continue\n }\n const postfixFailure = failure\n const i = tryOps(state, infixes, false)\n if (i === -2) return Fail\n if (i < 0) {\n const f =\n postfixFailure === undefined\n ? failure\n : failure === undefined\n ? postfixFailure\n : mergeFailures(postfixFailure, failure)\n if (f !== undefined && f.offset === state.pos) state.setHint(f.offset, f.expected)\n break\n }\n const op = infixes[i]\n const leftPower = op.precedence * 2\n if (leftPower < minPower) {\n state.pos = start\n break\n }\n const opOut = matched\n const rhs = expr(state, op.associativity === \"left\" ? leftPower + 1 : leftPower)\n if (rhs === Fail) return Fail\n lhs = op.fold(lhs, opOut, rhs)\n }\n return lhs\n }\n\n return makeParser((state: State<any>) => expr(state, 0), \"expression\")\n}\n"],"mappings":"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"}
|