@thomasfosterau/effect-parse 0.0.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.
Files changed (155) hide show
  1. package/README.md +247 -230
  2. package/dist/Ascii.d.ts +32 -53
  3. package/dist/Ascii.d.ts.map +1 -1
  4. package/dist/Ascii.js +576 -571
  5. package/dist/Ascii.js.map +1 -1
  6. package/dist/Binary.d.ts +6 -29
  7. package/dist/Binary.d.ts.map +1 -1
  8. package/dist/Binary.js +129 -116
  9. package/dist/Binary.js.map +1 -1
  10. package/dist/Bits.d.ts +4 -2
  11. package/dist/Bits.d.ts.map +1 -1
  12. package/dist/Bits.js +121 -123
  13. package/dist/Bits.js.map +1 -1
  14. package/dist/Compiler.d.ts +39 -0
  15. package/dist/Compiler.d.ts.map +1 -0
  16. package/dist/Compiler.js +48 -0
  17. package/dist/Compiler.js.map +1 -0
  18. package/dist/Encoding.d.ts +29 -46
  19. package/dist/Encoding.d.ts.map +1 -1
  20. package/dist/Encoding.js +76 -75
  21. package/dist/Encoding.js.map +1 -1
  22. package/dist/Expression.d.ts +15 -49
  23. package/dist/Expression.d.ts.map +1 -1
  24. package/dist/Expression.js +143 -131
  25. package/dist/Expression.js.map +1 -1
  26. package/dist/Input.d.ts +206 -177
  27. package/dist/Input.d.ts.map +1 -1
  28. package/dist/Input.js +317 -299
  29. package/dist/Input.js.map +1 -1
  30. package/dist/Nom.d.ts +44 -84
  31. package/dist/Nom.d.ts.map +1 -1
  32. package/dist/Nom.js +423 -453
  33. package/dist/Nom.js.map +1 -1
  34. package/dist/ParseError.d.ts +54 -49
  35. package/dist/ParseError.d.ts.map +1 -1
  36. package/dist/ParseError.js +233 -275
  37. package/dist/ParseError.js.map +1 -1
  38. package/dist/Parser.d.ts +345 -313
  39. package/dist/Parser.d.ts.map +1 -1
  40. package/dist/Parser.js +2010 -1802
  41. package/dist/Parser.js.map +1 -1
  42. package/dist/ParserSchema.d.ts +8 -7
  43. package/dist/ParserSchema.d.ts.map +1 -1
  44. package/dist/ParserSchema.js +49 -49
  45. package/dist/ParserSchema.js.map +1 -1
  46. package/dist/ParserStream.d.ts +26 -20
  47. package/dist/ParserStream.d.ts.map +1 -1
  48. package/dist/ParserStream.js +267 -255
  49. package/dist/ParserStream.js.map +1 -1
  50. package/dist/Syntax.d.ts +401 -0
  51. package/dist/Syntax.d.ts.map +1 -0
  52. package/dist/Syntax.js +717 -0
  53. package/dist/Syntax.js.map +1 -0
  54. package/dist/Text.d.ts +98 -134
  55. package/dist/Text.d.ts.map +1 -1
  56. package/dist/Text.js +534 -496
  57. package/dist/Text.js.map +1 -1
  58. package/dist/Token.d.ts +60 -42
  59. package/dist/Token.d.ts.map +1 -1
  60. package/dist/Token.js +331 -265
  61. package/dist/Token.js.map +1 -1
  62. package/dist/index.d.ts +16 -17
  63. package/dist/index.js +16 -17
  64. package/dist/internal/compiler/closure.d.ts +14 -16
  65. package/dist/internal/compiler/closure.d.ts.map +1 -1
  66. package/dist/internal/compiler/closure.js +1458 -1637
  67. package/dist/internal/compiler/closure.js.map +1 -1
  68. package/dist/internal/compiler/entries.d.ts +11 -11
  69. package/dist/internal/compiler/entries.d.ts.map +1 -1
  70. package/dist/internal/compiler/entries.js +36 -26
  71. package/dist/internal/compiler/entries.js.map +1 -1
  72. package/dist/internal/compiler/first.d.ts +19 -19
  73. package/dist/internal/compiler/first.d.ts.map +1 -1
  74. package/dist/internal/compiler/first.js +251 -227
  75. package/dist/internal/compiler/first.js.map +1 -1
  76. package/dist/internal/compiler/jit.d.ts +6 -17
  77. package/dist/internal/compiler/jit.d.ts.map +1 -1
  78. package/dist/internal/compiler/jit.js +860 -988
  79. package/dist/internal/compiler/jit.js.map +1 -1
  80. package/dist/internal/compiler/registry.d.ts +20 -21
  81. package/dist/internal/compiler/registry.d.ts.map +1 -1
  82. package/dist/internal/compiler/registry.js +21 -41
  83. package/dist/internal/compiler/registry.js.map +1 -1
  84. package/dist/internal/compiler/sets.d.ts +9 -13
  85. package/dist/internal/compiler/sets.d.ts.map +1 -1
  86. package/dist/internal/compiler/sets.js +76 -73
  87. package/dist/internal/compiler/sets.js.map +1 -1
  88. package/dist/internal/entries.d.ts +3 -3
  89. package/dist/internal/entries.d.ts.map +1 -1
  90. package/dist/internal/entries.js +38 -30
  91. package/dist/internal/entries.js.map +1 -1
  92. package/dist/internal/node.d.ts +177 -173
  93. package/dist/internal/node.d.ts.map +1 -1
  94. package/dist/internal/node.js +77 -66
  95. package/dist/internal/node.js.map +1 -1
  96. package/dist/internal/numbers.d.ts +7 -8
  97. package/dist/internal/numbers.d.ts.map +1 -1
  98. package/dist/internal/numbers.js +246 -276
  99. package/dist/internal/numbers.js.map +1 -1
  100. package/dist/internal/resume.d.ts +6 -24
  101. package/dist/internal/resume.d.ts.map +1 -1
  102. package/dist/internal/resume.js +30 -29
  103. package/dist/internal/resume.js.map +1 -1
  104. package/dist/internal/run.d.ts +15 -0
  105. package/dist/internal/run.d.ts.map +1 -0
  106. package/dist/internal/run.js +36 -0
  107. package/dist/internal/run.js.map +1 -0
  108. package/dist/internal/stack.d.ts +16 -0
  109. package/dist/internal/stack.d.ts.map +1 -0
  110. package/dist/internal/stack.js +26 -0
  111. package/dist/internal/stack.js.map +1 -0
  112. package/dist/internal/syntax.d.ts +146 -0
  113. package/dist/internal/syntax.d.ts.map +1 -0
  114. package/dist/internal/syntax.js +305 -0
  115. package/dist/internal/syntax.js.map +1 -0
  116. package/dist/internal/text.d.ts +10 -2
  117. package/dist/internal/text.d.ts.map +1 -1
  118. package/dist/internal/text.js +295 -345
  119. package/dist/internal/text.js.map +1 -1
  120. package/dist/internal/tokens.d.ts +25 -30
  121. package/dist/internal/tokens.d.ts.map +1 -1
  122. package/dist/internal/tokens.js +369 -363
  123. package/dist/internal/tokens.js.map +1 -1
  124. package/package.json +42 -28
  125. package/src/Ascii.ts +278 -187
  126. package/src/Binary.ts +150 -44
  127. package/src/Bits.ts +6 -3
  128. package/src/Compiler.ts +98 -0
  129. package/src/Expression.ts +10 -5
  130. package/src/Input.ts +106 -28
  131. package/src/Nom.ts +4 -3
  132. package/src/ParseError.ts +48 -51
  133. package/src/Parser.ts +1163 -795
  134. package/src/ParserStream.ts +104 -80
  135. package/src/Syntax.ts +900 -0
  136. package/src/Text.ts +272 -187
  137. package/src/Token.ts +180 -87
  138. package/src/index.ts +2 -0
  139. package/src/internal/compiler/closure.ts +121 -88
  140. package/src/internal/compiler/entries.ts +21 -8
  141. package/src/internal/compiler/first.ts +17 -15
  142. package/src/internal/compiler/jit.ts +360 -157
  143. package/src/internal/compiler/registry.ts +12 -33
  144. package/src/internal/compiler/sets.ts +17 -11
  145. package/src/internal/entries.ts +4 -2
  146. package/src/internal/node.ts +51 -37
  147. package/src/internal/numbers.ts +22 -20
  148. package/src/internal/resume.ts +8 -4
  149. package/src/internal/run.ts +41 -0
  150. package/src/internal/stack.ts +36 -0
  151. package/src/internal/syntax.ts +421 -0
  152. package/src/internal/text.ts +32 -25
  153. package/src/internal/tokens.ts +96 -51
  154. package/dist/index.d.ts.map +0 -1
  155. package/dist/index.js.map +0 -1
package/dist/Text.js CHANGED
@@ -1,529 +1,567 @@
1
- import * as Encodings from "./Encoding.js";
1
+ import * as Predicate from "effect/Predicate";
2
2
  import { Fail } from "./Input.js";
3
- import { escapedImpl, overflow, takeEscapedImpl, toFloat } from "./Ascii.js";
3
+ import * as P from "./Parser.js";
4
+ import { floatText } from "./internal/numbers.js";
4
5
  import { codePointPredicate, compile, indexOf, matchLiteral } from "./internal/tokens.js";
5
- import { floatText as markFloatText } from "./internal/numbers.js";
6
6
  import * as internal from "./internal/text.js";
7
- import * as P from "./Parser.js";
8
- const toCodePoint = (c) => typeof c === "number" ? c : c.codePointAt(0) ?? -1;
7
+ import { escapedImpl, overflow, takeEscapedImpl, toFloat as toFloat$1 } from "./Ascii.js";
8
+ import * as Encodings from "./Encoding.js";
9
+ //#region src/Text.ts
10
+ /**
11
+ * Unicode text parsers, generic over the input's encoding.
12
+ *
13
+ * `Text.make(encoding)` builds one set of parsers ({@link TextParsers}) for
14
+ * an {@link Encoding.Encoding}, and ready-made sets are provided for
15
+ * JavaScript strings and the common byte encodings:
16
+ *
17
+ * | Parsers | Input | Offsets |
18
+ * |---|---|---|
19
+ * | `Text.string` | `string` | UTF-16 code units |
20
+ * | `Text.utf8` | `Uint8Array` of UTF-8 | bytes |
21
+ * | `Text.utf16le`, `Text.utf16be` | `Uint8Array` of UTF-16 | bytes |
22
+ * | `Text.latin1` | `Uint8Array` of ISO-8859-1 | bytes |
23
+ *
24
+ * Every set has the same members, and every parser returns `string`s, so a
25
+ * grammar written against `TextParsers<I>` parses all of them:
26
+ *
27
+ * ```ts
28
+ * import { Parser, Text } from "@thomasfosterau/effect-parse"
29
+ *
30
+ * const greeting = <I extends string | Uint8Array>(T: Text.TextParsers<I>) =>
31
+ * Parser.preceded(T.literal("¡hola "), T.identifier)
32
+ *
33
+ * Parser.parse(greeting(Text.string), "¡hola mundo") // "mundo"
34
+ * Parser.parse(greeting(Text.utf8), new TextEncoder().encode("¡hola Zoë")) // "Zoë"
35
+ * ```
36
+ *
37
+ * Tokens are Unicode code points, and character classes follow Unicode
38
+ * properties: `alpha1` matches `"Ωμέγα"`, `space1` matches a no-break space.
39
+ * Use the `Ascii` module for the ASCII-only classes.
40
+ *
41
+ * Decoding is strict. Malformed input (invalid UTF-8, unpaired surrogates)
42
+ * never matches, and error messages point at it. On partial input, a
43
+ * character split across chunks reports `Incomplete`, so byte streams can be
44
+ * parsed as text without decoding them first.
45
+ *
46
+ * @since 0.1.0
47
+ */
48
+ const toCodePoint = (c) => Predicate.isNumber(c) ? c : c.codePointAt(0) ?? -1;
9
49
  const makePredicate = (name, re) => {
10
- // Results for the Basic Multilingual Plane are cached: a table lookup is
11
- // much faster than a regular expression test.
12
- let ascii;
13
- let bmp;
14
- return codePointPredicate(name, (c) => {
15
- const x = toCodePoint(c);
16
- if (x < 0)
17
- return false;
18
- let table;
19
- if (x < 128)
20
- table = ascii ??= new Uint8Array(128);
21
- else if (x < 0x10000)
22
- table = bmp ??= new Uint8Array(0x10000);
23
- else
24
- return re.test(String.fromCodePoint(x));
25
- let v = table[x];
26
- if (v === 0)
27
- table[x] = v = re.test(String.fromCharCode(x)) ? 2 : 1;
28
- return v === 2;
29
- });
50
+ let ascii;
51
+ let bmp;
52
+ return codePointPredicate(name, (c) => {
53
+ const x = toCodePoint(c);
54
+ if (x < 0) return false;
55
+ let table;
56
+ if (x < 128) table = ascii ??= /* @__PURE__ */ new Uint8Array(128);
57
+ else if (x < 65536) table = bmp ??= /* @__PURE__ */ new Uint8Array(65536);
58
+ else return re.test(String.fromCodePoint(x));
59
+ let v = table[x];
60
+ if (v === 0) table[x] = v = re.test(String.fromCharCode(x)) ? 2 : 1;
61
+ return v === 2;
62
+ });
30
63
  };
31
64
  /**
32
- * A predicate testing a Unicode property, using the syntax of regular
33
- * expression property escapes (`\p{...}`): a general category (`"Lu"`,
34
- * `"Letter"`), a binary property (`"Emoji"`, `"Dash"`) or a script
35
- * (`"Script=Greek"`).
36
- *
37
- * @example
38
- * ```ts
39
- * import { Text } from "@thomasfosterau/effect-parse"
40
- *
41
- * const greek = Text.string.takeWhile(Text.property("Script=Greek"), { min: 1 })
42
- * ```
43
- *
44
- * @since 0.1.0
45
- * @category predicates
46
- */
47
- export const property = (name) => makePredicate(name, new RegExp(`^\\p{${name}}$`, "u"));
65
+ * A predicate testing a Unicode property, using the syntax of regular
66
+ * expression property escapes (`\p{...}`): a general category (`"Lu"`,
67
+ * `"Letter"`), a binary property (`"Emoji"`, `"Dash"`) or a script
68
+ * (`"Script=Greek"`).
69
+ *
70
+ * @example
71
+ * ```ts
72
+ * import { Text } from "@thomasfosterau/effect-parse"
73
+ *
74
+ * const greek = Text.string.takeWhile(Text.property("Script=Greek"), { min: 1 })
75
+ * ```
76
+ *
77
+ * @since 0.1.0
78
+ * @category predicates
79
+ */
80
+ const property = (name) => makePredicate(name, new RegExp(`^\\p{${name}}$`, "u"));
48
81
  /**
49
- * Letters and other alphabetic characters (the Unicode `Alphabetic`
50
- * property, Rust's `char::is_alphabetic`).
51
- *
52
- * @since 0.1.0
53
- * @category predicates
54
- */
55
- export const isAlphabetic = makePredicate("isAlphabetic", /^\p{Alphabetic}$/u);
82
+ * Letters and other alphabetic characters (the Unicode `Alphabetic`
83
+ * property, Rust's `char::is_alphabetic`).
84
+ *
85
+ * @since 0.1.0
86
+ * @category predicates
87
+ */
88
+ const isAlphabetic = /*#__PURE__*/ makePredicate("isAlphabetic", /^\p{Alphabetic}$/u);
56
89
  /**
57
- * Letters (general category `L`).
58
- *
59
- * @since 0.1.0
60
- * @category predicates
61
- */
62
- export const isLetter = makePredicate("isLetter", /^\p{L}$/u);
90
+ * Letters (general category `L`).
91
+ *
92
+ * @since 0.1.0
93
+ * @category predicates
94
+ */
95
+ const isLetter = /*#__PURE__*/ makePredicate("isLetter", /^\p{L}$/u);
63
96
  /**
64
- * Uppercase characters (the Unicode `Uppercase` property).
65
- *
66
- * @since 0.1.0
67
- * @category predicates
68
- */
69
- export const isUppercase = makePredicate("isUppercase", /^\p{Uppercase}$/u);
97
+ * Uppercase characters (the Unicode `Uppercase` property).
98
+ *
99
+ * @since 0.1.0
100
+ * @category predicates
101
+ */
102
+ const isUppercase = /*#__PURE__*/ makePredicate("isUppercase", /^\p{Uppercase}$/u);
70
103
  /**
71
- * Lowercase characters (the Unicode `Lowercase` property).
72
- *
73
- * @since 0.1.0
74
- * @category predicates
75
- */
76
- export const isLowercase = makePredicate("isLowercase", /^\p{Lowercase}$/u);
104
+ * Lowercase characters (the Unicode `Lowercase` property).
105
+ *
106
+ * @since 0.1.0
107
+ * @category predicates
108
+ */
109
+ const isLowercase = /*#__PURE__*/ makePredicate("isLowercase", /^\p{Lowercase}$/u);
77
110
  /**
78
- * Decimal digits of any script (general category `Nd`): `0`–`9`, `٠`–`٩`,
79
- * `०`–`९`, ...
80
- *
81
- * @since 0.1.0
82
- * @category predicates
83
- */
84
- export const isDecimalDigit = makePredicate("isDecimalDigit", /^\p{Nd}$/u);
111
+ * Decimal digits of any script (general category `Nd`): `0`–`9`, `٠`–`٩`,
112
+ * `०`–`९`, ...
113
+ *
114
+ * @since 0.1.0
115
+ * @category predicates
116
+ */
117
+ const isDecimalDigit = /*#__PURE__*/ makePredicate("isDecimalDigit", /^\p{Nd}$/u);
85
118
  /**
86
- * Numeric characters (general category `N`), including `½` and `Ⅻ` (Rust's
87
- * `char::is_numeric`).
88
- *
89
- * @since 0.1.0
90
- * @category predicates
91
- */
92
- export const isNumeric = makePredicate("isNumeric", /^\p{N}$/u);
119
+ * Numeric characters (general category `N`), including `½` and `Ⅻ` (Rust's
120
+ * `char::is_numeric`).
121
+ *
122
+ * @since 0.1.0
123
+ * @category predicates
124
+ */
125
+ const isNumeric = /*#__PURE__*/ makePredicate("isNumeric", /^\p{N}$/u);
93
126
  /**
94
- * Alphabetic or numeric characters (Rust's `char::is_alphanumeric`).
95
- *
96
- * @since 0.1.0
97
- * @category predicates
98
- */
99
- export const isAlphanumeric = makePredicate("isAlphanumeric", /^[\p{Alphabetic}\p{N}]$/u);
127
+ * Alphabetic or numeric characters (Rust's `char::is_alphanumeric`).
128
+ *
129
+ * @since 0.1.0
130
+ * @category predicates
131
+ */
132
+ const isAlphanumeric = /*#__PURE__*/ makePredicate("isAlphanumeric", /^[\p{Alphabetic}\p{N}]$/u);
100
133
  /**
101
- * Whitespace, including line breaks (the Unicode `White_Space` property,
102
- * Rust's `char::is_whitespace`).
103
- *
104
- * @since 0.1.0
105
- * @category predicates
106
- */
107
- export const isWhitespace = makePredicate("isWhitespace", /^\p{White_Space}$/u);
134
+ * Whitespace, including line breaks (the Unicode `White_Space` property,
135
+ * Rust's `char::is_whitespace`).
136
+ *
137
+ * @since 0.1.0
138
+ * @category predicates
139
+ */
140
+ const isWhitespace = /*#__PURE__*/ makePredicate("isWhitespace", /^\p{White_Space}$/u);
108
141
  /**
109
- * Whitespace that does not break lines: `White_Space` except `\n`, `\v`,
110
- * `\f`, `\r`, U+0085, U+2028 and U+2029. Includes tabs and no-break spaces.
111
- *
112
- * @since 0.1.0
113
- * @category predicates
114
- */
115
- export const isSpace = makePredicate("isSpace", /^(?![\n\v\f\r\u0085\u2028\u2029])\p{White_Space}$/u);
142
+ * Whitespace that does not break lines: `White_Space` except `\n`, `\v`,
143
+ * `\f`, `\r`, U+0085, U+2028 and U+2029. Includes tabs and no-break spaces.
144
+ *
145
+ * @since 0.1.0
146
+ * @category predicates
147
+ */
148
+ const isSpace = /*#__PURE__*/ makePredicate("isSpace", /^(?![\n\v\f\r\u0085\u2028\u2029])\p{White_Space}$/u);
116
149
  /**
117
- * Characters that can start an identifier (the Unicode `ID_Start` property,
118
- * see UAX #31).
119
- *
120
- * @since 0.1.0
121
- * @category predicates
122
- */
123
- export const isIdStart = makePredicate("isIdStart", /^\p{ID_Start}$/u);
150
+ * Characters that can start an identifier (the Unicode `ID_Start` property,
151
+ * see UAX #31).
152
+ *
153
+ * @since 0.1.0
154
+ * @category predicates
155
+ */
156
+ const isIdStart = /*#__PURE__*/ makePredicate("isIdStart", /^\p{ID_Start}$/u);
124
157
  /**
125
- * Characters that can continue an identifier (the Unicode `ID_Continue`
126
- * property, see UAX #31).
127
- *
128
- * @since 0.1.0
129
- * @category predicates
130
- */
131
- export const isIdContinue = makePredicate("isIdContinue", /^\p{ID_Continue}$/u);
158
+ * Characters that can continue an identifier (the Unicode `ID_Continue`
159
+ * property, see UAX #31).
160
+ *
161
+ * @since 0.1.0
162
+ * @category predicates
163
+ */
164
+ const isIdContinue = /*#__PURE__*/ makePredicate("isIdContinue", /^\p{ID_Continue}$/u);
132
165
  /**
133
- * Punctuation (general category `P`).
134
- *
135
- * @since 0.1.0
136
- * @category predicates
137
- */
138
- export const isPunctuation = makePredicate("isPunctuation", /^\p{P}$/u);
166
+ * Punctuation (general category `P`).
167
+ *
168
+ * @since 0.1.0
169
+ * @category predicates
170
+ */
171
+ const isPunctuation = /*#__PURE__*/ makePredicate("isPunctuation", /^\p{P}$/u);
139
172
  /**
140
- * Control characters (general category `Cc`).
141
- *
142
- * @since 0.1.0
143
- * @category predicates
144
- */
145
- export const isControl = makePredicate("isControl", /^\p{Cc}$/u);
173
+ * Control characters (general category `Cc`).
174
+ *
175
+ * @since 0.1.0
176
+ * @category predicates
177
+ */
178
+ const isControl = /*#__PURE__*/ makePredicate("isControl", /^\p{Cc}$/u);
146
179
  const normalize = (r) => {
147
- if (r === undefined)
148
- return [0, Infinity];
149
- if (typeof r === "number")
150
- return [r, r];
151
- return [r.min ?? 0, r.max ?? Infinity];
180
+ if (r === void 0) return [0, Infinity];
181
+ if (Predicate.isNumber(r)) return [r, r];
182
+ return [r.min ?? 0, r.max ?? Infinity];
152
183
  };
153
- const isAsciiDigit = codePointPredicate("isAsciiDigit", (c) => c >= 48 && c <= 57, [[48, 57]]);
154
- const isAsciiHexDigit = codePointPredicate("isAsciiHexDigit", (c) => (c >= 48 && c <= 57) || (c >= 65 && c <= 70) || (c >= 97 && c <= 102), [[48, 57], [65, 70], [97, 102]]);
184
+ const isAsciiDigit = /*#__PURE__*/ codePointPredicate("isAsciiDigit", (c) => c >= 48 && c <= 57, [[48, 57]]);
185
+ const isAsciiHexDigit = /*#__PURE__*/ codePointPredicate("isAsciiHexDigit", (c) => c >= 48 && c <= 57 || c >= 65 && c <= 70 || c >= 97 && c <= 102, [
186
+ [48, 57],
187
+ [65, 70],
188
+ [97, 102]
189
+ ]);
155
190
  const isLineBreak = (c) => c === 10 || c === 13;
156
191
  const expectedAny = ["any character"];
157
192
  const expectedLineEnding = ["line ending"];
158
193
  const expectedIdentifier = ["identifier"];
159
194
  /**
160
- * Builds the text parsers for an encoding.
161
- *
162
- * @example
163
- * ```ts
164
- * import { Encoding, Parser, Text } from "@thomasfosterau/effect-parse"
165
- *
166
- * const T = Text.make(Encoding.latin1)
167
- * Parser.parse(T.alpha1, new Uint8Array([0x63, 0x61, 0x66, 0xe9])) // "café"
168
- * ```
169
- *
170
- * @since 0.1.0
171
- * @category constructors
172
- */
173
- export const make = (encoding) => {
174
- const enc = encoding;
175
- const fast = internal.fastLimit(enc);
176
- // Each parser records its encoding on byte input (`state.encoding`), so
177
- // that errors can show the input as text.
178
- const backtrack = (state, kind, expected, offset = state.pos) => state.backtrack(kind, expected, offset);
179
- /** The text `[start, end)` after checking it is well formed, or `Fail`. */
180
- const textOf = (state, start, end, kind, expected) => {
181
- const count = internal.validate(enc, state, start, end);
182
- if (count < 0)
183
- return backtrack(state, kind, expected, -1 - count);
184
- return enc.text(state.input, start, end);
185
- };
186
- const takeWhileText = (test, r, negate, name, expected, kind, hint, set = test) => {
187
- const [min, max] = normalize(r);
188
- return P.described((state) => {
189
- if (state.inputKind === 1)
190
- state.encoding = enc;
191
- const start = state.pos;
192
- internal.scan(enc, state, test, negate, max, state.pos, fast);
193
- const offset = internal.scanOffset;
194
- const count = internal.scanCount;
195
- const stop = internal.scanStop;
196
- if (state.partial && (stop === internal.End || stop === internal.Truncated))
197
- return state.incomplete(1, expected);
198
- if (count < min)
199
- return backtrack(state, kind, expected, offset);
200
- // More matching characters would have been accepted where we stopped
201
- if (hint && count < max)
202
- state.setHint(offset, expected);
203
- state.pos = offset;
204
- return enc.text(state.input, start, offset);
205
- }, name, { _tag: "TakeWhile", set, negate, min, max, encoding: enc });
206
- };
207
- const any = P.described((state) => {
208
- if (state.inputKind === 1)
209
- state.encoding = enc;
210
- const cp = internal.next(enc, state);
211
- if (cp < 0)
212
- return internal.failAt(state, cp, "Token", expectedAny);
213
- state.pos += internal.width;
214
- return internal.charOf(cp);
215
- }, "any", { _tag: "Any", encoding: enc });
216
- const literal = (lit) => {
217
- const encoded = enc.encode(lit);
218
- const len = encoded.length;
219
- const expected = [JSON.stringify(lit)];
220
- const node = { _tag: "Literal", literal: lit, caseless: false, encoding: enc };
221
- if (len === 1) {
222
- // Single unit literals (punctuation, mostly) are compared directly
223
- const unit = typeof encoded === "string" ? encoded.charCodeAt(0) : encoded[0];
224
- return P.described((state) => {
225
- const pos = state.pos;
226
- if (state.inputKind === 1)
227
- state.encoding = enc;
228
- if (pos >= state.end)
229
- return state.eoi("Literal", expected, 1);
230
- const input = state.input;
231
- if ((state.inputKind === 0 ? input.charCodeAt(pos) : input[pos]) !== unit) {
232
- return backtrack(state, "Literal", expected);
233
- }
234
- state.pos = pos + 1;
235
- return lit;
236
- }, expected[0], node);
237
- }
238
- return P.described((state) => {
239
- if (state.inputKind === 1)
240
- state.encoding = enc;
241
- const r = matchLiteral(state, encoded, false);
242
- if (r === -1)
243
- return backtrack(state, "Literal", expected);
244
- if (r === -2) {
245
- if (state.partial)
246
- return state.incomplete(len - (state.end - state.pos), expected);
247
- return backtrack(state, "Literal", expected);
248
- }
249
- state.pos += len;
250
- return lit;
251
- }, expected[0], node);
252
- };
253
- const caseless = (lit) => {
254
- const folded = Array.from(lit, (c) => internal.fold(c.codePointAt(0)));
255
- const expected = [`${JSON.stringify(lit)} (case insensitive)`];
256
- return P.described((state) => {
257
- if (state.inputKind === 1)
258
- state.encoding = enc;
259
- const start = state.pos;
260
- let pos = start;
261
- for (let i = 0; i < folded.length; i++) {
262
- const cp = internal.next(enc, state, pos);
263
- if (cp === internal.End || cp === internal.Truncated) {
264
- return state.partial ? state.incomplete(1, expected) : backtrack(state, "Literal", expected);
265
- }
266
- if (cp < 0 || internal.fold(cp) !== folded[i])
267
- return backtrack(state, "Literal", expected);
268
- pos += internal.width;
269
- }
270
- state.pos = pos;
271
- return enc.text(state.input, start, pos);
272
- }, expected[0], { _tag: "Literal", literal: lit, caseless: true, encoding: enc });
273
- };
274
- const oneOfImpl = (set, negate) => {
275
- const m = compile(set, "string");
276
- const test = m.code;
277
- const expected = [negate ? `anything but ${m.description}` : m.description];
278
- const kind = negate ? "NoneOf" : "OneOf";
279
- return P.described((state) => {
280
- if (state.inputKind === 1)
281
- state.encoding = enc;
282
- const cp = internal.next(enc, state);
283
- if (cp < 0)
284
- return internal.failAt(state, cp, kind, expected);
285
- const w = internal.width;
286
- if (test(cp) === negate)
287
- return state.backtrack(kind, expected);
288
- state.pos += w;
289
- return internal.charOf(cp);
290
- }, expected[0], { _tag: "OneOf", set, negate, encoding: enc });
291
- };
292
- const take = (count) => {
293
- const expected = [count === 1 ? "1 character" : `${count} characters`];
294
- return P.described((state) => {
295
- if (state.inputKind === 1)
296
- state.encoding = enc;
297
- const start = state.pos;
298
- let pos = start;
299
- for (let got = 0; got < count; got++) {
300
- const cp = internal.next(enc, state, pos);
301
- if (cp === internal.End)
302
- return state.eoi("Take", expected, count - got);
303
- if (cp < 0)
304
- return internal.failAt(state, cp, "Take", expected, pos);
305
- pos += internal.width;
306
- }
307
- state.pos = pos;
308
- return enc.text(state.input, start, pos);
309
- }, "take", { _tag: "Take", count, encoding: enc });
310
- };
311
- const takeUntil = (lit, r) => {
312
- const [min, max] = normalize(r);
313
- const needle = enc.encode(lit);
314
- const unit = enc.unit;
315
- const expected = [JSON.stringify(lit)];
316
- return P.described((state) => {
317
- if (state.inputKind === 1)
318
- state.encoding = enc;
319
- const start = state.pos;
320
- let idx = indexOf(state, needle, start);
321
- // Multi-unit encodings: only accept matches on a character boundary
322
- while (unit > 1 && idx >= 0 && (idx - start) % unit !== 0)
323
- idx = indexOf(state, needle, idx + 1);
324
- if (idx < 0) {
325
- if (state.partial)
326
- return state.incomplete(0, expected);
327
- return backtrack(state, "TakeUntil", expected, state.end);
328
- }
329
- const count = internal.validate(enc, state, start, idx);
330
- if (count < 0)
331
- return backtrack(state, "TakeUntil", expected, -1 - count);
332
- // As in winnow, the first occurrence must lie within the range
333
- if (count < min)
334
- return backtrack(state, "TakeUntil", expected, idx);
335
- if (count > max)
336
- return backtrack(state, "TakeUntil", expected);
337
- state.pos = idx;
338
- return enc.text(state.input, start, idx);
339
- }, "takeUntil", { _tag: "TakeUntil", literal: lit, min, max, encoding: enc });
340
- };
341
- const always = () => true;
342
- const rest = P.described((state) => {
343
- if (state.inputKind === 1)
344
- state.encoding = enc;
345
- const start = state.pos;
346
- internal.scan(enc, state, always, false, Infinity, state.pos, fast);
347
- const offset = internal.scanOffset;
348
- if (internal.scanStop === internal.Truncated)
349
- return state.incomplete(1, expectedAny);
350
- if (internal.scanStop === internal.Invalid)
351
- return backtrack(state, "Token", expectedAny, offset);
352
- state.pos = offset;
353
- return enc.text(state.input, start, offset);
354
- }, "rest", { _tag: "Rest", encoding: enc });
355
- const taken = (self) => {
356
- const step = self.step;
357
- return P.described((state) => {
358
- if (state.inputKind === 1)
359
- state.encoding = enc;
360
- const start = state.pos;
361
- if (step(state) === Fail)
362
- return Fail;
363
- return textOf(state, start, state.pos, "Slice", expectedAny);
364
- }, self.name, { _tag: "Taken", self, encoding: enc });
365
- };
366
- const cls = (test, min, description, kind, hint = true) => takeWhileText(test, { min }, false, `${kind.toLowerCase()}${min}`, [description], kind, hint);
367
- const identifierStart = (cp) => cp === 95 || isIdStart(cp);
368
- const identifier = P.described((state) => {
369
- if (state.inputKind === 1)
370
- state.encoding = enc;
371
- const start = state.pos;
372
- const cp = internal.next(enc, state);
373
- if (cp < 0)
374
- return internal.failAt(state, cp, "TakeWhile", expectedIdentifier);
375
- if (!identifierStart(cp))
376
- return state.backtrack("TakeWhile", expectedIdentifier);
377
- internal.scan(enc, state, isIdContinue, false, Infinity, start + internal.width, fast);
378
- const stop = internal.scanStop;
379
- if (state.partial && (stop === internal.End || stop === internal.Truncated)) {
380
- return state.incomplete(1, expectedIdentifier);
381
- }
382
- state.pos = internal.scanOffset;
383
- return enc.text(state.input, start, state.pos);
384
- }, "identifier", { _tag: "Identifier", encoding: enc });
385
- // Decoded rather than matched as a literal, as not every encoding can encode it
386
- const bom = P.described((state) => {
387
- if (state.inputKind === 1)
388
- state.encoding = enc;
389
- const cp = internal.next(enc, state);
390
- if (cp === 0xfeff) {
391
- state.pos += internal.width;
392
- return true;
393
- }
394
- if (cp === internal.Truncated || (cp === internal.End && state.partial)) {
395
- return state.incomplete(1, ["byte order mark"]);
396
- }
397
- return false;
398
- }, "bom", { _tag: "Bom", encoding: enc });
399
- const newline = literal("\n");
400
- const crlf = literal("\r\n");
401
- const tillLineEnding = P.described((state) => {
402
- if (state.inputKind === 1)
403
- state.encoding = enc;
404
- const start = state.pos;
405
- internal.scan(enc, state, isLineBreak, true, Infinity, state.pos, fast);
406
- const offset = internal.scanOffset;
407
- const stop = internal.scanStop;
408
- if (stop === internal.Truncated || (stop === internal.End && state.partial)) {
409
- return state.incomplete(1, expectedLineEnding);
410
- }
411
- if (stop === internal.Invalid)
412
- return backtrack(state, "LineEnding", expectedLineEnding, offset);
413
- if (stop === 0 && internal.next(enc, state, offset) === 13) {
414
- const after = internal.next(enc, state, offset + internal.width);
415
- if (after === internal.End && state.partial)
416
- return state.incomplete(1, expectedLineEnding);
417
- if (after !== 10)
418
- return backtrack(state, "LineEnding", expectedLineEnding, offset);
419
- }
420
- state.pos = offset;
421
- return enc.text(state.input, start, offset);
422
- }, "tillLineEnding", { _tag: "TillLineEnding", encoding: enc });
423
- const asciiDigits = takeWhileText(isAsciiDigit, { min: 1 }, false, "digit1", ["digit"], "Digit", true);
424
- const hexDigits = takeWhileText(isAsciiHexDigit, { min: 1 }, false, "hexDigit1", ["hexadecimal digit"], "HexDigit", true);
425
- const sign = P.opt(oneOfImpl("+-", false));
426
- const signed = taken(P.seq(sign, asciiDigits));
427
- const exponent = P.opt(P.seq(oneOfImpl("eE", false), sign, asciiDigits));
428
- const unsignedFloat = P.alt(P.seq(caseless("inf"), P.opt(caseless("inity"))), P.seq(literal("."), asciiDigits, exponent), P.seq(asciiDigits, P.opt(P.seq(literal("."), P.opt(asciiDigits))), exponent));
429
- const floatText = markFloatText(taken(P.alt(caseless("nan"), P.seq(sign, unsignedFloat))).pipe(P.expected("number")));
430
- const matchControl = (control) => {
431
- const ctrl = control.codePointAt(0);
432
- return (state) => {
433
- if (internal.next(enc, state) !== ctrl)
434
- return false;
435
- state.pos += internal.width;
436
- return true;
437
- };
438
- };
439
- return {
440
- encoding,
441
- any,
442
- literal,
443
- caseless,
444
- oneOf: (set) => oneOfImpl(set, false),
445
- noneOf: (set) => oneOfImpl(set, true),
446
- bom,
447
- take,
448
- takeWhile: (set, r) => {
449
- const m = compile(set, "string");
450
- return takeWhileText(m.code, r, false, "takeWhile", [m.description], "TakeWhile", false, set);
451
- },
452
- takeTill: (set, r) => {
453
- const m = compile(set, "string");
454
- return takeWhileText(m.code, r, true, "takeTill", [`anything but ${m.description}`], "TakeWhile", false, set);
455
- },
456
- takeUntil,
457
- rest,
458
- taken,
459
- alpha0: cls(isAlphabetic, 0, "letter", "Alpha"),
460
- alpha1: cls(isAlphabetic, 1, "letter", "Alpha"),
461
- digit0: cls(isDecimalDigit, 0, "digit", "Digit"),
462
- digit1: cls(isDecimalDigit, 1, "digit", "Digit"),
463
- alphanumeric0: cls(isAlphanumeric, 0, "letter or digit", "AlphaNumeric"),
464
- alphanumeric1: cls(isAlphanumeric, 1, "letter or digit", "AlphaNumeric"),
465
- space0: cls(isSpace, 0, "space", "Space", false),
466
- space1: cls(isSpace, 1, "space", "Space", false),
467
- multispace0: cls(isWhitespace, 0, "whitespace", "MultiSpace", false),
468
- multispace1: cls(isWhitespace, 1, "whitespace", "MultiSpace", false),
469
- identifier,
470
- newline,
471
- crlf,
472
- tab: literal("\t"),
473
- lineEnding: P.alt(newline, crlf).pipe(P.expected("line ending")),
474
- tillLineEnding,
475
- decUint: asciiDigits.pipe(P.tryMap((s) => overflow(Number(s))), P.named("decUint")),
476
- decInt: signed.pipe(P.tryMap((s) => overflow(Number(s))), P.named("decInt")),
477
- decBigUint: asciiDigits.pipe(P.map((s) => BigInt(s))),
478
- decBigInt: signed.pipe(P.map((s) => BigInt(s.startsWith("+") ? s.slice(1) : s))),
479
- hexUint: hexDigits.pipe(P.tryMap((s) => overflow(parseInt(s, 16))), P.named("hexUint")),
480
- float: floatText.pipe(P.map(toFloat), P.named("float")),
481
- takeEscaped: (normal, control, escapable) => takeEscapedImpl(normal, matchControl(control), escapable, (state, start) => enc.text(state.input, start, state.pos), control.codePointAt(0), enc),
482
- escaped: (normal, control, escape) => escapedImpl(normal, matchControl(control), escape, control.codePointAt(0), enc)
483
- };
195
+ * Builds the text parsers for an encoding.
196
+ *
197
+ * @example
198
+ * ```ts
199
+ * import { Encoding, Parser, Text } from "@thomasfosterau/effect-parse"
200
+ *
201
+ * const T = Text.make(Encoding.latin1)
202
+ * Parser.parse(T.alpha1, new Uint8Array([0x63, 0x61, 0x66, 0xe9])) // "café"
203
+ * ```
204
+ *
205
+ * @since 0.1.0
206
+ * @category constructors
207
+ */
208
+ const make = (encoding) => {
209
+ const enc = encoding;
210
+ const fast = internal.fastLimit(enc);
211
+ const backtrack = (state, kind, expected, offset = state.pos) => state.backtrack(kind, expected, offset);
212
+ /** The text `[start, end)` after checking it is well formed, or `Fail`. */
213
+ const textOf = (state, start, end, kind, expected) => {
214
+ const count = internal.validate(enc, state, start, end);
215
+ if (count < 0) return backtrack(state, kind, expected, -1 - count);
216
+ return enc.text(state.input, start, end);
217
+ };
218
+ const takeWhileText = (test, r, negate, name, expected, kind, hint, set = test) => {
219
+ const [min, max] = normalize(r);
220
+ return P.described((state) => {
221
+ if (state.inputKind === 1) state.encoding = enc;
222
+ const start = state.pos;
223
+ internal.scan(enc, state, test, negate, max, state.pos, fast);
224
+ const offset = internal.scanOffset;
225
+ const count = internal.scanCount;
226
+ const stop = internal.scanStop;
227
+ if (state.partial && (stop === internal.End || stop === internal.Truncated)) return state.incomplete(1, expected);
228
+ if (count < min) return backtrack(state, kind, expected, offset);
229
+ if (hint && count < max) state.setHint(offset, expected);
230
+ state.pos = offset;
231
+ return enc.text(state.input, start, offset);
232
+ }, name, {
233
+ _tag: "TakeWhile",
234
+ set,
235
+ negate,
236
+ min,
237
+ max,
238
+ encoding: enc
239
+ });
240
+ };
241
+ const any = P.described((state) => {
242
+ if (state.inputKind === 1) state.encoding = enc;
243
+ const cp = internal.next(enc, state);
244
+ if (cp < 0) return internal.failAt(state, cp, "Token", expectedAny);
245
+ state.pos += internal.width;
246
+ return internal.charOf(cp);
247
+ }, "any", {
248
+ _tag: "Any",
249
+ encoding: enc
250
+ });
251
+ const literal = (lit) => {
252
+ const encoded = enc.encode(lit);
253
+ const len = encoded.length;
254
+ const expected = [JSON.stringify(lit)];
255
+ const node = {
256
+ _tag: "Literal",
257
+ literal: lit,
258
+ caseless: false,
259
+ encoding: enc
260
+ };
261
+ if (len === 1) {
262
+ const unit = Predicate.isString(encoded) ? encoded.charCodeAt(0) : encoded[0];
263
+ return P.described((state) => {
264
+ const pos = state.pos;
265
+ if (state.inputKind === 1) state.encoding = enc;
266
+ if (pos >= state.end) return state.eoi("Literal", expected, 1);
267
+ const input = state.input;
268
+ if ((state.inputKind === 0 ? input.charCodeAt(pos) : input[pos]) !== unit) return backtrack(state, "Literal", expected);
269
+ state.pos = pos + 1;
270
+ return lit;
271
+ }, expected[0], node);
272
+ }
273
+ return P.described((state) => {
274
+ if (state.inputKind === 1) state.encoding = enc;
275
+ const r = matchLiteral(state, encoded, false);
276
+ if (r === -1) return backtrack(state, "Literal", expected);
277
+ if (r === -2) {
278
+ if (state.partial) return state.incomplete(len - (state.end - state.pos), expected);
279
+ return backtrack(state, "Literal", expected);
280
+ }
281
+ state.pos += len;
282
+ return lit;
283
+ }, expected[0], node);
284
+ };
285
+ const caseless = (lit) => {
286
+ const folded = Array.from(lit, (c) => internal.fold(internal.firstCodePoint(c)));
287
+ const expected = [`${JSON.stringify(lit)} (case insensitive)`];
288
+ return P.described((state) => {
289
+ if (state.inputKind === 1) state.encoding = enc;
290
+ const start = state.pos;
291
+ let pos = start;
292
+ for (let i = 0; i < folded.length; i++) {
293
+ const cp = internal.next(enc, state, pos);
294
+ if (cp === internal.End || cp === internal.Truncated) return state.partial ? state.incomplete(1, expected) : backtrack(state, "Literal", expected);
295
+ if (cp < 0 || internal.fold(cp) !== folded[i]) {
296
+ state.syntax?.read(pos + Math.max(internal.width, 1));
297
+ return backtrack(state, "Literal", expected);
298
+ }
299
+ pos += internal.width;
300
+ }
301
+ state.pos = pos;
302
+ return enc.text(state.input, start, pos);
303
+ }, expected[0], {
304
+ _tag: "Literal",
305
+ literal: lit,
306
+ caseless: true,
307
+ encoding: enc
308
+ });
309
+ };
310
+ const oneOfImpl = (set, negate) => {
311
+ const m = compile(set, "string");
312
+ const test = m.code;
313
+ const expected = [negate ? `anything but ${m.description}` : m.description];
314
+ const kind = negate ? "NoneOf" : "OneOf";
315
+ return P.described((state) => {
316
+ if (state.inputKind === 1) state.encoding = enc;
317
+ const cp = internal.next(enc, state);
318
+ if (cp < 0) return internal.failAt(state, cp, kind, expected);
319
+ const w = internal.width;
320
+ if (test(cp) === negate) return state.backtrack(kind, expected);
321
+ state.pos += w;
322
+ return internal.charOf(cp);
323
+ }, expected[0], {
324
+ _tag: "OneOf",
325
+ set,
326
+ negate,
327
+ encoding: enc
328
+ });
329
+ };
330
+ const take = (count) => {
331
+ const expected = [count === 1 ? "1 character" : `${count} characters`];
332
+ return P.described((state) => {
333
+ if (state.inputKind === 1) state.encoding = enc;
334
+ const start = state.pos;
335
+ let pos = start;
336
+ for (let got = 0; got < count; got++) {
337
+ const cp = internal.next(enc, state, pos);
338
+ if (cp === internal.End) return state.eoi("Take", expected, count - got);
339
+ if (cp < 0) return internal.failAt(state, cp, "Take", expected, pos);
340
+ pos += internal.width;
341
+ }
342
+ state.pos = pos;
343
+ return enc.text(state.input, start, pos);
344
+ }, "take", {
345
+ _tag: "Take",
346
+ count,
347
+ encoding: enc
348
+ });
349
+ };
350
+ const takeUntil = (lit, r) => {
351
+ const [min, max] = normalize(r);
352
+ const needle = enc.encode(lit);
353
+ const unit = enc.unit;
354
+ const expected = [JSON.stringify(lit)];
355
+ return P.described((state) => {
356
+ if (state.inputKind === 1) state.encoding = enc;
357
+ const start = state.pos;
358
+ let idx = indexOf(state, needle, start);
359
+ while (unit > 1 && idx >= 0 && (idx - start) % unit !== 0) idx = indexOf(state, needle, idx + 1);
360
+ if (idx < 0) {
361
+ if (state.partial) return state.incomplete(0, expected);
362
+ return backtrack(state, "TakeUntil", expected, state.end);
363
+ }
364
+ state.syntax?.read(idx + needle.length);
365
+ const count = internal.validate(enc, state, start, idx);
366
+ if (count < 0) return backtrack(state, "TakeUntil", expected, -1 - count);
367
+ if (count < min) return backtrack(state, "TakeUntil", expected, idx);
368
+ if (count > max) return backtrack(state, "TakeUntil", expected);
369
+ state.pos = idx;
370
+ return enc.text(state.input, start, idx);
371
+ }, "takeUntil", {
372
+ _tag: "TakeUntil",
373
+ literal: lit,
374
+ min,
375
+ max,
376
+ encoding: enc
377
+ });
378
+ };
379
+ const always = () => true;
380
+ const rest = P.described((state) => {
381
+ if (state.inputKind === 1) state.encoding = enc;
382
+ const start = state.pos;
383
+ internal.scan(enc, state, always, false, Infinity, state.pos, fast);
384
+ const offset = internal.scanOffset;
385
+ if (internal.scanStop === internal.Truncated) return state.incomplete(1, expectedAny);
386
+ if (internal.scanStop === internal.Invalid) return backtrack(state, "Token", expectedAny, offset);
387
+ state.pos = offset;
388
+ return enc.text(state.input, start, offset);
389
+ }, "rest", {
390
+ _tag: "Rest",
391
+ encoding: enc
392
+ });
393
+ const taken = (self) => {
394
+ const step = self.step;
395
+ return P.described((state) => {
396
+ if (state.inputKind === 1) state.encoding = enc;
397
+ const start = state.pos;
398
+ if (step(state) === Fail) return Fail;
399
+ return textOf(state, start, state.pos, "Slice", expectedAny);
400
+ }, self.name, {
401
+ _tag: "Taken",
402
+ self,
403
+ encoding: enc
404
+ });
405
+ };
406
+ const cls = (test, min, description, kind, hint = true) => takeWhileText(test, { min }, false, `${kind.toLowerCase()}${min}`, [description], kind, hint);
407
+ const identifierStart = (cp) => cp === 95 || isIdStart(cp);
408
+ const identifier = P.described((state) => {
409
+ if (state.inputKind === 1) state.encoding = enc;
410
+ const start = state.pos;
411
+ const cp = internal.next(enc, state);
412
+ if (cp < 0) return internal.failAt(state, cp, "TakeWhile", expectedIdentifier);
413
+ if (!identifierStart(cp)) return state.backtrack("TakeWhile", expectedIdentifier);
414
+ internal.scan(enc, state, isIdContinue, false, Infinity, start + internal.width, fast);
415
+ const stop = internal.scanStop;
416
+ if (state.partial && (stop === internal.End || stop === internal.Truncated)) return state.incomplete(1, expectedIdentifier);
417
+ state.pos = internal.scanOffset;
418
+ return enc.text(state.input, start, state.pos);
419
+ }, "identifier", {
420
+ _tag: "Identifier",
421
+ encoding: enc
422
+ });
423
+ const bom = P.described((state) => {
424
+ if (state.inputKind === 1) state.encoding = enc;
425
+ const cp = internal.next(enc, state);
426
+ if (cp === 65279) {
427
+ state.pos += internal.width;
428
+ return true;
429
+ }
430
+ if (cp === internal.Truncated || cp === internal.End && state.partial) return state.incomplete(1, ["byte order mark"]);
431
+ return false;
432
+ }, "bom", {
433
+ _tag: "Bom",
434
+ encoding: enc
435
+ });
436
+ const newline = literal("\n");
437
+ const crlf = literal("\r\n");
438
+ const tillLineEnding = P.described((state) => {
439
+ if (state.inputKind === 1) state.encoding = enc;
440
+ const start = state.pos;
441
+ internal.scan(enc, state, isLineBreak, true, Infinity, state.pos, fast);
442
+ const offset = internal.scanOffset;
443
+ const stop = internal.scanStop;
444
+ if (stop === internal.Truncated || stop === internal.End && state.partial) return state.incomplete(1, expectedLineEnding);
445
+ if (stop === internal.Invalid) return backtrack(state, "LineEnding", expectedLineEnding, offset);
446
+ if (stop === 0 && internal.next(enc, state, offset) === 13) {
447
+ const cr = internal.width;
448
+ state.syntax?.read(offset + 2 * cr);
449
+ const after = internal.next(enc, state, offset + cr);
450
+ if (after === internal.End && state.partial) return state.incomplete(1, expectedLineEnding);
451
+ if (after !== 10) return backtrack(state, "LineEnding", expectedLineEnding, offset);
452
+ }
453
+ state.pos = offset;
454
+ return enc.text(state.input, start, offset);
455
+ }, "tillLineEnding", {
456
+ _tag: "TillLineEnding",
457
+ encoding: enc
458
+ });
459
+ const asciiDigits = takeWhileText(isAsciiDigit, { min: 1 }, false, "digit1", ["digit"], "Digit", true);
460
+ const hexDigits = takeWhileText(isAsciiHexDigit, { min: 1 }, false, "hexDigit1", ["hexadecimal digit"], "HexDigit", true);
461
+ const sign = P.opt(oneOfImpl("+-", false));
462
+ const signed = taken(P.seq(sign, asciiDigits));
463
+ const exponent = P.opt(P.seq(oneOfImpl("eE", false), sign, asciiDigits));
464
+ const unsignedFloat = P.alt(P.seq(caseless("inf"), P.opt(caseless("inity"))), P.seq(literal("."), asciiDigits, exponent), P.seq(asciiDigits, P.opt(P.seq(literal("."), P.opt(asciiDigits))), exponent));
465
+ const floatText$1 = floatText(taken(P.alt(caseless("nan"), P.seq(sign, unsignedFloat))).pipe(P.expected("number")));
466
+ const matchControl = (control) => {
467
+ const ctrl = control.codePointAt(0);
468
+ return (state) => {
469
+ if (internal.next(enc, state) !== ctrl) return false;
470
+ state.pos += internal.width;
471
+ return true;
472
+ };
473
+ };
474
+ return {
475
+ encoding,
476
+ any,
477
+ literal,
478
+ caseless,
479
+ oneOf: (set) => oneOfImpl(set, false),
480
+ noneOf: (set) => oneOfImpl(set, true),
481
+ bom,
482
+ take,
483
+ takeWhile: (set, r) => {
484
+ const m = compile(set, "string");
485
+ return takeWhileText(m.code, r, false, "takeWhile", [m.description], "TakeWhile", false, set);
486
+ },
487
+ takeTill: (set, r) => {
488
+ const m = compile(set, "string");
489
+ return takeWhileText(m.code, r, true, "takeTill", [`anything but ${m.description}`], "TakeWhile", false, set);
490
+ },
491
+ takeUntil,
492
+ rest,
493
+ taken,
494
+ alpha0: cls(isAlphabetic, 0, "letter", "Alpha"),
495
+ alpha1: cls(isAlphabetic, 1, "letter", "Alpha"),
496
+ digit0: cls(isDecimalDigit, 0, "digit", "Digit"),
497
+ digit1: cls(isDecimalDigit, 1, "digit", "Digit"),
498
+ alphanumeric0: cls(isAlphanumeric, 0, "letter or digit", "AlphaNumeric"),
499
+ alphanumeric1: cls(isAlphanumeric, 1, "letter or digit", "AlphaNumeric"),
500
+ space0: cls(isSpace, 0, "space", "Space", false),
501
+ space1: cls(isSpace, 1, "space", "Space", false),
502
+ multispace0: cls(isWhitespace, 0, "whitespace", "MultiSpace", false),
503
+ multispace1: cls(isWhitespace, 1, "whitespace", "MultiSpace", false),
504
+ identifier,
505
+ newline,
506
+ crlf,
507
+ tab: literal(" "),
508
+ lineEnding: P.alt(newline, crlf).pipe(P.expected("line ending")),
509
+ tillLineEnding,
510
+ decUint: asciiDigits.pipe(P.tryMap((s) => overflow(Number(s))), P.named("decUint")),
511
+ decInt: signed.pipe(P.tryMap((s) => overflow(Number(s))), P.named("decInt")),
512
+ decBigUint: asciiDigits.pipe(P.map((s) => BigInt(s))),
513
+ decBigInt: signed.pipe(P.map((s) => BigInt(s.startsWith("+") ? s.slice(1) : s))),
514
+ hexUint: hexDigits.pipe(P.tryMap((s) => overflow(parseInt(s, 16))), P.named("hexUint")),
515
+ float: floatText$1.pipe(P.map(toFloat$1), P.named("float")),
516
+ takeEscaped: (normal, control, escapable) => takeEscapedImpl(normal, matchControl(control), escapable, (state, start) => enc.text(state.input, start, state.pos), internal.firstCodePoint(control), enc),
517
+ escaped: (normal, control, escape) => escapedImpl(normal, matchControl(control), escape, internal.firstCodePoint(control), enc)
518
+ };
484
519
  };
485
520
  /**
486
- * Text parsers for JavaScript strings.
487
- *
488
- * @since 0.1.0
489
- * @category instances
490
- */
491
- export const string = make(Encodings.string);
521
+ * Text parsers for JavaScript strings.
522
+ *
523
+ * @since 0.1.0
524
+ * @category instances
525
+ */
526
+ const string = /*#__PURE__*/ make(Encodings.string);
492
527
  /**
493
- * Text parsers for UTF-8 encoded bytes.
494
- *
495
- * @example
496
- * ```ts
497
- * import { Parser, Text } from "@thomasfosterau/effect-parse"
498
- *
499
- * const bytes = new TextEncoder().encode("naïve café")
500
- * Parser.parse(Parser.separatedPair(Text.utf8.alpha1, Text.utf8.space1, Text.utf8.alpha1), bytes)
501
- * // Result.succeed(["naïve", "café"])
502
- * ```
503
- *
504
- * @since 0.1.0
505
- * @category instances
506
- */
507
- export const utf8 = make(Encodings.utf8);
528
+ * Text parsers for UTF-8 encoded bytes.
529
+ *
530
+ * @example
531
+ * ```ts
532
+ * import { Parser, Text } from "@thomasfosterau/effect-parse"
533
+ *
534
+ * const bytes = new TextEncoder().encode("naïve café")
535
+ * Parser.parse(Parser.separatedPair(Text.utf8.alpha1, Text.utf8.space1, Text.utf8.alpha1), bytes)
536
+ * // Result.succeed(["naïve", "café"])
537
+ * ```
538
+ *
539
+ * @since 0.1.0
540
+ * @category instances
541
+ */
542
+ const utf8 = /*#__PURE__*/ make(Encodings.utf8);
508
543
  /**
509
- * Text parsers for UTF-16 little endian bytes.
510
- *
511
- * @since 0.1.0
512
- * @category instances
513
- */
514
- export const utf16le = make(Encodings.utf16le);
544
+ * Text parsers for UTF-16 little endian bytes.
545
+ *
546
+ * @since 0.1.0
547
+ * @category instances
548
+ */
549
+ const utf16le = /*#__PURE__*/ make(Encodings.utf16le);
515
550
  /**
516
- * Text parsers for UTF-16 big endian bytes.
517
- *
518
- * @since 0.1.0
519
- * @category instances
520
- */
521
- export const utf16be = make(Encodings.utf16be);
551
+ * Text parsers for UTF-16 big endian bytes.
552
+ *
553
+ * @since 0.1.0
554
+ * @category instances
555
+ */
556
+ const utf16be = /*#__PURE__*/ make(Encodings.utf16be);
522
557
  /**
523
- * Text parsers for ISO-8859-1 (Latin-1) bytes.
524
- *
525
- * @since 0.1.0
526
- * @category instances
527
- */
528
- export const latin1 = make(Encodings.latin1);
558
+ * Text parsers for ISO-8859-1 (Latin-1) bytes.
559
+ *
560
+ * @since 0.1.0
561
+ * @category instances
562
+ */
563
+ const latin1 = /*#__PURE__*/ make(Encodings.latin1);
564
+ //#endregion
565
+ export { isAlphabetic, isAlphanumeric, isControl, isDecimalDigit, isIdContinue, isIdStart, isLetter, isLowercase, isNumeric, isPunctuation, isSpace, isUppercase, isWhitespace, latin1, make, property, string, utf16be, utf16le, utf8 };
566
+
529
567
  //# sourceMappingURL=Text.js.map