@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/src/Text.ts CHANGED
@@ -36,6 +36,7 @@
36
36
  *
37
37
  * @since 0.1.0
38
38
  */
39
+ import * as Predicate from "effect/Predicate"
39
40
  import type { Encoding } from "./Encoding.js"
40
41
  import * as Encodings from "./Encoding.js"
41
42
  import type { Input, State } from "./Input.js"
@@ -63,7 +64,7 @@ import type { StringTokenSet } from "./Token.js"
63
64
  */
64
65
  export type CharPredicate = (char: string | number) => boolean
65
66
 
66
- const toCodePoint = (c: string | number): number => typeof c === "number" ? c : c.codePointAt(0) ?? -1
67
+ const toCodePoint = (c: string | number): number => (Predicate.isNumber(c) ? c : (c.codePointAt(0) ?? -1))
67
68
 
68
69
  const makePredicate = (name: string, re: RegExp): CharPredicate => {
69
70
  // Results for the Basic Multilingual Plane are cached: a table lookup is
@@ -77,7 +78,7 @@ const makePredicate = (name: string, re: RegExp): CharPredicate => {
77
78
  if (x < 128) table = ascii ??= new Uint8Array(128)
78
79
  else if (x < 0x10000) table = bmp ??= new Uint8Array(0x10000)
79
80
  else return re.test(String.fromCodePoint(x))
80
- let v = table[x]!
81
+ let v = table[x]
81
82
  if (v === 0) table[x] = v = re.test(String.fromCharCode(x)) ? 2 : 1
82
83
  return v === 2
83
84
  })
@@ -108,7 +109,7 @@ export const property = (name: string): CharPredicate => makePredicate(name, new
108
109
  * @since 0.1.0
109
110
  * @category predicates
110
111
  */
111
- export const isAlphabetic: CharPredicate = makePredicate("isAlphabetic", /^\p{Alphabetic}$/u)
112
+ export const isAlphabetic: CharPredicate = /*#__PURE__*/ makePredicate("isAlphabetic", /^\p{Alphabetic}$/u)
112
113
 
113
114
  /**
114
115
  * Letters (general category `L`).
@@ -116,7 +117,7 @@ export const isAlphabetic: CharPredicate = makePredicate("isAlphabetic", /^\p{Al
116
117
  * @since 0.1.0
117
118
  * @category predicates
118
119
  */
119
- export const isLetter: CharPredicate = makePredicate("isLetter", /^\p{L}$/u)
120
+ export const isLetter: CharPredicate = /*#__PURE__*/ makePredicate("isLetter", /^\p{L}$/u)
120
121
 
121
122
  /**
122
123
  * Uppercase characters (the Unicode `Uppercase` property).
@@ -124,7 +125,7 @@ export const isLetter: CharPredicate = makePredicate("isLetter", /^\p{L}$/u)
124
125
  * @since 0.1.0
125
126
  * @category predicates
126
127
  */
127
- export const isUppercase: CharPredicate = makePredicate("isUppercase", /^\p{Uppercase}$/u)
128
+ export const isUppercase: CharPredicate = /*#__PURE__*/ makePredicate("isUppercase", /^\p{Uppercase}$/u)
128
129
 
129
130
  /**
130
131
  * Lowercase characters (the Unicode `Lowercase` property).
@@ -132,7 +133,7 @@ export const isUppercase: CharPredicate = makePredicate("isUppercase", /^\p{Uppe
132
133
  * @since 0.1.0
133
134
  * @category predicates
134
135
  */
135
- export const isLowercase: CharPredicate = makePredicate("isLowercase", /^\p{Lowercase}$/u)
136
+ export const isLowercase: CharPredicate = /*#__PURE__*/ makePredicate("isLowercase", /^\p{Lowercase}$/u)
136
137
 
137
138
  /**
138
139
  * Decimal digits of any script (general category `Nd`): `0`–`9`, `٠`–`٩`,
@@ -141,7 +142,7 @@ export const isLowercase: CharPredicate = makePredicate("isLowercase", /^\p{Lowe
141
142
  * @since 0.1.0
142
143
  * @category predicates
143
144
  */
144
- export const isDecimalDigit: CharPredicate = makePredicate("isDecimalDigit", /^\p{Nd}$/u)
145
+ export const isDecimalDigit: CharPredicate = /*#__PURE__*/ makePredicate("isDecimalDigit", /^\p{Nd}$/u)
145
146
 
146
147
  /**
147
148
  * Numeric characters (general category `N`), including `½` and `Ⅻ` (Rust's
@@ -150,7 +151,7 @@ export const isDecimalDigit: CharPredicate = makePredicate("isDecimalDigit", /^\
150
151
  * @since 0.1.0
151
152
  * @category predicates
152
153
  */
153
- export const isNumeric: CharPredicate = makePredicate("isNumeric", /^\p{N}$/u)
154
+ export const isNumeric: CharPredicate = /*#__PURE__*/ makePredicate("isNumeric", /^\p{N}$/u)
154
155
 
155
156
  /**
156
157
  * Alphabetic or numeric characters (Rust's `char::is_alphanumeric`).
@@ -158,7 +159,7 @@ export const isNumeric: CharPredicate = makePredicate("isNumeric", /^\p{N}$/u)
158
159
  * @since 0.1.0
159
160
  * @category predicates
160
161
  */
161
- export const isAlphanumeric: CharPredicate = makePredicate("isAlphanumeric", /^[\p{Alphabetic}\p{N}]$/u)
162
+ export const isAlphanumeric: CharPredicate = /*#__PURE__*/ makePredicate("isAlphanumeric", /^[\p{Alphabetic}\p{N}]$/u)
162
163
 
163
164
  /**
164
165
  * Whitespace, including line breaks (the Unicode `White_Space` property,
@@ -167,7 +168,7 @@ export const isAlphanumeric: CharPredicate = makePredicate("isAlphanumeric", /^[
167
168
  * @since 0.1.0
168
169
  * @category predicates
169
170
  */
170
- export const isWhitespace: CharPredicate = makePredicate("isWhitespace", /^\p{White_Space}$/u)
171
+ export const isWhitespace: CharPredicate = /*#__PURE__*/ makePredicate("isWhitespace", /^\p{White_Space}$/u)
171
172
 
172
173
  /**
173
174
  * Whitespace that does not break lines: `White_Space` except `\n`, `\v`,
@@ -176,7 +177,7 @@ export const isWhitespace: CharPredicate = makePredicate("isWhitespace", /^\p{Wh
176
177
  * @since 0.1.0
177
178
  * @category predicates
178
179
  */
179
- export const isSpace: CharPredicate = makePredicate(
180
+ export const isSpace: CharPredicate = /*#__PURE__*/ makePredicate(
180
181
  "isSpace",
181
182
  /^(?![\n\v\f\r\u0085\u2028\u2029])\p{White_Space}$/u
182
183
  )
@@ -188,7 +189,7 @@ export const isSpace: CharPredicate = makePredicate(
188
189
  * @since 0.1.0
189
190
  * @category predicates
190
191
  */
191
- export const isIdStart: CharPredicate = makePredicate("isIdStart", /^\p{ID_Start}$/u)
192
+ export const isIdStart: CharPredicate = /*#__PURE__*/ makePredicate("isIdStart", /^\p{ID_Start}$/u)
192
193
 
193
194
  /**
194
195
  * Characters that can continue an identifier (the Unicode `ID_Continue`
@@ -197,7 +198,7 @@ export const isIdStart: CharPredicate = makePredicate("isIdStart", /^\p{ID_Start
197
198
  * @since 0.1.0
198
199
  * @category predicates
199
200
  */
200
- export const isIdContinue: CharPredicate = makePredicate("isIdContinue", /^\p{ID_Continue}$/u)
201
+ export const isIdContinue: CharPredicate = /*#__PURE__*/ makePredicate("isIdContinue", /^\p{ID_Continue}$/u)
201
202
 
202
203
  /**
203
204
  * Punctuation (general category `P`).
@@ -205,7 +206,7 @@ export const isIdContinue: CharPredicate = makePredicate("isIdContinue", /^\p{ID
205
206
  * @since 0.1.0
206
207
  * @category predicates
207
208
  */
208
- export const isPunctuation: CharPredicate = makePredicate("isPunctuation", /^\p{P}$/u)
209
+ export const isPunctuation: CharPredicate = /*#__PURE__*/ makePredicate("isPunctuation", /^\p{P}$/u)
209
210
 
210
211
  /**
211
212
  * Control characters (general category `Cc`).
@@ -213,7 +214,7 @@ export const isPunctuation: CharPredicate = makePredicate("isPunctuation", /^\p{
213
214
  * @since 0.1.0
214
215
  * @category predicates
215
216
  */
216
- export const isControl: CharPredicate = makePredicate("isControl", /^\p{Cc}$/u)
217
+ export const isControl: CharPredicate = /*#__PURE__*/ makePredicate("isControl", /^\p{Cc}$/u)
217
218
 
218
219
  // -----------------------------------------------------------------------------
219
220
  // Parsers
@@ -354,15 +355,21 @@ export interface TextParsers<I extends string | Uint8Array> {
354
355
 
355
356
  const normalize = (r: Range | undefined): [number, number] => {
356
357
  if (r === undefined) return [0, Infinity]
357
- if (typeof r === "number") return [r, r]
358
+ if (Predicate.isNumber(r)) return [r, r]
358
359
  return [r.min ?? 0, r.max ?? Infinity]
359
360
  }
360
361
 
361
- const isAsciiDigit = codePointPredicate("isAsciiDigit", (c: number): boolean => c >= 48 && c <= 57, [[48, 57]])
362
- const isAsciiHexDigit = codePointPredicate(
362
+ const isAsciiDigit = /*#__PURE__*/ codePointPredicate("isAsciiDigit", (c: number): boolean => c >= 48 && c <= 57, [
363
+ [48, 57]
364
+ ])
365
+ const isAsciiHexDigit = /*#__PURE__*/ codePointPredicate(
363
366
  "isAsciiHexDigit",
364
367
  (c: number): boolean => (c >= 48 && c <= 57) || (c >= 65 && c <= 70) || (c >= 97 && c <= 102),
365
- [[48, 57], [65, 70], [97, 102]]
368
+ [
369
+ [48, 57],
370
+ [65, 70],
371
+ [97, 102]
372
+ ]
366
373
  )
367
374
  const isLineBreak = (c: number): boolean => c === 10 || c === 13
368
375
 
@@ -417,29 +424,38 @@ export const make = <I extends string | Uint8Array>(encoding: Encoding<I>): Text
417
424
  set: unknown = test
418
425
  ): Parser<string, never, never, I> => {
419
426
  const [min, max] = normalize(r)
420
- return P.described<string, never, never, I>((state: State<any>) => {
421
- if (state.inputKind === 1) state.encoding = enc
422
- const start = state.pos
423
- internal.scan(enc, state, test, negate, max, state.pos, fast)
424
- const offset = internal.scanOffset
425
- const count = internal.scanCount
426
- const stop = internal.scanStop
427
- if (state.partial && (stop === internal.End || stop === internal.Truncated)) return state.incomplete(1, expected)
428
- if (count < min) return backtrack(state, kind, expected, offset)
429
- // More matching characters would have been accepted where we stopped
430
- if (hint && count < max) state.setHint(offset, expected)
431
- state.pos = offset
432
- return enc.text(state.input, start, offset)
433
- }, name, { _tag: "TakeWhile", set, negate, min, max, encoding: enc })
427
+ return P.described<string, never, never, I>(
428
+ (state: State<any>) => {
429
+ if (state.inputKind === 1) state.encoding = enc
430
+ const start = state.pos
431
+ internal.scan(enc, state, test, negate, max, state.pos, fast)
432
+ const offset = internal.scanOffset
433
+ const count = internal.scanCount
434
+ const stop = internal.scanStop
435
+ if (state.partial && (stop === internal.End || stop === internal.Truncated))
436
+ return state.incomplete(1, expected)
437
+ if (count < min) return backtrack(state, kind, expected, offset)
438
+ // More matching characters would have been accepted where we stopped
439
+ if (hint && count < max) state.setHint(offset, expected)
440
+ state.pos = offset
441
+ return enc.text(state.input, start, offset)
442
+ },
443
+ name,
444
+ { _tag: "TakeWhile", set, negate, min, max, encoding: enc }
445
+ )
434
446
  }
435
447
 
436
- const any: Parser<string, never, never, I> = P.described<string, never, never, I>((state: State<any>) => {
437
- if (state.inputKind === 1) state.encoding = enc
438
- const cp = internal.next(enc, state)
439
- if (cp < 0) return internal.failAt(state, cp, "Token", expectedAny)
440
- state.pos += internal.width
441
- return internal.charOf(cp)
442
- }, "any", { _tag: "Any", encoding: enc })
448
+ const any: Parser<string, never, never, I> = P.described<string, never, never, I>(
449
+ (state: State<any>) => {
450
+ if (state.inputKind === 1) state.encoding = enc
451
+ const cp = internal.next(enc, state)
452
+ if (cp < 0) return internal.failAt(state, cp, "Token", expectedAny)
453
+ state.pos += internal.width
454
+ return internal.charOf(cp)
455
+ },
456
+ "any",
457
+ { _tag: "Any", encoding: enc }
458
+ )
443
459
 
444
460
  const literal = <const L extends string>(lit: L): Parser<L, never, never, I> => {
445
461
  const encoded = enc.encode(lit)
@@ -448,50 +464,65 @@ export const make = <I extends string | Uint8Array>(encoding: Encoding<I>): Text
448
464
  const node: Node = { _tag: "Literal", literal: lit, caseless: false, encoding: enc }
449
465
  if (len === 1) {
450
466
  // Single unit literals (punctuation, mostly) are compared directly
451
- const unit = typeof encoded === "string" ? encoded.charCodeAt(0) : encoded[0]!
452
- return P.described<L, never, never, I>((state: State<any>) => {
453
- const pos = state.pos
467
+ const unit = Predicate.isString(encoded) ? encoded.charCodeAt(0) : encoded[0]
468
+ return P.described<L, never, never, I>(
469
+ (state: State<any>) => {
470
+ const pos = state.pos
471
+ if (state.inputKind === 1) state.encoding = enc
472
+ if (pos >= state.end) return state.eoi("Literal", expected, 1)
473
+ const input = state.input
474
+ if ((state.inputKind === 0 ? (input as string).charCodeAt(pos) : (input as Uint8Array)[pos]) !== unit) {
475
+ return backtrack(state, "Literal", expected)
476
+ }
477
+ state.pos = pos + 1
478
+ return lit
479
+ },
480
+ expected[0],
481
+ node
482
+ )
483
+ }
484
+ return P.described<L, never, never, I>(
485
+ (state: State<any>) => {
454
486
  if (state.inputKind === 1) state.encoding = enc
455
- if (pos >= state.end) return state.eoi("Literal", expected, 1)
456
- const input = state.input
457
- if ((state.inputKind === 0 ? (input as string).charCodeAt(pos) : (input as Uint8Array)[pos]) !== unit) {
487
+ const r = matchLiteral(state, encoded, false)
488
+ if (r === -1) return backtrack(state, "Literal", expected)
489
+ if (r === -2) {
490
+ if (state.partial) return state.incomplete(len - (state.end - state.pos), expected)
458
491
  return backtrack(state, "Literal", expected)
459
492
  }
460
- state.pos = pos + 1
493
+ state.pos += len
461
494
  return lit
462
- }, expected[0], node)
463
- }
464
- return P.described<L, never, never, I>((state: State<any>) => {
465
- if (state.inputKind === 1) state.encoding = enc
466
- const r = matchLiteral(state, encoded, false)
467
- if (r === -1) return backtrack(state, "Literal", expected)
468
- if (r === -2) {
469
- if (state.partial) return state.incomplete(len - (state.end - state.pos), expected)
470
- return backtrack(state, "Literal", expected)
471
- }
472
- state.pos += len
473
- return lit
474
- }, expected[0], node)
495
+ },
496
+ expected[0],
497
+ node
498
+ )
475
499
  }
476
500
 
477
501
  const caseless = (lit: string): Parser<string, never, never, I> => {
478
- const folded = Array.from(lit, (c) => internal.fold(c.codePointAt(0)!))
502
+ const folded = Array.from(lit, (c) => internal.fold(internal.firstCodePoint(c)))
479
503
  const expected = [`${JSON.stringify(lit)} (case insensitive)`]
480
- return P.described<string, never, never, I>((state: State<any>) => {
481
- if (state.inputKind === 1) state.encoding = enc
482
- const start = state.pos
483
- let pos = start
484
- for (let i = 0; i < folded.length; i++) {
485
- const cp = internal.next(enc, state, pos)
486
- if (cp === internal.End || cp === internal.Truncated) {
487
- return state.partial ? state.incomplete(1, expected) : backtrack(state, "Literal", expected)
504
+ return P.described<string, never, never, I>(
505
+ (state: State<any>) => {
506
+ if (state.inputKind === 1) state.encoding = enc
507
+ const start = state.pos
508
+ let pos = start
509
+ for (let i = 0; i < folded.length; i++) {
510
+ const cp = internal.next(enc, state, pos)
511
+ if (cp === internal.End || cp === internal.Truncated) {
512
+ return state.partial ? state.incomplete(1, expected) : backtrack(state, "Literal", expected)
513
+ }
514
+ if (cp < 0 || internal.fold(cp) !== folded[i]) {
515
+ state.syntax?.read(pos + Math.max(internal.width, 1))
516
+ return backtrack(state, "Literal", expected)
517
+ }
518
+ pos += internal.width
488
519
  }
489
- if (cp < 0 || internal.fold(cp) !== folded[i]) return backtrack(state, "Literal", expected)
490
- pos += internal.width
491
- }
492
- state.pos = pos
493
- return enc.text(state.input, start, pos)
494
- }, expected[0], { _tag: "Literal", literal: lit, caseless: true, encoding: enc })
520
+ state.pos = pos
521
+ return enc.text(state.input, start, pos)
522
+ },
523
+ expected[0],
524
+ { _tag: "Literal", literal: lit, caseless: true, encoding: enc }
525
+ )
495
526
  }
496
527
 
497
528
  const oneOfImpl = (set: StringTokenSet, negate: boolean): Parser<string, never, never, I> => {
@@ -499,32 +530,40 @@ export const make = <I extends string | Uint8Array>(encoding: Encoding<I>): Text
499
530
  const test = m.code
500
531
  const expected = [negate ? `anything but ${m.description}` : m.description]
501
532
  const kind: ErrorKind = negate ? "NoneOf" : "OneOf"
502
- return P.described<string, never, never, I>((state: State<any>) => {
503
- if (state.inputKind === 1) state.encoding = enc
504
- const cp = internal.next(enc, state)
505
- if (cp < 0) return internal.failAt(state, cp, kind, expected)
506
- const w = internal.width
507
- if (test(cp) === negate) return state.backtrack(kind, expected)
508
- state.pos += w
509
- return internal.charOf(cp)
510
- }, expected[0], { _tag: "OneOf", set, negate, encoding: enc })
533
+ return P.described<string, never, never, I>(
534
+ (state: State<any>) => {
535
+ if (state.inputKind === 1) state.encoding = enc
536
+ const cp = internal.next(enc, state)
537
+ if (cp < 0) return internal.failAt(state, cp, kind, expected)
538
+ const w = internal.width
539
+ if (test(cp) === negate) return state.backtrack(kind, expected)
540
+ state.pos += w
541
+ return internal.charOf(cp)
542
+ },
543
+ expected[0],
544
+ { _tag: "OneOf", set, negate, encoding: enc }
545
+ )
511
546
  }
512
547
 
513
548
  const take = (count: number): Parser<string, never, never, I> => {
514
549
  const expected = [count === 1 ? "1 character" : `${count} characters`]
515
- return P.described<string, never, never, I>((state: State<any>) => {
516
- if (state.inputKind === 1) state.encoding = enc
517
- const start = state.pos
518
- let pos = start
519
- for (let got = 0; got < count; got++) {
520
- const cp = internal.next(enc, state, pos)
521
- if (cp === internal.End) return state.eoi("Take", expected, count - got)
522
- if (cp < 0) return internal.failAt(state, cp, "Take", expected, pos)
523
- pos += internal.width
524
- }
525
- state.pos = pos
526
- return enc.text(state.input, start, pos)
527
- }, "take", { _tag: "Take", count, encoding: enc })
550
+ return P.described<string, never, never, I>(
551
+ (state: State<any>) => {
552
+ if (state.inputKind === 1) state.encoding = enc
553
+ const start = state.pos
554
+ let pos = start
555
+ for (let got = 0; got < count; got++) {
556
+ const cp = internal.next(enc, state, pos)
557
+ if (cp === internal.End) return state.eoi("Take", expected, count - got)
558
+ if (cp < 0) return internal.failAt(state, cp, "Take", expected, pos)
559
+ pos += internal.width
560
+ }
561
+ state.pos = pos
562
+ return enc.text(state.input, start, pos)
563
+ },
564
+ "take",
565
+ { _tag: "Take", count, encoding: enc }
566
+ )
528
567
  }
529
568
 
530
569
  const takeUntil = (lit: string, r?: Range): Parser<string, never, never, I> => {
@@ -532,105 +571,142 @@ export const make = <I extends string | Uint8Array>(encoding: Encoding<I>): Text
532
571
  const needle = enc.encode(lit)
533
572
  const unit = enc.unit
534
573
  const expected = [JSON.stringify(lit)]
535
- return P.described<string, never, never, I>((state: State<any>) => {
536
- if (state.inputKind === 1) state.encoding = enc
537
- const start = state.pos
538
- let idx = indexOf(state, needle as Input, start)
539
- // Multi-unit encodings: only accept matches on a character boundary
540
- while (unit > 1 && idx >= 0 && (idx - start) % unit !== 0) idx = indexOf(state, needle as Input, idx + 1)
541
- if (idx < 0) {
542
- if (state.partial) return state.incomplete(0, expected)
543
- return backtrack(state, "TakeUntil", expected, state.end)
544
- }
545
- const count = internal.validate(enc, state, start, idx)
546
- if (count < 0) return backtrack(state, "TakeUntil", expected, -1 - count)
547
- // As in winnow, the first occurrence must lie within the range
548
- if (count < min) return backtrack(state, "TakeUntil", expected, idx)
549
- if (count > max) return backtrack(state, "TakeUntil", expected)
550
- state.pos = idx
551
- return enc.text(state.input, start, idx)
552
- }, "takeUntil", { _tag: "TakeUntil", literal: lit, min, max, encoding: enc })
574
+ return P.described<string, never, never, I>(
575
+ (state: State<any>) => {
576
+ if (state.inputKind === 1) state.encoding = enc
577
+ const start = state.pos
578
+ let idx = indexOf(state, needle as Input, start)
579
+ // Multi-unit encodings: only accept matches on a character boundary
580
+ while (unit > 1 && idx >= 0 && (idx - start) % unit !== 0) idx = indexOf(state, needle as Input, idx + 1)
581
+ if (idx < 0) {
582
+ if (state.partial) return state.incomplete(0, expected)
583
+ return backtrack(state, "TakeUntil", expected, state.end)
584
+ }
585
+ // The literal was read but is not consumed
586
+ state.syntax?.read(idx + needle.length)
587
+ const count = internal.validate(enc, state, start, idx)
588
+ if (count < 0) return backtrack(state, "TakeUntil", expected, -1 - count)
589
+ // As in winnow, the first occurrence must lie within the range
590
+ if (count < min) return backtrack(state, "TakeUntil", expected, idx)
591
+ if (count > max) return backtrack(state, "TakeUntil", expected)
592
+ state.pos = idx
593
+ return enc.text(state.input, start, idx)
594
+ },
595
+ "takeUntil",
596
+ { _tag: "TakeUntil", literal: lit, min, max, encoding: enc }
597
+ )
553
598
  }
554
599
 
555
600
  const always = () => true
556
- const rest: Parser<string, never, never, I> = P.described<string, never, never, I>((state: State<any>) => {
557
- if (state.inputKind === 1) state.encoding = enc
558
- const start = state.pos
559
- internal.scan(enc, state, always, false, Infinity, state.pos, fast)
560
- const offset = internal.scanOffset
561
- if (internal.scanStop === internal.Truncated) return state.incomplete(1, expectedAny)
562
- if (internal.scanStop === internal.Invalid) return backtrack(state, "Token", expectedAny, offset)
563
- state.pos = offset
564
- return enc.text(state.input, start, offset)
565
- }, "rest", { _tag: "Rest", encoding: enc })
601
+ const rest: Parser<string, never, never, I> = P.described<string, never, never, I>(
602
+ (state: State<any>) => {
603
+ if (state.inputKind === 1) state.encoding = enc
604
+ const start = state.pos
605
+ internal.scan(enc, state, always, false, Infinity, state.pos, fast)
606
+ const offset = internal.scanOffset
607
+ if (internal.scanStop === internal.Truncated) return state.incomplete(1, expectedAny)
608
+ if (internal.scanStop === internal.Invalid) return backtrack(state, "Token", expectedAny, offset)
609
+ state.pos = offset
610
+ return enc.text(state.input, start, offset)
611
+ },
612
+ "rest",
613
+ { _tag: "Rest", encoding: enc }
614
+ )
566
615
 
567
616
  const taken = <A, E, R>(self: Parser<A, E, R, I>): Parser<string, E, R, I> => {
568
617
  const step = self.step
569
- return P.described<string, E, R, I>((state: State<any>) => {
570
- if (state.inputKind === 1) state.encoding = enc
571
- const start = state.pos
572
- if (step(state) === Fail) return Fail
573
- return textOf(state, start, state.pos, "Slice", expectedAny)
574
- }, self.name, { _tag: "Taken", self, encoding: enc })
618
+ return P.described<string, E, R, I>(
619
+ (state: State<any>) => {
620
+ if (state.inputKind === 1) state.encoding = enc
621
+ const start = state.pos
622
+ if (step(state) === Fail) return Fail
623
+ return textOf(state, start, state.pos, "Slice", expectedAny)
624
+ },
625
+ self.name,
626
+ { _tag: "Taken", self, encoding: enc }
627
+ )
575
628
  }
576
629
 
577
630
  const cls = (test: CharPredicate, min: 0 | 1, description: string, kind: ErrorKind, hint = true) =>
578
631
  takeWhileText(test as any, { min }, false, `${kind.toLowerCase()}${min}`, [description], kind, hint)
579
632
 
580
633
  const identifierStart = (cp: number) => cp === 95 || isIdStart(cp)
581
- const identifier: Parser<string, never, never, I> = P.described<string, never, never, I>((state: State<any>) => {
582
- if (state.inputKind === 1) state.encoding = enc
583
- const start = state.pos
584
- const cp = internal.next(enc, state)
585
- if (cp < 0) return internal.failAt(state, cp, "TakeWhile", expectedIdentifier)
586
- if (!identifierStart(cp)) return state.backtrack("TakeWhile", expectedIdentifier)
587
- internal.scan(enc, state, isIdContinue as any, false, Infinity, start + internal.width, fast)
588
- const stop = internal.scanStop
589
- if (state.partial && (stop === internal.End || stop === internal.Truncated)) {
590
- return state.incomplete(1, expectedIdentifier)
591
- }
592
- state.pos = internal.scanOffset
593
- return enc.text(state.input, start, state.pos)
594
- }, "identifier", { _tag: "Identifier", encoding: enc })
634
+ const identifier: Parser<string, never, never, I> = P.described<string, never, never, I>(
635
+ (state: State<any>) => {
636
+ if (state.inputKind === 1) state.encoding = enc
637
+ const start = state.pos
638
+ const cp = internal.next(enc, state)
639
+ if (cp < 0) return internal.failAt(state, cp, "TakeWhile", expectedIdentifier)
640
+ if (!identifierStart(cp)) return state.backtrack("TakeWhile", expectedIdentifier)
641
+ internal.scan(enc, state, isIdContinue as any, false, Infinity, start + internal.width, fast)
642
+ const stop = internal.scanStop
643
+ if (state.partial && (stop === internal.End || stop === internal.Truncated)) {
644
+ return state.incomplete(1, expectedIdentifier)
645
+ }
646
+ state.pos = internal.scanOffset
647
+ return enc.text(state.input, start, state.pos)
648
+ },
649
+ "identifier",
650
+ { _tag: "Identifier", encoding: enc }
651
+ )
595
652
 
596
653
  // Decoded rather than matched as a literal, as not every encoding can encode it
597
- const bom: Parser<boolean, never, never, I> = P.described<boolean, never, never, I>((state: State<any>) => {
598
- if (state.inputKind === 1) state.encoding = enc
599
- const cp = internal.next(enc, state)
600
- if (cp === 0xfeff) {
601
- state.pos += internal.width
602
- return true
603
- }
604
- if (cp === internal.Truncated || (cp === internal.End && state.partial)) {
605
- return state.incomplete(1, ["byte order mark"])
606
- }
607
- return false
608
- }, "bom", { _tag: "Bom", encoding: enc })
654
+ const bom: Parser<boolean, never, never, I> = P.described<boolean, never, never, I>(
655
+ (state: State<any>) => {
656
+ if (state.inputKind === 1) state.encoding = enc
657
+ const cp = internal.next(enc, state)
658
+ if (cp === 0xfeff) {
659
+ state.pos += internal.width
660
+ return true
661
+ }
662
+ if (cp === internal.Truncated || (cp === internal.End && state.partial)) {
663
+ return state.incomplete(1, ["byte order mark"])
664
+ }
665
+ return false
666
+ },
667
+ "bom",
668
+ { _tag: "Bom", encoding: enc }
669
+ )
609
670
 
610
671
  const newline = literal("\n")
611
672
  const crlf = literal("\r\n")
612
673
 
613
- const tillLineEnding: Parser<string, never, never, I> = P.described<string, never, never, I>((state: State<any>) => {
614
- if (state.inputKind === 1) state.encoding = enc
615
- const start = state.pos
616
- internal.scan(enc, state, isLineBreak, true, Infinity, state.pos, fast)
617
- const offset = internal.scanOffset
618
- const stop = internal.scanStop
619
- if (stop === internal.Truncated || (stop === internal.End && state.partial)) {
620
- return state.incomplete(1, expectedLineEnding)
621
- }
622
- if (stop === internal.Invalid) return backtrack(state, "LineEnding", expectedLineEnding, offset)
623
- if (stop === 0 && internal.next(enc, state, offset) === 13) {
624
- const after = internal.next(enc, state, offset + internal.width)
625
- if (after === internal.End && state.partial) return state.incomplete(1, expectedLineEnding)
626
- if (after !== 10) return backtrack(state, "LineEnding", expectedLineEnding, offset)
627
- }
628
- state.pos = offset
629
- return enc.text(state.input, start, offset)
630
- }, "tillLineEnding", { _tag: "TillLineEnding", encoding: enc })
674
+ const tillLineEnding: Parser<string, never, never, I> = P.described<string, never, never, I>(
675
+ (state: State<any>) => {
676
+ if (state.inputKind === 1) state.encoding = enc
677
+ const start = state.pos
678
+ internal.scan(enc, state, isLineBreak, true, Infinity, state.pos, fast)
679
+ const offset = internal.scanOffset
680
+ const stop = internal.scanStop
681
+ if (stop === internal.Truncated || (stop === internal.End && state.partial)) {
682
+ return state.incomplete(1, expectedLineEnding)
683
+ }
684
+ if (stop === internal.Invalid) return backtrack(state, "LineEnding", expectedLineEnding, offset)
685
+ if (stop === 0 && internal.next(enc, state, offset) === 13) {
686
+ const cr = internal.width
687
+ // The line feed after it is read, not consumed
688
+ state.syntax?.read(offset + 2 * cr)
689
+ const after = internal.next(enc, state, offset + cr)
690
+ if (after === internal.End && state.partial) return state.incomplete(1, expectedLineEnding)
691
+ if (after !== 10) return backtrack(state, "LineEnding", expectedLineEnding, offset)
692
+ }
693
+ state.pos = offset
694
+ return enc.text(state.input, start, offset)
695
+ },
696
+ "tillLineEnding",
697
+ { _tag: "TillLineEnding", encoding: enc }
698
+ )
631
699
 
632
700
  const asciiDigits = takeWhileText(isAsciiDigit, { min: 1 }, false, "digit1", ["digit"], "Digit", true)
633
- const hexDigits = takeWhileText(isAsciiHexDigit, { min: 1 }, false, "hexDigit1", ["hexadecimal digit"], "HexDigit", true)
701
+ const hexDigits = takeWhileText(
702
+ isAsciiHexDigit,
703
+ { min: 1 },
704
+ false,
705
+ "hexDigit1",
706
+ ["hexadecimal digit"],
707
+ "HexDigit",
708
+ true
709
+ )
634
710
  const sign = P.opt(oneOfImpl("+-", false))
635
711
  const signed = taken(P.seq(sign, asciiDigits))
636
712
 
@@ -643,7 +719,7 @@ export const make = <I extends string | Uint8Array>(encoding: Encoding<I>): Text
643
719
  const floatText = markFloatText(taken(P.alt(caseless("nan"), P.seq(sign, unsignedFloat))).pipe(P.expected("number")))
644
720
 
645
721
  const matchControl = (control: string) => {
646
- const ctrl = control.codePointAt(0)!
722
+ const ctrl = control.codePointAt(0)
647
723
  return (state: State<any>): boolean => {
648
724
  if (internal.next(enc, state) !== ctrl) return false
649
725
  state.pos += internal.width
@@ -687,11 +763,20 @@ export const make = <I extends string | Uint8Array>(encoding: Encoding<I>): Text
687
763
  tab: literal("\t"),
688
764
  lineEnding: P.alt(newline, crlf).pipe(P.expected("line ending")),
689
765
  tillLineEnding,
690
- decUint: asciiDigits.pipe(P.tryMap((s) => overflow(Number(s))), P.named("decUint")),
691
- decInt: signed.pipe(P.tryMap((s) => overflow(Number(s))), P.named("decInt")),
766
+ decUint: asciiDigits.pipe(
767
+ P.tryMap((s) => overflow(Number(s))),
768
+ P.named("decUint")
769
+ ),
770
+ decInt: signed.pipe(
771
+ P.tryMap((s) => overflow(Number(s))),
772
+ P.named("decInt")
773
+ ),
692
774
  decBigUint: asciiDigits.pipe(P.map((s) => BigInt(s))),
693
775
  decBigInt: signed.pipe(P.map((s) => BigInt(s.startsWith("+") ? s.slice(1) : s))),
694
- hexUint: hexDigits.pipe(P.tryMap((s) => overflow(parseInt(s, 16))), P.named("hexUint")),
776
+ hexUint: hexDigits.pipe(
777
+ P.tryMap((s) => overflow(parseInt(s, 16))),
778
+ P.named("hexUint")
779
+ ),
695
780
  float: floatText.pipe(P.map(toFloat), P.named("float")),
696
781
  takeEscaped: (normal, control, escapable) =>
697
782
  takeEscapedImpl(
@@ -699,11 +784,11 @@ export const make = <I extends string | Uint8Array>(encoding: Encoding<I>): Text
699
784
  matchControl(control),
700
785
  escapable,
701
786
  (state, start) => enc.text(state.input, start, state.pos),
702
- control.codePointAt(0)!,
787
+ internal.firstCodePoint(control),
703
788
  enc
704
789
  ),
705
790
  escaped: (normal, control, escape) =>
706
- escapedImpl(normal, matchControl(control), escape, control.codePointAt(0)!, enc)
791
+ escapedImpl(normal, matchControl(control), escape, internal.firstCodePoint(control), enc)
707
792
  }
708
793
  }
709
794
 
@@ -713,7 +798,7 @@ export const make = <I extends string | Uint8Array>(encoding: Encoding<I>): Text
713
798
  * @since 0.1.0
714
799
  * @category instances
715
800
  */
716
- export const string: TextParsers<string> = make(Encodings.string)
801
+ export const string: TextParsers<string> = /*#__PURE__*/ make(Encodings.string)
717
802
 
718
803
  /**
719
804
  * Text parsers for UTF-8 encoded bytes.
@@ -730,7 +815,7 @@ export const string: TextParsers<string> = make(Encodings.string)
730
815
  * @since 0.1.0
731
816
  * @category instances
732
817
  */
733
- export const utf8: TextParsers<Uint8Array> = make(Encodings.utf8)
818
+ export const utf8: TextParsers<Uint8Array> = /*#__PURE__*/ make(Encodings.utf8)
734
819
 
735
820
  /**
736
821
  * Text parsers for UTF-16 little endian bytes.
@@ -738,7 +823,7 @@ export const utf8: TextParsers<Uint8Array> = make(Encodings.utf8)
738
823
  * @since 0.1.0
739
824
  * @category instances
740
825
  */
741
- export const utf16le: TextParsers<Uint8Array> = make(Encodings.utf16le)
826
+ export const utf16le: TextParsers<Uint8Array> = /*#__PURE__*/ make(Encodings.utf16le)
742
827
 
743
828
  /**
744
829
  * Text parsers for UTF-16 big endian bytes.
@@ -746,7 +831,7 @@ export const utf16le: TextParsers<Uint8Array> = make(Encodings.utf16le)
746
831
  * @since 0.1.0
747
832
  * @category instances
748
833
  */
749
- export const utf16be: TextParsers<Uint8Array> = make(Encodings.utf16be)
834
+ export const utf16be: TextParsers<Uint8Array> = /*#__PURE__*/ make(Encodings.utf16be)
750
835
 
751
836
  /**
752
837
  * Text parsers for ISO-8859-1 (Latin-1) bytes.
@@ -754,4 +839,4 @@ export const utf16be: TextParsers<Uint8Array> = make(Encodings.utf16be)
754
839
  * @since 0.1.0
755
840
  * @category instances
756
841
  */
757
- export const latin1: TextParsers<Uint8Array> = make(Encodings.latin1)
842
+ export const latin1: TextParsers<Uint8Array> = /*#__PURE__*/ make(Encodings.latin1)