@thomasfosterau/effect-parse 0.1.0 → 0.3.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 (161) hide show
  1. package/README.md +291 -231
  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 +151 -132
  25. package/dist/Expression.js.map +1 -1
  26. package/dist/Input.d.ts +251 -177
  27. package/dist/Input.d.ts.map +1 -1
  28. package/dist/Input.js +409 -299
  29. package/dist/Input.js.map +1 -1
  30. package/dist/Nom.d.ts +45 -85
  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 +232 -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 +2034 -1802
  41. package/dist/Parser.js.map +1 -1
  42. package/dist/ParserSchema.d.ts +206 -7
  43. package/dist/ParserSchema.d.ts.map +1 -1
  44. package/dist/ParserSchema.js +678 -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 +36 -0
  111. package/dist/internal/stack.js.map +1 -0
  112. package/dist/internal/syntax.d.ts +147 -0
  113. package/dist/internal/syntax.d.ts.map +1 -0
  114. package/dist/internal/syntax.js +309 -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/ties.d.ts +30 -0
  121. package/dist/internal/ties.d.ts.map +1 -0
  122. package/dist/internal/ties.js +67 -0
  123. package/dist/internal/ties.js.map +1 -0
  124. package/dist/internal/tokens.d.ts +25 -30
  125. package/dist/internal/tokens.d.ts.map +1 -1
  126. package/dist/internal/tokens.js +369 -363
  127. package/dist/internal/tokens.js.map +1 -1
  128. package/package.json +42 -28
  129. package/src/Ascii.ts +278 -187
  130. package/src/Binary.ts +150 -44
  131. package/src/Bits.ts +6 -3
  132. package/src/Compiler.ts +98 -0
  133. package/src/Expression.ts +24 -16
  134. package/src/Input.ts +210 -35
  135. package/src/Nom.ts +4 -3
  136. package/src/ParseError.ts +49 -52
  137. package/src/Parser.ts +1199 -799
  138. package/src/ParserSchema.ts +982 -23
  139. package/src/ParserStream.ts +104 -80
  140. package/src/Syntax.ts +900 -0
  141. package/src/Text.ts +272 -187
  142. package/src/Token.ts +180 -87
  143. package/src/index.ts +2 -0
  144. package/src/internal/compiler/closure.ts +121 -88
  145. package/src/internal/compiler/entries.ts +21 -8
  146. package/src/internal/compiler/first.ts +17 -15
  147. package/src/internal/compiler/jit.ts +360 -157
  148. package/src/internal/compiler/registry.ts +12 -33
  149. package/src/internal/compiler/sets.ts +17 -11
  150. package/src/internal/entries.ts +4 -2
  151. package/src/internal/node.ts +51 -37
  152. package/src/internal/numbers.ts +22 -20
  153. package/src/internal/resume.ts +8 -4
  154. package/src/internal/run.ts +41 -0
  155. package/src/internal/stack.ts +41 -0
  156. package/src/internal/syntax.ts +426 -0
  157. package/src/internal/text.ts +32 -25
  158. package/src/internal/ties.ts +83 -0
  159. package/src/internal/tokens.ts +96 -51
  160. package/dist/index.d.ts.map +0 -1
  161. 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"
@@ -39,12 +40,15 @@ import { pipeArguments } from "effect/Pipeable"
39
40
  import * as Result from "effect/Result"
40
41
  import type { Contravariant, Covariant, Simplify } from "effect/Types"
41
42
  import type { ErrMode, Input, Slice, Source, TraceEvent } from "./Input.js"
42
- import { Fail, Failure, mergeExpected, mergeFailures, State } from "./Input.js"
43
+ import { Fail, Failure, mergeExpected, mergeFailures, mergeTiedFailures, 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"
51
+ import { TiedFailures } from "./internal/ties.js"
48
52
  import type { Node } from "./internal/node.js"
49
53
  import { bounds, NodeId } from "./internal/node.js"
50
54
 
@@ -56,7 +60,7 @@ import { bounds, NodeId } from "./internal/node.js"
56
60
  * @since 0.1.0
57
61
  * @category type ids
58
62
  */
59
- export const TypeId: "~effect-parse/Parser" = "~effect-parse/Parser"
63
+ export const TypeId = "~effect-parse/Parser" as const
60
64
 
61
65
  /**
62
66
  * A parser that consumes input of type `I`, producing a value of type `A`,
@@ -134,9 +138,11 @@ export declare namespace Parser {
134
138
  *
135
139
  * @since 0.1.0
136
140
  */
137
- export type InputOf<P> = [P] extends [never] ? Input
138
- : [P] extends [Parser<infer _A, infer _E, infer _R, infer I>] ? I
139
- : never
141
+ export type InputOf<P> = [P] extends [never]
142
+ ? Input
143
+ : [P] extends [Parser<infer _A, infer _E, infer _R, infer I>]
144
+ ? I
145
+ : never
140
146
  }
141
147
 
142
148
  /**
@@ -158,10 +164,19 @@ export type Range = number | { readonly min?: number | undefined; readonly max?:
158
164
  * @since 0.1.0
159
165
  * @category models
160
166
  */
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>
167
+ export type Repeated<A, Rg> = Rg extends number
168
+ ? number extends Rg
169
+ ? Array<A>
170
+ : Rg extends 0
171
+ ? Array<A>
172
+ : NonEmpty<A>
173
+ : Rg extends { readonly min: infer M extends number }
174
+ ? number extends M
175
+ ? Array<A>
176
+ : M extends 0
177
+ ? Array<A>
178
+ : NonEmpty<A>
179
+ : Array<A>
165
180
 
166
181
  type NonEmpty<A> = [A, ...Array<A>]
167
182
 
@@ -241,7 +256,7 @@ class ParserImpl<A, E, R, I extends Input> implements Parser<A, E, R, I> {
241
256
  * @category guards
242
257
  */
243
258
  export const isParser = (u: unknown): u is Parser<unknown, unknown, unknown, never> =>
244
- typeof u === "object" && u !== null && TypeId in u
259
+ Predicate.isObjectOrArray(u) && TypeId in u
245
260
 
246
261
  const isParserArg = (args: IArguments) => isParser(args[0])
247
262
  const isTwoParserArgs = (args: IArguments) => isParser(args[0]) && isParser(args[1])
@@ -306,8 +321,11 @@ const nodeOfParser = (p: Parser.Any): Node | undefined => (p as any)[NodeId]
306
321
  export const named: {
307
322
  (name: string): <A, E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<A, E, R, I>
308
323
  <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)))
324
+ } = /*#__PURE__*/ dual(
325
+ 2,
326
+ <A, E, R, I extends Input>(self: Parser<A, E, R, I>, name: string): Parser<A, E, R, I> =>
327
+ new ParserImpl(self.step, name, nodeOfParser(self))
328
+ )
311
329
 
312
330
  /**
313
331
  * A parser that consumes nothing and succeeds with the given value.
@@ -334,7 +352,7 @@ export const sync = <A>(evaluate: () => A): Parser<A, never, never, Input> =>
334
352
  * @since 0.1.0
335
353
  * @category constructors
336
354
  */
337
- export const empty: Parser<void, never, never, Input> = described(() => undefined, "empty", {
355
+ export const empty: Parser<void, never, never, Input> = /*#__PURE__*/ described(() => undefined, "empty", {
338
356
  _tag: "Succeed",
339
357
  value: undefined
340
358
  })
@@ -374,7 +392,7 @@ const failBacktrack: Node = { _tag: "Fail", mode: "Backtrack" }
374
392
  * @since 0.1.0
375
393
  * @category constructors
376
394
  */
377
- export const reject: Parser<never, never, never, Input> = described<never, never, never, Input>(
395
+ export const reject: Parser<never, never, never, Input> = /*#__PURE__*/ described<never, never, never, Input>(
378
396
  (state) => state.backtrack("Fail"),
379
397
  "reject",
380
398
  failBacktrack
@@ -400,7 +418,7 @@ export const failMessage = (message: string): Parser<never, never, never, Input>
400
418
  * @since 0.1.0
401
419
  * @category constructors
402
420
  */
403
- export const todo: Parser<never, never, never, Input> = described<never, never, never, Input>(
421
+ export const todo: Parser<never, never, never, Input> = /*#__PURE__*/ described<never, never, never, Input>(
404
422
  (state) => state.failMessage("Cut", "Assert", "`todo` parser reached"),
405
423
  "todo",
406
424
  { _tag: "Fail", mode: "Cut" }
@@ -410,6 +428,11 @@ export const todo: Parser<never, never, never, Input> = described<never, never,
410
428
  * Lazily constructs a parser, which is needed to define recursive grammars.
411
429
  * The thunk is evaluated once, on first use.
412
430
  *
431
+ * Each level of recursion uses some of the call stack, interpreted or
432
+ * compiled, so input nested a few thousand levels deep exhausts it. The
433
+ * runners catch the overflow and fail with an unrecoverable `ParseError` of
434
+ * kind `"TooDeep"` at the offset reached, instead of throwing.
435
+ *
413
436
  * @example
414
437
  * ```ts
415
438
  * import { Parser, Token } from "@thomasfosterau/effect-parse"
@@ -431,7 +454,7 @@ export const suspend = <A, E = never, R = never, I extends Input = string>(
431
454
  let parser: Parser<A, E, R, I> | undefined
432
455
  return described((state) => (parser ??= evaluate()).step(state), "suspend", {
433
456
  _tag: "Suspend",
434
- resolve: () => parser ??= evaluate()
457
+ resolve: () => (parser ??= evaluate())
435
458
  })
436
459
  }
437
460
 
@@ -441,7 +464,7 @@ export const suspend = <A, E = never, R = never, I extends Input = string>(
441
464
  * @since 0.1.0
442
465
  * @category constructors
443
466
  */
444
- export const location: Parser<number, never, never, Input> = described((state) => state.pos, "location", {
467
+ export const location: Parser<number, never, never, Input> = /*#__PURE__*/ described((state) => state.pos, "location", {
445
468
  _tag: "Location"
446
469
  })
447
470
 
@@ -453,11 +476,15 @@ export const location: Parser<number, never, never, Input> = described((state) =
453
476
  * @since 0.1.0
454
477
  * @category constructors
455
478
  */
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" })
479
+ export const eof: Parser<void, never, never, Input> = /*#__PURE__*/ described(
480
+ (state) => {
481
+ if (state.pos < state.end) return state.backtrack("Eof", expectedEof)
482
+ if (state.partial) return state.incomplete(1, expectedEof)
483
+ return undefined
484
+ },
485
+ "eof",
486
+ { _tag: "Eof" }
487
+ )
461
488
 
462
489
  const expectedEof = ["end of input"]
463
490
 
@@ -474,13 +501,20 @@ const expectedEof = ["end of input"]
474
501
  export const map: {
475
502
  <A, B>(f: (a: A) => B): <E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<B, E, R, I>
476
503
  <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
- })
504
+ } = /*#__PURE__*/ dual(
505
+ 2,
506
+ <A, E, R, I extends Input, B>(self: Parser<A, E, R, I>, f: (a: A) => B): Parser<B, E, R, I> => {
507
+ const step = self.step
508
+ return described(
509
+ (state) => {
510
+ const a = step(state)
511
+ return a === Fail ? Fail : f(a)
512
+ },
513
+ self.name,
514
+ { _tag: "Map", self, f }
515
+ )
516
+ }
517
+ )
484
518
 
485
519
  /**
486
520
  * Builds an object from the `[key, value]` entries a parser returns, as
@@ -518,9 +552,9 @@ export const fromEntries = <K extends PropertyKey, V, E, R, I extends Input>(
518
552
  export const as: {
519
553
  <B>(value: B): <A, E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<B, E, R, I>
520
554
  <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> => {
555
+ } = /*#__PURE__*/ dual(2, <A, E, R, I extends Input, B>(self: Parser<A, E, R, I>, value: B): Parser<B, E, R, I> => {
522
556
  const step = self.step
523
- return described((state) => step(state) === Fail ? Fail : value, self.name, { _tag: "As", self, value })
557
+ return described((state) => (step(state) === Fail ? Fail : value), self.name, { _tag: "As", self, value })
524
558
  })
525
559
 
526
560
  /**
@@ -529,8 +563,7 @@ export const as: {
529
563
  * @since 0.1.0
530
564
  * @category mapping
531
565
  */
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)
566
+ export const asVoid = <A, E, R, I extends Input>(self: Parser<A, E, R, I>): Parser<void, E, R, I> => as(self, undefined)
534
567
 
535
568
  /**
536
569
  * Replaces the output of a parser with `Option.some(output)`.
@@ -550,14 +583,21 @@ export const asSome = <A, E, R, I extends Input>(self: Parser<A, E, R, I>): Pars
550
583
  export const tap: {
551
584
  <A>(f: (a: A) => void): <E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<A, E, R, I>
552
585
  <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
- })
586
+ } = /*#__PURE__*/ dual(
587
+ 2,
588
+ <A, E, R, I extends Input>(self: Parser<A, E, R, I>, f: (a: A) => void): Parser<A, E, R, I> => {
589
+ const step = self.step
590
+ return described(
591
+ (state) => {
592
+ const a = step(state)
593
+ if (a !== Fail) f(a)
594
+ return a
595
+ },
596
+ self.name,
597
+ { _tag: "Tap", self, f }
598
+ )
599
+ }
600
+ )
561
601
 
562
602
  /**
563
603
  * Uses the output of a parser to choose the parser that consumes the rest
@@ -574,16 +614,23 @@ export const flatMap: {
574
614
  self: Parser<A, E, R, I>,
575
615
  f: (a: A) => Parser<B, E2, R2, I2>
576
616
  ): 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
- })
617
+ } = /*#__PURE__*/ dual(
618
+ 2,
619
+ <A, E, R, I extends Input, B, E2, R2, I2 extends Input>(
620
+ self: Parser<A, E, R, I>,
621
+ f: (a: A) => Parser<B, E2, R2, I2>
622
+ ): Parser<B, E | E2, R | R2, I & I2> => {
623
+ const step = self.step
624
+ return described(
625
+ (state) => {
626
+ const a = step(state)
627
+ return a === Fail ? Fail : f(a).step(state)
628
+ },
629
+ undefined,
630
+ { _tag: "FlatMap", self, f }
631
+ )
632
+ }
633
+ )
587
634
 
588
635
  /**
589
636
  * Applies a second parser to the *output* of the first (winnow's
@@ -613,34 +660,37 @@ export const mapParser: {
613
660
  self: Parser<A, E, R, I>,
614
661
  inner: Parser<B, E2, R2, A>
615
662
  ): 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
- })
663
+ } = /*#__PURE__*/ dual(
664
+ 2,
665
+ <A extends Input, E, R, I extends Input, B, E2, R2>(
666
+ self: Parser<A, E, R, I>,
667
+ inner: Parser<B, E2, R2, A>
668
+ ): Parser<B, E | E2, R | R2, I> => {
669
+ const step = self.step
670
+ return make((state) => {
671
+ const start = state.pos
672
+ const a = step(state)
673
+ if (a === Fail) return Fail
674
+ const sub = new State(a, { context: state.context })
675
+ sub.tracer = state.tracer
676
+ sub.depth = state.depth
677
+ sub.recovered = state.recovered
678
+ const b = inner.step(sub)
679
+ if (b === Fail) {
680
+ const f = sub.failure
681
+ if (sub.encoding !== undefined) state.encoding = sub.encoding
682
+ // The inner input is usually a slice ending where the outer parser stopped
683
+ const base = Math.max(start, state.pos - a.length)
684
+ const offset = Math.min(base + f.offset, state.pos)
685
+ return state.failWith(
686
+ sub.mode === "Incomplete" ? "Backtrack" : sub.mode,
687
+ new Failure(offset, f.kind, f.expected, f.context, f.hasCause, f.cause, f.message, 0)
688
+ )
689
+ }
690
+ return b
691
+ })
692
+ }
693
+ )
644
694
 
645
695
  /**
646
696
  * Transforms the output of a parser with a function that may fail with a
@@ -659,21 +709,28 @@ export const tryMap: {
659
709
  self: Parser<A, E, R, I>,
660
710
  f: (a: A) => Result.Result<B, E2>
661
711
  ): 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
- })
712
+ } = /*#__PURE__*/ dual(
713
+ 2,
714
+ <A, E, R, I extends Input, B, E2>(
715
+ self: Parser<A, E, R, I>,
716
+ f: (a: A) => Result.Result<B, E2>
717
+ ): Parser<B, E | E2, R, I> => {
718
+ const step = self.step
719
+ return described(
720
+ (state) => {
721
+ const start = state.pos
722
+ const a = step(state)
723
+ if (a === Fail) return Fail
724
+ const r = f(a)
725
+ if (Result.isSuccess(r)) return r.success
726
+ state.pos = start
727
+ return state.failCause("Backtrack", "Verify", r.failure)
728
+ },
729
+ self.name,
730
+ { _tag: "TryMap", self, f }
731
+ )
732
+ }
733
+ )
677
734
 
678
735
  /**
679
736
  * Like {@link tryMap}, but the function may throw. Thrown values become the
@@ -685,14 +742,18 @@ export const tryMap: {
685
742
  export const tryMapUnknown: {
686
743
  <A, B>(f: (a: A) => B): <E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<B, E | unknown, R, I>
687
744
  <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
- }))
745
+ } = /*#__PURE__*/ dual(
746
+ 2,
747
+ <A, E, R, I extends Input, B>(self: Parser<A, E, R, I>, f: (a: A) => B): Parser<B, unknown, R, I> =>
748
+ tryMap(self, (a) => {
749
+ try {
750
+ return Result.succeed(f(a))
751
+ } catch (e) {
752
+ if (Stack.isStackOverflow(e)) throw e
753
+ return Result.fail(e)
754
+ }
755
+ })
756
+ )
696
757
 
697
758
  /**
698
759
  * Transforms the output of a parser with a function returning an `Option`;
@@ -705,21 +766,25 @@ export const tryMapUnknown: {
705
766
  export const filterMap: {
706
767
  <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
768
  <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
- })
769
+ } = /*#__PURE__*/ dual(
770
+ 2,
771
+ <A, E, R, I extends Input, B>(self: Parser<A, E, R, I>, f: (a: A) => Option.Option<B>): Parser<B, E, R, I> => {
772
+ const step = self.step
773
+ return described(
774
+ (state) => {
775
+ const start = state.pos
776
+ const a = step(state)
777
+ if (a === Fail) return Fail
778
+ const o = f(a)
779
+ if (Option.isSome(o)) return o.value
780
+ state.pos = start
781
+ return state.backtrack("Verify")
782
+ },
783
+ self.name,
784
+ { _tag: "FilterMap", self, f }
785
+ )
786
+ }
787
+ )
723
788
 
724
789
  /**
725
790
  * Keeps the output of a parser only if it satisfies a predicate, otherwise
@@ -735,16 +800,20 @@ export const filter: {
735
800
  <A>(predicate: (a: NoInfer<A>) => boolean): <E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<A, E, R, I>
736
801
  <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
802
  <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) => {
803
+ } = /*#__PURE__*/ dual(2, <A, E, R, I extends Input>(self: Parser<A, E, R, I>, predicate: (a: A) => boolean) => {
739
804
  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 })
805
+ return described<A, E, R, I>(
806
+ (state) => {
807
+ const start = state.pos
808
+ const a = step(state)
809
+ if (a === Fail) return Fail
810
+ if (predicate(a)) return a
811
+ state.pos = start
812
+ return state.backtrack("Verify")
813
+ },
814
+ self.name,
815
+ { _tag: "Filter", self, predicate }
816
+ )
748
817
  })
749
818
 
750
819
  /**
@@ -773,21 +842,24 @@ export const filterOrFail: {
773
842
  predicate: (a: A) => boolean,
774
843
  orFailWith: (a: A) => E2
775
844
  ): 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
- })
845
+ } = /*#__PURE__*/ dual(
846
+ 3,
847
+ <A, E, R, I extends Input, E2>(self: Parser<A, E, R, I>, predicate: (a: A) => boolean, orFailWith: (a: A) => E2) => {
848
+ const step = self.step
849
+ return described<A, E | E2, R, I>(
850
+ (state) => {
851
+ const start = state.pos
852
+ const a = step(state)
853
+ if (a === Fail) return Fail
854
+ if (predicate(a)) return a
855
+ state.pos = start
856
+ return state.failCause("Backtrack", "Verify", orFailWith(a))
857
+ },
858
+ self.name,
859
+ { _tag: "Filter", self, predicate }
860
+ )
861
+ }
862
+ )
791
863
 
792
864
  // -----------------------------------------------------------------------------
793
865
  // Consumed input
@@ -802,10 +874,14 @@ export const filterOrFail: {
802
874
  */
803
875
  export const taken = <A, E, R, I extends Input>(self: Parser<A, E, R, I>): Parser<Slice<I>, E, R, I> => {
804
876
  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 })
877
+ return described(
878
+ (state) => {
879
+ const start = state.pos
880
+ return step(state) === Fail ? Fail : state.slice(start, state.pos)
881
+ },
882
+ self.name,
883
+ { _tag: "Taken", self, encoding: undefined }
884
+ )
809
885
  }
810
886
 
811
887
  /**
@@ -819,11 +895,15 @@ export const withTaken = <A, E, R, I extends Input>(
819
895
  self: Parser<A, E, R, I>
820
896
  ): Parser<[output: A, taken: Slice<I>], E, R, I> => {
821
897
  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 })
898
+ return described(
899
+ (state) => {
900
+ const start = state.pos
901
+ const a = step(state)
902
+ return a === Fail ? Fail : [a, state.slice(start, state.pos)]
903
+ },
904
+ self.name,
905
+ { _tag: "WithTaken", self }
906
+ )
827
907
  }
828
908
 
829
909
  /**
@@ -835,10 +915,14 @@ export const withTaken = <A, E, R, I extends Input>(
835
915
  */
836
916
  export const span = <A, E, R, I extends Input>(self: Parser<A, E, R, I>): Parser<Span, E, R, I> => {
837
917
  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 })
918
+ return described(
919
+ (state) => {
920
+ const start = state.pos
921
+ return step(state) === Fail ? Fail : { start, end: state.pos }
922
+ },
923
+ self.name,
924
+ { _tag: "Span", self }
925
+ )
842
926
  }
843
927
 
844
928
  /**
@@ -848,13 +932,19 @@ export const span = <A, E, R, I extends Input>(self: Parser<A, E, R, I>): Parser
848
932
  * @since 0.1.0
849
933
  * @category consumed input
850
934
  */
851
- export const withSpan = <A, E, R, I extends Input>(self: Parser<A, E, R, I>): Parser<[output: A, span: Span], E, R, I> => {
935
+ export const withSpan = <A, E, R, I extends Input>(
936
+ self: Parser<A, E, R, I>
937
+ ): Parser<[output: A, span: Span], E, R, I> => {
852
938
  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 })
939
+ return described(
940
+ (state) => {
941
+ const start = state.pos
942
+ const a = step(state)
943
+ return a === Fail ? Fail : [a, { start, end: state.pos }]
944
+ },
945
+ self.name,
946
+ { _tag: "WithSpan", self }
947
+ )
858
948
  }
859
949
 
860
950
  // -----------------------------------------------------------------------------
@@ -867,11 +957,15 @@ const changeMode = <A, E, R, I extends Input>(
867
957
  to: ErrMode
868
958
  ): Parser<A, E, R, I> => {
869
959
  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 })
960
+ return described(
961
+ (state) => {
962
+ const a = step(state)
963
+ if (a === Fail && state.mode === from) state.mode = to
964
+ return a
965
+ },
966
+ self.name,
967
+ { _tag: "Mode", self, from, to }
968
+ )
875
969
  }
876
970
 
877
971
  /**
@@ -890,8 +984,29 @@ const changeMode = <A, E, R, I extends Input>(
890
984
  * @since 0.1.0
891
985
  * @category error management
892
986
  */
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")
987
+ export const cut = <A, E, R, I extends Input>(self: Parser<A, E, R, I>): Parser<A, E, R, I> => {
988
+ const step = self.step
989
+ return described(
990
+ (state) => {
991
+ // A committed failure is reported where it happened (winnow's
992
+ // `cut_err`): only failures recorded inside `self` can outrank it as the
993
+ // furthest failure, not ones from abandoned branches or lookaheads before
994
+ // the commit.
995
+ const deepest = state.deepest
996
+ state.deepest = undefined
997
+ const a = step(state)
998
+ if (a === Fail && state.mode !== "Incomplete") {
999
+ state.mode = "Cut"
1000
+ return a
1001
+ }
1002
+ const inner = state.deepest as Failure | undefined
1003
+ if (deepest !== undefined && (inner === undefined || deepest.offset > inner.offset)) state.deepest = deepest
1004
+ return a
1005
+ },
1006
+ self.name,
1007
+ { _tag: "Mode", self, from: "Backtrack", to: "Cut" }
1008
+ )
1009
+ }
895
1010
 
896
1011
  /**
897
1012
  * Turns unrecoverable failures back into recoverable ones (winnow's
@@ -912,15 +1027,19 @@ export const backtrack = <A, E, R, I extends Input>(self: Parser<A, E, R, I>): P
912
1027
  */
913
1028
  export const complete = <A, E, R, I extends Input>(self: Parser<A, E, R, I>): Parser<A, E, R, I> => {
914
1029
  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" })
1030
+ return described(
1031
+ (state) => {
1032
+ const start = state.pos
1033
+ const a = step(state)
1034
+ if (a === Fail && state.mode === "Incomplete") {
1035
+ state.pos = start
1036
+ return state.backtrack("Complete")
1037
+ }
1038
+ return a
1039
+ },
1040
+ self.name,
1041
+ { _tag: "Mode", self, from: "Incomplete", to: "Backtrack" }
1042
+ )
924
1043
  }
925
1044
 
926
1045
  /**
@@ -934,25 +1053,22 @@ export const complete = <A, E, R, I extends Input>(self: Parser<A, E, R, I>): Pa
934
1053
  export const context: {
935
1054
  (label: string): <A, E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<A, E, R, I>
936
1055
  <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> => {
1056
+ } = /*#__PURE__*/ dual(2, <A, E, R, I extends Input>(self: Parser<A, E, R, I>, label: string): Parser<A, E, R, I> => {
938
1057
  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 })
1058
+ return described(
1059
+ (state) => {
1060
+ const a = step(state)
1061
+ if (a === Fail && state.mode !== "Incomplete") {
1062
+ const f = state.failure
1063
+ state.replaceFailure(
1064
+ new Failure(f.offset, f.kind, f.expected, [...f.context, label], f.hasCause, f.cause, f.message, f.needed)
1065
+ )
1066
+ }
1067
+ return a
1068
+ },
1069
+ self.name ?? label,
1070
+ { _tag: "Context", self, label }
1071
+ )
956
1072
  })
957
1073
 
958
1074
  /**
@@ -967,22 +1083,31 @@ export const context: {
967
1083
  export const expected: {
968
1084
  (description: string): <A, E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<A, E, R, I>
969
1085
  <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
- })
1086
+ } = /*#__PURE__*/ dual(
1087
+ 2,
1088
+ <A, E, R, I extends Input>(self: Parser<A, E, R, I>, description: string): Parser<A, E, R, I> => {
1089
+ const step = self.step
1090
+ const desc = [description]
1091
+ return described(
1092
+ (state) => {
1093
+ const start = state.pos
1094
+ const hintOffset = state.hintOffset
1095
+ const hintExpected = state.hintExpected
1096
+ const a = step(state)
1097
+ if (a === Fail && state.failure.offset === start) {
1098
+ const f = state.failure
1099
+ const expected = hintOffset === start ? mergeExpected(hintExpected, desc) : desc
1100
+ state.replaceFailure(
1101
+ new Failure(f.offset, f.kind, expected, f.context, f.hasCause, f.cause, f.message, f.needed)
1102
+ )
1103
+ }
1104
+ return a
1105
+ },
1106
+ description,
1107
+ { _tag: "Expected", self, description }
1108
+ )
1109
+ }
1110
+ )
986
1111
 
987
1112
  /**
988
1113
  * Transforms the user error (cause) of a parser's failures.
@@ -993,17 +1118,26 @@ export const expected: {
993
1118
  export const mapError: {
994
1119
  <E, E2>(f: (e: E) => E2): <A, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<A, E2, R, I>
995
1120
  <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
- })
1121
+ } = /*#__PURE__*/ dual(
1122
+ 2,
1123
+ <A, E, R, I extends Input, E2>(self: Parser<A, E, R, I>, f: (e: E) => E2): Parser<A, E2, R, I> => {
1124
+ const step = self.step
1125
+ return described(
1126
+ (state) => {
1127
+ const a = step(state)
1128
+ if (a === Fail && state.failure.hasCause) {
1129
+ const x = state.failure
1130
+ state.replaceFailure(
1131
+ new Failure(x.offset, x.kind, x.expected, x.context, true, f(x.cause as E), x.message, x.needed)
1132
+ )
1133
+ }
1134
+ return a
1135
+ },
1136
+ self.name,
1137
+ { _tag: "MapError", self }
1138
+ )
1139
+ }
1140
+ )
1007
1141
 
1008
1142
  /**
1009
1143
  * Replaces any failure of a parser with the given user error, keeping the
@@ -1015,18 +1149,25 @@ export const mapError: {
1015
1149
  export const orFail: {
1016
1150
  <E2>(error: () => E2): <A, E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<A, E2, R, I>
1017
1151
  <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
- })
1152
+ } = /*#__PURE__*/ dual(
1153
+ 2,
1154
+ <A, E, R, I extends Input, E2>(self: Parser<A, E, R, I>, error: () => E2): Parser<A, E2, R, I> => {
1155
+ const step = self.step
1156
+ return described(
1157
+ (state) => {
1158
+ const start = state.pos
1159
+ const a = step(state)
1160
+ if (a === Fail && state.mode !== "Incomplete") {
1161
+ const x = state.failure
1162
+ state.replaceFailure(new Failure(start, x.kind, [], x.context, true, error(), undefined, 0))
1163
+ }
1164
+ return a
1165
+ },
1166
+ self.name,
1167
+ { _tag: "OrFail", self }
1168
+ )
1169
+ }
1170
+ )
1030
1171
 
1031
1172
  /**
1032
1173
  * If the parser fails recoverably, tries `that` from the same position.
@@ -1043,10 +1184,13 @@ export const orElse: {
1043
1184
  self: Parser<A, E, R, I>,
1044
1185
  that: () => Parser<B, E2, R2, I2>
1045
1186
  ): 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)))
1187
+ } = /*#__PURE__*/ dual(
1188
+ 2,
1189
+ <A, E, R, I extends Input, B, E2, R2, I2 extends Input>(
1190
+ self: Parser<A, E, R, I>,
1191
+ that: () => Parser<B, E2, R2, I2>
1192
+ ): Parser<A | B, E | E2, R | R2, I & I2> => alt(self, suspend(that))
1193
+ )
1050
1194
 
1051
1195
  /**
1052
1196
  * If the parser fails recoverably, succeeds with the given value without
@@ -1058,17 +1202,24 @@ export const orElse: {
1058
1202
  export const orElseSucceed: {
1059
1203
  <B>(value: () => B): <A, E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<A | B, E, R, I>
1060
1204
  <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
- })
1205
+ } = /*#__PURE__*/ dual(
1206
+ 2,
1207
+ <A, E, R, I extends Input, B>(self: Parser<A, E, R, I>, value: () => B): Parser<A | B, E, R, I> => {
1208
+ const step = self.step
1209
+ return described(
1210
+ (state) => {
1211
+ const start = state.pos
1212
+ const a = step(state)
1213
+ if (a !== Fail) return a
1214
+ if (state.mode !== "Backtrack") return Fail
1215
+ recover(state, start)
1216
+ return value()
1217
+ },
1218
+ self.name,
1219
+ { _tag: "OrElseSucceed", self, value }
1220
+ )
1221
+ }
1222
+ )
1072
1223
 
1073
1224
  /** Rewinds after a recoverable failure, remembering it as a hint. */
1074
1225
  const recover = (state: State<any>, start: number): void => {
@@ -1093,14 +1244,18 @@ const recover = (state: State<any>, start: number): void => {
1093
1244
  */
1094
1245
  export const opt = <A, E, R, I extends Input>(self: Parser<A, E, R, I>): Parser<Option.Option<A>, E, R, I> => {
1095
1246
  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 })
1247
+ return described(
1248
+ (state) => {
1249
+ const start = state.pos
1250
+ const a = step(state)
1251
+ if (a !== Fail) return Option.some(a)
1252
+ if (state.mode !== "Backtrack") return Fail
1253
+ recover(state, start)
1254
+ return Option.none()
1255
+ },
1256
+ self.name,
1257
+ { _tag: "Opt", self }
1258
+ )
1104
1259
  }
1105
1260
 
1106
1261
  /**
@@ -1122,7 +1277,7 @@ export const optional = <A, E, R, I extends Input>(self: Parser<A, E, R, I>): Pa
1122
1277
  export const cond = <A, E, R, I extends Input>(
1123
1278
  condition: boolean,
1124
1279
  self: Parser<A, E, R, I>
1125
- ): Parser<Option.Option<A>, E, R, I> => condition ? asSome(self) : succeed(Option.none())
1280
+ ): Parser<Option.Option<A>, E, R, I> => (condition ? asSome(self) : succeed(Option.none()))
1126
1281
 
1127
1282
  /**
1128
1283
  * Runs a parser without consuming input (winnow's and nom's `peek`).
@@ -1132,18 +1287,26 @@ export const cond = <A, E, R, I extends Input>(
1132
1287
  */
1133
1288
  export const peek = <A, E, R, I extends Input>(self: Parser<A, E, R, I>): Parser<A, E, R, I> => {
1134
1289
  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 })
1290
+ return described(
1291
+ (state) => {
1292
+ const start = state.pos
1293
+ const hintOffset = state.hintOffset
1294
+ const hintExpected = state.hintExpected
1295
+ const deepest = state.deepest
1296
+ const a = step(state)
1297
+ if (a !== Fail) {
1298
+ // Failures inside a lookahead that succeeded are about input that was
1299
+ // never consumed, so they are not reported as the furthest failure
1300
+ state.pos = start
1301
+ state.hintOffset = hintOffset
1302
+ state.hintExpected = hintExpected
1303
+ state.deepest = deepest
1304
+ }
1305
+ return a
1306
+ },
1307
+ self.name,
1308
+ { _tag: "Peek", self }
1309
+ )
1147
1310
  }
1148
1311
 
1149
1312
  /**
@@ -1155,21 +1318,29 @@ export const peek = <A, E, R, I extends Input>(self: Parser<A, E, R, I>): Parser
1155
1318
  */
1156
1319
  export const not = <A, E, R, I extends Input>(self: Parser<A, E, R, I>): Parser<void, E, R, I> => {
1157
1320
  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) {
1321
+ return described(
1322
+ (state) => {
1323
+ const start = state.pos
1324
+ const hintOffset = state.hintOffset
1325
+ const hintExpected = state.hintExpected
1326
+ const deepest = state.deepest
1327
+ const a = step(state)
1328
+ if (a !== Fail) {
1329
+ // The failures inside `self` are not this parser's failure
1330
+ state.pos = start
1331
+ state.deepest = deepest
1332
+ return state.backtrack("Not")
1333
+ }
1334
+ if (state.mode !== "Backtrack") return Fail
1164
1335
  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 })
1336
+ state.hintOffset = hintOffset
1337
+ state.hintExpected = hintExpected
1338
+ state.deepest = deepest
1339
+ return undefined
1340
+ },
1341
+ self.name,
1342
+ { _tag: "Not", self }
1343
+ )
1173
1344
  }
1174
1345
 
1175
1346
  /**
@@ -1202,15 +1373,19 @@ export const seq = <const Ps extends ReadonlyArray<Parser.Any>>(
1202
1373
  > => {
1203
1374
  const steps = parsers.map((p) => p.step)
1204
1375
  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" })
1376
+ return described(
1377
+ (state: State<any>) => {
1378
+ const out = new Array(n)
1379
+ for (let i = 0; i < n; i++) {
1380
+ const a = steps[i](state)
1381
+ if (a === Fail) return Fail
1382
+ out[i] = a
1383
+ }
1384
+ return out as any
1385
+ },
1386
+ "seq",
1387
+ { _tag: "Seq", parsers, output: "tuple" }
1388
+ )
1214
1389
  }
1215
1390
 
1216
1391
  /**
@@ -1230,17 +1405,21 @@ export const struct = <const Fields extends Readonly<Record<string, Parser.Any>>
1230
1405
  Parser.InputOf<Fields[keyof Fields]>
1231
1406
  > => {
1232
1407
  const keys = Object.keys(fields)
1233
- const steps = keys.map((k) => fields[k]!.step)
1408
+ const steps = keys.map((k) => fields[k].step)
1234
1409
  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]!) })
1410
+ return described(
1411
+ (state: State<any>) => {
1412
+ const out: Record<string, unknown> = {}
1413
+ for (let i = 0; i < n; i++) {
1414
+ const a = steps[i](state)
1415
+ if (a === Fail) return Fail
1416
+ out[keys[i]] = a
1417
+ }
1418
+ return out as any
1419
+ },
1420
+ "struct",
1421
+ { _tag: "Struct", keys, parsers: keys.map((k) => fields[k]) }
1422
+ )
1244
1423
  }
1245
1424
 
1246
1425
  /**
@@ -1257,10 +1436,13 @@ export const zip: {
1257
1436
  self: Parser<A, E, R, I>,
1258
1437
  that: Parser<B, E2, R2, I2>
1259
1438
  ): 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]))
1439
+ } = /*#__PURE__*/ dual(
1440
+ 2,
1441
+ <A, E, R, I extends Input, B, E2, R2, I2 extends Input>(
1442
+ self: Parser<A, E, R, I>,
1443
+ that: Parser<B, E2, R2, I2>
1444
+ ): Parser<[A, B], E | E2, R | R2, I & I2> => zipWith(self, that, (a, b) => [a, b])
1445
+ )
1264
1446
 
1265
1447
  /**
1266
1448
  * Runs two parsers in sequence and combines their outputs.
@@ -1278,21 +1460,28 @@ export const zipWith: {
1278
1460
  that: Parser<B, E2, R2, I2>,
1279
1461
  f: (a: A, b: B) => C
1280
1462
  ): 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
- })
1463
+ } = /*#__PURE__*/ dual(
1464
+ 3,
1465
+ <A, E, R, I extends Input, B, E2, R2, I2 extends Input, C>(
1466
+ self: Parser<A, E, R, I>,
1467
+ that: Parser<B, E2, R2, I2>,
1468
+ f: (a: A, b: B) => C
1469
+ ): Parser<C, E | E2, R | R2, I & I2> => {
1470
+ const s1 = self.step
1471
+ const s2 = that.step
1472
+ return described(
1473
+ (state) => {
1474
+ const a = s1(state)
1475
+ if (a === Fail) return Fail
1476
+ const b = s2(state)
1477
+ if (b === Fail) return Fail
1478
+ return f(a, b)
1479
+ },
1480
+ undefined,
1481
+ { _tag: "ZipWith", self, that, f }
1482
+ )
1483
+ }
1484
+ )
1296
1485
 
1297
1486
  /**
1298
1487
  * Runs two parsers in sequence, keeping the output of the first.
@@ -1308,10 +1497,13 @@ export const zipLeft: {
1308
1497
  self: Parser<A, E, R, I>,
1309
1498
  that: Parser<B, E2, R2, I2>
1310
1499
  ): 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))
1500
+ } = /*#__PURE__*/ dual(
1501
+ 2,
1502
+ <A, E, R, I extends Input, B, E2, R2, I2 extends Input>(
1503
+ self: Parser<A, E, R, I>,
1504
+ that: Parser<B, E2, R2, I2>
1505
+ ): Parser<A, E | E2, R | R2, I & I2> => terminated(self, that)
1506
+ )
1315
1507
 
1316
1508
  /**
1317
1509
  * Runs two parsers in sequence, keeping the output of the second.
@@ -1327,10 +1519,13 @@ export const zipRight: {
1327
1519
  self: Parser<A, E, R, I>,
1328
1520
  that: Parser<B, E2, R2, I2>
1329
1521
  ): 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))
1522
+ } = /*#__PURE__*/ dual(
1523
+ 2,
1524
+ <A, E, R, I extends Input, B, E2, R2, I2 extends Input>(
1525
+ self: Parser<A, E, R, I>,
1526
+ that: Parser<B, E2, R2, I2>
1527
+ ): Parser<B, E | E2, R | R2, I & I2> => preceded(self, that)
1528
+ )
1334
1529
 
1335
1530
  /**
1336
1531
  * Runs `prefix` then `parser`, keeping the output of `parser` (winnow's and
@@ -1345,7 +1540,7 @@ export const preceded = <A1, E1, R1, I1 extends Input, A2, E2, R2, I2 extends In
1345
1540
  ): Parser<A2, E1 | E2, R1 | R2, I1 & I2> => {
1346
1541
  const s1 = prefix.step
1347
1542
  const s2 = parser.step
1348
- return described((state) => s1(state) === Fail ? Fail : s2(state), parser.name, {
1543
+ return described((state) => (s1(state) === Fail ? Fail : s2(state)), parser.name, {
1349
1544
  _tag: "Seq",
1350
1545
  parsers: [prefix, parser],
1351
1546
  output: 1
@@ -1365,11 +1560,15 @@ export const terminated = <A1, E1, R1, I1 extends Input, A2, E2, R2, I2 extends
1365
1560
  ): Parser<A1, E1 | E2, R1 | R2, I1 & I2> => {
1366
1561
  const s1 = parser.step
1367
1562
  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 })
1563
+ return described(
1564
+ (state) => {
1565
+ const a = s1(state)
1566
+ if (a === Fail) return Fail
1567
+ return s2(state) === Fail ? Fail : a
1568
+ },
1569
+ parser.name,
1570
+ { _tag: "Seq", parsers: [parser, suffix], output: 0 }
1571
+ )
1373
1572
  }
1374
1573
 
1375
1574
  /**
@@ -1379,20 +1578,7 @@ export const terminated = <A1, E1, R1, I1 extends Input, A2, E2, R2, I2 extends
1379
1578
  * @since 0.1.0
1380
1579
  * @category sequencing
1381
1580
  */
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
- >(
1581
+ export const delimited = <A1, E1, R1, I1 extends Input, A2, E2, R2, I2 extends Input, A3, E3, R3, I3 extends Input>(
1396
1582
  open: Parser<A1, E1, R1, I1>,
1397
1583
  parser: Parser<A2, E2, R2, I2>,
1398
1584
  close: Parser<A3, E3, R3, I3>
@@ -1400,12 +1586,16 @@ export const delimited = <
1400
1586
  const s1 = open.step
1401
1587
  const s2 = parser.step
1402
1588
  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 })
1589
+ return described(
1590
+ (state) => {
1591
+ if (s1(state) === Fail) return Fail
1592
+ const a = s2(state)
1593
+ if (a === Fail) return Fail
1594
+ return s3(state) === Fail ? Fail : a
1595
+ },
1596
+ parser.name,
1597
+ { _tag: "Seq", parsers: [open, parser, close], output: 1 }
1598
+ )
1409
1599
  }
1410
1600
 
1411
1601
  /**
@@ -1415,20 +1605,7 @@ export const delimited = <
1415
1605
  * @since 0.1.0
1416
1606
  * @category sequencing
1417
1607
  */
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
- >(
1608
+ export const separatedPair = <A1, E1, R1, I1 extends Input, A2, E2, R2, I2 extends Input, A3, E3, R3, I3 extends Input>(
1432
1609
  first: Parser<A1, E1, R1, I1>,
1433
1610
  separator: Parser<A2, E2, R2, I2>,
1434
1611
  second: Parser<A3, E3, R3, I3>
@@ -1436,13 +1613,17 @@ export const separatedPair = <
1436
1613
  const s1 = first.step
1437
1614
  const s2 = separator.step
1438
1615
  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] })
1616
+ return described(
1617
+ (state) => {
1618
+ const a = s1(state)
1619
+ if (a === Fail) return Fail
1620
+ if (s2(state) === Fail) return Fail
1621
+ const b = s3(state)
1622
+ return b === Fail ? Fail : [a, b]
1623
+ },
1624
+ undefined,
1625
+ { _tag: "Seq", parsers: [first, separator, second], output: [0, 2] }
1626
+ )
1446
1627
  }
1447
1628
 
1448
1629
  /**
@@ -1461,6 +1642,23 @@ export const separatedPair = <
1461
1642
  * })
1462
1643
  * ```
1463
1644
  *
1645
+ * The body runs on every parse, so parsers created inside it, like
1646
+ * `Token.literal("=")` above, are rebuilt on every run. On hot paths, build
1647
+ * them once outside the body:
1648
+ *
1649
+ * ```ts
1650
+ * import { Ascii, Parser, Token } from "@thomasfosterau/effect-parse"
1651
+ *
1652
+ * const equals = Token.literal("=")
1653
+ *
1654
+ * const keyValue = Parser.gen(function*() {
1655
+ * const key = yield* Ascii.alpha1
1656
+ * yield* equals
1657
+ * const value = yield* Ascii.decInt
1658
+ * return [key, value] as const
1659
+ * })
1660
+ * ```
1661
+ *
1464
1662
  * @since 0.1.0
1465
1663
  * @category sequencing
1466
1664
  */
@@ -1498,7 +1696,7 @@ export const gen = <Eff extends Parser.Any, AEff>(
1498
1696
  * @since 0.1.0
1499
1697
  * @category do notation
1500
1698
  */
1501
- export const Do: Parser<{}, never, never, Input> = succeed({})
1699
+ export const Do: Parser<Record<never, never>, never, never, Input> = /*#__PURE__*/ succeed({})
1502
1700
 
1503
1701
  /**
1504
1702
  * Binds the output of a parser to a field of the Do record.
@@ -1518,8 +1716,9 @@ export const bind: {
1518
1716
  name: Exclude<N, keyof A>,
1519
1717
  f: (a: NoInfer<A>) => Parser<B, E2, R2, I2>
1520
1718
  ): 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 }))))
1719
+ } = /*#__PURE__*/ dual(3, (self: Parser.Any, name: string, f: (a: any) => Parser.Any): Parser.Any =>
1720
+ flatMap(self, (a) => map(f(a), (b) => ({ ...a, [name]: b })))
1721
+ )
1523
1722
 
1524
1723
  /**
1525
1724
  * Wraps the output of a parser in a record with a single field.
@@ -1530,7 +1729,7 @@ export const bind: {
1530
1729
  export const bindTo: {
1531
1730
  <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
1731
  <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 })))
1732
+ } = /*#__PURE__*/ dual(2, (self: Parser.Any, name: string): Parser.Any => map(self, (a) => ({ [name]: a })))
1534
1733
 
1535
1734
  const let_: {
1536
1735
  <N extends string, A extends object, B>(
@@ -1542,8 +1741,9 @@ const let_: {
1542
1741
  name: Exclude<N, keyof A>,
1543
1742
  f: (a: NoInfer<A>) => B
1544
1743
  ): 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) })))
1744
+ } = /*#__PURE__*/ dual(3, (self: Parser.Any, name: string, f: (a: any) => unknown): Parser.Any =>
1745
+ map(self, (a) => ({ ...a, [name]: f(a) }))
1746
+ )
1547
1747
 
1548
1748
  export {
1549
1749
  /**
@@ -1582,22 +1782,56 @@ export const alt = <const Ps extends ReadonlyArray<Parser.Any>>(
1582
1782
  const steps = parsers.map((p) => p.step)
1583
1783
  const n = steps.length
1584
1784
  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
1785
+ if (n === 1) return parsers[0]
1786
+ return described(
1787
+ (state: State<any>) => {
1788
+ const start = state.pos
1789
+ // The branches' failures merged left to right, as `mergeFailures` would,
1790
+ // except that the last two failures tied with `failure` wait in `tie1`
1791
+ // and `tie2` and are merged only when needed: when a third tie arrives,
1792
+ // when a succeeding branch stops where they failed (for the hint), or
1793
+ // when the merge is read from the state after `failTies`. An `alt` whose
1794
+ // later branch consumes input discards them unmerged.
1795
+ let failure: Failure | undefined
1796
+ let tie1: Failure | undefined
1797
+ let tie2: Failure | undefined
1798
+ for (let i = 0; i < n; i++) {
1799
+ const a = steps[i](state)
1800
+ if (a !== Fail) {
1801
+ if (failure !== undefined && failure.offset === state.pos) {
1802
+ let expected = failure.expected
1803
+ if (tie1 !== undefined) expected = mergeExpected(expected, tie1.expected)
1804
+ if (tie2 !== undefined) expected = mergeExpected(expected, tie2.expected)
1805
+ state.setHint(failure.offset, expected)
1806
+ }
1807
+ return a
1808
+ }
1809
+ if (state.mode !== "Backtrack") return Fail
1810
+ state.pos = start
1811
+ // The branch's failure, whose own ties (from a nested `alt`) can be taken over unmerged
1812
+ const head = state.failureHead
1813
+ if (failure === undefined || head.offset > failure.offset) {
1814
+ failure = head
1815
+ tie1 = state.failureTie1
1816
+ tie2 = state.failureTie2
1817
+ } else if (head.offset === failure.offset) {
1818
+ const f = state.failure
1819
+ if (tie1 === undefined) tie1 = f
1820
+ else if (tie2 === undefined) tie2 = f
1821
+ else {
1822
+ failure = mergeTiedFailures(failure, tie1, mergeExpected(failure.expected, tie1.expected))
1823
+ tie1 = tie2
1824
+ tie2 = f
1825
+ }
1826
+ }
1594
1827
  }
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 })
1828
+ // `failure` is set: there are at least two alternatives, and each one that fails sets it
1829
+ if (failure === undefined) return state.failWith("Backtrack", state.failure)
1830
+ return tie1 === undefined ? state.failWith("Backtrack", failure) : state.failTies(failure, tie1, tie2)
1831
+ },
1832
+ "alt",
1833
+ { _tag: "Alt", parsers }
1834
+ )
1601
1835
  }
1602
1836
 
1603
1837
  /**
@@ -1609,6 +1843,11 @@ export const alt = <const Ps extends ReadonlyArray<Parser.Any>>(
1609
1843
  * an optional `otherwise` parser for unlisted keys, like winnow's `_ =>`
1610
1844
  * arm), or as a function returning a parser (or `undefined` for no match).
1611
1845
  *
1846
+ * Prefer a record where the keys are known. Compiled code (see the
1847
+ * `Compiler` module) switches on the key and runs every case compiled; the
1848
+ * parser a function returns always runs interpreted, and one the function
1849
+ * builds (`(c) => Parser.cut(p)`) is rebuilt on every run.
1850
+ *
1612
1851
  * @example
1613
1852
  * ```ts
1614
1853
  * import { Ascii, Parser, Token } from "@thomasfosterau/effect-parse"
@@ -1656,26 +1895,31 @@ export const dispatch: {
1656
1895
  cases: ((key: any) => Parser.Any | undefined) | Record<PropertyKey, Parser.Any>,
1657
1896
  otherwise?: Parser.Any
1658
1897
  ) => {
1659
- const choose = typeof cases === "function" ? cases : (key: PropertyKey) =>
1660
- Object.prototype.hasOwnProperty.call(cases, key) ? cases[key] : otherwise
1898
+ const choose = Predicate.isFunction(cases)
1899
+ ? cases
1900
+ : (key: PropertyKey) => (Object.prototype.hasOwnProperty.call(cases, key) ? cases[key] : otherwise)
1661
1901
  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")
1902
+ return described(
1903
+ (state: State<any>) => {
1904
+ const start = state.pos
1905
+ const key = step(state)
1906
+ if (key === Fail) return Fail
1907
+ const parser = choose(key)
1908
+ if (parser === undefined) {
1909
+ state.pos = start
1910
+ return state.backtrack("Dispatch")
1911
+ }
1912
+ return parser.step(state)
1913
+ },
1914
+ "dispatch",
1915
+ {
1916
+ _tag: "Dispatch",
1917
+ selector,
1918
+ cases: Predicate.isFunction(cases) ? undefined : cases,
1919
+ otherwise: Predicate.isFunction(cases) ? undefined : otherwise,
1920
+ choose
1670
1921
  }
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
- })
1922
+ )
1679
1923
  }
1680
1924
 
1681
1925
  /**
@@ -1697,16 +1941,18 @@ export const permutation = <const Ps extends ReadonlyArray<Parser.Any>>(
1697
1941
  const steps = parsers.map((p) => p.step)
1698
1942
  const n = steps.length
1699
1943
  return make((state: State<any>) => {
1700
- const out = new Array(n)
1944
+ // A round's failures, merged only if no parser matches in it (#44)
1945
+ const ties = new TiedFailures()
1701
1946
  const done = new Array<boolean>(n).fill(false)
1947
+ const out = new Array(n)
1702
1948
  let remaining = n
1703
1949
  while (remaining > 0) {
1704
- let failure: Failure | undefined
1950
+ ties.clear()
1705
1951
  let matched = false
1706
1952
  for (let i = 0; i < n; i++) {
1707
1953
  if (done[i]) continue
1708
1954
  const start = state.pos
1709
- const a = steps[i]!(state)
1955
+ const a = steps[i](state)
1710
1956
  if (a !== Fail) {
1711
1957
  out[i] = a
1712
1958
  done[i] = true
@@ -1715,10 +1961,11 @@ export const permutation = <const Ps extends ReadonlyArray<Parser.Any>>(
1715
1961
  break
1716
1962
  }
1717
1963
  if (state.mode !== "Backtrack") return Fail
1718
- failure = failure === undefined ? state.failure : mergeFailures(failure, state.failure)
1719
1964
  state.pos = start
1965
+ ties.add(state)
1720
1966
  }
1721
- if (!matched) return state.failWith("Backtrack", failure!)
1967
+ // Some parser is not done yet, and each one that fails is folded in
1968
+ if (!matched) return ties.fail(state)
1722
1969
  }
1723
1970
  return out as any
1724
1971
  }, "permutation")
@@ -1730,7 +1977,7 @@ export const permutation = <const Ps extends ReadonlyArray<Parser.Any>>(
1730
1977
 
1731
1978
  const normalizeRange = (range: Range | undefined): [min: number, max: number] => {
1732
1979
  if (range === undefined) return [0, Infinity]
1733
- if (typeof range === "number") return [range, range]
1980
+ if (Predicate.isNumber(range)) return [range, range]
1734
1981
  const min = range.min ?? 0
1735
1982
  const max = range.max ?? Infinity
1736
1983
  if (min > max) throw new RangeError(`invalid range: min (${min}) > max (${max})`)
@@ -1757,44 +2004,50 @@ const foldImpl = <A, B, E, R, I extends Input>(
1757
2004
  init: () => B,
1758
2005
  f: (acc: B, a: A) => B,
1759
2006
  name: string,
1760
- node?: Node
2007
+ node?: Node,
2008
+ cond?: (acc: B) => boolean
1761
2009
  ): Parser<B, E, R, I> => {
1762
2010
  const [min, max] = normalizeRange(range)
1763
2011
  const step = self.step
1764
2012
  const checkLoop = max === Infinity
1765
2013
  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>)
2014
+ return described(
2015
+ (state) => {
2016
+ const entry = state.pos
2017
+ let acc: B
2018
+ let count = 0
2019
+ const resumed = state.resume === undefined ? undefined : (Resume.take(state, key, entry) as FoldCheckpoint<B>)
2020
+ if (resumed instanceof Resume.Done) {
2021
+ state.pos = resumed.pos
2022
+ return resumed.value as B
2023
+ }
2024
+ if (resumed !== undefined) {
2025
+ acc = resumed.acc
2026
+ count = resumed.count
2027
+ state.pos = resumed.pos
2028
+ } else {
2029
+ acc = init()
2030
+ }
2031
+ for (; count < max; count++) {
2032
+ if (cond !== undefined && count >= min && !cond(acc)) break
2033
+ const start = state.pos
2034
+ const a = step(state)
2035
+ if (a === Fail) {
2036
+ if (state.mode === "Incomplete" && state.resume !== undefined) {
2037
+ Resume.save(state, key, entry, { acc, count, pos: start } satisfies FoldCheckpoint<B>)
2038
+ }
2039
+ if (state.mode !== "Backtrack" || count < min) return Fail
2040
+ recover(state, start)
2041
+ return Resume.done(state, key, entry, resumed !== undefined, acc)
1788
2042
  }
1789
- if (state.mode !== "Backtrack" || count < min) return Fail
1790
- recover(state, start)
1791
- return Resume.done(state, key, entry, resumed !== undefined, acc)
2043
+ if (checkLoop && state.pos === start) return assertConsumes(state, name)
2044
+ acc = f(acc, a)
1792
2045
  }
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) })
2046
+ return Resume.done(state, key, entry, resumed !== undefined, acc)
2047
+ },
2048
+ name,
2049
+ node ?? { _tag: "Fold", self, init, f, while: cond, name, ...bounds(range) }
2050
+ )
1798
2051
  }
1799
2052
 
1800
2053
  /**
@@ -1828,17 +2081,43 @@ export const repeat: {
1828
2081
  self: Parser<A, E, R, I>,
1829
2082
  range?: Rg
1830
2083
  ): 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) }))
2084
+ } = /*#__PURE__*/ dual(isParserArg, <A, E, R, I extends Input>(self: Parser<A, E, R, I>, range?: Range) =>
2085
+ foldImpl<A, Array<A>, E, R, I>(
2086
+ self,
2087
+ range,
2088
+ () => [],
2089
+ (acc, a) => {
2090
+ acc.push(a)
2091
+ return acc
2092
+ },
2093
+ "repeat",
2094
+ { _tag: "Repeat", self, ...bounds(range) }
2095
+ )
2096
+ )
1836
2097
 
1837
2098
  /**
1838
2099
  * Applies a parser repeatedly, folding the outputs into an accumulator
1839
2100
  * (winnow's `repeat(..).fold(..)`, nom's `fold_many0`/`fold_many1`/
1840
2101
  * `fold_many_m_n`).
1841
2102
  *
2103
+ * With `while`, the repetition also stops, successfully and without
2104
+ * consuming more input, as soon as the predicate is false of the
2105
+ * accumulator. It is checked before each element once `range.min` elements
2106
+ * have been folded, so `min` still holds.
2107
+ *
2108
+ * @example
2109
+ * ```ts
2110
+ * import { Parser, Token } from "@thomasfosterau/effect-parse"
2111
+ *
2112
+ * // Keeps the first two digits, leaving the rest unparsed
2113
+ * const two = Parser.fold(Token.oneOf("0123456789"), {
2114
+ * init: () => "",
2115
+ * f: (acc, d) => acc + d,
2116
+ * while: (acc) => acc.length < 2
2117
+ * })
2118
+ * Parser.parsePeek(two, "1234") // Result.succeed(["34", "12"])
2119
+ * ```
2120
+ *
1842
2121
  * @since 0.1.0
1843
2122
  * @category repetition
1844
2123
  */
@@ -1847,17 +2126,29 @@ export const fold: {
1847
2126
  readonly init: () => B
1848
2127
  readonly f: (acc: B, a: A) => B
1849
2128
  readonly range?: Range | undefined
2129
+ readonly while?: ((acc: B) => boolean) | undefined
1850
2130
  }): <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"))
2131
+ <A, E, R, I extends Input, B>(
2132
+ self: Parser<A, E, R, I>,
2133
+ options: {
2134
+ readonly init: () => B
2135
+ readonly f: (acc: B, a: A) => B
2136
+ readonly range?: Range | undefined
2137
+ readonly while?: ((acc: B) => boolean) | undefined
2138
+ }
2139
+ ): Parser<B, E, R, I>
2140
+ } = /*#__PURE__*/ dual(
2141
+ 2,
2142
+ <A, E, R, I extends Input, B>(
2143
+ self: Parser<A, E, R, I>,
2144
+ options: {
2145
+ readonly init: () => B
2146
+ readonly f: (acc: B, a: A) => B
2147
+ readonly range?: Range | undefined
2148
+ readonly while?: ((acc: B) => boolean) | undefined
2149
+ }
2150
+ ): Parser<B, E, R, I> => foldImpl(self, options.range, options.init, options.f, "fold", undefined, options.while)
2151
+ )
1861
2152
 
1862
2153
  /**
1863
2154
  * Applies `self` repeatedly until `end` succeeds, returning the collected
@@ -1871,47 +2162,58 @@ export const repeatTill: {
1871
2162
  <B, E2, R2, I2 extends Input, const Rg extends Range = { readonly min: 0 }>(
1872
2163
  end: Parser<B, E2, R2, I2>,
1873
2164
  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>
2165
+ ): <A, E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<[Repeated<A, Rg>, B], E | E2, R | R2, I & I2>
1877
2166
  <A, E, R, I extends Input, B, E2, R2, I2 extends Input, const Rg extends Range = { readonly min: 0 }>(
1878
2167
  self: Parser<A, E, R, I>,
1879
2168
  end: Parser<B, E2, R2, I2>,
1880
2169
  range?: Rg
1881
2170
  ): 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))
2171
+ } = /*#__PURE__*/ dual(
2172
+ isTwoParserArgs,
2173
+ <A, E, R, I extends Input, B, E2, R2, I2 extends Input>(
2174
+ self: Parser<A, E, R, I>,
2175
+ end: Parser<B, E2, R2, I2>,
2176
+ range?: Range
2177
+ ): Parser<[Array<A>, B], E | E2, R | R2, I & I2> => {
2178
+ const [min, max] = normalizeRange(range)
2179
+ const step = self.step
2180
+ const endStep = end.step
2181
+ return described(
2182
+ (state) => {
2183
+ const acc: Array<A> = []
2184
+ while (true) {
2185
+ const start = state.pos
2186
+ let endFailure: Failure | undefined
2187
+ if (acc.length >= min) {
2188
+ const b = endStep(state)
2189
+ if (b !== Fail) return [acc, b]
2190
+ if (state.mode !== "Backtrack") return Fail
2191
+ endFailure = state.failure
2192
+ state.pos = start
2193
+ if (acc.length >= max) return Fail
2194
+ }
2195
+ const a = step(state)
2196
+ if (a === Fail) {
2197
+ if (endFailure !== undefined && state.mode === "Backtrack") {
2198
+ state.failWith("Backtrack", mergeFailures(endFailure, state.failure))
2199
+ }
2200
+ return Fail
2201
+ }
2202
+ if (state.pos === start) return assertConsumes(state, "repeatTill")
2203
+ acc.push(a)
1907
2204
  }
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
- })
2205
+ },
2206
+ "repeatTill",
2207
+ { _tag: "RepeatTill", self, end, ...bounds(range) }
2208
+ )
2209
+ }
2210
+ )
2211
+
2212
+ /** How far `separated` got: the elements so far, and where the next separator starts. */
2213
+ interface SeparatedCheckpoint<A> {
2214
+ readonly acc: Array<A>
2215
+ readonly pos: number
2216
+ }
1915
2217
 
1916
2218
  /**
1917
2219
  * Applies `self` repeatedly, separated by `separator`, collecting the
@@ -1929,12 +2231,6 @@ export const repeatTill: {
1929
2231
  * @since 0.1.0
1930
2232
  * @category repetition
1931
2233
  */
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
2234
  export const separated: {
1939
2235
  <S, E2, R2, I2 extends Input, const Rg extends Range = { readonly min: 0 }>(
1940
2236
  separator: Parser<S, E2, R2, I2>,
@@ -1945,64 +2241,72 @@ export const separated: {
1945
2241
  separator: Parser<S, E2, R2, I2>,
1946
2242
  range?: Rg
1947
2243
  ): 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>)
2244
+ } = /*#__PURE__*/ dual(
2245
+ isTwoParserArgs,
2246
+ <A, E, R, I extends Input, S, E2, R2, I2 extends Input>(
2247
+ self: Parser<A, E, R, I>,
2248
+ separator: Parser<S, E2, R2, I2>,
2249
+ range?: Range
2250
+ ): Parser<Array<A>, E | E2, R | R2, I & I2> => {
2251
+ const [min, max] = normalizeRange(range)
2252
+ const step = self.step
2253
+ const sepStep = separator.step
2254
+ const checkLoop = max === Infinity
2255
+ const key = {}
2256
+ return described(
2257
+ (state) => {
2258
+ const entry = state.pos
2259
+ let acc: Array<A>
2260
+ const resumed =
2261
+ state.resume === undefined ? undefined : (Resume.take(state, key, entry) as SeparatedCheckpoint<A>)
2262
+ if (resumed instanceof Resume.Done) {
2263
+ state.pos = resumed.pos
2264
+ return resumed.value as Array<A>
1986
2265
  }
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>)
2266
+ if (resumed !== undefined) {
2267
+ acc = resumed.acc
2268
+ state.pos = resumed.pos
2269
+ } else {
2270
+ acc = []
2271
+ if (max === 0) return acc
2272
+ const start = state.pos
2273
+ const first = step(state)
2274
+ if (first === Fail) {
2275
+ if (state.mode !== "Backtrack" || min > 0) return Fail
2276
+ recover(state, start)
2277
+ return acc
2278
+ }
2279
+ acc.push(first)
2280
+ }
2281
+ while (acc.length < max) {
2282
+ const start = state.pos
2283
+ if (sepStep(state) === Fail) {
2284
+ if (state.mode === "Incomplete" && state.resume !== undefined) {
2285
+ Resume.save(state, key, entry, { acc, pos: start } satisfies SeparatedCheckpoint<A>)
2286
+ }
2287
+ if (state.mode !== "Backtrack" || acc.length < min) return Fail
2288
+ recover(state, start)
2289
+ return Resume.done(state, key, entry, resumed !== undefined, acc)
2290
+ }
2291
+ if (checkLoop && state.pos === start) return assertConsumes(state, "separated")
2292
+ const a = step(state)
2293
+ if (a === Fail) {
2294
+ if (state.mode === "Incomplete" && state.resume !== undefined) {
2295
+ Resume.save(state, key, entry, { acc, pos: start } satisfies SeparatedCheckpoint<A>)
2296
+ }
2297
+ if (state.mode !== "Backtrack" || acc.length < min) return Fail
2298
+ state.pos = start
2299
+ return Resume.done(state, key, entry, resumed !== undefined, acc)
2300
+ }
2301
+ acc.push(a)
1996
2302
  }
1997
- if (state.mode !== "Backtrack" || acc.length < min) return Fail
1998
- state.pos = start
1999
2303
  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
- })
2304
+ },
2305
+ "separated",
2306
+ { _tag: "Separated", self, separator, ...bounds(range) }
2307
+ )
2308
+ }
2309
+ )
2006
2310
 
2007
2311
  /**
2008
2312
  * Parses one or more `self` separated by `separator`, folding them from the
@@ -2033,41 +2337,45 @@ export const separatedFoldl1 = <A, E, R, I extends Input, S, E2, R2, I2 extends
2033
2337
  const step = self.step
2034
2338
  const sepStep = separator.step
2035
2339
  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)
2340
+ return described(
2341
+ (state) => {
2342
+ const entry = state.pos
2343
+ const resumed = state.resume === undefined ? undefined : (Resume.take(state, key, entry) as FoldCheckpoint<A>)
2344
+ let acc: A | Fail
2345
+ if (resumed instanceof Resume.Done) {
2346
+ state.pos = resumed.pos
2347
+ return resumed.value as A
2059
2348
  }
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)
2349
+ if (resumed !== undefined) {
2350
+ acc = resumed.acc
2351
+ state.pos = resumed.pos
2352
+ } else {
2353
+ acc = step(state)
2354
+ if (acc === Fail) return Fail
2067
2355
  }
2068
- acc = op(acc, s, a)
2069
- }
2070
- }, "separatedFoldl1", { _tag: "SeparatedFold", self, separator, op, right: false })
2356
+ while (true) {
2357
+ const start = state.pos
2358
+ const s = sepStep(state)
2359
+ if (s === Fail) {
2360
+ if (state.mode === "Incomplete" && state.resume !== undefined) saveFold(state, key, entry, acc, start)
2361
+ if (state.mode !== "Backtrack") return Fail
2362
+ recover(state, start)
2363
+ return Resume.done(state, key, entry, resumed !== undefined, acc as A)
2364
+ }
2365
+ if (state.pos === start) return assertConsumes(state, "separatedFoldl1")
2366
+ const a = step(state)
2367
+ if (a === Fail) {
2368
+ if (state.mode === "Incomplete" && state.resume !== undefined) saveFold(state, key, entry, acc, start)
2369
+ if (state.mode !== "Backtrack") return Fail
2370
+ state.pos = start
2371
+ return Resume.done(state, key, entry, resumed !== undefined, acc as A)
2372
+ }
2373
+ acc = op(acc, s, a)
2374
+ }
2375
+ },
2376
+ "separatedFoldl1",
2377
+ { _tag: "SeparatedFold", self, separator, op, right: false }
2378
+ )
2071
2379
  }
2072
2380
 
2073
2381
  /**
@@ -2086,35 +2394,39 @@ export const separatedFoldr1 = <A, E, R, I extends Input, S, E2, R2, I2 extends
2086
2394
  ): Parser<A, E | E2, R | R2, I & I2> => {
2087
2395
  const step = self.step
2088
2396
  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
2397
+ return described(
2398
+ (state) => {
2399
+ const first = step(state)
2400
+ if (first === Fail) return Fail
2401
+ const values: Array<A> = [first]
2402
+ const seps: Array<S> = []
2403
+ while (true) {
2404
+ const start = state.pos
2405
+ const s = sepStep(state)
2406
+ if (s === Fail) {
2407
+ if (state.mode !== "Backtrack") return Fail
2408
+ recover(state, start)
2409
+ break
2410
+ }
2411
+ if (state.pos === start) return assertConsumes(state, "separatedFoldr1")
2412
+ const a = step(state)
2413
+ if (a === Fail) {
2414
+ if (state.mode !== "Backtrack") return Fail
2415
+ state.pos = start
2416
+ break
2417
+ }
2418
+ seps.push(s)
2419
+ values.push(a)
2101
2420
  }
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
2421
+ let acc = values[values.length - 1] as A
2422
+ for (let i = seps.length - 1; i >= 0; i--) {
2423
+ acc = op(values[i] as A, seps[i] as S, acc)
2108
2424
  }
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 })
2425
+ return acc
2426
+ },
2427
+ "separatedFoldr1",
2428
+ { _tag: "SeparatedFold", self, separator, op, right: true }
2429
+ )
2118
2430
  }
2119
2431
 
2120
2432
  // -----------------------------------------------------------------------------
@@ -2173,22 +2485,29 @@ export const provideService: {
2173
2485
  key: Context.Key<Id, S>,
2174
2486
  service: NoInfer<S>
2175
2487
  ): 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
- })
2488
+ } = /*#__PURE__*/ dual(
2489
+ 3,
2490
+ <A, E, R, I extends Input, Id, S>(
2491
+ self: Parser<A, E, R, I>,
2492
+ key: Context.Key<Id, S>,
2493
+ service: S
2494
+ ): Parser<A, E, Exclude<R, Id>, I> => {
2495
+ const step = self.step
2496
+ return described(
2497
+ (state) => {
2498
+ const prev = state.context
2499
+ state.context = Context.add(prev, key, service) as Context.Context<never>
2500
+ try {
2501
+ return step(state)
2502
+ } finally {
2503
+ state.context = prev
2504
+ }
2505
+ },
2506
+ self.name,
2507
+ { _tag: "Provide", self }
2508
+ )
2509
+ }
2510
+ )
2192
2511
 
2193
2512
  /**
2194
2513
  * Provides a context of services to a parser.
@@ -2204,21 +2523,28 @@ export const provide: {
2204
2523
  self: Parser<A, E, R, I>,
2205
2524
  context: Context.Context<R2>
2206
2525
  ): 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
- })
2526
+ } = /*#__PURE__*/ dual(
2527
+ 2,
2528
+ <A, E, R, I extends Input, R2>(
2529
+ self: Parser<A, E, R, I>,
2530
+ context: Context.Context<R2>
2531
+ ): Parser<A, E, Exclude<R, R2>, I> => {
2532
+ const step = self.step
2533
+ return described(
2534
+ (state) => {
2535
+ const prev = state.context
2536
+ state.context = Context.merge(prev, context) as Context.Context<never>
2537
+ try {
2538
+ return step(state)
2539
+ } finally {
2540
+ state.context = prev
2541
+ }
2542
+ },
2543
+ self.name,
2544
+ { _tag: "Provide", self }
2545
+ )
2546
+ }
2547
+ )
2222
2548
 
2223
2549
  // -----------------------------------------------------------------------------
2224
2550
  // Error recovery
@@ -2242,25 +2568,33 @@ export const resumeAfter: {
2242
2568
  self: Parser<A, E, R, I>,
2243
2569
  recover: Parser<B, E2, R2, I2>
2244
2570
  ): 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
- })
2571
+ } = /*#__PURE__*/ dual(
2572
+ 2,
2573
+ <A, E, R, I extends Input, B, E2, R2, I2 extends Input>(
2574
+ self: Parser<A, E, R, I>,
2575
+ recover: Parser<B, E2, R2, I2>
2576
+ ): Parser<Option.Option<A>, E | E2, R | R2, I & I2> => {
2577
+ const step = self.step
2578
+ const recoverStep = recover.step
2579
+ return described(
2580
+ (state) => {
2581
+ const start = state.pos
2582
+ const a = step(state)
2583
+ if (a !== Fail) return Option.some(a)
2584
+ if (state.recovered === undefined || state.mode === "Incomplete") return Fail
2585
+ const failure = state.failure
2586
+ const mode = state.mode
2587
+ state.pos = start
2588
+ if (recoverStep(state) === Fail) return state.failWith(mode, failure)
2589
+ state.recovered.push(failure)
2590
+ state.syntax?.skipped(start, failure, mode)
2591
+ return Option.none()
2592
+ },
2593
+ self.name,
2594
+ { _tag: "ResumeAfter", self, recover }
2595
+ )
2596
+ }
2597
+ )
2264
2598
 
2265
2599
  /**
2266
2600
  * Error recovery: if the parser fails, record the failure, skip input with
@@ -2280,26 +2614,34 @@ export const retryAfter: {
2280
2614
  self: Parser<A, E, R, I>,
2281
2615
  recover: Parser<B, E2, R2, I2>
2282
2616
  ): 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
- })
2617
+ } = /*#__PURE__*/ dual(
2618
+ 2,
2619
+ <A, E, R, I extends Input, B, E2, R2, I2 extends Input>(
2620
+ self: Parser<A, E, R, I>,
2621
+ recover: Parser<B, E2, R2, I2>
2622
+ ): Parser<A, E | E2, R | R2, I & I2> => {
2623
+ const step = self.step
2624
+ const recoverStep = recover.step
2625
+ return described(
2626
+ (state) => {
2627
+ while (true) {
2628
+ const start = state.pos
2629
+ const a = step(state)
2630
+ if (a !== Fail) return a
2631
+ if (state.recovered === undefined || state.mode === "Incomplete") return Fail
2632
+ const failure = state.failure
2633
+ const mode = state.mode
2634
+ state.pos = start
2635
+ if (recoverStep(state) === Fail || state.pos === start) return state.failWith(mode, failure)
2636
+ state.recovered.push(failure)
2637
+ state.syntax?.skipped(start, failure, mode)
2638
+ }
2639
+ },
2640
+ self.name,
2641
+ { _tag: "RetryAfter", self, recover }
2642
+ )
2643
+ }
2644
+ )
2303
2645
 
2304
2646
  // -----------------------------------------------------------------------------
2305
2647
  // Debugging
@@ -2317,33 +2659,37 @@ export const retryAfter: {
2317
2659
  export const trace: {
2318
2660
  (name: string): <A, E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<A, E, R, I>
2319
2661
  <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> => {
2662
+ } = /*#__PURE__*/ dual(2, <A, E, R, I extends Input>(self: Parser<A, E, R, I>, name: string): Parser<A, E, R, I> => {
2321
2663
  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 })
2664
+ return described(
2665
+ (state) => {
2666
+ const tracer = state.tracer
2667
+ if (tracer === undefined) return step(state)
2668
+ const start = state.pos
2669
+ const depth = state.depth
2670
+ tracer({ _tag: "Enter", name, depth, offset: start, state })
2671
+ state.depth = depth + 1
2672
+ const a = step(state)
2673
+ state.depth = depth
2674
+ tracer({
2675
+ _tag: "Exit",
2676
+ name,
2677
+ depth,
2678
+ offset: start,
2679
+ endOffset: state.pos,
2680
+ result: a === Fail ? state.mode : "Ok",
2681
+ state
2682
+ })
2683
+ return a
2684
+ },
2685
+ name,
2686
+ { _tag: "Trace", self, name }
2687
+ )
2342
2688
  })
2343
2689
 
2344
2690
  const preview = (state: State<any>, offset: number): string => {
2345
2691
  const input = state.input
2346
- if (typeof input === "string") {
2692
+ if (Predicate.isString(input)) {
2347
2693
  const s = input.slice(offset, offset + 24)
2348
2694
  return JSON.stringify(s) + (offset + 24 < input.length ? "…" : "∅")
2349
2695
  }
@@ -2371,88 +2717,28 @@ export const consoleTracer = (event: TraceEvent): void => {
2371
2717
  }
2372
2718
 
2373
2719
  // -----------------------------------------------------------------------------
2374
- // Compilation
2720
+ // Compiled parsers
2375
2721
  // -----------------------------------------------------------------------------
2376
2722
 
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
2723
  /** Returned by {@link runCompiled} when there is no compiled form to run. */
2444
- const NotCompiled: unique symbol = Symbol("NotCompiled")
2724
+ const NotCompiled: unique symbol = /*#__PURE__*/ Symbol("NotCompiled")
2445
2725
 
2446
2726
  /**
2447
2727
  * Runs the compiled form of `self`, if it has one: returns its value, or
2448
2728
  * `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 => {
2729
+ * input), in which case the state must be thrown away. `resumable` selects
2730
+ * the build that handles partial input.
2731
+ */
2732
+ const runCompiled = <I extends Input>(
2733
+ self: Parser.Any,
2734
+ state: State<I>,
2735
+ whole: boolean,
2736
+ resumable = false
2737
+ ): unknown => {
2452
2738
  if (state.tracer !== undefined || state.recovered !== undefined) return NotCompiled
2453
- const step = Compiler.stepFor(self, state)
2739
+ const step = Registry.stepFor(self, state, resumable)
2454
2740
  if (step === undefined) return NotCompiled
2455
- const a = step(state)
2741
+ const a = Stack.run(step, state)
2456
2742
  if (a === Fail || (whole && state.pos < state.end)) return Fail
2457
2743
  return a
2458
2744
  }
@@ -2473,6 +2759,19 @@ export interface ParseOptions {
2473
2759
  * {@link consoleTracer}.
2474
2760
  */
2475
2761
  readonly trace?: boolean | ((event: TraceEvent) => void) | undefined
2762
+ /**
2763
+ * Where to start parsing (default `0`): in code units for strings, bytes
2764
+ * for byte input and elements for arrays. The result is that of parsing
2765
+ * `input.slice(offset)`, but without copying the input, and every offset
2766
+ * (`parsePartial`'s `Done`, `location`, spans, `ParseError.offset` and its
2767
+ * line and column) is a position in the whole input. This is what an
2768
+ * incremental driver, such as a lexer reading one token at a time from a
2769
+ * buffer, needs: compiled parsers run compiled from any offset.
2770
+ *
2771
+ * Throws a `RangeError` unless it is an integer from `0` to the input's
2772
+ * length.
2773
+ */
2774
+ readonly offset?: number | undefined
2476
2775
  }
2477
2776
 
2478
2777
  /**
@@ -2490,7 +2789,11 @@ const makeState = <I extends Input>(
2490
2789
  options: (ParseOptions & { readonly context?: Context.Context<any> }) | undefined,
2491
2790
  partial: boolean
2492
2791
  ): State<I> => {
2493
- const state = new State(input, { partial, context: options?.context })
2792
+ const offset = options?.offset
2793
+ const state = new State(input, { partial, context: options?.context, offset })
2794
+ if (offset !== undefined && !(Number.isInteger(offset) && offset >= 0 && offset <= state.end)) {
2795
+ throw new RangeError(`Invalid offset ${offset} for an input of length ${state.end}`)
2796
+ }
2494
2797
  const t = options?.trace
2495
2798
  if (t !== undefined && t !== false) state.tracer = t === true ? consoleTracer : t
2496
2799
  return state
@@ -2517,7 +2820,7 @@ const runComplete = <A, E, R, I extends Input>(
2517
2820
  self: Parser<A, E, R, I>,
2518
2821
  state: State<I>
2519
2822
  ): Result.Result<A, ParseError.ParseError<E>> => {
2520
- const a = self.step(state)
2823
+ const a = Stack.run(self.step, state)
2521
2824
  if (a === Fail) return Result.fail(toError(state))
2522
2825
  if (state.pos < state.end) {
2523
2826
  state.backtrack("Eof", expectedEof)
@@ -2567,7 +2870,11 @@ export const parse: {
2567
2870
  */
2568
2871
  export const parseSync: {
2569
2872
  <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
2873
+ <A, E, R, I extends Input>(
2874
+ self: Parser<A, E, R, I>,
2875
+ input: NoInfer<Source<I>>,
2876
+ options: ParseOptionsWithContext<R>
2877
+ ): A
2571
2878
  } = <A, E, R, I extends Input>(
2572
2879
  self: Parser<A, E, R, I>,
2573
2880
  input: I | Source<I>,
@@ -2583,6 +2890,10 @@ export const parseSync: {
2583
2890
  * input along with the output, nom-style (winnow's `parse_peek`, nom's
2584
2891
  * `IResult`).
2585
2892
  *
2893
+ * The parser ended at offset `input.length - remaining.length`, which is
2894
+ * how a caller running from an `offset` (see {@link ParseOptions}) finds
2895
+ * where to continue.
2896
+ *
2586
2897
  * @since 0.1.0
2587
2898
  * @category running
2588
2899
  */
@@ -2608,7 +2919,7 @@ export const parsePeek: {
2608
2919
  return Result.succeed([state.slice(state.pos, state.end), compiled as A])
2609
2920
  }
2610
2921
  if (compiled === Fail) state = makeState(input, options, false)
2611
- const a = self.step(state)
2922
+ const a = Stack.run(self.step, state)
2612
2923
  if (a === Fail) return Result.fail(toError(state))
2613
2924
  return Result.succeed([state.slice(state.pos, state.end), a])
2614
2925
  }
@@ -2633,7 +2944,14 @@ export type PartialResult<A> =
2633
2944
  * of failing or succeeding early.
2634
2945
  *
2635
2946
  * The parser does not have to consume the whole input; the returned
2636
- * `offset` says how much was consumed.
2947
+ * `offset` says where it stopped. It is a position in the whole input, so
2948
+ * with the `offset` option (see {@link ParseOptions}) it is where the next
2949
+ * parse starts.
2950
+ *
2951
+ * A parser compiled with the `Compiler` module runs compiled, with a build
2952
+ * that handles partial input. When it fails or needs more input, it runs again
2953
+ * interpreted, so `Incomplete`'s `needed` and every `ParseError` are the
2954
+ * interpreter's.
2637
2955
  *
2638
2956
  * @example
2639
2957
  * ```ts
@@ -2664,8 +2982,14 @@ export const parsePartial: {
2664
2982
  input: I | Source<I>,
2665
2983
  options?: ParseOptions & { readonly context?: Context.Context<R> }
2666
2984
  ): Result.Result<PartialResult<A>, ParseError.ParseError<E>> => {
2667
- const state = makeState(input, options, true)
2668
- const a = self.step(state)
2985
+ let state = makeState(input, options, true)
2986
+ const compiled = runCompiled(self, state, false, true)
2987
+ if (compiled !== NotCompiled && compiled !== Fail) {
2988
+ return Result.succeed({ _tag: "Done", value: compiled as A, offset: state.pos })
2989
+ }
2990
+ // Re-run interpreted for `needed` and the diagnostics
2991
+ if (compiled === Fail) state = makeState(input, options, true)
2992
+ const a = Stack.run(self.step, state)
2669
2993
  if (a !== Fail) return Result.succeed({ _tag: "Done", value: a, offset: state.pos })
2670
2994
  if (state.mode === "Incomplete") {
2671
2995
  const needed = state.failure.needed
@@ -2697,11 +3021,87 @@ export const parseEffect = <A, E, R, I extends Input>(
2697
3021
  input: NoInfer<Source<I>>,
2698
3022
  options?: ParseOptions
2699
3023
  ): Effect.Effect<A, ParseError.ParseError<E>, R> =>
2700
- Effect.flatMap(
2701
- Effect.context<R>(),
2702
- (context) => Effect.fromResult(parseComplete(self, input, { ...options, context }))
3024
+ Effect.flatMap(Effect.context<R>(), (context) =>
3025
+ Effect.fromResult(parseComplete(self, input, { ...options, context }))
2703
3026
  )
2704
3027
 
3028
+ /**
3029
+ * Runs a parser on a state you own, from `state.pos`, and returns its output
3030
+ * or {@link Fail}: like calling `self.step(state)`, but using the parser's
3031
+ * compiled form when it has one (see the `Compiler` module). This is the
3032
+ * runner for drivers that make many small runs over one buffer, such as a
3033
+ * lexer reading one token at a time: keep one `Input.State` and
3034
+ * `reset` it (`Input.State.reset`) before each run, and no run allocates a
3035
+ * state, a `Result` or a slice.
3036
+ *
3037
+ * On success the cursor is where the parser stopped. On failure the state
3038
+ * holds the interpreter's failure (`mode`, `failure`, and what
3039
+ * `reportedFailure()` returns): a compiled run that fails is thrown away and
3040
+ * the parser's step runs again from the same position. A partial state
3041
+ * (`partial: true`) runs the compiled build that handles partial input, so
3042
+ * `Incomplete` is reported as the step would report it. Under a tracer,
3043
+ * with recovery on or inside a `Syntax` parse, the step runs interpreted.
3044
+ *
3045
+ * A driver that only needs to know *that* a parser failed (it tries
3046
+ * another, or skips a character) can pass `{ diagnostics: false }` to skip
3047
+ * the interpreted re-run; see {@link RunOptions}.
3048
+ *
3049
+ * Compiled code records no hints or furthest failure when it succeeds, so
3050
+ * a later failure on the same state can list fewer expectations than one
3051
+ * after interpreted runs would: reset the state between runs (as above) and
3052
+ * its errors are the ones {@link parse} reports. Deep nesting fails with an
3053
+ * unrecoverable `TooDeep` failure instead of throwing, as in the other
3054
+ * runners.
3055
+ *
3056
+ * @example
3057
+ * ```ts
3058
+ * import { Ascii, Compiler, Input, Parser, Token } from "@thomasfosterau/effect-parse"
3059
+ *
3060
+ * const token = Compiler.jit(Parser.preceded(Ascii.space0, Parser.alt(Ascii.alpha1, Token.oneOf("+-"))))
3061
+ *
3062
+ * const tokens = (text: string): Array<string> => {
3063
+ * const state = new Input.State(text)
3064
+ * const out: Array<string> = []
3065
+ * while (state.pos < state.end) {
3066
+ * const t = Parser.run(token, state.reset(state.pos))
3067
+ * if (t === Input.Fail) break
3068
+ * out.push(t)
3069
+ * }
3070
+ * return out
3071
+ * }
3072
+ *
3073
+ * tokens("a + b") // ["a", "+", "b"]
3074
+ * ```
3075
+ *
3076
+ * @since 0.2.0
3077
+ * @category running
3078
+ */
3079
+ export const run = <A, E, R, I extends Input>(
3080
+ self: Parser<A, E, R, I>,
3081
+ state: State<I>,
3082
+ options?: RunOptions
3083
+ ): A | Fail => Run.runOn(self, self.step, state, options?.diagnostics !== false)
3084
+
3085
+ /**
3086
+ * Options for {@link run}.
3087
+ *
3088
+ * @since 0.2.0
3089
+ * @category running
3090
+ */
3091
+ export interface RunOptions {
3092
+ /**
3093
+ * Whether a failure records the interpreter's diagnostics (default
3094
+ * `true`). With `false`, a compiled run that fails is not run again
3095
+ * interpreted: the state's `mode` (`Backtrack`, `Cut` or `Incomplete`)
3096
+ * is set and the cursor is back where the run started, but `failure`,
3097
+ * hints and the furthest failure are left as they were. For drivers that
3098
+ * try a parser and move on when it fails, without reporting why, this
3099
+ * halves the cost of each failure. Parsers that run interpreted record
3100
+ * their diagnostics either way.
3101
+ */
3102
+ readonly diagnostics?: boolean | undefined
3103
+ }
3104
+
2705
3105
  /**
2706
3106
  * The outcome of {@link parseRecoverable}.
2707
3107
  *