@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/Parser.ts CHANGED
@@ -29,6 +29,7 @@
29
29
  *
30
30
  * @since 0.1.0
31
31
  */
32
+ import * as Predicate from "effect/Predicate"
32
33
  import * as Context from "effect/Context"
33
34
  import * as Effect from "effect/Effect"
34
35
  import { dual } from "effect/Function"
@@ -42,9 +43,11 @@ import type { ErrMode, Input, Slice, Source, TraceEvent } from "./Input.js"
42
43
  import { Fail, Failure, mergeExpected, mergeFailures, State } from "./Input.js"
43
44
  import type { ErrorKind } from "./ParseError.js"
44
45
  import * as ParseError from "./ParseError.js"
45
- import * as Compiler from "./internal/compiler/registry.js"
46
+ import * as Registry from "./internal/compiler/registry.js"
46
47
  import * as Entries from "./internal/entries.js"
47
48
  import * as Resume from "./internal/resume.js"
49
+ import * as Run from "./internal/run.js"
50
+ import * as Stack from "./internal/stack.js"
48
51
  import type { Node } from "./internal/node.js"
49
52
  import { bounds, NodeId } from "./internal/node.js"
50
53
 
@@ -56,7 +59,7 @@ import { bounds, NodeId } from "./internal/node.js"
56
59
  * @since 0.1.0
57
60
  * @category type ids
58
61
  */
59
- export const TypeId: "~effect-parse/Parser" = "~effect-parse/Parser"
62
+ export const TypeId = "~effect-parse/Parser" as const
60
63
 
61
64
  /**
62
65
  * A parser that consumes input of type `I`, producing a value of type `A`,
@@ -134,9 +137,11 @@ export declare namespace Parser {
134
137
  *
135
138
  * @since 0.1.0
136
139
  */
137
- export type InputOf<P> = [P] extends [never] ? Input
138
- : [P] extends [Parser<infer _A, infer _E, infer _R, infer I>] ? I
139
- : never
140
+ export type InputOf<P> = [P] extends [never]
141
+ ? Input
142
+ : [P] extends [Parser<infer _A, infer _E, infer _R, infer I>]
143
+ ? I
144
+ : never
140
145
  }
141
146
 
142
147
  /**
@@ -158,10 +163,19 @@ export type Range = number | { readonly min?: number | undefined; readonly max?:
158
163
  * @since 0.1.0
159
164
  * @category models
160
165
  */
161
- export type Repeated<A, Rg> = Rg extends number ? number extends Rg ? Array<A> : Rg extends 0 ? Array<A> : NonEmpty<A>
162
- : Rg extends { readonly min: infer M extends number } ? number extends M ? Array<A> : M extends 0 ? Array<A>
163
- : NonEmpty<A>
164
- : Array<A>
166
+ export type Repeated<A, Rg> = Rg extends number
167
+ ? number extends Rg
168
+ ? Array<A>
169
+ : Rg extends 0
170
+ ? Array<A>
171
+ : NonEmpty<A>
172
+ : Rg extends { readonly min: infer M extends number }
173
+ ? number extends M
174
+ ? Array<A>
175
+ : M extends 0
176
+ ? Array<A>
177
+ : NonEmpty<A>
178
+ : Array<A>
165
179
 
166
180
  type NonEmpty<A> = [A, ...Array<A>]
167
181
 
@@ -241,7 +255,7 @@ class ParserImpl<A, E, R, I extends Input> implements Parser<A, E, R, I> {
241
255
  * @category guards
242
256
  */
243
257
  export const isParser = (u: unknown): u is Parser<unknown, unknown, unknown, never> =>
244
- typeof u === "object" && u !== null && TypeId in u
258
+ Predicate.isObjectOrArray(u) && TypeId in u
245
259
 
246
260
  const isParserArg = (args: IArguments) => isParser(args[0])
247
261
  const isTwoParserArgs = (args: IArguments) => isParser(args[0]) && isParser(args[1])
@@ -306,8 +320,11 @@ const nodeOfParser = (p: Parser.Any): Node | undefined => (p as any)[NodeId]
306
320
  export const named: {
307
321
  (name: string): <A, E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<A, E, R, I>
308
322
  <A, E, R, I extends Input>(self: Parser<A, E, R, I>, name: string): Parser<A, E, R, I>
309
- } = dual(2, <A, E, R, I extends Input>(self: Parser<A, E, R, I>, name: string): Parser<A, E, R, I> =>
310
- new ParserImpl(self.step, name, nodeOfParser(self)))
323
+ } = /*#__PURE__*/ dual(
324
+ 2,
325
+ <A, E, R, I extends Input>(self: Parser<A, E, R, I>, name: string): Parser<A, E, R, I> =>
326
+ new ParserImpl(self.step, name, nodeOfParser(self))
327
+ )
311
328
 
312
329
  /**
313
330
  * A parser that consumes nothing and succeeds with the given value.
@@ -334,7 +351,7 @@ export const sync = <A>(evaluate: () => A): Parser<A, never, never, Input> =>
334
351
  * @since 0.1.0
335
352
  * @category constructors
336
353
  */
337
- export const empty: Parser<void, never, never, Input> = described(() => undefined, "empty", {
354
+ export const empty: Parser<void, never, never, Input> = /*#__PURE__*/ described(() => undefined, "empty", {
338
355
  _tag: "Succeed",
339
356
  value: undefined
340
357
  })
@@ -374,7 +391,7 @@ const failBacktrack: Node = { _tag: "Fail", mode: "Backtrack" }
374
391
  * @since 0.1.0
375
392
  * @category constructors
376
393
  */
377
- export const reject: Parser<never, never, never, Input> = described<never, never, never, Input>(
394
+ export const reject: Parser<never, never, never, Input> = /*#__PURE__*/ described<never, never, never, Input>(
378
395
  (state) => state.backtrack("Fail"),
379
396
  "reject",
380
397
  failBacktrack
@@ -400,7 +417,7 @@ export const failMessage = (message: string): Parser<never, never, never, Input>
400
417
  * @since 0.1.0
401
418
  * @category constructors
402
419
  */
403
- export const todo: Parser<never, never, never, Input> = described<never, never, never, Input>(
420
+ export const todo: Parser<never, never, never, Input> = /*#__PURE__*/ described<never, never, never, Input>(
404
421
  (state) => state.failMessage("Cut", "Assert", "`todo` parser reached"),
405
422
  "todo",
406
423
  { _tag: "Fail", mode: "Cut" }
@@ -410,6 +427,11 @@ export const todo: Parser<never, never, never, Input> = described<never, never,
410
427
  * Lazily constructs a parser, which is needed to define recursive grammars.
411
428
  * The thunk is evaluated once, on first use.
412
429
  *
430
+ * Each level of recursion uses some of the call stack, interpreted or
431
+ * compiled, so input nested a few thousand levels deep exhausts it. The
432
+ * runners catch the overflow and fail with an unrecoverable `ParseError` of
433
+ * kind `"TooDeep"` at the offset reached, instead of throwing.
434
+ *
413
435
  * @example
414
436
  * ```ts
415
437
  * import { Parser, Token } from "@thomasfosterau/effect-parse"
@@ -431,7 +453,7 @@ export const suspend = <A, E = never, R = never, I extends Input = string>(
431
453
  let parser: Parser<A, E, R, I> | undefined
432
454
  return described((state) => (parser ??= evaluate()).step(state), "suspend", {
433
455
  _tag: "Suspend",
434
- resolve: () => parser ??= evaluate()
456
+ resolve: () => (parser ??= evaluate())
435
457
  })
436
458
  }
437
459
 
@@ -441,7 +463,7 @@ export const suspend = <A, E = never, R = never, I extends Input = string>(
441
463
  * @since 0.1.0
442
464
  * @category constructors
443
465
  */
444
- export const location: Parser<number, never, never, Input> = described((state) => state.pos, "location", {
466
+ export const location: Parser<number, never, never, Input> = /*#__PURE__*/ described((state) => state.pos, "location", {
445
467
  _tag: "Location"
446
468
  })
447
469
 
@@ -453,11 +475,15 @@ export const location: Parser<number, never, never, Input> = described((state) =
453
475
  * @since 0.1.0
454
476
  * @category constructors
455
477
  */
456
- export const eof: Parser<void, never, never, Input> = described((state) => {
457
- if (state.pos < state.end) return state.backtrack("Eof", expectedEof)
458
- if (state.partial) return state.incomplete(1, expectedEof)
459
- return undefined
460
- }, "eof", { _tag: "Eof" })
478
+ export const eof: Parser<void, never, never, Input> = /*#__PURE__*/ described(
479
+ (state) => {
480
+ if (state.pos < state.end) return state.backtrack("Eof", expectedEof)
481
+ if (state.partial) return state.incomplete(1, expectedEof)
482
+ return undefined
483
+ },
484
+ "eof",
485
+ { _tag: "Eof" }
486
+ )
461
487
 
462
488
  const expectedEof = ["end of input"]
463
489
 
@@ -474,13 +500,20 @@ const expectedEof = ["end of input"]
474
500
  export const map: {
475
501
  <A, B>(f: (a: A) => B): <E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<B, E, R, I>
476
502
  <A, E, R, I extends Input, B>(self: Parser<A, E, R, I>, f: (a: A) => B): Parser<B, E, R, I>
477
- } = dual(2, <A, E, R, I extends Input, B>(self: Parser<A, E, R, I>, f: (a: A) => B): Parser<B, E, R, I> => {
478
- const step = self.step
479
- return described((state) => {
480
- const a = step(state)
481
- return a === Fail ? Fail : f(a)
482
- }, self.name, { _tag: "Map", self, f })
483
- })
503
+ } = /*#__PURE__*/ dual(
504
+ 2,
505
+ <A, E, R, I extends Input, B>(self: Parser<A, E, R, I>, f: (a: A) => B): Parser<B, E, R, I> => {
506
+ const step = self.step
507
+ return described(
508
+ (state) => {
509
+ const a = step(state)
510
+ return a === Fail ? Fail : f(a)
511
+ },
512
+ self.name,
513
+ { _tag: "Map", self, f }
514
+ )
515
+ }
516
+ )
484
517
 
485
518
  /**
486
519
  * Builds an object from the `[key, value]` entries a parser returns, as
@@ -518,9 +551,9 @@ export const fromEntries = <K extends PropertyKey, V, E, R, I extends Input>(
518
551
  export const as: {
519
552
  <B>(value: B): <A, E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<B, E, R, I>
520
553
  <A, E, R, I extends Input, B>(self: Parser<A, E, R, I>, value: B): Parser<B, E, R, I>
521
- } = dual(2, <A, E, R, I extends Input, B>(self: Parser<A, E, R, I>, value: B): Parser<B, E, R, I> => {
554
+ } = /*#__PURE__*/ dual(2, <A, E, R, I extends Input, B>(self: Parser<A, E, R, I>, value: B): Parser<B, E, R, I> => {
522
555
  const step = self.step
523
- return described((state) => step(state) === Fail ? Fail : value, self.name, { _tag: "As", self, value })
556
+ return described((state) => (step(state) === Fail ? Fail : value), self.name, { _tag: "As", self, value })
524
557
  })
525
558
 
526
559
  /**
@@ -529,8 +562,7 @@ export const as: {
529
562
  * @since 0.1.0
530
563
  * @category mapping
531
564
  */
532
- export const asVoid = <A, E, R, I extends Input>(self: Parser<A, E, R, I>): Parser<void, E, R, I> =>
533
- as(self, undefined)
565
+ export const asVoid = <A, E, R, I extends Input>(self: Parser<A, E, R, I>): Parser<void, E, R, I> => as(self, undefined)
534
566
 
535
567
  /**
536
568
  * Replaces the output of a parser with `Option.some(output)`.
@@ -550,14 +582,21 @@ export const asSome = <A, E, R, I extends Input>(self: Parser<A, E, R, I>): Pars
550
582
  export const tap: {
551
583
  <A>(f: (a: A) => void): <E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<A, E, R, I>
552
584
  <A, E, R, I extends Input>(self: Parser<A, E, R, I>, f: (a: A) => void): Parser<A, E, R, I>
553
- } = dual(2, <A, E, R, I extends Input>(self: Parser<A, E, R, I>, f: (a: A) => void): Parser<A, E, R, I> => {
554
- const step = self.step
555
- return described((state) => {
556
- const a = step(state)
557
- if (a !== Fail) f(a)
558
- return a
559
- }, self.name, { _tag: "Tap", self, f })
560
- })
585
+ } = /*#__PURE__*/ dual(
586
+ 2,
587
+ <A, E, R, I extends Input>(self: Parser<A, E, R, I>, f: (a: A) => void): Parser<A, E, R, I> => {
588
+ const step = self.step
589
+ return described(
590
+ (state) => {
591
+ const a = step(state)
592
+ if (a !== Fail) f(a)
593
+ return a
594
+ },
595
+ self.name,
596
+ { _tag: "Tap", self, f }
597
+ )
598
+ }
599
+ )
561
600
 
562
601
  /**
563
602
  * Uses the output of a parser to choose the parser that consumes the rest
@@ -574,16 +613,23 @@ export const flatMap: {
574
613
  self: Parser<A, E, R, I>,
575
614
  f: (a: A) => Parser<B, E2, R2, I2>
576
615
  ): Parser<B, E | E2, R | R2, I & I2>
577
- } = dual(2, <A, E, R, I extends Input, B, E2, R2, I2 extends Input>(
578
- self: Parser<A, E, R, I>,
579
- f: (a: A) => Parser<B, E2, R2, I2>
580
- ): Parser<B, E | E2, R | R2, I & I2> => {
581
- const step = self.step
582
- return described((state) => {
583
- const a = step(state)
584
- return a === Fail ? Fail : f(a).step(state)
585
- }, undefined, { _tag: "FlatMap", self, f })
586
- })
616
+ } = /*#__PURE__*/ dual(
617
+ 2,
618
+ <A, E, R, I extends Input, B, E2, R2, I2 extends Input>(
619
+ self: Parser<A, E, R, I>,
620
+ f: (a: A) => Parser<B, E2, R2, I2>
621
+ ): Parser<B, E | E2, R | R2, I & I2> => {
622
+ const step = self.step
623
+ return described(
624
+ (state) => {
625
+ const a = step(state)
626
+ return a === Fail ? Fail : f(a).step(state)
627
+ },
628
+ undefined,
629
+ { _tag: "FlatMap", self, f }
630
+ )
631
+ }
632
+ )
587
633
 
588
634
  /**
589
635
  * Applies a second parser to the *output* of the first (winnow's
@@ -613,34 +659,37 @@ export const mapParser: {
613
659
  self: Parser<A, E, R, I>,
614
660
  inner: Parser<B, E2, R2, A>
615
661
  ): Parser<B, E | E2, R | R2, I>
616
- } = dual(2, <A extends Input, E, R, I extends Input, B, E2, R2>(
617
- self: Parser<A, E, R, I>,
618
- inner: Parser<B, E2, R2, A>
619
- ): Parser<B, E | E2, R | R2, I> => {
620
- const step = self.step
621
- return make((state) => {
622
- const start = state.pos
623
- const a = step(state)
624
- if (a === Fail) return Fail
625
- const sub = new State(a, { context: state.context })
626
- sub.tracer = state.tracer
627
- sub.depth = state.depth
628
- sub.recovered = state.recovered
629
- const b = inner.step(sub)
630
- if (b === Fail) {
631
- const f = sub.failure
632
- if (sub.encoding !== undefined) state.encoding = sub.encoding
633
- // The inner input is usually a slice ending where the outer parser stopped
634
- const base = Math.max(start, state.pos - a.length)
635
- const offset = Math.min(base + f.offset, state.pos)
636
- return state.failWith(
637
- sub.mode === "Incomplete" ? "Backtrack" : sub.mode,
638
- new Failure(offset, f.kind, f.expected, f.context, f.hasCause, f.cause, f.message, 0)
639
- )
640
- }
641
- return b
642
- })
643
- })
662
+ } = /*#__PURE__*/ dual(
663
+ 2,
664
+ <A extends Input, E, R, I extends Input, B, E2, R2>(
665
+ self: Parser<A, E, R, I>,
666
+ inner: Parser<B, E2, R2, A>
667
+ ): Parser<B, E | E2, R | R2, I> => {
668
+ const step = self.step
669
+ return make((state) => {
670
+ const start = state.pos
671
+ const a = step(state)
672
+ if (a === Fail) return Fail
673
+ const sub = new State(a, { context: state.context })
674
+ sub.tracer = state.tracer
675
+ sub.depth = state.depth
676
+ sub.recovered = state.recovered
677
+ const b = inner.step(sub)
678
+ if (b === Fail) {
679
+ const f = sub.failure
680
+ if (sub.encoding !== undefined) state.encoding = sub.encoding
681
+ // The inner input is usually a slice ending where the outer parser stopped
682
+ const base = Math.max(start, state.pos - a.length)
683
+ const offset = Math.min(base + f.offset, state.pos)
684
+ return state.failWith(
685
+ sub.mode === "Incomplete" ? "Backtrack" : sub.mode,
686
+ new Failure(offset, f.kind, f.expected, f.context, f.hasCause, f.cause, f.message, 0)
687
+ )
688
+ }
689
+ return b
690
+ })
691
+ }
692
+ )
644
693
 
645
694
  /**
646
695
  * Transforms the output of a parser with a function that may fail with a
@@ -659,21 +708,28 @@ export const tryMap: {
659
708
  self: Parser<A, E, R, I>,
660
709
  f: (a: A) => Result.Result<B, E2>
661
710
  ): Parser<B, E | E2, R, I>
662
- } = dual(2, <A, E, R, I extends Input, B, E2>(
663
- self: Parser<A, E, R, I>,
664
- f: (a: A) => Result.Result<B, E2>
665
- ): Parser<B, E | E2, R, I> => {
666
- const step = self.step
667
- return described((state) => {
668
- const start = state.pos
669
- const a = step(state)
670
- if (a === Fail) return Fail
671
- const r = f(a)
672
- if (Result.isSuccess(r)) return r.success
673
- state.pos = start
674
- return state.failCause("Backtrack", "Verify", r.failure)
675
- }, self.name, { _tag: "TryMap", self, f })
676
- })
711
+ } = /*#__PURE__*/ dual(
712
+ 2,
713
+ <A, E, R, I extends Input, B, E2>(
714
+ self: Parser<A, E, R, I>,
715
+ f: (a: A) => Result.Result<B, E2>
716
+ ): Parser<B, E | E2, R, I> => {
717
+ const step = self.step
718
+ return described(
719
+ (state) => {
720
+ const start = state.pos
721
+ const a = step(state)
722
+ if (a === Fail) return Fail
723
+ const r = f(a)
724
+ if (Result.isSuccess(r)) return r.success
725
+ state.pos = start
726
+ return state.failCause("Backtrack", "Verify", r.failure)
727
+ },
728
+ self.name,
729
+ { _tag: "TryMap", self, f }
730
+ )
731
+ }
732
+ )
677
733
 
678
734
  /**
679
735
  * Like {@link tryMap}, but the function may throw. Thrown values become the
@@ -685,14 +741,18 @@ export const tryMap: {
685
741
  export const tryMapUnknown: {
686
742
  <A, B>(f: (a: A) => B): <E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<B, E | unknown, R, I>
687
743
  <A, E, R, I extends Input, B>(self: Parser<A, E, R, I>, f: (a: A) => B): Parser<B, E | unknown, R, I>
688
- } = dual(2, <A, E, R, I extends Input, B>(self: Parser<A, E, R, I>, f: (a: A) => B): Parser<B, unknown, R, I> =>
689
- tryMap(self, (a) => {
690
- try {
691
- return Result.succeed(f(a))
692
- } catch (e) {
693
- return Result.fail(e)
694
- }
695
- }))
744
+ } = /*#__PURE__*/ dual(
745
+ 2,
746
+ <A, E, R, I extends Input, B>(self: Parser<A, E, R, I>, f: (a: A) => B): Parser<B, unknown, R, I> =>
747
+ tryMap(self, (a) => {
748
+ try {
749
+ return Result.succeed(f(a))
750
+ } catch (e) {
751
+ if (Stack.isStackOverflow(e)) throw e
752
+ return Result.fail(e)
753
+ }
754
+ })
755
+ )
696
756
 
697
757
  /**
698
758
  * Transforms the output of a parser with a function returning an `Option`;
@@ -705,21 +765,25 @@ export const tryMapUnknown: {
705
765
  export const filterMap: {
706
766
  <A, B>(f: (a: A) => Option.Option<B>): <E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<B, E, R, I>
707
767
  <A, E, R, I extends Input, B>(self: Parser<A, E, R, I>, f: (a: A) => Option.Option<B>): Parser<B, E, R, I>
708
- } = dual(2, <A, E, R, I extends Input, B>(
709
- self: Parser<A, E, R, I>,
710
- f: (a: A) => Option.Option<B>
711
- ): Parser<B, E, R, I> => {
712
- const step = self.step
713
- return described((state) => {
714
- const start = state.pos
715
- const a = step(state)
716
- if (a === Fail) return Fail
717
- const o = f(a)
718
- if (Option.isSome(o)) return o.value
719
- state.pos = start
720
- return state.backtrack("Verify")
721
- }, self.name, { _tag: "FilterMap", self, f })
722
- })
768
+ } = /*#__PURE__*/ dual(
769
+ 2,
770
+ <A, E, R, I extends Input, B>(self: Parser<A, E, R, I>, f: (a: A) => Option.Option<B>): Parser<B, E, R, I> => {
771
+ const step = self.step
772
+ return described(
773
+ (state) => {
774
+ const start = state.pos
775
+ const a = step(state)
776
+ if (a === Fail) return Fail
777
+ const o = f(a)
778
+ if (Option.isSome(o)) return o.value
779
+ state.pos = start
780
+ return state.backtrack("Verify")
781
+ },
782
+ self.name,
783
+ { _tag: "FilterMap", self, f }
784
+ )
785
+ }
786
+ )
723
787
 
724
788
  /**
725
789
  * Keeps the output of a parser only if it satisfies a predicate, otherwise
@@ -735,16 +799,20 @@ export const filter: {
735
799
  <A>(predicate: (a: NoInfer<A>) => boolean): <E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<A, E, R, I>
736
800
  <A, E, R, I extends Input, B extends A>(self: Parser<A, E, R, I>, refinement: (a: A) => a is B): Parser<B, E, R, I>
737
801
  <A, E, R, I extends Input>(self: Parser<A, E, R, I>, predicate: (a: A) => boolean): Parser<A, E, R, I>
738
- } = dual(2, <A, E, R, I extends Input>(self: Parser<A, E, R, I>, predicate: (a: A) => boolean) => {
802
+ } = /*#__PURE__*/ dual(2, <A, E, R, I extends Input>(self: Parser<A, E, R, I>, predicate: (a: A) => boolean) => {
739
803
  const step = self.step
740
- return described<A, E, R, I>((state) => {
741
- const start = state.pos
742
- const a = step(state)
743
- if (a === Fail) return Fail
744
- if (predicate(a)) return a
745
- state.pos = start
746
- return state.backtrack("Verify")
747
- }, self.name, { _tag: "Filter", self, predicate })
804
+ return described<A, E, R, I>(
805
+ (state) => {
806
+ const start = state.pos
807
+ const a = step(state)
808
+ if (a === Fail) return Fail
809
+ if (predicate(a)) return a
810
+ state.pos = start
811
+ return state.backtrack("Verify")
812
+ },
813
+ self.name,
814
+ { _tag: "Filter", self, predicate }
815
+ )
748
816
  })
749
817
 
750
818
  /**
@@ -773,21 +841,24 @@ export const filterOrFail: {
773
841
  predicate: (a: A) => boolean,
774
842
  orFailWith: (a: A) => E2
775
843
  ): Parser<A, E | E2, R, I>
776
- } = dual(3, <A, E, R, I extends Input, E2>(
777
- self: Parser<A, E, R, I>,
778
- predicate: (a: A) => boolean,
779
- orFailWith: (a: A) => E2
780
- ) => {
781
- const step = self.step
782
- return described<A, E | E2, R, I>((state) => {
783
- const start = state.pos
784
- const a = step(state)
785
- if (a === Fail) return Fail
786
- if (predicate(a)) return a
787
- state.pos = start
788
- return state.failCause("Backtrack", "Verify", orFailWith(a))
789
- }, self.name, { _tag: "Filter", self, predicate })
790
- })
844
+ } = /*#__PURE__*/ dual(
845
+ 3,
846
+ <A, E, R, I extends Input, E2>(self: Parser<A, E, R, I>, predicate: (a: A) => boolean, orFailWith: (a: A) => E2) => {
847
+ const step = self.step
848
+ return described<A, E | E2, R, I>(
849
+ (state) => {
850
+ const start = state.pos
851
+ const a = step(state)
852
+ if (a === Fail) return Fail
853
+ if (predicate(a)) return a
854
+ state.pos = start
855
+ return state.failCause("Backtrack", "Verify", orFailWith(a))
856
+ },
857
+ self.name,
858
+ { _tag: "Filter", self, predicate }
859
+ )
860
+ }
861
+ )
791
862
 
792
863
  // -----------------------------------------------------------------------------
793
864
  // Consumed input
@@ -802,10 +873,14 @@ export const filterOrFail: {
802
873
  */
803
874
  export const taken = <A, E, R, I extends Input>(self: Parser<A, E, R, I>): Parser<Slice<I>, E, R, I> => {
804
875
  const step = self.step
805
- return described((state) => {
806
- const start = state.pos
807
- return step(state) === Fail ? Fail : state.slice(start, state.pos)
808
- }, self.name, { _tag: "Taken", self, encoding: undefined })
876
+ return described(
877
+ (state) => {
878
+ const start = state.pos
879
+ return step(state) === Fail ? Fail : state.slice(start, state.pos)
880
+ },
881
+ self.name,
882
+ { _tag: "Taken", self, encoding: undefined }
883
+ )
809
884
  }
810
885
 
811
886
  /**
@@ -819,11 +894,15 @@ export const withTaken = <A, E, R, I extends Input>(
819
894
  self: Parser<A, E, R, I>
820
895
  ): Parser<[output: A, taken: Slice<I>], E, R, I> => {
821
896
  const step = self.step
822
- return described((state) => {
823
- const start = state.pos
824
- const a = step(state)
825
- return a === Fail ? Fail : [a, state.slice(start, state.pos)]
826
- }, self.name, { _tag: "WithTaken", self })
897
+ return described(
898
+ (state) => {
899
+ const start = state.pos
900
+ const a = step(state)
901
+ return a === Fail ? Fail : [a, state.slice(start, state.pos)]
902
+ },
903
+ self.name,
904
+ { _tag: "WithTaken", self }
905
+ )
827
906
  }
828
907
 
829
908
  /**
@@ -835,10 +914,14 @@ export const withTaken = <A, E, R, I extends Input>(
835
914
  */
836
915
  export const span = <A, E, R, I extends Input>(self: Parser<A, E, R, I>): Parser<Span, E, R, I> => {
837
916
  const step = self.step
838
- return described((state) => {
839
- const start = state.pos
840
- return step(state) === Fail ? Fail : { start, end: state.pos }
841
- }, self.name, { _tag: "Span", self })
917
+ return described(
918
+ (state) => {
919
+ const start = state.pos
920
+ return step(state) === Fail ? Fail : { start, end: state.pos }
921
+ },
922
+ self.name,
923
+ { _tag: "Span", self }
924
+ )
842
925
  }
843
926
 
844
927
  /**
@@ -848,13 +931,19 @@ export const span = <A, E, R, I extends Input>(self: Parser<A, E, R, I>): Parser
848
931
  * @since 0.1.0
849
932
  * @category consumed input
850
933
  */
851
- export const withSpan = <A, E, R, I extends Input>(self: Parser<A, E, R, I>): Parser<[output: A, span: Span], E, R, I> => {
934
+ export const withSpan = <A, E, R, I extends Input>(
935
+ self: Parser<A, E, R, I>
936
+ ): Parser<[output: A, span: Span], E, R, I> => {
852
937
  const step = self.step
853
- return described((state) => {
854
- const start = state.pos
855
- const a = step(state)
856
- return a === Fail ? Fail : [a, { start, end: state.pos }]
857
- }, self.name, { _tag: "WithSpan", self })
938
+ return described(
939
+ (state) => {
940
+ const start = state.pos
941
+ const a = step(state)
942
+ return a === Fail ? Fail : [a, { start, end: state.pos }]
943
+ },
944
+ self.name,
945
+ { _tag: "WithSpan", self }
946
+ )
858
947
  }
859
948
 
860
949
  // -----------------------------------------------------------------------------
@@ -867,11 +956,15 @@ const changeMode = <A, E, R, I extends Input>(
867
956
  to: ErrMode
868
957
  ): Parser<A, E, R, I> => {
869
958
  const step = self.step
870
- return described((state) => {
871
- const a = step(state)
872
- if (a === Fail && state.mode === from) state.mode = to
873
- return a
874
- }, self.name, { _tag: "Mode", self, from, to })
959
+ return described(
960
+ (state) => {
961
+ const a = step(state)
962
+ if (a === Fail && state.mode === from) state.mode = to
963
+ return a
964
+ },
965
+ self.name,
966
+ { _tag: "Mode", self, from, to }
967
+ )
875
968
  }
876
969
 
877
970
  /**
@@ -890,8 +983,29 @@ const changeMode = <A, E, R, I extends Input>(
890
983
  * @since 0.1.0
891
984
  * @category error management
892
985
  */
893
- export const cut = <A, E, R, I extends Input>(self: Parser<A, E, R, I>): Parser<A, E, R, I> =>
894
- changeMode(self, "Backtrack", "Cut")
986
+ export const cut = <A, E, R, I extends Input>(self: Parser<A, E, R, I>): Parser<A, E, R, I> => {
987
+ const step = self.step
988
+ return described(
989
+ (state) => {
990
+ // A committed failure is reported where it happened (winnow's
991
+ // `cut_err`): only failures recorded inside `self` can outrank it as the
992
+ // furthest failure, not ones from abandoned branches or lookaheads before
993
+ // the commit.
994
+ const deepest = state.deepest
995
+ state.deepest = undefined
996
+ const a = step(state)
997
+ if (a === Fail && state.mode !== "Incomplete") {
998
+ state.mode = "Cut"
999
+ return a
1000
+ }
1001
+ const inner = state.deepest as Failure | undefined
1002
+ if (deepest !== undefined && (inner === undefined || deepest.offset > inner.offset)) state.deepest = deepest
1003
+ return a
1004
+ },
1005
+ self.name,
1006
+ { _tag: "Mode", self, from: "Backtrack", to: "Cut" }
1007
+ )
1008
+ }
895
1009
 
896
1010
  /**
897
1011
  * Turns unrecoverable failures back into recoverable ones (winnow's
@@ -912,15 +1026,19 @@ export const backtrack = <A, E, R, I extends Input>(self: Parser<A, E, R, I>): P
912
1026
  */
913
1027
  export const complete = <A, E, R, I extends Input>(self: Parser<A, E, R, I>): Parser<A, E, R, I> => {
914
1028
  const step = self.step
915
- return described((state) => {
916
- const start = state.pos
917
- const a = step(state)
918
- if (a === Fail && state.mode === "Incomplete") {
919
- state.pos = start
920
- return state.backtrack("Complete")
921
- }
922
- return a
923
- }, self.name, { _tag: "Mode", self, from: "Incomplete", to: "Backtrack" })
1029
+ return described(
1030
+ (state) => {
1031
+ const start = state.pos
1032
+ const a = step(state)
1033
+ if (a === Fail && state.mode === "Incomplete") {
1034
+ state.pos = start
1035
+ return state.backtrack("Complete")
1036
+ }
1037
+ return a
1038
+ },
1039
+ self.name,
1040
+ { _tag: "Mode", self, from: "Incomplete", to: "Backtrack" }
1041
+ )
924
1042
  }
925
1043
 
926
1044
  /**
@@ -934,25 +1052,22 @@ export const complete = <A, E, R, I extends Input>(self: Parser<A, E, R, I>): Pa
934
1052
  export const context: {
935
1053
  (label: string): <A, E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<A, E, R, I>
936
1054
  <A, E, R, I extends Input>(self: Parser<A, E, R, I>, label: string): Parser<A, E, R, I>
937
- } = dual(2, <A, E, R, I extends Input>(self: Parser<A, E, R, I>, label: string): Parser<A, E, R, I> => {
1055
+ } = /*#__PURE__*/ dual(2, <A, E, R, I extends Input>(self: Parser<A, E, R, I>, label: string): Parser<A, E, R, I> => {
938
1056
  const step = self.step
939
- return described((state) => {
940
- const a = step(state)
941
- if (a === Fail && state.mode !== "Incomplete") {
942
- const f = state.failure
943
- state.replaceFailure(new Failure(
944
- f.offset,
945
- f.kind,
946
- f.expected,
947
- [...f.context, label],
948
- f.hasCause,
949
- f.cause,
950
- f.message,
951
- f.needed
952
- ))
953
- }
954
- return a
955
- }, self.name ?? label, { _tag: "Context", self, label })
1057
+ return described(
1058
+ (state) => {
1059
+ const a = step(state)
1060
+ if (a === Fail && state.mode !== "Incomplete") {
1061
+ const f = state.failure
1062
+ state.replaceFailure(
1063
+ new Failure(f.offset, f.kind, f.expected, [...f.context, label], f.hasCause, f.cause, f.message, f.needed)
1064
+ )
1065
+ }
1066
+ return a
1067
+ },
1068
+ self.name ?? label,
1069
+ { _tag: "Context", self, label }
1070
+ )
956
1071
  })
957
1072
 
958
1073
  /**
@@ -967,22 +1082,31 @@ export const context: {
967
1082
  export const expected: {
968
1083
  (description: string): <A, E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<A, E, R, I>
969
1084
  <A, E, R, I extends Input>(self: Parser<A, E, R, I>, description: string): Parser<A, E, R, I>
970
- } = dual(2, <A, E, R, I extends Input>(self: Parser<A, E, R, I>, description: string): Parser<A, E, R, I> => {
971
- const step = self.step
972
- const desc = [description]
973
- return described((state) => {
974
- const start = state.pos
975
- const hintOffset = state.hintOffset
976
- const hintExpected = state.hintExpected
977
- const a = step(state)
978
- if (a === Fail && state.failure.offset === start) {
979
- const f = state.failure
980
- const expected = hintOffset === start ? mergeExpected(hintExpected, desc) : desc
981
- state.replaceFailure(new Failure(f.offset, f.kind, expected, f.context, f.hasCause, f.cause, f.message, f.needed))
982
- }
983
- return a
984
- }, description, { _tag: "Expected", self, description })
985
- })
1085
+ } = /*#__PURE__*/ dual(
1086
+ 2,
1087
+ <A, E, R, I extends Input>(self: Parser<A, E, R, I>, description: string): Parser<A, E, R, I> => {
1088
+ const step = self.step
1089
+ const desc = [description]
1090
+ return described(
1091
+ (state) => {
1092
+ const start = state.pos
1093
+ const hintOffset = state.hintOffset
1094
+ const hintExpected = state.hintExpected
1095
+ const a = step(state)
1096
+ if (a === Fail && state.failure.offset === start) {
1097
+ const f = state.failure
1098
+ const expected = hintOffset === start ? mergeExpected(hintExpected, desc) : desc
1099
+ state.replaceFailure(
1100
+ new Failure(f.offset, f.kind, expected, f.context, f.hasCause, f.cause, f.message, f.needed)
1101
+ )
1102
+ }
1103
+ return a
1104
+ },
1105
+ description,
1106
+ { _tag: "Expected", self, description }
1107
+ )
1108
+ }
1109
+ )
986
1110
 
987
1111
  /**
988
1112
  * Transforms the user error (cause) of a parser's failures.
@@ -993,17 +1117,26 @@ export const expected: {
993
1117
  export const mapError: {
994
1118
  <E, E2>(f: (e: E) => E2): <A, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<A, E2, R, I>
995
1119
  <A, E, R, I extends Input, E2>(self: Parser<A, E, R, I>, f: (e: E) => E2): Parser<A, E2, R, I>
996
- } = dual(2, <A, E, R, I extends Input, E2>(self: Parser<A, E, R, I>, f: (e: E) => E2): Parser<A, E2, R, I> => {
997
- const step = self.step
998
- return described((state) => {
999
- const a = step(state)
1000
- if (a === Fail && state.failure.hasCause) {
1001
- const x = state.failure
1002
- state.replaceFailure(new Failure(x.offset, x.kind, x.expected, x.context, true, f(x.cause as E), x.message, x.needed))
1003
- }
1004
- return a
1005
- }, self.name, { _tag: "MapError", self })
1006
- })
1120
+ } = /*#__PURE__*/ dual(
1121
+ 2,
1122
+ <A, E, R, I extends Input, E2>(self: Parser<A, E, R, I>, f: (e: E) => E2): Parser<A, E2, R, I> => {
1123
+ const step = self.step
1124
+ return described(
1125
+ (state) => {
1126
+ const a = step(state)
1127
+ if (a === Fail && state.failure.hasCause) {
1128
+ const x = state.failure
1129
+ state.replaceFailure(
1130
+ new Failure(x.offset, x.kind, x.expected, x.context, true, f(x.cause as E), x.message, x.needed)
1131
+ )
1132
+ }
1133
+ return a
1134
+ },
1135
+ self.name,
1136
+ { _tag: "MapError", self }
1137
+ )
1138
+ }
1139
+ )
1007
1140
 
1008
1141
  /**
1009
1142
  * Replaces any failure of a parser with the given user error, keeping the
@@ -1015,18 +1148,25 @@ export const mapError: {
1015
1148
  export const orFail: {
1016
1149
  <E2>(error: () => E2): <A, E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<A, E2, R, I>
1017
1150
  <A, E, R, I extends Input, E2>(self: Parser<A, E, R, I>, error: () => E2): Parser<A, E2, R, I>
1018
- } = dual(2, <A, E, R, I extends Input, E2>(self: Parser<A, E, R, I>, error: () => E2): Parser<A, E2, R, I> => {
1019
- const step = self.step
1020
- return described((state) => {
1021
- const start = state.pos
1022
- const a = step(state)
1023
- if (a === Fail && state.mode !== "Incomplete") {
1024
- const x = state.failure
1025
- state.replaceFailure(new Failure(start, x.kind, [], x.context, true, error(), undefined, 0))
1026
- }
1027
- return a
1028
- }, self.name, { _tag: "OrFail", self })
1029
- })
1151
+ } = /*#__PURE__*/ dual(
1152
+ 2,
1153
+ <A, E, R, I extends Input, E2>(self: Parser<A, E, R, I>, error: () => E2): Parser<A, E2, R, I> => {
1154
+ const step = self.step
1155
+ return described(
1156
+ (state) => {
1157
+ const start = state.pos
1158
+ const a = step(state)
1159
+ if (a === Fail && state.mode !== "Incomplete") {
1160
+ const x = state.failure
1161
+ state.replaceFailure(new Failure(start, x.kind, [], x.context, true, error(), undefined, 0))
1162
+ }
1163
+ return a
1164
+ },
1165
+ self.name,
1166
+ { _tag: "OrFail", self }
1167
+ )
1168
+ }
1169
+ )
1030
1170
 
1031
1171
  /**
1032
1172
  * If the parser fails recoverably, tries `that` from the same position.
@@ -1043,10 +1183,13 @@ export const orElse: {
1043
1183
  self: Parser<A, E, R, I>,
1044
1184
  that: () => Parser<B, E2, R2, I2>
1045
1185
  ): Parser<A | B, E | E2, R | R2, I & I2>
1046
- } = dual(2, <A, E, R, I extends Input, B, E2, R2, I2 extends Input>(
1047
- self: Parser<A, E, R, I>,
1048
- that: () => Parser<B, E2, R2, I2>
1049
- ): Parser<A | B, E | E2, R | R2, I & I2> => alt(self, suspend(that)))
1186
+ } = /*#__PURE__*/ dual(
1187
+ 2,
1188
+ <A, E, R, I extends Input, B, E2, R2, I2 extends Input>(
1189
+ self: Parser<A, E, R, I>,
1190
+ that: () => Parser<B, E2, R2, I2>
1191
+ ): Parser<A | B, E | E2, R | R2, I & I2> => alt(self, suspend(that))
1192
+ )
1050
1193
 
1051
1194
  /**
1052
1195
  * If the parser fails recoverably, succeeds with the given value without
@@ -1058,17 +1201,24 @@ export const orElse: {
1058
1201
  export const orElseSucceed: {
1059
1202
  <B>(value: () => B): <A, E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<A | B, E, R, I>
1060
1203
  <A, E, R, I extends Input, B>(self: Parser<A, E, R, I>, value: () => B): Parser<A | B, E, R, I>
1061
- } = dual(2, <A, E, R, I extends Input, B>(self: Parser<A, E, R, I>, value: () => B): Parser<A | B, E, R, I> => {
1062
- const step = self.step
1063
- return described((state) => {
1064
- const start = state.pos
1065
- const a = step(state)
1066
- if (a !== Fail) return a
1067
- if (state.mode !== "Backtrack") return Fail
1068
- recover(state, start)
1069
- return value()
1070
- }, self.name, { _tag: "OrElseSucceed", self, value })
1071
- })
1204
+ } = /*#__PURE__*/ dual(
1205
+ 2,
1206
+ <A, E, R, I extends Input, B>(self: Parser<A, E, R, I>, value: () => B): Parser<A | B, E, R, I> => {
1207
+ const step = self.step
1208
+ return described(
1209
+ (state) => {
1210
+ const start = state.pos
1211
+ const a = step(state)
1212
+ if (a !== Fail) return a
1213
+ if (state.mode !== "Backtrack") return Fail
1214
+ recover(state, start)
1215
+ return value()
1216
+ },
1217
+ self.name,
1218
+ { _tag: "OrElseSucceed", self, value }
1219
+ )
1220
+ }
1221
+ )
1072
1222
 
1073
1223
  /** Rewinds after a recoverable failure, remembering it as a hint. */
1074
1224
  const recover = (state: State<any>, start: number): void => {
@@ -1093,14 +1243,18 @@ const recover = (state: State<any>, start: number): void => {
1093
1243
  */
1094
1244
  export const opt = <A, E, R, I extends Input>(self: Parser<A, E, R, I>): Parser<Option.Option<A>, E, R, I> => {
1095
1245
  const step = self.step
1096
- return described((state) => {
1097
- const start = state.pos
1098
- const a = step(state)
1099
- if (a !== Fail) return Option.some(a)
1100
- if (state.mode !== "Backtrack") return Fail
1101
- recover(state, start)
1102
- return Option.none()
1103
- }, self.name, { _tag: "Opt", self })
1246
+ return described(
1247
+ (state) => {
1248
+ const start = state.pos
1249
+ const a = step(state)
1250
+ if (a !== Fail) return Option.some(a)
1251
+ if (state.mode !== "Backtrack") return Fail
1252
+ recover(state, start)
1253
+ return Option.none()
1254
+ },
1255
+ self.name,
1256
+ { _tag: "Opt", self }
1257
+ )
1104
1258
  }
1105
1259
 
1106
1260
  /**
@@ -1122,7 +1276,7 @@ export const optional = <A, E, R, I extends Input>(self: Parser<A, E, R, I>): Pa
1122
1276
  export const cond = <A, E, R, I extends Input>(
1123
1277
  condition: boolean,
1124
1278
  self: Parser<A, E, R, I>
1125
- ): Parser<Option.Option<A>, E, R, I> => condition ? asSome(self) : succeed(Option.none())
1279
+ ): Parser<Option.Option<A>, E, R, I> => (condition ? asSome(self) : succeed(Option.none()))
1126
1280
 
1127
1281
  /**
1128
1282
  * Runs a parser without consuming input (winnow's and nom's `peek`).
@@ -1132,18 +1286,26 @@ export const cond = <A, E, R, I extends Input>(
1132
1286
  */
1133
1287
  export const peek = <A, E, R, I extends Input>(self: Parser<A, E, R, I>): Parser<A, E, R, I> => {
1134
1288
  const step = self.step
1135
- return described((state) => {
1136
- const start = state.pos
1137
- const hintOffset = state.hintOffset
1138
- const hintExpected = state.hintExpected
1139
- const a = step(state)
1140
- if (a !== Fail) {
1141
- state.pos = start
1142
- state.hintOffset = hintOffset
1143
- state.hintExpected = hintExpected
1144
- }
1145
- return a
1146
- }, self.name, { _tag: "Peek", self })
1289
+ return described(
1290
+ (state) => {
1291
+ const start = state.pos
1292
+ const hintOffset = state.hintOffset
1293
+ const hintExpected = state.hintExpected
1294
+ const deepest = state.deepest
1295
+ const a = step(state)
1296
+ if (a !== Fail) {
1297
+ // Failures inside a lookahead that succeeded are about input that was
1298
+ // never consumed, so they are not reported as the furthest failure
1299
+ state.pos = start
1300
+ state.hintOffset = hintOffset
1301
+ state.hintExpected = hintExpected
1302
+ state.deepest = deepest
1303
+ }
1304
+ return a
1305
+ },
1306
+ self.name,
1307
+ { _tag: "Peek", self }
1308
+ )
1147
1309
  }
1148
1310
 
1149
1311
  /**
@@ -1155,21 +1317,29 @@ export const peek = <A, E, R, I extends Input>(self: Parser<A, E, R, I>): Parser
1155
1317
  */
1156
1318
  export const not = <A, E, R, I extends Input>(self: Parser<A, E, R, I>): Parser<void, E, R, I> => {
1157
1319
  const step = self.step
1158
- return described((state) => {
1159
- const start = state.pos
1160
- const hintOffset = state.hintOffset
1161
- const hintExpected = state.hintExpected
1162
- const a = step(state)
1163
- if (a !== Fail) {
1320
+ return described(
1321
+ (state) => {
1322
+ const start = state.pos
1323
+ const hintOffset = state.hintOffset
1324
+ const hintExpected = state.hintExpected
1325
+ const deepest = state.deepest
1326
+ const a = step(state)
1327
+ if (a !== Fail) {
1328
+ // The failures inside `self` are not this parser's failure
1329
+ state.pos = start
1330
+ state.deepest = deepest
1331
+ return state.backtrack("Not")
1332
+ }
1333
+ if (state.mode !== "Backtrack") return Fail
1164
1334
  state.pos = start
1165
- return state.backtrack("Not")
1166
- }
1167
- if (state.mode !== "Backtrack") return Fail
1168
- state.pos = start
1169
- state.hintOffset = hintOffset
1170
- state.hintExpected = hintExpected
1171
- return undefined
1172
- }, self.name, { _tag: "Not", self })
1335
+ state.hintOffset = hintOffset
1336
+ state.hintExpected = hintExpected
1337
+ state.deepest = deepest
1338
+ return undefined
1339
+ },
1340
+ self.name,
1341
+ { _tag: "Not", self }
1342
+ )
1173
1343
  }
1174
1344
 
1175
1345
  /**
@@ -1202,15 +1372,19 @@ export const seq = <const Ps extends ReadonlyArray<Parser.Any>>(
1202
1372
  > => {
1203
1373
  const steps = parsers.map((p) => p.step)
1204
1374
  const n = steps.length
1205
- return described((state: State<any>) => {
1206
- const out = new Array(n)
1207
- for (let i = 0; i < n; i++) {
1208
- const a = steps[i]!(state)
1209
- if (a === Fail) return Fail
1210
- out[i] = a
1211
- }
1212
- return out as any
1213
- }, "seq", { _tag: "Seq", parsers, output: "tuple" })
1375
+ return described(
1376
+ (state: State<any>) => {
1377
+ const out = new Array(n)
1378
+ for (let i = 0; i < n; i++) {
1379
+ const a = steps[i](state)
1380
+ if (a === Fail) return Fail
1381
+ out[i] = a
1382
+ }
1383
+ return out as any
1384
+ },
1385
+ "seq",
1386
+ { _tag: "Seq", parsers, output: "tuple" }
1387
+ )
1214
1388
  }
1215
1389
 
1216
1390
  /**
@@ -1230,17 +1404,21 @@ export const struct = <const Fields extends Readonly<Record<string, Parser.Any>>
1230
1404
  Parser.InputOf<Fields[keyof Fields]>
1231
1405
  > => {
1232
1406
  const keys = Object.keys(fields)
1233
- const steps = keys.map((k) => fields[k]!.step)
1407
+ const steps = keys.map((k) => fields[k].step)
1234
1408
  const n = keys.length
1235
- return described((state: State<any>) => {
1236
- const out: Record<string, unknown> = {}
1237
- for (let i = 0; i < n; i++) {
1238
- const a = steps[i]!(state)
1239
- if (a === Fail) return Fail
1240
- out[keys[i]!] = a
1241
- }
1242
- return out as any
1243
- }, "struct", { _tag: "Struct", keys, parsers: keys.map((k) => fields[k]!) })
1409
+ return described(
1410
+ (state: State<any>) => {
1411
+ const out: Record<string, unknown> = {}
1412
+ for (let i = 0; i < n; i++) {
1413
+ const a = steps[i](state)
1414
+ if (a === Fail) return Fail
1415
+ out[keys[i]] = a
1416
+ }
1417
+ return out as any
1418
+ },
1419
+ "struct",
1420
+ { _tag: "Struct", keys, parsers: keys.map((k) => fields[k]) }
1421
+ )
1244
1422
  }
1245
1423
 
1246
1424
  /**
@@ -1257,10 +1435,13 @@ export const zip: {
1257
1435
  self: Parser<A, E, R, I>,
1258
1436
  that: Parser<B, E2, R2, I2>
1259
1437
  ): Parser<[A, B], E | E2, R | R2, I & I2>
1260
- } = dual(2, <A, E, R, I extends Input, B, E2, R2, I2 extends Input>(
1261
- self: Parser<A, E, R, I>,
1262
- that: Parser<B, E2, R2, I2>
1263
- ): Parser<[A, B], E | E2, R | R2, I & I2> => zipWith(self, that, (a, b) => [a, b]))
1438
+ } = /*#__PURE__*/ dual(
1439
+ 2,
1440
+ <A, E, R, I extends Input, B, E2, R2, I2 extends Input>(
1441
+ self: Parser<A, E, R, I>,
1442
+ that: Parser<B, E2, R2, I2>
1443
+ ): Parser<[A, B], E | E2, R | R2, I & I2> => zipWith(self, that, (a, b) => [a, b])
1444
+ )
1264
1445
 
1265
1446
  /**
1266
1447
  * Runs two parsers in sequence and combines their outputs.
@@ -1278,21 +1459,28 @@ export const zipWith: {
1278
1459
  that: Parser<B, E2, R2, I2>,
1279
1460
  f: (a: A, b: B) => C
1280
1461
  ): Parser<C, E | E2, R | R2, I & I2>
1281
- } = dual(3, <A, E, R, I extends Input, B, E2, R2, I2 extends Input, C>(
1282
- self: Parser<A, E, R, I>,
1283
- that: Parser<B, E2, R2, I2>,
1284
- f: (a: A, b: B) => C
1285
- ): Parser<C, E | E2, R | R2, I & I2> => {
1286
- const s1 = self.step
1287
- const s2 = that.step
1288
- return described((state) => {
1289
- const a = s1(state)
1290
- if (a === Fail) return Fail
1291
- const b = s2(state)
1292
- if (b === Fail) return Fail
1293
- return f(a, b)
1294
- }, undefined, { _tag: "ZipWith", self, that, f })
1295
- })
1462
+ } = /*#__PURE__*/ dual(
1463
+ 3,
1464
+ <A, E, R, I extends Input, B, E2, R2, I2 extends Input, C>(
1465
+ self: Parser<A, E, R, I>,
1466
+ that: Parser<B, E2, R2, I2>,
1467
+ f: (a: A, b: B) => C
1468
+ ): Parser<C, E | E2, R | R2, I & I2> => {
1469
+ const s1 = self.step
1470
+ const s2 = that.step
1471
+ return described(
1472
+ (state) => {
1473
+ const a = s1(state)
1474
+ if (a === Fail) return Fail
1475
+ const b = s2(state)
1476
+ if (b === Fail) return Fail
1477
+ return f(a, b)
1478
+ },
1479
+ undefined,
1480
+ { _tag: "ZipWith", self, that, f }
1481
+ )
1482
+ }
1483
+ )
1296
1484
 
1297
1485
  /**
1298
1486
  * Runs two parsers in sequence, keeping the output of the first.
@@ -1308,10 +1496,13 @@ export const zipLeft: {
1308
1496
  self: Parser<A, E, R, I>,
1309
1497
  that: Parser<B, E2, R2, I2>
1310
1498
  ): Parser<A, E | E2, R | R2, I & I2>
1311
- } = dual(2, <A, E, R, I extends Input, B, E2, R2, I2 extends Input>(
1312
- self: Parser<A, E, R, I>,
1313
- that: Parser<B, E2, R2, I2>
1314
- ): Parser<A, E | E2, R | R2, I & I2> => terminated(self, that))
1499
+ } = /*#__PURE__*/ dual(
1500
+ 2,
1501
+ <A, E, R, I extends Input, B, E2, R2, I2 extends Input>(
1502
+ self: Parser<A, E, R, I>,
1503
+ that: Parser<B, E2, R2, I2>
1504
+ ): Parser<A, E | E2, R | R2, I & I2> => terminated(self, that)
1505
+ )
1315
1506
 
1316
1507
  /**
1317
1508
  * Runs two parsers in sequence, keeping the output of the second.
@@ -1327,10 +1518,13 @@ export const zipRight: {
1327
1518
  self: Parser<A, E, R, I>,
1328
1519
  that: Parser<B, E2, R2, I2>
1329
1520
  ): Parser<B, E | E2, R | R2, I & I2>
1330
- } = dual(2, <A, E, R, I extends Input, B, E2, R2, I2 extends Input>(
1331
- self: Parser<A, E, R, I>,
1332
- that: Parser<B, E2, R2, I2>
1333
- ): Parser<B, E | E2, R | R2, I & I2> => preceded(self, that))
1521
+ } = /*#__PURE__*/ dual(
1522
+ 2,
1523
+ <A, E, R, I extends Input, B, E2, R2, I2 extends Input>(
1524
+ self: Parser<A, E, R, I>,
1525
+ that: Parser<B, E2, R2, I2>
1526
+ ): Parser<B, E | E2, R | R2, I & I2> => preceded(self, that)
1527
+ )
1334
1528
 
1335
1529
  /**
1336
1530
  * Runs `prefix` then `parser`, keeping the output of `parser` (winnow's and
@@ -1345,7 +1539,7 @@ export const preceded = <A1, E1, R1, I1 extends Input, A2, E2, R2, I2 extends In
1345
1539
  ): Parser<A2, E1 | E2, R1 | R2, I1 & I2> => {
1346
1540
  const s1 = prefix.step
1347
1541
  const s2 = parser.step
1348
- return described((state) => s1(state) === Fail ? Fail : s2(state), parser.name, {
1542
+ return described((state) => (s1(state) === Fail ? Fail : s2(state)), parser.name, {
1349
1543
  _tag: "Seq",
1350
1544
  parsers: [prefix, parser],
1351
1545
  output: 1
@@ -1365,11 +1559,15 @@ export const terminated = <A1, E1, R1, I1 extends Input, A2, E2, R2, I2 extends
1365
1559
  ): Parser<A1, E1 | E2, R1 | R2, I1 & I2> => {
1366
1560
  const s1 = parser.step
1367
1561
  const s2 = suffix.step
1368
- return described((state) => {
1369
- const a = s1(state)
1370
- if (a === Fail) return Fail
1371
- return s2(state) === Fail ? Fail : a
1372
- }, parser.name, { _tag: "Seq", parsers: [parser, suffix], output: 0 })
1562
+ return described(
1563
+ (state) => {
1564
+ const a = s1(state)
1565
+ if (a === Fail) return Fail
1566
+ return s2(state) === Fail ? Fail : a
1567
+ },
1568
+ parser.name,
1569
+ { _tag: "Seq", parsers: [parser, suffix], output: 0 }
1570
+ )
1373
1571
  }
1374
1572
 
1375
1573
  /**
@@ -1379,20 +1577,7 @@ export const terminated = <A1, E1, R1, I1 extends Input, A2, E2, R2, I2 extends
1379
1577
  * @since 0.1.0
1380
1578
  * @category sequencing
1381
1579
  */
1382
- export const delimited = <
1383
- A1,
1384
- E1,
1385
- R1,
1386
- I1 extends Input,
1387
- A2,
1388
- E2,
1389
- R2,
1390
- I2 extends Input,
1391
- A3,
1392
- E3,
1393
- R3,
1394
- I3 extends Input
1395
- >(
1580
+ export const delimited = <A1, E1, R1, I1 extends Input, A2, E2, R2, I2 extends Input, A3, E3, R3, I3 extends Input>(
1396
1581
  open: Parser<A1, E1, R1, I1>,
1397
1582
  parser: Parser<A2, E2, R2, I2>,
1398
1583
  close: Parser<A3, E3, R3, I3>
@@ -1400,12 +1585,16 @@ export const delimited = <
1400
1585
  const s1 = open.step
1401
1586
  const s2 = parser.step
1402
1587
  const s3 = close.step
1403
- return described((state) => {
1404
- if (s1(state) === Fail) return Fail
1405
- const a = s2(state)
1406
- if (a === Fail) return Fail
1407
- return s3(state) === Fail ? Fail : a
1408
- }, parser.name, { _tag: "Seq", parsers: [open, parser, close], output: 1 })
1588
+ return described(
1589
+ (state) => {
1590
+ if (s1(state) === Fail) return Fail
1591
+ const a = s2(state)
1592
+ if (a === Fail) return Fail
1593
+ return s3(state) === Fail ? Fail : a
1594
+ },
1595
+ parser.name,
1596
+ { _tag: "Seq", parsers: [open, parser, close], output: 1 }
1597
+ )
1409
1598
  }
1410
1599
 
1411
1600
  /**
@@ -1415,20 +1604,7 @@ export const delimited = <
1415
1604
  * @since 0.1.0
1416
1605
  * @category sequencing
1417
1606
  */
1418
- export const separatedPair = <
1419
- A1,
1420
- E1,
1421
- R1,
1422
- I1 extends Input,
1423
- A2,
1424
- E2,
1425
- R2,
1426
- I2 extends Input,
1427
- A3,
1428
- E3,
1429
- R3,
1430
- I3 extends Input
1431
- >(
1607
+ export const separatedPair = <A1, E1, R1, I1 extends Input, A2, E2, R2, I2 extends Input, A3, E3, R3, I3 extends Input>(
1432
1608
  first: Parser<A1, E1, R1, I1>,
1433
1609
  separator: Parser<A2, E2, R2, I2>,
1434
1610
  second: Parser<A3, E3, R3, I3>
@@ -1436,13 +1612,17 @@ export const separatedPair = <
1436
1612
  const s1 = first.step
1437
1613
  const s2 = separator.step
1438
1614
  const s3 = second.step
1439
- return described((state) => {
1440
- const a = s1(state)
1441
- if (a === Fail) return Fail
1442
- if (s2(state) === Fail) return Fail
1443
- const b = s3(state)
1444
- return b === Fail ? Fail : [a, b]
1445
- }, undefined, { _tag: "Seq", parsers: [first, separator, second], output: [0, 2] })
1615
+ return described(
1616
+ (state) => {
1617
+ const a = s1(state)
1618
+ if (a === Fail) return Fail
1619
+ if (s2(state) === Fail) return Fail
1620
+ const b = s3(state)
1621
+ return b === Fail ? Fail : [a, b]
1622
+ },
1623
+ undefined,
1624
+ { _tag: "Seq", parsers: [first, separator, second], output: [0, 2] }
1625
+ )
1446
1626
  }
1447
1627
 
1448
1628
  /**
@@ -1461,6 +1641,23 @@ export const separatedPair = <
1461
1641
  * })
1462
1642
  * ```
1463
1643
  *
1644
+ * The body runs on every parse, so parsers created inside it, like
1645
+ * `Token.literal("=")` above, are rebuilt on every run. On hot paths, build
1646
+ * them once outside the body:
1647
+ *
1648
+ * ```ts
1649
+ * import { Ascii, Parser, Token } from "@thomasfosterau/effect-parse"
1650
+ *
1651
+ * const equals = Token.literal("=")
1652
+ *
1653
+ * const keyValue = Parser.gen(function*() {
1654
+ * const key = yield* Ascii.alpha1
1655
+ * yield* equals
1656
+ * const value = yield* Ascii.decInt
1657
+ * return [key, value] as const
1658
+ * })
1659
+ * ```
1660
+ *
1464
1661
  * @since 0.1.0
1465
1662
  * @category sequencing
1466
1663
  */
@@ -1498,7 +1695,7 @@ export const gen = <Eff extends Parser.Any, AEff>(
1498
1695
  * @since 0.1.0
1499
1696
  * @category do notation
1500
1697
  */
1501
- export const Do: Parser<{}, never, never, Input> = succeed({})
1698
+ export const Do: Parser<Record<never, never>, never, never, Input> = /*#__PURE__*/ succeed({})
1502
1699
 
1503
1700
  /**
1504
1701
  * Binds the output of a parser to a field of the Do record.
@@ -1518,8 +1715,9 @@ export const bind: {
1518
1715
  name: Exclude<N, keyof A>,
1519
1716
  f: (a: NoInfer<A>) => Parser<B, E2, R2, I2>
1520
1717
  ): Parser<Simplify<Omit<A, N> & { [K in N]: B }>, E | E2, R | R2, I & I2>
1521
- } = dual(3, (self: Parser.Any, name: string, f: (a: any) => Parser.Any): Parser.Any =>
1522
- flatMap(self, (a) => map(f(a), (b) => ({ ...a, [name]: b }))))
1718
+ } = /*#__PURE__*/ dual(3, (self: Parser.Any, name: string, f: (a: any) => Parser.Any): Parser.Any =>
1719
+ flatMap(self, (a) => map(f(a), (b) => ({ ...a, [name]: b })))
1720
+ )
1523
1721
 
1524
1722
  /**
1525
1723
  * Wraps the output of a parser in a record with a single field.
@@ -1530,7 +1728,7 @@ export const bind: {
1530
1728
  export const bindTo: {
1531
1729
  <N extends string>(name: N): <A, E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<{ [K in N]: A }, E, R, I>
1532
1730
  <A, E, R, I extends Input, N extends string>(self: Parser<A, E, R, I>, name: N): Parser<{ [K in N]: A }, E, R, I>
1533
- } = dual(2, (self: Parser.Any, name: string): Parser.Any => map(self, (a) => ({ [name]: a })))
1731
+ } = /*#__PURE__*/ dual(2, (self: Parser.Any, name: string): Parser.Any => map(self, (a) => ({ [name]: a })))
1534
1732
 
1535
1733
  const let_: {
1536
1734
  <N extends string, A extends object, B>(
@@ -1542,8 +1740,9 @@ const let_: {
1542
1740
  name: Exclude<N, keyof A>,
1543
1741
  f: (a: NoInfer<A>) => B
1544
1742
  ): Parser<Simplify<Omit<A, N> & { [K in N]: B }>, E, R, I>
1545
- } = dual(3, (self: Parser.Any, name: string, f: (a: any) => unknown): Parser.Any =>
1546
- map(self, (a) => ({ ...a, [name]: f(a) })))
1743
+ } = /*#__PURE__*/ dual(3, (self: Parser.Any, name: string, f: (a: any) => unknown): Parser.Any =>
1744
+ map(self, (a) => ({ ...a, [name]: f(a) }))
1745
+ )
1547
1746
 
1548
1747
  export {
1549
1748
  /**
@@ -1582,22 +1781,27 @@ export const alt = <const Ps extends ReadonlyArray<Parser.Any>>(
1582
1781
  const steps = parsers.map((p) => p.step)
1583
1782
  const n = steps.length
1584
1783
  if (n === 0) return reject as any
1585
- if (n === 1) return parsers[0]!
1586
- return described((state: State<any>) => {
1587
- const start = state.pos
1588
- let failure: Failure | undefined
1589
- for (let i = 0; i < n; i++) {
1590
- const a = steps[i]!(state)
1591
- if (a !== Fail) {
1592
- if (failure !== undefined && failure.offset === state.pos) state.setHint(failure.offset, failure.expected)
1593
- return a
1784
+ if (n === 1) return parsers[0]
1785
+ return described(
1786
+ (state: State<any>) => {
1787
+ const start = state.pos
1788
+ let failure: Failure | undefined
1789
+ for (let i = 0; i < n; i++) {
1790
+ const a = steps[i](state)
1791
+ if (a !== Fail) {
1792
+ if (failure !== undefined && failure.offset === state.pos) state.setHint(failure.offset, failure.expected)
1793
+ return a
1794
+ }
1795
+ if (state.mode !== "Backtrack") return Fail
1796
+ failure = failure === undefined ? state.failure : mergeFailures(failure, state.failure)
1797
+ state.pos = start
1594
1798
  }
1595
- if (state.mode !== "Backtrack") return Fail
1596
- failure = failure === undefined ? state.failure : mergeFailures(failure, state.failure)
1597
- state.pos = start
1598
- }
1599
- return state.failWith("Backtrack", failure!)
1600
- }, "alt", { _tag: "Alt", parsers })
1799
+ // `failure` is set: there are at least two alternatives, and each one that fails sets it
1800
+ return state.failWith("Backtrack", failure ?? state.failure)
1801
+ },
1802
+ "alt",
1803
+ { _tag: "Alt", parsers }
1804
+ )
1601
1805
  }
1602
1806
 
1603
1807
  /**
@@ -1609,6 +1813,11 @@ export const alt = <const Ps extends ReadonlyArray<Parser.Any>>(
1609
1813
  * an optional `otherwise` parser for unlisted keys, like winnow's `_ =>`
1610
1814
  * arm), or as a function returning a parser (or `undefined` for no match).
1611
1815
  *
1816
+ * Prefer a record where the keys are known. Compiled code (see the
1817
+ * `Compiler` module) switches on the key and runs every case compiled; the
1818
+ * parser a function returns always runs interpreted, and one the function
1819
+ * builds (`(c) => Parser.cut(p)`) is rebuilt on every run.
1820
+ *
1612
1821
  * @example
1613
1822
  * ```ts
1614
1823
  * import { Ascii, Parser, Token } from "@thomasfosterau/effect-parse"
@@ -1656,26 +1865,31 @@ export const dispatch: {
1656
1865
  cases: ((key: any) => Parser.Any | undefined) | Record<PropertyKey, Parser.Any>,
1657
1866
  otherwise?: Parser.Any
1658
1867
  ) => {
1659
- const choose = typeof cases === "function" ? cases : (key: PropertyKey) =>
1660
- Object.prototype.hasOwnProperty.call(cases, key) ? cases[key] : otherwise
1868
+ const choose = Predicate.isFunction(cases)
1869
+ ? cases
1870
+ : (key: PropertyKey) => (Object.prototype.hasOwnProperty.call(cases, key) ? cases[key] : otherwise)
1661
1871
  const step = selector.step
1662
- return described((state: State<any>) => {
1663
- const start = state.pos
1664
- const key = step(state)
1665
- if (key === Fail) return Fail
1666
- const parser = choose(key)
1667
- if (parser === undefined) {
1668
- state.pos = start
1669
- return state.backtrack("Dispatch")
1872
+ return described(
1873
+ (state: State<any>) => {
1874
+ const start = state.pos
1875
+ const key = step(state)
1876
+ if (key === Fail) return Fail
1877
+ const parser = choose(key)
1878
+ if (parser === undefined) {
1879
+ state.pos = start
1880
+ return state.backtrack("Dispatch")
1881
+ }
1882
+ return parser.step(state)
1883
+ },
1884
+ "dispatch",
1885
+ {
1886
+ _tag: "Dispatch",
1887
+ selector,
1888
+ cases: Predicate.isFunction(cases) ? undefined : cases,
1889
+ otherwise: Predicate.isFunction(cases) ? undefined : otherwise,
1890
+ choose
1670
1891
  }
1671
- return parser.step(state)
1672
- }, "dispatch", {
1673
- _tag: "Dispatch",
1674
- selector,
1675
- cases: typeof cases === "function" ? undefined : cases,
1676
- otherwise: typeof cases === "function" ? undefined : otherwise,
1677
- choose
1678
- })
1892
+ )
1679
1893
  }
1680
1894
 
1681
1895
  /**
@@ -1706,7 +1920,7 @@ export const permutation = <const Ps extends ReadonlyArray<Parser.Any>>(
1706
1920
  for (let i = 0; i < n; i++) {
1707
1921
  if (done[i]) continue
1708
1922
  const start = state.pos
1709
- const a = steps[i]!(state)
1923
+ const a = steps[i](state)
1710
1924
  if (a !== Fail) {
1711
1925
  out[i] = a
1712
1926
  done[i] = true
@@ -1718,7 +1932,8 @@ export const permutation = <const Ps extends ReadonlyArray<Parser.Any>>(
1718
1932
  failure = failure === undefined ? state.failure : mergeFailures(failure, state.failure)
1719
1933
  state.pos = start
1720
1934
  }
1721
- if (!matched) return state.failWith("Backtrack", failure!)
1935
+ // `failure` is set: some parser is not done yet, and each one that fails sets it
1936
+ if (!matched) return state.failWith("Backtrack", failure ?? state.failure)
1722
1937
  }
1723
1938
  return out as any
1724
1939
  }, "permutation")
@@ -1730,7 +1945,7 @@ export const permutation = <const Ps extends ReadonlyArray<Parser.Any>>(
1730
1945
 
1731
1946
  const normalizeRange = (range: Range | undefined): [min: number, max: number] => {
1732
1947
  if (range === undefined) return [0, Infinity]
1733
- if (typeof range === "number") return [range, range]
1948
+ if (Predicate.isNumber(range)) return [range, range]
1734
1949
  const min = range.min ?? 0
1735
1950
  const max = range.max ?? Infinity
1736
1951
  if (min > max) throw new RangeError(`invalid range: min (${min}) > max (${max})`)
@@ -1757,44 +1972,50 @@ const foldImpl = <A, B, E, R, I extends Input>(
1757
1972
  init: () => B,
1758
1973
  f: (acc: B, a: A) => B,
1759
1974
  name: string,
1760
- node?: Node
1975
+ node?: Node,
1976
+ cond?: (acc: B) => boolean
1761
1977
  ): Parser<B, E, R, I> => {
1762
1978
  const [min, max] = normalizeRange(range)
1763
1979
  const step = self.step
1764
1980
  const checkLoop = max === Infinity
1765
1981
  const key = {}
1766
- return described((state) => {
1767
- const entry = state.pos
1768
- let acc: B
1769
- let count = 0
1770
- const resumed = state.resume === undefined ? undefined : Resume.take(state, key, entry) as FoldCheckpoint<B>
1771
- if (resumed instanceof Resume.Done) {
1772
- state.pos = resumed.pos
1773
- return resumed.value as B
1774
- }
1775
- if (resumed !== undefined) {
1776
- acc = resumed.acc
1777
- count = resumed.count
1778
- state.pos = resumed.pos
1779
- } else {
1780
- acc = init()
1781
- }
1782
- for (; count < max; count++) {
1783
- const start = state.pos
1784
- const a = step(state)
1785
- if (a === Fail) {
1786
- if (state.mode === "Incomplete" && state.resume !== undefined) {
1787
- Resume.save(state, key, entry, { acc, count, pos: start } satisfies FoldCheckpoint<B>)
1982
+ return described(
1983
+ (state) => {
1984
+ const entry = state.pos
1985
+ let acc: B
1986
+ let count = 0
1987
+ const resumed = state.resume === undefined ? undefined : (Resume.take(state, key, entry) as FoldCheckpoint<B>)
1988
+ if (resumed instanceof Resume.Done) {
1989
+ state.pos = resumed.pos
1990
+ return resumed.value as B
1991
+ }
1992
+ if (resumed !== undefined) {
1993
+ acc = resumed.acc
1994
+ count = resumed.count
1995
+ state.pos = resumed.pos
1996
+ } else {
1997
+ acc = init()
1998
+ }
1999
+ for (; count < max; count++) {
2000
+ if (cond !== undefined && count >= min && !cond(acc)) break
2001
+ const start = state.pos
2002
+ const a = step(state)
2003
+ if (a === Fail) {
2004
+ if (state.mode === "Incomplete" && state.resume !== undefined) {
2005
+ Resume.save(state, key, entry, { acc, count, pos: start } satisfies FoldCheckpoint<B>)
2006
+ }
2007
+ if (state.mode !== "Backtrack" || count < min) return Fail
2008
+ recover(state, start)
2009
+ return Resume.done(state, key, entry, resumed !== undefined, acc)
1788
2010
  }
1789
- if (state.mode !== "Backtrack" || count < min) return Fail
1790
- recover(state, start)
1791
- return Resume.done(state, key, entry, resumed !== undefined, acc)
2011
+ if (checkLoop && state.pos === start) return assertConsumes(state, name)
2012
+ acc = f(acc, a)
1792
2013
  }
1793
- if (checkLoop && state.pos === start) return assertConsumes(state, name)
1794
- acc = f(acc, a)
1795
- }
1796
- return Resume.done(state, key, entry, resumed !== undefined, acc)
1797
- }, name, node ?? { _tag: "Fold", self, init, f, name, ...bounds(range) })
2014
+ return Resume.done(state, key, entry, resumed !== undefined, acc)
2015
+ },
2016
+ name,
2017
+ node ?? { _tag: "Fold", self, init, f, while: cond, name, ...bounds(range) }
2018
+ )
1798
2019
  }
1799
2020
 
1800
2021
  /**
@@ -1828,17 +2049,43 @@ export const repeat: {
1828
2049
  self: Parser<A, E, R, I>,
1829
2050
  range?: Rg
1830
2051
  ): Parser<Repeated<A, Rg>, E, R, I>
1831
- } = dual(isParserArg, <A, E, R, I extends Input>(self: Parser<A, E, R, I>, range?: Range) =>
1832
- foldImpl<A, Array<A>, E, R, I>(self, range, () => [], (acc, a) => {
1833
- acc.push(a)
1834
- return acc
1835
- }, "repeat", { _tag: "Repeat", self, ...bounds(range) }))
2052
+ } = /*#__PURE__*/ dual(isParserArg, <A, E, R, I extends Input>(self: Parser<A, E, R, I>, range?: Range) =>
2053
+ foldImpl<A, Array<A>, E, R, I>(
2054
+ self,
2055
+ range,
2056
+ () => [],
2057
+ (acc, a) => {
2058
+ acc.push(a)
2059
+ return acc
2060
+ },
2061
+ "repeat",
2062
+ { _tag: "Repeat", self, ...bounds(range) }
2063
+ )
2064
+ )
1836
2065
 
1837
2066
  /**
1838
2067
  * Applies a parser repeatedly, folding the outputs into an accumulator
1839
2068
  * (winnow's `repeat(..).fold(..)`, nom's `fold_many0`/`fold_many1`/
1840
2069
  * `fold_many_m_n`).
1841
2070
  *
2071
+ * With `while`, the repetition also stops, successfully and without
2072
+ * consuming more input, as soon as the predicate is false of the
2073
+ * accumulator. It is checked before each element once `range.min` elements
2074
+ * have been folded, so `min` still holds.
2075
+ *
2076
+ * @example
2077
+ * ```ts
2078
+ * import { Parser, Token } from "@thomasfosterau/effect-parse"
2079
+ *
2080
+ * // Keeps the first two digits, leaving the rest unparsed
2081
+ * const two = Parser.fold(Token.oneOf("0123456789"), {
2082
+ * init: () => "",
2083
+ * f: (acc, d) => acc + d,
2084
+ * while: (acc) => acc.length < 2
2085
+ * })
2086
+ * Parser.parsePeek(two, "1234") // Result.succeed(["34", "12"])
2087
+ * ```
2088
+ *
1842
2089
  * @since 0.1.0
1843
2090
  * @category repetition
1844
2091
  */
@@ -1847,17 +2094,29 @@ export const fold: {
1847
2094
  readonly init: () => B
1848
2095
  readonly f: (acc: B, a: A) => B
1849
2096
  readonly range?: Range | undefined
2097
+ readonly while?: ((acc: B) => boolean) | undefined
1850
2098
  }): <E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<B, E, R, I>
1851
- <A, E, R, I extends Input, B>(self: Parser<A, E, R, I>, options: {
1852
- readonly init: () => B
1853
- readonly f: (acc: B, a: A) => B
1854
- readonly range?: Range | undefined
1855
- }): Parser<B, E, R, I>
1856
- } = dual(2, <A, E, R, I extends Input, B>(self: Parser<A, E, R, I>, options: {
1857
- readonly init: () => B
1858
- readonly f: (acc: B, a: A) => B
1859
- readonly range?: Range | undefined
1860
- }): Parser<B, E, R, I> => foldImpl(self, options.range, options.init, options.f, "fold"))
2099
+ <A, E, R, I extends Input, B>(
2100
+ self: Parser<A, E, R, I>,
2101
+ options: {
2102
+ readonly init: () => B
2103
+ readonly f: (acc: B, a: A) => B
2104
+ readonly range?: Range | undefined
2105
+ readonly while?: ((acc: B) => boolean) | undefined
2106
+ }
2107
+ ): Parser<B, E, R, I>
2108
+ } = /*#__PURE__*/ dual(
2109
+ 2,
2110
+ <A, E, R, I extends Input, B>(
2111
+ self: Parser<A, E, R, I>,
2112
+ options: {
2113
+ readonly init: () => B
2114
+ readonly f: (acc: B, a: A) => B
2115
+ readonly range?: Range | undefined
2116
+ readonly while?: ((acc: B) => boolean) | undefined
2117
+ }
2118
+ ): Parser<B, E, R, I> => foldImpl(self, options.range, options.init, options.f, "fold", undefined, options.while)
2119
+ )
1861
2120
 
1862
2121
  /**
1863
2122
  * Applies `self` repeatedly until `end` succeeds, returning the collected
@@ -1871,47 +2130,58 @@ export const repeatTill: {
1871
2130
  <B, E2, R2, I2 extends Input, const Rg extends Range = { readonly min: 0 }>(
1872
2131
  end: Parser<B, E2, R2, I2>,
1873
2132
  range?: Rg
1874
- ): <A, E, R, I extends Input>(
1875
- self: Parser<A, E, R, I>
1876
- ) => Parser<[Repeated<A, Rg>, B], E | E2, R | R2, I & I2>
2133
+ ): <A, E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<[Repeated<A, Rg>, B], E | E2, R | R2, I & I2>
1877
2134
  <A, E, R, I extends Input, B, E2, R2, I2 extends Input, const Rg extends Range = { readonly min: 0 }>(
1878
2135
  self: Parser<A, E, R, I>,
1879
2136
  end: Parser<B, E2, R2, I2>,
1880
2137
  range?: Rg
1881
2138
  ): Parser<[Repeated<A, Rg>, B], E | E2, R | R2, I & I2>
1882
- } = dual(isTwoParserArgs, <A, E, R, I extends Input, B, E2, R2, I2 extends Input>(
1883
- self: Parser<A, E, R, I>,
1884
- end: Parser<B, E2, R2, I2>,
1885
- range?: Range
1886
- ): Parser<[Array<A>, B], E | E2, R | R2, I & I2> => {
1887
- const [min, max] = normalizeRange(range)
1888
- const step = self.step
1889
- const endStep = end.step
1890
- return described((state) => {
1891
- const acc: Array<A> = []
1892
- while (true) {
1893
- const start = state.pos
1894
- let endFailure: Failure | undefined
1895
- if (acc.length >= min) {
1896
- const b = endStep(state)
1897
- if (b !== Fail) return [acc, b]
1898
- if (state.mode !== "Backtrack") return Fail
1899
- endFailure = state.failure
1900
- state.pos = start
1901
- if (acc.length >= max) return Fail
1902
- }
1903
- const a = step(state)
1904
- if (a === Fail) {
1905
- if (endFailure !== undefined && state.mode === "Backtrack") {
1906
- state.failWith("Backtrack", mergeFailures(endFailure, state.failure))
2139
+ } = /*#__PURE__*/ dual(
2140
+ isTwoParserArgs,
2141
+ <A, E, R, I extends Input, B, E2, R2, I2 extends Input>(
2142
+ self: Parser<A, E, R, I>,
2143
+ end: Parser<B, E2, R2, I2>,
2144
+ range?: Range
2145
+ ): Parser<[Array<A>, B], E | E2, R | R2, I & I2> => {
2146
+ const [min, max] = normalizeRange(range)
2147
+ const step = self.step
2148
+ const endStep = end.step
2149
+ return described(
2150
+ (state) => {
2151
+ const acc: Array<A> = []
2152
+ while (true) {
2153
+ const start = state.pos
2154
+ let endFailure: Failure | undefined
2155
+ if (acc.length >= min) {
2156
+ const b = endStep(state)
2157
+ if (b !== Fail) return [acc, b]
2158
+ if (state.mode !== "Backtrack") return Fail
2159
+ endFailure = state.failure
2160
+ state.pos = start
2161
+ if (acc.length >= max) return Fail
2162
+ }
2163
+ const a = step(state)
2164
+ if (a === Fail) {
2165
+ if (endFailure !== undefined && state.mode === "Backtrack") {
2166
+ state.failWith("Backtrack", mergeFailures(endFailure, state.failure))
2167
+ }
2168
+ return Fail
2169
+ }
2170
+ if (state.pos === start) return assertConsumes(state, "repeatTill")
2171
+ acc.push(a)
1907
2172
  }
1908
- return Fail
1909
- }
1910
- if (state.pos === start) return assertConsumes(state, "repeatTill")
1911
- acc.push(a)
1912
- }
1913
- }, "repeatTill", { _tag: "RepeatTill", self, end, ...bounds(range) })
1914
- })
2173
+ },
2174
+ "repeatTill",
2175
+ { _tag: "RepeatTill", self, end, ...bounds(range) }
2176
+ )
2177
+ }
2178
+ )
2179
+
2180
+ /** How far `separated` got: the elements so far, and where the next separator starts. */
2181
+ interface SeparatedCheckpoint<A> {
2182
+ readonly acc: Array<A>
2183
+ readonly pos: number
2184
+ }
1915
2185
 
1916
2186
  /**
1917
2187
  * Applies `self` repeatedly, separated by `separator`, collecting the
@@ -1929,12 +2199,6 @@ export const repeatTill: {
1929
2199
  * @since 0.1.0
1930
2200
  * @category repetition
1931
2201
  */
1932
- /** How far `separated` got: the elements so far, and where the next separator starts. */
1933
- interface SeparatedCheckpoint<A> {
1934
- readonly acc: Array<A>
1935
- readonly pos: number
1936
- }
1937
-
1938
2202
  export const separated: {
1939
2203
  <S, E2, R2, I2 extends Input, const Rg extends Range = { readonly min: 0 }>(
1940
2204
  separator: Parser<S, E2, R2, I2>,
@@ -1945,64 +2209,72 @@ export const separated: {
1945
2209
  separator: Parser<S, E2, R2, I2>,
1946
2210
  range?: Rg
1947
2211
  ): Parser<Repeated<A, Rg>, E | E2, R | R2, I & I2>
1948
- } = dual(isTwoParserArgs, <A, E, R, I extends Input, S, E2, R2, I2 extends Input>(
1949
- self: Parser<A, E, R, I>,
1950
- separator: Parser<S, E2, R2, I2>,
1951
- range?: Range
1952
- ): Parser<Array<A>, E | E2, R | R2, I & I2> => {
1953
- const [min, max] = normalizeRange(range)
1954
- const step = self.step
1955
- const sepStep = separator.step
1956
- const checkLoop = max === Infinity
1957
- const key = {}
1958
- return described((state) => {
1959
- const entry = state.pos
1960
- let acc: Array<A>
1961
- const resumed = state.resume === undefined ? undefined : Resume.take(state, key, entry) as SeparatedCheckpoint<A>
1962
- if (resumed instanceof Resume.Done) {
1963
- state.pos = resumed.pos
1964
- return resumed.value as Array<A>
1965
- }
1966
- if (resumed !== undefined) {
1967
- acc = resumed.acc
1968
- state.pos = resumed.pos
1969
- } else {
1970
- acc = []
1971
- if (max === 0) return acc
1972
- const start = state.pos
1973
- const first = step(state)
1974
- if (first === Fail) {
1975
- if (state.mode !== "Backtrack" || min > 0) return Fail
1976
- recover(state, start)
1977
- return acc
1978
- }
1979
- acc.push(first)
1980
- }
1981
- while (acc.length < max) {
1982
- const start = state.pos
1983
- if (sepStep(state) === Fail) {
1984
- if (state.mode === "Incomplete" && state.resume !== undefined) {
1985
- Resume.save(state, key, entry, { acc, pos: start } satisfies SeparatedCheckpoint<A>)
2212
+ } = /*#__PURE__*/ dual(
2213
+ isTwoParserArgs,
2214
+ <A, E, R, I extends Input, S, E2, R2, I2 extends Input>(
2215
+ self: Parser<A, E, R, I>,
2216
+ separator: Parser<S, E2, R2, I2>,
2217
+ range?: Range
2218
+ ): Parser<Array<A>, E | E2, R | R2, I & I2> => {
2219
+ const [min, max] = normalizeRange(range)
2220
+ const step = self.step
2221
+ const sepStep = separator.step
2222
+ const checkLoop = max === Infinity
2223
+ const key = {}
2224
+ return described(
2225
+ (state) => {
2226
+ const entry = state.pos
2227
+ let acc: Array<A>
2228
+ const resumed =
2229
+ state.resume === undefined ? undefined : (Resume.take(state, key, entry) as SeparatedCheckpoint<A>)
2230
+ if (resumed instanceof Resume.Done) {
2231
+ state.pos = resumed.pos
2232
+ return resumed.value as Array<A>
1986
2233
  }
1987
- if (state.mode !== "Backtrack" || acc.length < min) return Fail
1988
- recover(state, start)
1989
- return Resume.done(state, key, entry, resumed !== undefined, acc)
1990
- }
1991
- if (checkLoop && state.pos === start) return assertConsumes(state, "separated")
1992
- const a = step(state)
1993
- if (a === Fail) {
1994
- if (state.mode === "Incomplete" && state.resume !== undefined) {
1995
- Resume.save(state, key, entry, { acc, pos: start } satisfies SeparatedCheckpoint<A>)
2234
+ if (resumed !== undefined) {
2235
+ acc = resumed.acc
2236
+ state.pos = resumed.pos
2237
+ } else {
2238
+ acc = []
2239
+ if (max === 0) return acc
2240
+ const start = state.pos
2241
+ const first = step(state)
2242
+ if (first === Fail) {
2243
+ if (state.mode !== "Backtrack" || min > 0) return Fail
2244
+ recover(state, start)
2245
+ return acc
2246
+ }
2247
+ acc.push(first)
2248
+ }
2249
+ while (acc.length < max) {
2250
+ const start = state.pos
2251
+ if (sepStep(state) === Fail) {
2252
+ if (state.mode === "Incomplete" && state.resume !== undefined) {
2253
+ Resume.save(state, key, entry, { acc, pos: start } satisfies SeparatedCheckpoint<A>)
2254
+ }
2255
+ if (state.mode !== "Backtrack" || acc.length < min) return Fail
2256
+ recover(state, start)
2257
+ return Resume.done(state, key, entry, resumed !== undefined, acc)
2258
+ }
2259
+ if (checkLoop && state.pos === start) return assertConsumes(state, "separated")
2260
+ const a = step(state)
2261
+ if (a === Fail) {
2262
+ if (state.mode === "Incomplete" && state.resume !== undefined) {
2263
+ Resume.save(state, key, entry, { acc, pos: start } satisfies SeparatedCheckpoint<A>)
2264
+ }
2265
+ if (state.mode !== "Backtrack" || acc.length < min) return Fail
2266
+ state.pos = start
2267
+ return Resume.done(state, key, entry, resumed !== undefined, acc)
2268
+ }
2269
+ acc.push(a)
1996
2270
  }
1997
- if (state.mode !== "Backtrack" || acc.length < min) return Fail
1998
- state.pos = start
1999
2271
  return Resume.done(state, key, entry, resumed !== undefined, acc)
2000
- }
2001
- acc.push(a)
2002
- }
2003
- return Resume.done(state, key, entry, resumed !== undefined, acc)
2004
- }, "separated", { _tag: "Separated", self, separator, ...bounds(range) })
2005
- })
2272
+ },
2273
+ "separated",
2274
+ { _tag: "Separated", self, separator, ...bounds(range) }
2275
+ )
2276
+ }
2277
+ )
2006
2278
 
2007
2279
  /**
2008
2280
  * Parses one or more `self` separated by `separator`, folding them from the
@@ -2033,41 +2305,45 @@ export const separatedFoldl1 = <A, E, R, I extends Input, S, E2, R2, I2 extends
2033
2305
  const step = self.step
2034
2306
  const sepStep = separator.step
2035
2307
  const key = {}
2036
- return described((state) => {
2037
- const entry = state.pos
2038
- const resumed = state.resume === undefined ? undefined : Resume.take(state, key, entry) as FoldCheckpoint<A>
2039
- let acc: A | Fail
2040
- if (resumed instanceof Resume.Done) {
2041
- state.pos = resumed.pos
2042
- return resumed.value as A
2043
- }
2044
- if (resumed !== undefined) {
2045
- acc = resumed.acc
2046
- state.pos = resumed.pos
2047
- } else {
2048
- acc = step(state)
2049
- if (acc === Fail) return Fail
2050
- }
2051
- while (true) {
2052
- const start = state.pos
2053
- const s = sepStep(state)
2054
- if (s === Fail) {
2055
- if (state.mode === "Incomplete" && state.resume !== undefined) saveFold(state, key, entry, acc, start)
2056
- if (state.mode !== "Backtrack") return Fail
2057
- recover(state, start)
2058
- return Resume.done(state, key, entry, resumed !== undefined, acc as A)
2308
+ return described(
2309
+ (state) => {
2310
+ const entry = state.pos
2311
+ const resumed = state.resume === undefined ? undefined : (Resume.take(state, key, entry) as FoldCheckpoint<A>)
2312
+ let acc: A | Fail
2313
+ if (resumed instanceof Resume.Done) {
2314
+ state.pos = resumed.pos
2315
+ return resumed.value as A
2059
2316
  }
2060
- if (state.pos === start) return assertConsumes(state, "separatedFoldl1")
2061
- const a = step(state)
2062
- if (a === Fail) {
2063
- if (state.mode === "Incomplete" && state.resume !== undefined) saveFold(state, key, entry, acc, start)
2064
- if (state.mode !== "Backtrack") return Fail
2065
- state.pos = start
2066
- return Resume.done(state, key, entry, resumed !== undefined, acc as A)
2317
+ if (resumed !== undefined) {
2318
+ acc = resumed.acc
2319
+ state.pos = resumed.pos
2320
+ } else {
2321
+ acc = step(state)
2322
+ if (acc === Fail) return Fail
2067
2323
  }
2068
- acc = op(acc, s, a)
2069
- }
2070
- }, "separatedFoldl1", { _tag: "SeparatedFold", self, separator, op, right: false })
2324
+ while (true) {
2325
+ const start = state.pos
2326
+ const s = sepStep(state)
2327
+ if (s === Fail) {
2328
+ if (state.mode === "Incomplete" && state.resume !== undefined) saveFold(state, key, entry, acc, start)
2329
+ if (state.mode !== "Backtrack") return Fail
2330
+ recover(state, start)
2331
+ return Resume.done(state, key, entry, resumed !== undefined, acc as A)
2332
+ }
2333
+ if (state.pos === start) return assertConsumes(state, "separatedFoldl1")
2334
+ const a = step(state)
2335
+ if (a === Fail) {
2336
+ if (state.mode === "Incomplete" && state.resume !== undefined) saveFold(state, key, entry, acc, start)
2337
+ if (state.mode !== "Backtrack") return Fail
2338
+ state.pos = start
2339
+ return Resume.done(state, key, entry, resumed !== undefined, acc as A)
2340
+ }
2341
+ acc = op(acc, s, a)
2342
+ }
2343
+ },
2344
+ "separatedFoldl1",
2345
+ { _tag: "SeparatedFold", self, separator, op, right: false }
2346
+ )
2071
2347
  }
2072
2348
 
2073
2349
  /**
@@ -2086,35 +2362,39 @@ export const separatedFoldr1 = <A, E, R, I extends Input, S, E2, R2, I2 extends
2086
2362
  ): Parser<A, E | E2, R | R2, I & I2> => {
2087
2363
  const step = self.step
2088
2364
  const sepStep = separator.step
2089
- return described((state) => {
2090
- const first = step(state)
2091
- if (first === Fail) return Fail
2092
- const values: Array<A> = [first]
2093
- const seps: Array<S> = []
2094
- while (true) {
2095
- const start = state.pos
2096
- const s = sepStep(state)
2097
- if (s === Fail) {
2098
- if (state.mode !== "Backtrack") return Fail
2099
- recover(state, start)
2100
- break
2365
+ return described(
2366
+ (state) => {
2367
+ const first = step(state)
2368
+ if (first === Fail) return Fail
2369
+ const values: Array<A> = [first]
2370
+ const seps: Array<S> = []
2371
+ while (true) {
2372
+ const start = state.pos
2373
+ const s = sepStep(state)
2374
+ if (s === Fail) {
2375
+ if (state.mode !== "Backtrack") return Fail
2376
+ recover(state, start)
2377
+ break
2378
+ }
2379
+ if (state.pos === start) return assertConsumes(state, "separatedFoldr1")
2380
+ const a = step(state)
2381
+ if (a === Fail) {
2382
+ if (state.mode !== "Backtrack") return Fail
2383
+ state.pos = start
2384
+ break
2385
+ }
2386
+ seps.push(s)
2387
+ values.push(a)
2101
2388
  }
2102
- if (state.pos === start) return assertConsumes(state, "separatedFoldr1")
2103
- const a = step(state)
2104
- if (a === Fail) {
2105
- if (state.mode !== "Backtrack") return Fail
2106
- state.pos = start
2107
- break
2389
+ let acc = values[values.length - 1] as A
2390
+ for (let i = seps.length - 1; i >= 0; i--) {
2391
+ acc = op(values[i] as A, seps[i] as S, acc)
2108
2392
  }
2109
- seps.push(s)
2110
- values.push(a)
2111
- }
2112
- let acc = values[values.length - 1] as A
2113
- for (let i = seps.length - 1; i >= 0; i--) {
2114
- acc = op(values[i] as A, seps[i] as S, acc)
2115
- }
2116
- return acc
2117
- }, "separatedFoldr1", { _tag: "SeparatedFold", self, separator, op, right: true })
2393
+ return acc
2394
+ },
2395
+ "separatedFoldr1",
2396
+ { _tag: "SeparatedFold", self, separator, op, right: true }
2397
+ )
2118
2398
  }
2119
2399
 
2120
2400
  // -----------------------------------------------------------------------------
@@ -2173,22 +2453,29 @@ export const provideService: {
2173
2453
  key: Context.Key<Id, S>,
2174
2454
  service: NoInfer<S>
2175
2455
  ): Parser<A, E, Exclude<R, Id>, I>
2176
- } = dual(3, <A, E, R, I extends Input, Id, S>(
2177
- self: Parser<A, E, R, I>,
2178
- key: Context.Key<Id, S>,
2179
- service: S
2180
- ): Parser<A, E, Exclude<R, Id>, I> => {
2181
- const step = self.step
2182
- return described((state) => {
2183
- const prev = state.context
2184
- state.context = Context.add(prev, key, service) as Context.Context<never>
2185
- try {
2186
- return step(state)
2187
- } finally {
2188
- state.context = prev
2189
- }
2190
- }, self.name, { _tag: "Provide", self })
2191
- })
2456
+ } = /*#__PURE__*/ dual(
2457
+ 3,
2458
+ <A, E, R, I extends Input, Id, S>(
2459
+ self: Parser<A, E, R, I>,
2460
+ key: Context.Key<Id, S>,
2461
+ service: S
2462
+ ): Parser<A, E, Exclude<R, Id>, I> => {
2463
+ const step = self.step
2464
+ return described(
2465
+ (state) => {
2466
+ const prev = state.context
2467
+ state.context = Context.add(prev, key, service) as Context.Context<never>
2468
+ try {
2469
+ return step(state)
2470
+ } finally {
2471
+ state.context = prev
2472
+ }
2473
+ },
2474
+ self.name,
2475
+ { _tag: "Provide", self }
2476
+ )
2477
+ }
2478
+ )
2192
2479
 
2193
2480
  /**
2194
2481
  * Provides a context of services to a parser.
@@ -2204,21 +2491,28 @@ export const provide: {
2204
2491
  self: Parser<A, E, R, I>,
2205
2492
  context: Context.Context<R2>
2206
2493
  ): Parser<A, E, Exclude<R, R2>, I>
2207
- } = dual(2, <A, E, R, I extends Input, R2>(
2208
- self: Parser<A, E, R, I>,
2209
- context: Context.Context<R2>
2210
- ): Parser<A, E, Exclude<R, R2>, I> => {
2211
- const step = self.step
2212
- return described((state) => {
2213
- const prev = state.context
2214
- state.context = Context.merge(prev, context) as Context.Context<never>
2215
- try {
2216
- return step(state)
2217
- } finally {
2218
- state.context = prev
2219
- }
2220
- }, self.name, { _tag: "Provide", self })
2221
- })
2494
+ } = /*#__PURE__*/ dual(
2495
+ 2,
2496
+ <A, E, R, I extends Input, R2>(
2497
+ self: Parser<A, E, R, I>,
2498
+ context: Context.Context<R2>
2499
+ ): Parser<A, E, Exclude<R, R2>, I> => {
2500
+ const step = self.step
2501
+ return described(
2502
+ (state) => {
2503
+ const prev = state.context
2504
+ state.context = Context.merge(prev, context) as Context.Context<never>
2505
+ try {
2506
+ return step(state)
2507
+ } finally {
2508
+ state.context = prev
2509
+ }
2510
+ },
2511
+ self.name,
2512
+ { _tag: "Provide", self }
2513
+ )
2514
+ }
2515
+ )
2222
2516
 
2223
2517
  // -----------------------------------------------------------------------------
2224
2518
  // Error recovery
@@ -2242,25 +2536,33 @@ export const resumeAfter: {
2242
2536
  self: Parser<A, E, R, I>,
2243
2537
  recover: Parser<B, E2, R2, I2>
2244
2538
  ): Parser<Option.Option<A>, E | E2, R | R2, I & I2>
2245
- } = dual(2, <A, E, R, I extends Input, B, E2, R2, I2 extends Input>(
2246
- self: Parser<A, E, R, I>,
2247
- recover: Parser<B, E2, R2, I2>
2248
- ): Parser<Option.Option<A>, E | E2, R | R2, I & I2> => {
2249
- const step = self.step
2250
- const recoverStep = recover.step
2251
- return described((state) => {
2252
- const start = state.pos
2253
- const a = step(state)
2254
- if (a !== Fail) return Option.some(a)
2255
- if (state.recovered === undefined || state.mode === "Incomplete") return Fail
2256
- const failure = state.failure
2257
- const mode = state.mode
2258
- state.pos = start
2259
- if (recoverStep(state) === Fail) return state.failWith(mode, failure)
2260
- state.recovered.push(failure)
2261
- return Option.none()
2262
- }, self.name, { _tag: "ResumeAfter", self, recover })
2263
- })
2539
+ } = /*#__PURE__*/ dual(
2540
+ 2,
2541
+ <A, E, R, I extends Input, B, E2, R2, I2 extends Input>(
2542
+ self: Parser<A, E, R, I>,
2543
+ recover: Parser<B, E2, R2, I2>
2544
+ ): Parser<Option.Option<A>, E | E2, R | R2, I & I2> => {
2545
+ const step = self.step
2546
+ const recoverStep = recover.step
2547
+ return described(
2548
+ (state) => {
2549
+ const start = state.pos
2550
+ const a = step(state)
2551
+ if (a !== Fail) return Option.some(a)
2552
+ if (state.recovered === undefined || state.mode === "Incomplete") return Fail
2553
+ const failure = state.failure
2554
+ const mode = state.mode
2555
+ state.pos = start
2556
+ if (recoverStep(state) === Fail) return state.failWith(mode, failure)
2557
+ state.recovered.push(failure)
2558
+ state.syntax?.skipped(start, failure, mode)
2559
+ return Option.none()
2560
+ },
2561
+ self.name,
2562
+ { _tag: "ResumeAfter", self, recover }
2563
+ )
2564
+ }
2565
+ )
2264
2566
 
2265
2567
  /**
2266
2568
  * Error recovery: if the parser fails, record the failure, skip input with
@@ -2280,26 +2582,34 @@ export const retryAfter: {
2280
2582
  self: Parser<A, E, R, I>,
2281
2583
  recover: Parser<B, E2, R2, I2>
2282
2584
  ): Parser<A, E | E2, R | R2, I & I2>
2283
- } = dual(2, <A, E, R, I extends Input, B, E2, R2, I2 extends Input>(
2284
- self: Parser<A, E, R, I>,
2285
- recover: Parser<B, E2, R2, I2>
2286
- ): Parser<A, E | E2, R | R2, I & I2> => {
2287
- const step = self.step
2288
- const recoverStep = recover.step
2289
- return described((state) => {
2290
- while (true) {
2291
- const start = state.pos
2292
- const a = step(state)
2293
- if (a !== Fail) return a
2294
- if (state.recovered === undefined || state.mode === "Incomplete") return Fail
2295
- const failure = state.failure
2296
- const mode = state.mode
2297
- state.pos = start
2298
- if (recoverStep(state) === Fail || state.pos === start) return state.failWith(mode, failure)
2299
- state.recovered.push(failure)
2300
- }
2301
- }, self.name, { _tag: "RetryAfter", self, recover })
2302
- })
2585
+ } = /*#__PURE__*/ dual(
2586
+ 2,
2587
+ <A, E, R, I extends Input, B, E2, R2, I2 extends Input>(
2588
+ self: Parser<A, E, R, I>,
2589
+ recover: Parser<B, E2, R2, I2>
2590
+ ): Parser<A, E | E2, R | R2, I & I2> => {
2591
+ const step = self.step
2592
+ const recoverStep = recover.step
2593
+ return described(
2594
+ (state) => {
2595
+ while (true) {
2596
+ const start = state.pos
2597
+ const a = step(state)
2598
+ if (a !== Fail) return a
2599
+ if (state.recovered === undefined || state.mode === "Incomplete") return Fail
2600
+ const failure = state.failure
2601
+ const mode = state.mode
2602
+ state.pos = start
2603
+ if (recoverStep(state) === Fail || state.pos === start) return state.failWith(mode, failure)
2604
+ state.recovered.push(failure)
2605
+ state.syntax?.skipped(start, failure, mode)
2606
+ }
2607
+ },
2608
+ self.name,
2609
+ { _tag: "RetryAfter", self, recover }
2610
+ )
2611
+ }
2612
+ )
2303
2613
 
2304
2614
  // -----------------------------------------------------------------------------
2305
2615
  // Debugging
@@ -2317,33 +2627,37 @@ export const retryAfter: {
2317
2627
  export const trace: {
2318
2628
  (name: string): <A, E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<A, E, R, I>
2319
2629
  <A, E, R, I extends Input>(self: Parser<A, E, R, I>, name: string): Parser<A, E, R, I>
2320
- } = dual(2, <A, E, R, I extends Input>(self: Parser<A, E, R, I>, name: string): Parser<A, E, R, I> => {
2630
+ } = /*#__PURE__*/ dual(2, <A, E, R, I extends Input>(self: Parser<A, E, R, I>, name: string): Parser<A, E, R, I> => {
2321
2631
  const step = self.step
2322
- return described((state) => {
2323
- const tracer = state.tracer
2324
- if (tracer === undefined) return step(state)
2325
- const start = state.pos
2326
- const depth = state.depth
2327
- tracer({ _tag: "Enter", name, depth, offset: start, state })
2328
- state.depth = depth + 1
2329
- const a = step(state)
2330
- state.depth = depth
2331
- tracer({
2332
- _tag: "Exit",
2333
- name,
2334
- depth,
2335
- offset: start,
2336
- endOffset: state.pos,
2337
- result: a === Fail ? state.mode : "Ok",
2338
- state
2339
- })
2340
- return a
2341
- }, name, { _tag: "Trace", self, name })
2632
+ return described(
2633
+ (state) => {
2634
+ const tracer = state.tracer
2635
+ if (tracer === undefined) return step(state)
2636
+ const start = state.pos
2637
+ const depth = state.depth
2638
+ tracer({ _tag: "Enter", name, depth, offset: start, state })
2639
+ state.depth = depth + 1
2640
+ const a = step(state)
2641
+ state.depth = depth
2642
+ tracer({
2643
+ _tag: "Exit",
2644
+ name,
2645
+ depth,
2646
+ offset: start,
2647
+ endOffset: state.pos,
2648
+ result: a === Fail ? state.mode : "Ok",
2649
+ state
2650
+ })
2651
+ return a
2652
+ },
2653
+ name,
2654
+ { _tag: "Trace", self, name }
2655
+ )
2342
2656
  })
2343
2657
 
2344
2658
  const preview = (state: State<any>, offset: number): string => {
2345
2659
  const input = state.input
2346
- if (typeof input === "string") {
2660
+ if (Predicate.isString(input)) {
2347
2661
  const s = input.slice(offset, offset + 24)
2348
2662
  return JSON.stringify(s) + (offset + 24 < input.length ? "…" : "∅")
2349
2663
  }
@@ -2371,88 +2685,28 @@ export const consoleTracer = (event: TraceEvent): void => {
2371
2685
  }
2372
2686
 
2373
2687
  // -----------------------------------------------------------------------------
2374
- // Compilation
2688
+ // Compiled parsers
2375
2689
  // -----------------------------------------------------------------------------
2376
2690
 
2377
- /**
2378
- * Options for {@link compile}.
2379
- *
2380
- * @since 0.1.0
2381
- * @category compilation
2382
- */
2383
- export interface CompileOptions {
2384
- /**
2385
- * Which compiler to use:
2386
- *
2387
- * - `"auto"` (the default): generated code (a JIT) where `new Function`
2388
- * is allowed, otherwise specialized closures
2389
- * - `"closure"`: specialized closures only. It never generates code, so
2390
- * it is the choice under a Content Security Policy, where even probing
2391
- * for `new Function` is reported as a violation.
2392
- */
2393
- readonly backend?: "auto" | "closure" | undefined
2394
- }
2395
-
2396
- /**
2397
- * Compiles a parser into fused, specialized code, and returns the same
2398
- * parser. Grammars are written as usual; compilation only makes
2399
- * {@link parse}, {@link parseSync}, {@link parsePeek} and
2400
- * {@link parseEffect} faster. Compile the root of a grammar once, where it
2401
- * is defined:
2402
- *
2403
- * ```ts
2404
- * import { Ascii, Parser, Token } from "@thomasfosterau/effect-parse"
2405
- *
2406
- * export const list = Parser.compile(
2407
- * Parser.separated(Ascii.decInt, Token.literal(","))
2408
- * )
2409
- * Parser.parse(list, "1,2,3") // Result.succeed([1, 2, 3]), compiled
2410
- * ```
2411
- *
2412
- * The code is generated lazily on the first run, for each kind of input
2413
- * (string, bytes or array), and cached with the parser.
2414
- *
2415
- * **Results and errors are unchanged.** Compiled code records no
2416
- * diagnostics. When it fails, the parser runs again, interpreted, from the
2417
- * start, so every `ParseError` (offset, expected, context, cause and
2418
- * message) is exactly the one the interpreter reports.
2419
- *
2420
- * **Callbacks should be pure.** On an input that fails, the callbacks given
2421
- * to `map`, `filter`, `tryMap`, `tap`, `fold`, ... may run twice, once
2422
- * compiled and once interpreted. Callbacks whose results are discarded
2423
- * (a `map` inside `taken` or `preceded`, for example) may not run at all,
2424
- * nor those of a branch that is certain to fail, and token-set predicates
2425
- * may be called once per character code and cached.
2426
- *
2427
- * Runs on partial input ({@link parsePartial}, `ParserStream`), with
2428
- * {@link parseRecoverable} or with the `trace` option are always
2429
- * interpreted. Parsers that can't be described, such as {@link make} and
2430
- * {@link gen}, run interpreted inside compiled code.
2431
- *
2432
- * @since 0.1.0
2433
- * @category compilation
2434
- */
2435
- export const compile: {
2436
- (options?: CompileOptions): <A, E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<A, E, R, I>
2437
- <A, E, R, I extends Input>(self: Parser<A, E, R, I>, options?: CompileOptions): Parser<A, E, R, I>
2438
- } = dual(isParserArg, <A, E, R, I extends Input>(self: Parser<A, E, R, I>, options?: CompileOptions) => {
2439
- Compiler.register(self, options?.backend ?? "auto")
2440
- return self
2441
- })
2442
-
2443
2691
  /** Returned by {@link runCompiled} when there is no compiled form to run. */
2444
- const NotCompiled: unique symbol = Symbol("NotCompiled")
2692
+ const NotCompiled: unique symbol = /*#__PURE__*/ Symbol("NotCompiled")
2445
2693
 
2446
2694
  /**
2447
2695
  * Runs the compiled form of `self`, if it has one: returns its value, or
2448
2696
  * `Fail` when it failed (or, with `whole`, did not consume the whole
2449
- * input), in which case the state must be thrown away.
2450
- */
2451
- const runCompiled = <I extends Input>(self: Parser.Any, state: State<I>, whole: boolean): unknown => {
2697
+ * input), in which case the state must be thrown away. `resumable` selects
2698
+ * the build that handles partial input.
2699
+ */
2700
+ const runCompiled = <I extends Input>(
2701
+ self: Parser.Any,
2702
+ state: State<I>,
2703
+ whole: boolean,
2704
+ resumable = false
2705
+ ): unknown => {
2452
2706
  if (state.tracer !== undefined || state.recovered !== undefined) return NotCompiled
2453
- const step = Compiler.stepFor(self, state)
2707
+ const step = Registry.stepFor(self, state, resumable)
2454
2708
  if (step === undefined) return NotCompiled
2455
- const a = step(state)
2709
+ const a = Stack.run(step, state)
2456
2710
  if (a === Fail || (whole && state.pos < state.end)) return Fail
2457
2711
  return a
2458
2712
  }
@@ -2473,6 +2727,19 @@ export interface ParseOptions {
2473
2727
  * {@link consoleTracer}.
2474
2728
  */
2475
2729
  readonly trace?: boolean | ((event: TraceEvent) => void) | undefined
2730
+ /**
2731
+ * Where to start parsing (default `0`): in code units for strings, bytes
2732
+ * for byte input and elements for arrays. The result is that of parsing
2733
+ * `input.slice(offset)`, but without copying the input, and every offset
2734
+ * (`parsePartial`'s `Done`, `location`, spans, `ParseError.offset` and its
2735
+ * line and column) is a position in the whole input. This is what an
2736
+ * incremental driver, such as a lexer reading one token at a time from a
2737
+ * buffer, needs: compiled parsers run compiled from any offset.
2738
+ *
2739
+ * Throws a `RangeError` unless it is an integer from `0` to the input's
2740
+ * length.
2741
+ */
2742
+ readonly offset?: number | undefined
2476
2743
  }
2477
2744
 
2478
2745
  /**
@@ -2490,7 +2757,11 @@ const makeState = <I extends Input>(
2490
2757
  options: (ParseOptions & { readonly context?: Context.Context<any> }) | undefined,
2491
2758
  partial: boolean
2492
2759
  ): State<I> => {
2493
- const state = new State(input, { partial, context: options?.context })
2760
+ const offset = options?.offset
2761
+ const state = new State(input, { partial, context: options?.context, offset })
2762
+ if (offset !== undefined && !(Number.isInteger(offset) && offset >= 0 && offset <= state.end)) {
2763
+ throw new RangeError(`Invalid offset ${offset} for an input of length ${state.end}`)
2764
+ }
2494
2765
  const t = options?.trace
2495
2766
  if (t !== undefined && t !== false) state.tracer = t === true ? consoleTracer : t
2496
2767
  return state
@@ -2517,7 +2788,7 @@ const runComplete = <A, E, R, I extends Input>(
2517
2788
  self: Parser<A, E, R, I>,
2518
2789
  state: State<I>
2519
2790
  ): Result.Result<A, ParseError.ParseError<E>> => {
2520
- const a = self.step(state)
2791
+ const a = Stack.run(self.step, state)
2521
2792
  if (a === Fail) return Result.fail(toError(state))
2522
2793
  if (state.pos < state.end) {
2523
2794
  state.backtrack("Eof", expectedEof)
@@ -2567,7 +2838,11 @@ export const parse: {
2567
2838
  */
2568
2839
  export const parseSync: {
2569
2840
  <A, E, I extends Input>(self: Parser<A, E, never, I>, input: NoInfer<Source<I>>, options?: ParseOptions): A
2570
- <A, E, R, I extends Input>(self: Parser<A, E, R, I>, input: NoInfer<Source<I>>, options: ParseOptionsWithContext<R>): A
2841
+ <A, E, R, I extends Input>(
2842
+ self: Parser<A, E, R, I>,
2843
+ input: NoInfer<Source<I>>,
2844
+ options: ParseOptionsWithContext<R>
2845
+ ): A
2571
2846
  } = <A, E, R, I extends Input>(
2572
2847
  self: Parser<A, E, R, I>,
2573
2848
  input: I | Source<I>,
@@ -2583,6 +2858,10 @@ export const parseSync: {
2583
2858
  * input along with the output, nom-style (winnow's `parse_peek`, nom's
2584
2859
  * `IResult`).
2585
2860
  *
2861
+ * The parser ended at offset `input.length - remaining.length`, which is
2862
+ * how a caller running from an `offset` (see {@link ParseOptions}) finds
2863
+ * where to continue.
2864
+ *
2586
2865
  * @since 0.1.0
2587
2866
  * @category running
2588
2867
  */
@@ -2608,7 +2887,7 @@ export const parsePeek: {
2608
2887
  return Result.succeed([state.slice(state.pos, state.end), compiled as A])
2609
2888
  }
2610
2889
  if (compiled === Fail) state = makeState(input, options, false)
2611
- const a = self.step(state)
2890
+ const a = Stack.run(self.step, state)
2612
2891
  if (a === Fail) return Result.fail(toError(state))
2613
2892
  return Result.succeed([state.slice(state.pos, state.end), a])
2614
2893
  }
@@ -2633,7 +2912,14 @@ export type PartialResult<A> =
2633
2912
  * of failing or succeeding early.
2634
2913
  *
2635
2914
  * The parser does not have to consume the whole input; the returned
2636
- * `offset` says how much was consumed.
2915
+ * `offset` says where it stopped. It is a position in the whole input, so
2916
+ * with the `offset` option (see {@link ParseOptions}) it is where the next
2917
+ * parse starts.
2918
+ *
2919
+ * A parser compiled with the `Compiler` module runs compiled, with a build
2920
+ * that handles partial input. When it fails or needs more input, it runs again
2921
+ * interpreted, so `Incomplete`'s `needed` and every `ParseError` are the
2922
+ * interpreter's.
2637
2923
  *
2638
2924
  * @example
2639
2925
  * ```ts
@@ -2664,8 +2950,14 @@ export const parsePartial: {
2664
2950
  input: I | Source<I>,
2665
2951
  options?: ParseOptions & { readonly context?: Context.Context<R> }
2666
2952
  ): Result.Result<PartialResult<A>, ParseError.ParseError<E>> => {
2667
- const state = makeState(input, options, true)
2668
- const a = self.step(state)
2953
+ let state = makeState(input, options, true)
2954
+ const compiled = runCompiled(self, state, false, true)
2955
+ if (compiled !== NotCompiled && compiled !== Fail) {
2956
+ return Result.succeed({ _tag: "Done", value: compiled as A, offset: state.pos })
2957
+ }
2958
+ // Re-run interpreted for `needed` and the diagnostics
2959
+ if (compiled === Fail) state = makeState(input, options, true)
2960
+ const a = Stack.run(self.step, state)
2669
2961
  if (a !== Fail) return Result.succeed({ _tag: "Done", value: a, offset: state.pos })
2670
2962
  if (state.mode === "Incomplete") {
2671
2963
  const needed = state.failure.needed
@@ -2697,11 +2989,87 @@ export const parseEffect = <A, E, R, I extends Input>(
2697
2989
  input: NoInfer<Source<I>>,
2698
2990
  options?: ParseOptions
2699
2991
  ): Effect.Effect<A, ParseError.ParseError<E>, R> =>
2700
- Effect.flatMap(
2701
- Effect.context<R>(),
2702
- (context) => Effect.fromResult(parseComplete(self, input, { ...options, context }))
2992
+ Effect.flatMap(Effect.context<R>(), (context) =>
2993
+ Effect.fromResult(parseComplete(self, input, { ...options, context }))
2703
2994
  )
2704
2995
 
2996
+ /**
2997
+ * Runs a parser on a state you own, from `state.pos`, and returns its output
2998
+ * or {@link Fail}: like calling `self.step(state)`, but using the parser's
2999
+ * compiled form when it has one (see the `Compiler` module). This is the
3000
+ * runner for drivers that make many small runs over one buffer, such as a
3001
+ * lexer reading one token at a time: keep one `Input.State` and
3002
+ * `reset` it (`Input.State.reset`) before each run, and no run allocates a
3003
+ * state, a `Result` or a slice.
3004
+ *
3005
+ * On success the cursor is where the parser stopped. On failure the state
3006
+ * holds the interpreter's failure (`mode`, `failure`, and what
3007
+ * `reportedFailure()` returns): a compiled run that fails is thrown away and
3008
+ * the parser's step runs again from the same position. A partial state
3009
+ * (`partial: true`) runs the compiled build that handles partial input, so
3010
+ * `Incomplete` is reported as the step would report it. Under a tracer,
3011
+ * with recovery on or inside a `Syntax` parse, the step runs interpreted.
3012
+ *
3013
+ * A driver that only needs to know *that* a parser failed (it tries
3014
+ * another, or skips a character) can pass `{ diagnostics: false }` to skip
3015
+ * the interpreted re-run; see {@link RunOptions}.
3016
+ *
3017
+ * Compiled code records no hints or furthest failure when it succeeds, so
3018
+ * a later failure on the same state can list fewer expectations than one
3019
+ * after interpreted runs would: reset the state between runs (as above) and
3020
+ * its errors are the ones {@link parse} reports. Deep nesting fails with an
3021
+ * unrecoverable `TooDeep` failure instead of throwing, as in the other
3022
+ * runners.
3023
+ *
3024
+ * @example
3025
+ * ```ts
3026
+ * import { Ascii, Compiler, Input, Parser, Token } from "@thomasfosterau/effect-parse"
3027
+ *
3028
+ * const token = Compiler.jit(Parser.preceded(Ascii.space0, Parser.alt(Ascii.alpha1, Token.oneOf("+-"))))
3029
+ *
3030
+ * const tokens = (text: string): Array<string> => {
3031
+ * const state = new Input.State(text)
3032
+ * const out: Array<string> = []
3033
+ * while (state.pos < state.end) {
3034
+ * const t = Parser.run(token, state.reset(state.pos))
3035
+ * if (t === Input.Fail) break
3036
+ * out.push(t)
3037
+ * }
3038
+ * return out
3039
+ * }
3040
+ *
3041
+ * tokens("a + b") // ["a", "+", "b"]
3042
+ * ```
3043
+ *
3044
+ * @since 0.2.0
3045
+ * @category running
3046
+ */
3047
+ export const run = <A, E, R, I extends Input>(
3048
+ self: Parser<A, E, R, I>,
3049
+ state: State<I>,
3050
+ options?: RunOptions
3051
+ ): A | Fail => Run.runOn(self, self.step, state, options?.diagnostics !== false)
3052
+
3053
+ /**
3054
+ * Options for {@link run}.
3055
+ *
3056
+ * @since 0.2.0
3057
+ * @category running
3058
+ */
3059
+ export interface RunOptions {
3060
+ /**
3061
+ * Whether a failure records the interpreter's diagnostics (default
3062
+ * `true`). With `false`, a compiled run that fails is not run again
3063
+ * interpreted: the state's `mode` (`Backtrack`, `Cut` or `Incomplete`)
3064
+ * is set and the cursor is back where the run started, but `failure`,
3065
+ * hints and the furthest failure are left as they were. For drivers that
3066
+ * try a parser and move on when it fails, without reporting why, this
3067
+ * halves the cost of each failure. Parsers that run interpreted record
3068
+ * their diagnostics either way.
3069
+ */
3070
+ readonly diagnostics?: boolean | undefined
3071
+ }
3072
+
2705
3073
  /**
2706
3074
  * The outcome of {@link parseRecoverable}.
2707
3075
  *