@thomasfosterau/effect-parse 0.4.1 → 0.6.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 (157) hide show
  1. package/CHANGELOG.md +202 -0
  2. package/README.md +56 -14
  3. package/dist/Ascii.d.ts +11 -4
  4. package/dist/Ascii.d.ts.map +1 -1
  5. package/dist/Ascii.js +12 -4
  6. package/dist/Ascii.js.map +1 -1
  7. package/dist/Binary.d.ts +5 -2
  8. package/dist/Binary.d.ts.map +1 -1
  9. package/dist/Binary.js +83 -37
  10. package/dist/Binary.js.map +1 -1
  11. package/dist/Bits.d.ts.map +1 -1
  12. package/dist/Bits.js +11 -4
  13. package/dist/Bits.js.map +1 -1
  14. package/dist/Compiler.d.ts +74 -2
  15. package/dist/Compiler.d.ts.map +1 -1
  16. package/dist/Compiler.js +78 -1
  17. package/dist/Compiler.js.map +1 -1
  18. package/dist/Expression.d.ts.map +1 -1
  19. package/dist/Expression.js +86 -74
  20. package/dist/Expression.js.map +1 -1
  21. package/dist/Input.d.ts +56 -5
  22. package/dist/Input.d.ts.map +1 -1
  23. package/dist/Input.js +70 -1
  24. package/dist/Input.js.map +1 -1
  25. package/dist/Nom.d.ts +5 -15
  26. package/dist/Nom.d.ts.map +1 -1
  27. package/dist/Nom.js.map +1 -1
  28. package/dist/ParseError.d.ts +69 -11
  29. package/dist/ParseError.d.ts.map +1 -1
  30. package/dist/ParseError.js +129 -28
  31. package/dist/ParseError.js.map +1 -1
  32. package/dist/Parser.d.ts +375 -29
  33. package/dist/Parser.d.ts.map +1 -1
  34. package/dist/Parser.js +394 -37
  35. package/dist/Parser.js.map +1 -1
  36. package/dist/ParserSchema.d.ts.map +1 -1
  37. package/dist/ParserSchema.js +2 -3
  38. package/dist/ParserSchema.js.map +1 -1
  39. package/dist/ParserStream.d.ts +122 -14
  40. package/dist/ParserStream.d.ts.map +1 -1
  41. package/dist/ParserStream.js +293 -62
  42. package/dist/ParserStream.js.map +1 -1
  43. package/dist/Syntax.d.ts +23 -5
  44. package/dist/Syntax.d.ts.map +1 -1
  45. package/dist/Syntax.js +1 -1
  46. package/dist/Syntax.js.map +1 -1
  47. package/dist/Text.d.ts.map +1 -1
  48. package/dist/Text.js +21 -15
  49. package/dist/Text.js.map +1 -1
  50. package/dist/Token.d.ts +65 -11
  51. package/dist/Token.d.ts.map +1 -1
  52. package/dist/Token.js +73 -26
  53. package/dist/Token.js.map +1 -1
  54. package/dist/internal/compiler/closure.d.ts +1 -1
  55. package/dist/internal/compiler/closure.d.ts.map +1 -1
  56. package/dist/internal/compiler/closure.js +263 -113
  57. package/dist/internal/compiler/closure.js.map +1 -1
  58. package/dist/internal/compiler/entries.d.ts +3 -1
  59. package/dist/internal/compiler/entries.d.ts.map +1 -1
  60. package/dist/internal/compiler/entries.js +3 -2
  61. package/dist/internal/compiler/entries.js.map +1 -1
  62. package/dist/internal/compiler/first.d.ts.map +1 -1
  63. package/dist/internal/compiler/first.js +9 -2
  64. package/dist/internal/compiler/first.js.map +1 -1
  65. package/dist/internal/compiler/graph.d.ts +39 -0
  66. package/dist/internal/compiler/graph.d.ts.map +1 -0
  67. package/dist/internal/compiler/graph.js +78 -0
  68. package/dist/internal/compiler/graph.js.map +1 -0
  69. package/dist/internal/compiler/jit.d.ts +5 -0
  70. package/dist/internal/compiler/jit.d.ts.map +1 -1
  71. package/dist/internal/compiler/jit.js +208 -106
  72. package/dist/internal/compiler/jit.js.map +1 -1
  73. package/dist/internal/compiler/registry.d.ts +11 -3
  74. package/dist/internal/compiler/registry.d.ts.map +1 -1
  75. package/dist/internal/compiler/registry.js.map +1 -1
  76. package/dist/internal/compiler/search.d.ts +32 -0
  77. package/dist/internal/compiler/search.d.ts.map +1 -0
  78. package/dist/internal/compiler/search.js +68 -0
  79. package/dist/internal/compiler/search.js.map +1 -0
  80. package/dist/internal/compiler/sets.d.ts.map +1 -1
  81. package/dist/internal/compiler/sets.js +1 -1
  82. package/dist/internal/compiler/sets.js.map +1 -1
  83. package/dist/internal/compiler/wasm.d.ts +8 -0
  84. package/dist/internal/compiler/wasm.d.ts.map +1 -0
  85. package/dist/internal/compiler/wasm.js +2840 -0
  86. package/dist/internal/compiler/wasm.js.map +1 -0
  87. package/dist/internal/compiler/wasmAsm.d.ts +199 -0
  88. package/dist/internal/compiler/wasmAsm.d.ts.map +1 -0
  89. package/dist/internal/compiler/wasmAsm.js +427 -0
  90. package/dist/internal/compiler/wasmAsm.js.map +1 -0
  91. package/dist/internal/entries.d.ts +3 -1
  92. package/dist/internal/entries.d.ts.map +1 -1
  93. package/dist/internal/entries.js.map +1 -1
  94. package/dist/internal/node.d.ts +77 -3
  95. package/dist/internal/node.d.ts.map +1 -1
  96. package/dist/internal/node.js +54 -10
  97. package/dist/internal/node.js.map +1 -1
  98. package/dist/internal/numbers.d.ts.map +1 -1
  99. package/dist/internal/numbers.js.map +1 -1
  100. package/dist/internal/run.d.ts +14 -0
  101. package/dist/internal/run.d.ts.map +1 -1
  102. package/dist/internal/run.js +53 -11
  103. package/dist/internal/run.js.map +1 -1
  104. package/dist/internal/stack.d.ts +14 -0
  105. package/dist/internal/stack.d.ts.map +1 -1
  106. package/dist/internal/stack.js +24 -2
  107. package/dist/internal/stack.js.map +1 -1
  108. package/dist/internal/syntax.d.ts +4 -4
  109. package/dist/internal/syntax.d.ts.map +1 -1
  110. package/dist/internal/syntax.js +18 -10
  111. package/dist/internal/syntax.js.map +1 -1
  112. package/dist/internal/text.d.ts +32 -0
  113. package/dist/internal/text.d.ts.map +1 -1
  114. package/dist/internal/text.js +68 -14
  115. package/dist/internal/text.js.map +1 -1
  116. package/dist/internal/tokens.d.ts +20 -0
  117. package/dist/internal/tokens.d.ts.map +1 -1
  118. package/dist/internal/tokens.js +72 -39
  119. package/dist/internal/tokens.js.map +1 -1
  120. package/dist/internal/tuple.d.ts +6 -0
  121. package/dist/internal/tuple.d.ts.map +1 -0
  122. package/dist/internal/tuple.js +170 -0
  123. package/dist/internal/tuple.js.map +1 -0
  124. package/package.json +18 -10
  125. package/src/Ascii.ts +47 -12
  126. package/src/Binary.ts +174 -73
  127. package/src/Bits.ts +16 -6
  128. package/src/Compiler.ts +101 -10
  129. package/src/Expression.ts +94 -81
  130. package/src/Input.ts +99 -7
  131. package/src/Nom.ts +15 -5
  132. package/src/ParseError.ts +209 -52
  133. package/src/Parser.ts +684 -143
  134. package/src/ParserSchema.ts +1 -2
  135. package/src/ParserStream.ts +361 -68
  136. package/src/Syntax.ts +60 -36
  137. package/src/Text.ts +32 -27
  138. package/src/Token.ts +152 -34
  139. package/src/internal/compiler/closure.ts +371 -153
  140. package/src/internal/compiler/entries.ts +4 -2
  141. package/src/internal/compiler/first.ts +16 -0
  142. package/src/internal/compiler/graph.ts +96 -0
  143. package/src/internal/compiler/jit.ts +319 -169
  144. package/src/internal/compiler/registry.ts +10 -2
  145. package/src/internal/compiler/search.ts +68 -0
  146. package/src/internal/compiler/sets.ts +7 -3
  147. package/src/internal/compiler/wasm.ts +3276 -0
  148. package/src/internal/compiler/wasmAsm.ts +484 -0
  149. package/src/internal/entries.ts +8 -2
  150. package/src/internal/node.ts +103 -7
  151. package/src/internal/numbers.ts +3 -1
  152. package/src/internal/run.ts +73 -12
  153. package/src/internal/stack.ts +25 -1
  154. package/src/internal/syntax.ts +39 -18
  155. package/src/internal/text.ts +97 -9
  156. package/src/internal/tokens.ts +106 -14
  157. package/src/internal/tuple.ts +141 -0
package/src/Token.ts CHANGED
@@ -30,6 +30,7 @@ import {
30
30
  describeLiteral,
31
31
  End,
32
32
  indexOf,
33
+ indexOfAny,
33
34
  matchLiteral,
34
35
  nextIf,
35
36
  NoMatch,
@@ -37,7 +38,7 @@ import {
37
38
  splitSurrogate
38
39
  } from "./internal/tokens.js"
39
40
  import type { ErrorKind } from "./ParseError.js"
40
- import { bounds } from "./internal/node.js"
41
+ import { bounds, checkCount } from "./internal/node.js"
41
42
  import type { Parser, Range } from "./Parser.js"
42
43
  import { described } from "./Parser.js"
43
44
 
@@ -116,12 +117,13 @@ export const codePoints = (
116
117
  predicate: (codePoint: number) => boolean,
117
118
  ranges?: ReadonlyArray<readonly [number, number]>
118
119
  ): CodePoints =>
119
- // Wrapped, so the caller's function is left unmarked
120
+ // Wrapped, so the caller's function is left unmarked.
121
+ // SAFETY: `CodePointsBrand` is a declared, phantom key, so the marked function is all a `CodePoints` is at runtime
120
122
  codePointPredicate(
121
123
  name,
122
124
  (c: number): boolean => predicate(c),
123
125
  ranges?.map(([from, to]) => [from, to] as const)
124
- ) as unknown as CodePoints
126
+ ) as CodePoints
125
127
 
126
128
  /**
127
129
  * A set of string tokens: the characters of a string, a range, a predicate,
@@ -177,6 +179,7 @@ const anyStep = (state: State<Input>): unknown => {
177
179
  if (pos >= state.end) return state.eoi("Token", expectedAny, 1)
178
180
  switch (state.inputKind) {
179
181
  case 0: {
182
+ // SAFETY: `inputKind` 0 is set only for a string input
180
183
  const s = state.input as string
181
184
  if (splitSurrogate(state, pos)) return state.incomplete(1, expectedAny)
182
185
  const c = s.charCodeAt(pos)
@@ -189,13 +192,21 @@ const anyStep = (state: State<Input>): unknown => {
189
192
  }
190
193
  case 1:
191
194
  state.pos = pos + 1
195
+ // SAFETY: `inputKind` 1 is set only for a `Uint8Array` input
192
196
  return (state.input as Uint8Array)[pos]
193
197
  default:
194
198
  state.pos = pos + 1
199
+ // SAFETY: `inputKind` 2 is set for every input that is neither a string nor a `Uint8Array`, an array
195
200
  return (state.input as ReadonlyArray<unknown>)[pos]
196
201
  }
197
202
  }
198
203
 
204
+ /** The parser behind `any` and `anyToken`, on every input kind. */
205
+ const anyInput: Parser<unknown, never, never, Input> = /*#__PURE__*/ described(anyStep, "any", {
206
+ _tag: "Any",
207
+ encoding: undefined
208
+ })
209
+
199
210
  /**
200
211
  * Matches any single token: a character of a string (winnow's `any`, nom's
201
212
  * `anychar`).
@@ -203,7 +214,9 @@ const anyStep = (state: State<Input>): unknown => {
203
214
  * @since 0.1.0
204
215
  * @category tokens
205
216
  */
206
- export const any: Parser<string> = /*#__PURE__*/ described(anyStep as any, "any", { _tag: "Any", encoding: undefined })
217
+ export const any: Parser<string> =
218
+ // SAFETY: on string input, `anyStep` returns the character (one or two code units) at the position, a string
219
+ anyInput as Parser<string>
207
220
 
208
221
  /**
209
222
  * Matches any single token of an input of type `I`.
@@ -219,7 +232,21 @@ export const any: Parser<string> = /*#__PURE__*/ described(anyStep as any, "any"
219
232
  * @since 0.1.0
220
233
  * @category tokens
221
234
  */
222
- export const anyToken = <I extends Input = string>(): Parser<Token<NoInfer<I>>, never, never, NoInfer<I>> => any as any
235
+ export const anyToken = <I extends Input = string>(): Parser<Token<NoInfer<I>>, never, never, NoInfer<I>> =>
236
+ // SAFETY: `anyStep` handles every input kind, returning the token at the position (a character, byte or element)
237
+ anyInput as Parser<Token<NoInfer<I>>, never, never, NoInfer<I>>
238
+
239
+ /**
240
+ * The overloads of {@link literal}.
241
+ *
242
+ * @since 0.5.0
243
+ * @category tokens
244
+ */
245
+ export interface LiteralFn {
246
+ <const L extends string>(literal: L): Parser<L, never, never, string>
247
+ (literal: Uint8Array): Parser<Uint8Array, never, never, Uint8Array>
248
+ <const T>(literal: ReadonlyArray<T>): Parser<ReadonlyArray<T>, never, never, ReadonlyArray<T>>
249
+ }
223
250
 
224
251
  /**
225
252
  * Matches a literal sequence of tokens (winnow's `literal`, nom's `tag`).
@@ -237,11 +264,7 @@ export const anyToken = <I extends Input = string>(): Parser<Token<NoInfer<I>>,
237
264
  * @since 0.1.0
238
265
  * @category tokens
239
266
  */
240
- export const literal: {
241
- <const L extends string>(literal: L): Parser<L, never, never, string>
242
- (literal: Uint8Array): Parser<Uint8Array, never, never, Uint8Array>
243
- <const T>(literal: ReadonlyArray<T>): Parser<ReadonlyArray<T>, never, never, ReadonlyArray<T>>
244
- } = (lit: Input): Parser<any, never, never, any> => literalImpl(lit, false)
267
+ export const literal: LiteralFn = (lit: Input): Parser<any, never, never, any> => literalImpl(lit, false)
245
268
 
246
269
  /** @internal */
247
270
  export const literalImpl = (lit: Input, caseless: boolean): Parser<any, never, never, any> => {
@@ -253,6 +276,7 @@ export const literalImpl = (lit: Input, caseless: boolean): Parser<any, never, n
253
276
  return described(
254
277
  (state: State<Input>) => {
255
278
  const pos = state.pos
279
+ // SAFETY: `literalKind` 0 is set only for a string literal
256
280
  const l = literalKind === 0 && state.inputKind === 1 ? (asBytes ??= new TextEncoder().encode(lit as string)) : lit
257
281
  const len = l.length
258
282
  const r = matchLiteral(state, l, caseless)
@@ -295,6 +319,7 @@ export const oneOf = <I extends Input = string>(
295
319
  const t = nextIf(state, m, false)
296
320
  if (t === End) return state.eoi("OneOf", expected, 1)
297
321
  if (t === NoMatch) return state.backtrack("OneOf", expected)
322
+ // SAFETY: past `End` and `NoMatch`, `nextIf` returns the token it consumed from the parser's input `I`
298
323
  return t as Token<I>
299
324
  },
300
325
  m.description,
@@ -319,6 +344,7 @@ export const noneOf = <I extends Input = string>(
319
344
  const t = nextIf(state, m, true)
320
345
  if (t === End) return state.eoi("NoneOf", expected, 1)
321
346
  if (t === NoMatch) return state.backtrack("NoneOf", expected)
347
+ // SAFETY: past `End` and `NoMatch`, `nextIf` returns the token it consumed from the parser's input `I`
322
348
  return t as Token<I>
323
349
  },
324
350
  expected[0],
@@ -327,12 +353,22 @@ export const noneOf = <I extends Input = string>(
327
353
  }
328
354
 
329
355
  /**
330
- * Takes exactly `count` tokens (winnow's and nom's `take`).
356
+ * Takes exactly `count` tokens (winnow's and nom's `take`). `count` must be
357
+ * a non-negative integer: anything else throws a `RangeError` here, when
358
+ * the parser is built.
359
+ *
360
+ * @example
361
+ * ```ts
362
+ * import { Parser, Token } from "@thomasfosterau/effect-parse"
363
+ *
364
+ * Parser.parsePeek(Token.take(2), "abc") // Result.succeed(["c", "ab"])
365
+ * ```
331
366
  *
332
367
  * @since 0.1.0
333
368
  * @category slices
334
369
  */
335
370
  export const take = <I extends Input = string>(count: number): Parser<Slice<NoInfer<I>>, never, never, NoInfer<I>> => {
371
+ checkCount(count)
336
372
  const expected = [count === 1 ? "1 token" : `${count} tokens`]
337
373
  return described(
338
374
  (state) => {
@@ -348,9 +384,8 @@ export const take = <I extends Input = string>(count: number): Parser<Slice<NoIn
348
384
  }
349
385
 
350
386
  const normalize = (r: Range | undefined): [number, number] => {
351
- if (r === undefined) return [0, Infinity]
352
- if (Predicate.isNumber(r)) return [r, r]
353
- return [r.min ?? 0, r.max ?? Infinity]
387
+ const { max, min } = bounds(r)
388
+ return [min, max]
354
389
  }
355
390
 
356
391
  /** @internal */
@@ -418,6 +453,18 @@ export const takeTill = <I extends Input = string>(
418
453
  range?: Range
419
454
  ): Parser<Slice<NoInfer<I>>, never, never, NoInfer<I>> => takeWhileImpl(set, range, true, "takeTill")
420
455
 
456
+ /**
457
+ * The overloads of {@link takeUntil}.
458
+ *
459
+ * @since 0.5.0
460
+ * @category slices
461
+ */
462
+ export interface TakeUntilFn {
463
+ (literal: string, range?: Range): Parser<string, never, never, string>
464
+ (literal: Uint8Array, range?: Range): Parser<Uint8Array, never, never, Uint8Array>
465
+ <T>(literal: ReadonlyArray<T>, range?: Range): Parser<ReadonlyArray<T>, never, never, ReadonlyArray<T>>
466
+ }
467
+
421
468
  /**
422
469
  * Takes tokens up to (not including) the first occurrence of a literal
423
470
  * (winnow's `take_until`, nom's `take_until`). The literal is not
@@ -426,25 +473,40 @@ export const takeTill = <I extends Input = string>(
426
473
  * @since 0.1.0
427
474
  * @category slices
428
475
  */
429
- export const takeUntil: {
430
- (literal: string, range?: Range): Parser<string, never, never, string>
431
- (literal: Uint8Array, range?: Range): Parser<Uint8Array, never, never, Uint8Array>
432
- <T>(literal: ReadonlyArray<T>, range?: Range): Parser<ReadonlyArray<T>, never, never, ReadonlyArray<T>>
433
- } = (lit: Input, r?: Range): Parser<any, never, never, any> => {
476
+ export const takeUntil: TakeUntilFn = (lit: Input, r?: Range): Parser<any, never, never, any> =>
477
+ untilParser(
478
+ (state, from) => indexOf(state, lit, from),
479
+ // A string literal is up to three bytes per unit of UTF-8
480
+ (state) => lit.length * (Predicate.isString(lit) && state.inputKind === 1 ? 3 : 1),
481
+ [describeLiteral(lit)],
482
+ r,
483
+ "takeUntil",
484
+ { _tag: "TakeUntil", literal: lit, ...bounds(r), encoding: undefined }
485
+ )
486
+
487
+ /**
488
+ * The parser of `takeUntil` and `takeUntilAny`: `search` finds the first
489
+ * occurrence, which is not consumed (`read` is how far past it the search
490
+ * read). As in winnow, the first occurrence must lie within the range.
491
+ */
492
+ const untilParser = (
493
+ search: (state: State<Input>, from: number) => number,
494
+ read: (state: State<Input>) => number,
495
+ expected: ReadonlyArray<string>,
496
+ r: Range | undefined,
497
+ name: string,
498
+ node: Parameters<typeof described>[2]
499
+ ): Parser<any, never, never, any> => {
434
500
  const [min, max] = normalize(r)
435
- const description = describeLiteral(lit)
436
- const expected = [description]
437
501
  return described(
438
502
  (state: State<Input>) => {
439
503
  const start = state.pos
440
- const idx = indexOf(state, lit, start)
504
+ const idx = search(state, start)
441
505
  if (idx < 0) {
442
506
  if (state.partial) return state.incomplete(0, expected)
443
507
  return state.backtrack("TakeUntil", expected, state.end)
444
508
  }
445
- // The literal was read but is not consumed (a string literal is up to three bytes per unit of UTF-8)
446
- state.syntax?.read(idx + lit.length * (Predicate.isString(lit) && state.inputKind === 1 ? 3 : 1))
447
- // As in winnow, the first occurrence must lie within the range
509
+ state.syntax?.read(idx + read(state))
448
510
  if (min > 0 || max !== Infinity) {
449
511
  const count = countTokens(state, start, idx)
450
512
  if (count < min) return state.backtrack("TakeUntil", expected, idx)
@@ -453,34 +515,88 @@ export const takeUntil: {
453
515
  state.pos = idx
454
516
  return state.slice(start, idx)
455
517
  },
456
- "takeUntil",
457
- { _tag: "TakeUntil", literal: lit, ...bounds(r), encoding: undefined }
518
+ name,
519
+ node
458
520
  )
459
521
  }
460
522
 
461
523
  /**
462
- * Takes the rest of the input (winnow's and nom's `rest`).
524
+ * The overloads of {@link takeUntilAny}.
463
525
  *
464
- * @since 0.1.0
526
+ * @since 0.5.0
465
527
  * @category slices
466
528
  */
467
- export const rest: Parser<string> = /*#__PURE__*/ described(
468
- (state: State<any>) => {
529
+ export interface TakeUntilAnyFn {
530
+ (literals: ReadonlyArray<string>, range?: Range): Parser<string, never, never, string>
531
+ (literals: ReadonlyArray<Uint8Array>, range?: Range): Parser<Uint8Array, never, never, Uint8Array>
532
+ }
533
+
534
+ /**
535
+ * Takes tokens up to (not including) the first occurrence of any of
536
+ * several literals: {@link takeUntil} for a set of them, the search a
537
+ * multi-pattern prefilter makes. No literal is consumed. `range` constrains
538
+ * the number of tokens taken. On bytes, `Compiler.wasm` searches with SIMD
539
+ * (Teddy, from ripgrep), sixteen bytes at a time.
540
+ *
541
+ * @example
542
+ * ```ts
543
+ * import { Parser, Token } from "@thomasfosterau/effect-parse"
544
+ * import * as Result from "effect/Result"
545
+ *
546
+ * const upTo = Parser.seq(Token.takeUntilAny(["Holmes", "Watson"]), Token.rest)
547
+ * console.log(Result.getOrThrow(Parser.parseSync(upTo, "Dr. Watson and Holmes")))
548
+ * // ["Dr. ", "Watson and Holmes"]
549
+ * ```
550
+ *
551
+ * @since 0.5.0
552
+ * @category slices
553
+ */
554
+ export const takeUntilAny: TakeUntilAnyFn = (
555
+ literals: ReadonlyArray<Input>,
556
+ r?: Range
557
+ ): Parser<any, never, never, any> => {
558
+ const longest = Math.max(0, ...literals.map((lit) => lit.length))
559
+ return untilParser(
560
+ (state, from) => indexOfAny(state, literals, from),
561
+ // Every literal was read up to where it would end (a string literal is up to three bytes per unit of UTF-8)
562
+ (state) => longest * (state.inputKind === 1 ? 3 : 1),
563
+ literals.map(describeLiteral),
564
+ r,
565
+ "takeUntilAny",
566
+ { _tag: "TakeUntilAny", literals, ...bounds(r), encoding: undefined }
567
+ )
568
+ }
569
+
570
+ /** The parser behind `rest` and `restOf`, on every input kind. */
571
+ const restInput: Parser<unknown, never, never, Input> = /*#__PURE__*/ described(
572
+ (state) => {
469
573
  const start = state.pos
470
574
  state.pos = state.end
471
- return state.slice(start, state.end) as string
575
+ return state.slice(start, state.end)
472
576
  },
473
577
  "rest",
474
578
  { _tag: "Rest", encoding: undefined }
475
579
  )
476
580
 
581
+ /**
582
+ * Takes the rest of the input (winnow's and nom's `rest`).
583
+ *
584
+ * @since 0.1.0
585
+ * @category slices
586
+ */
587
+ export const rest: Parser<string> =
588
+ // SAFETY: on string input, `State.slice` returns a string
589
+ restInput as Parser<string>
590
+
477
591
  /**
478
592
  * Takes the rest of an input of type `I`.
479
593
  *
480
594
  * @since 0.1.0
481
595
  * @category slices
482
596
  */
483
- export const restOf = <I extends Input = string>(): Parser<Slice<NoInfer<I>>, never, never, NoInfer<I>> => rest as any
597
+ export const restOf = <I extends Input = string>(): Parser<Slice<NoInfer<I>>, never, never, NoInfer<I>> =>
598
+ // SAFETY: `State.slice` returns the input's own slice type for every input kind, so `restInput` returns `Slice<I>`
599
+ restInput as Parser<Slice<NoInfer<I>>, never, never, NoInfer<I>>
484
600
 
485
601
  /**
486
602
  * Returns the length of the remaining input without consuming it (winnow's
@@ -506,4 +622,6 @@ export const restLen: Parser<number, never, never, Input> = /*#__PURE__*/ descri
506
622
  */
507
623
  export const satisfy = <I extends Input = string>(
508
624
  predicate: (token: Token<I>) => boolean
509
- ): Parser<Token<NoInfer<I>>, never, never, NoInfer<I>> => oneOf<I>(predicate as any)
625
+ ): Parser<Token<NoInfer<I>>, never, never, NoInfer<I>> =>
626
+ // SAFETY: a predicate over the input's tokens is a member of `TokenSet<I>` for each input kind
627
+ oneOf<I>(predicate as TokenSet<I>)