@thomasfosterau/effect-parse 0.4.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/CHANGELOG.md +202 -0
  2. package/README.md +56 -14
  3. package/dist/Ascii.d.ts +11 -4
  4. package/dist/Ascii.d.ts.map +1 -1
  5. package/dist/Ascii.js +12 -4
  6. package/dist/Ascii.js.map +1 -1
  7. package/dist/Binary.d.ts +5 -2
  8. package/dist/Binary.d.ts.map +1 -1
  9. package/dist/Binary.js +83 -37
  10. package/dist/Binary.js.map +1 -1
  11. package/dist/Bits.d.ts.map +1 -1
  12. package/dist/Bits.js +11 -4
  13. package/dist/Bits.js.map +1 -1
  14. package/dist/Compiler.d.ts +74 -2
  15. package/dist/Compiler.d.ts.map +1 -1
  16. package/dist/Compiler.js +78 -1
  17. package/dist/Compiler.js.map +1 -1
  18. package/dist/Expression.d.ts.map +1 -1
  19. package/dist/Expression.js +86 -74
  20. package/dist/Expression.js.map +1 -1
  21. package/dist/Input.d.ts +56 -5
  22. package/dist/Input.d.ts.map +1 -1
  23. package/dist/Input.js +70 -1
  24. package/dist/Input.js.map +1 -1
  25. package/dist/Nom.d.ts +5 -15
  26. package/dist/Nom.d.ts.map +1 -1
  27. package/dist/Nom.js.map +1 -1
  28. package/dist/ParseError.d.ts +69 -11
  29. package/dist/ParseError.d.ts.map +1 -1
  30. package/dist/ParseError.js +129 -28
  31. package/dist/ParseError.js.map +1 -1
  32. package/dist/Parser.d.ts +375 -29
  33. package/dist/Parser.d.ts.map +1 -1
  34. package/dist/Parser.js +394 -37
  35. package/dist/Parser.js.map +1 -1
  36. package/dist/ParserSchema.d.ts.map +1 -1
  37. package/dist/ParserSchema.js +2 -3
  38. package/dist/ParserSchema.js.map +1 -1
  39. package/dist/ParserStream.d.ts +122 -14
  40. package/dist/ParserStream.d.ts.map +1 -1
  41. package/dist/ParserStream.js +293 -62
  42. package/dist/ParserStream.js.map +1 -1
  43. package/dist/Syntax.d.ts +23 -5
  44. package/dist/Syntax.d.ts.map +1 -1
  45. package/dist/Syntax.js +1 -1
  46. package/dist/Syntax.js.map +1 -1
  47. package/dist/Text.d.ts.map +1 -1
  48. package/dist/Text.js +21 -15
  49. package/dist/Text.js.map +1 -1
  50. package/dist/Token.d.ts +65 -11
  51. package/dist/Token.d.ts.map +1 -1
  52. package/dist/Token.js +73 -26
  53. package/dist/Token.js.map +1 -1
  54. package/dist/internal/compiler/closure.d.ts +1 -1
  55. package/dist/internal/compiler/closure.d.ts.map +1 -1
  56. package/dist/internal/compiler/closure.js +263 -113
  57. package/dist/internal/compiler/closure.js.map +1 -1
  58. package/dist/internal/compiler/entries.d.ts +3 -1
  59. package/dist/internal/compiler/entries.d.ts.map +1 -1
  60. package/dist/internal/compiler/entries.js +3 -2
  61. package/dist/internal/compiler/entries.js.map +1 -1
  62. package/dist/internal/compiler/first.d.ts.map +1 -1
  63. package/dist/internal/compiler/first.js +9 -2
  64. package/dist/internal/compiler/first.js.map +1 -1
  65. package/dist/internal/compiler/graph.d.ts +39 -0
  66. package/dist/internal/compiler/graph.d.ts.map +1 -0
  67. package/dist/internal/compiler/graph.js +78 -0
  68. package/dist/internal/compiler/graph.js.map +1 -0
  69. package/dist/internal/compiler/jit.d.ts +5 -0
  70. package/dist/internal/compiler/jit.d.ts.map +1 -1
  71. package/dist/internal/compiler/jit.js +208 -106
  72. package/dist/internal/compiler/jit.js.map +1 -1
  73. package/dist/internal/compiler/registry.d.ts +11 -3
  74. package/dist/internal/compiler/registry.d.ts.map +1 -1
  75. package/dist/internal/compiler/registry.js.map +1 -1
  76. package/dist/internal/compiler/search.d.ts +32 -0
  77. package/dist/internal/compiler/search.d.ts.map +1 -0
  78. package/dist/internal/compiler/search.js +68 -0
  79. package/dist/internal/compiler/search.js.map +1 -0
  80. package/dist/internal/compiler/sets.d.ts.map +1 -1
  81. package/dist/internal/compiler/sets.js +1 -1
  82. package/dist/internal/compiler/sets.js.map +1 -1
  83. package/dist/internal/compiler/wasm.d.ts +8 -0
  84. package/dist/internal/compiler/wasm.d.ts.map +1 -0
  85. package/dist/internal/compiler/wasm.js +2840 -0
  86. package/dist/internal/compiler/wasm.js.map +1 -0
  87. package/dist/internal/compiler/wasmAsm.d.ts +199 -0
  88. package/dist/internal/compiler/wasmAsm.d.ts.map +1 -0
  89. package/dist/internal/compiler/wasmAsm.js +427 -0
  90. package/dist/internal/compiler/wasmAsm.js.map +1 -0
  91. package/dist/internal/entries.d.ts +3 -1
  92. package/dist/internal/entries.d.ts.map +1 -1
  93. package/dist/internal/entries.js.map +1 -1
  94. package/dist/internal/node.d.ts +77 -3
  95. package/dist/internal/node.d.ts.map +1 -1
  96. package/dist/internal/node.js +54 -10
  97. package/dist/internal/node.js.map +1 -1
  98. package/dist/internal/numbers.d.ts.map +1 -1
  99. package/dist/internal/numbers.js.map +1 -1
  100. package/dist/internal/run.d.ts +14 -0
  101. package/dist/internal/run.d.ts.map +1 -1
  102. package/dist/internal/run.js +53 -11
  103. package/dist/internal/run.js.map +1 -1
  104. package/dist/internal/stack.d.ts +14 -0
  105. package/dist/internal/stack.d.ts.map +1 -1
  106. package/dist/internal/stack.js +24 -2
  107. package/dist/internal/stack.js.map +1 -1
  108. package/dist/internal/syntax.d.ts +4 -4
  109. package/dist/internal/syntax.d.ts.map +1 -1
  110. package/dist/internal/syntax.js +18 -10
  111. package/dist/internal/syntax.js.map +1 -1
  112. package/dist/internal/text.d.ts +32 -0
  113. package/dist/internal/text.d.ts.map +1 -1
  114. package/dist/internal/text.js +68 -14
  115. package/dist/internal/text.js.map +1 -1
  116. package/dist/internal/tokens.d.ts +20 -0
  117. package/dist/internal/tokens.d.ts.map +1 -1
  118. package/dist/internal/tokens.js +72 -39
  119. package/dist/internal/tokens.js.map +1 -1
  120. package/dist/internal/tuple.d.ts +6 -0
  121. package/dist/internal/tuple.d.ts.map +1 -0
  122. package/dist/internal/tuple.js +170 -0
  123. package/dist/internal/tuple.js.map +1 -0
  124. package/package.json +18 -10
  125. package/src/Ascii.ts +47 -12
  126. package/src/Binary.ts +174 -73
  127. package/src/Bits.ts +16 -6
  128. package/src/Compiler.ts +101 -10
  129. package/src/Expression.ts +94 -81
  130. package/src/Input.ts +99 -7
  131. package/src/Nom.ts +15 -5
  132. package/src/ParseError.ts +209 -52
  133. package/src/Parser.ts +684 -143
  134. package/src/ParserSchema.ts +1 -2
  135. package/src/ParserStream.ts +361 -68
  136. package/src/Syntax.ts +60 -36
  137. package/src/Text.ts +32 -27
  138. package/src/Token.ts +152 -34
  139. package/src/internal/compiler/closure.ts +371 -153
  140. package/src/internal/compiler/entries.ts +4 -2
  141. package/src/internal/compiler/first.ts +16 -0
  142. package/src/internal/compiler/graph.ts +96 -0
  143. package/src/internal/compiler/jit.ts +319 -169
  144. package/src/internal/compiler/registry.ts +10 -2
  145. package/src/internal/compiler/search.ts +68 -0
  146. package/src/internal/compiler/sets.ts +7 -3
  147. package/src/internal/compiler/wasm.ts +3276 -0
  148. package/src/internal/compiler/wasmAsm.ts +484 -0
  149. package/src/internal/entries.ts +8 -2
  150. package/src/internal/node.ts +103 -7
  151. package/src/internal/numbers.ts +3 -1
  152. package/src/internal/run.ts +73 -12
  153. package/src/internal/stack.ts +25 -1
  154. package/src/internal/syntax.ts +39 -18
  155. package/src/internal/text.ts +97 -9
  156. package/src/internal/tokens.ts +106 -14
  157. package/src/internal/tuple.ts +141 -0
package/src/Syntax.ts CHANGED
@@ -66,11 +66,15 @@ import { described, isParser } from "./Parser.js"
66
66
  // Grammar annotations
67
67
  // -----------------------------------------------------------------------------
68
68
 
69
- const syntaxNode = (self: Parser.Any, kind: string, named: boolean): Parser.Any => {
69
+ const syntaxNode = <A, E, R, I extends Input>(
70
+ self: Parser<A, E, R, I>,
71
+ kind: string,
72
+ named: boolean
73
+ ): Parser<A, E, R, I> => {
70
74
  const step = self.step
71
75
  // Identifies the nodes this parser builds, so a reparse can reuse them
72
76
  const key = new Key()
73
- return described<unknown, unknown, unknown, Input>(
77
+ return described<A, E, R, I>(
74
78
  (state) => {
75
79
  const builder = state.syntax
76
80
  return builder === undefined ? step(state) : builder.node(state, step, key, kind, named)
@@ -101,10 +105,8 @@ const syntaxNode = (self: Parser.Any, kind: string, named: boolean): Parser.Any
101
105
  export const node: {
102
106
  (kind: string): <A, E, R, I extends Input>(self: Parser<A, E, R, I>) => Parser<A, E, R, I>
103
107
  <A, E, R, I extends Input>(self: Parser<A, E, R, I>, kind: string): Parser<A, E, R, I>
104
- } = /*#__PURE__*/ dual(
105
- 2,
106
- <A, E, R, I extends Input>(self: Parser<A, E, R, I>, kind: string): Parser<A, E, R, I> =>
107
- syntaxNode(self, kind, true) as Parser<A, E, R, I>
108
+ } = /*#__PURE__*/ dual(2, <A, E, R, I extends Input>(self: Parser<A, E, R, I>, kind: string): Parser<A, E, R, I> =>
109
+ syntaxNode(self, kind, true)
108
110
  )
109
111
 
110
112
  /**
@@ -130,7 +132,7 @@ export const token: {
130
132
  } = /*#__PURE__*/ dual(
131
133
  (args) => isParser(args[0]),
132
134
  <A, E, R, I extends Input>(self: Parser<A, E, R, I>, kind?: string): Parser<A, E, R, I> =>
133
- syntaxNode(self, kind ?? defaultTokenKind(self), false) as Parser<A, E, R, I>
135
+ syntaxNode(self, kind ?? defaultTokenKind(self), false)
134
136
  )
135
137
 
136
138
  const defaultTokenKind = (self: Parser.Any): string => {
@@ -168,7 +170,7 @@ export const field: {
168
170
  return described<A, E, R, I>(
169
171
  (state) => {
170
172
  const builder = state.syntax
171
- return (builder === undefined ? step(state) : builder.field(state, step, name)) as A | typeof Fail
173
+ return builder === undefined ? step(state) : builder.field(state, step, name)
172
174
  },
173
175
  self.name,
174
176
  { _tag: "Syntax", self, kind: undefined, named: false }
@@ -346,6 +348,18 @@ export class Tree<out A, out E = never, I extends Input = string> {
346
348
  }
347
349
  }
348
350
 
351
+ /**
352
+ * What `JSON.stringify` writes for a {@link SyntaxNode}: its kind and span.
353
+ *
354
+ * @since 0.5.0
355
+ * @category models
356
+ */
357
+ export interface SyntaxNodeJson {
358
+ readonly kind: string
359
+ readonly start: number
360
+ readonly end: number
361
+ }
362
+
349
363
  /**
350
364
  * A node of a syntax tree: its kind, span and value, and its place in the
351
365
  * tree. Nodes are views built on demand; two views of the same node are
@@ -403,10 +417,11 @@ export class SyntaxNode<I extends Input = string> {
403
417
 
404
418
  /** The input the node spans. */
405
419
  get text(): Slice<I> {
406
- const input = this.tree.input as any
407
- return input instanceof Uint8Array
408
- ? (input.subarray(this.start, this.end) as any)
409
- : input.slice(this.start, this.end)
420
+ const input: Input = this.tree.input
421
+ // SAFETY: a `subarray` of a `Uint8Array`, or a `slice` of a string or array, has the input's own kind, `Slice<I>`
422
+ return (
423
+ input instanceof Uint8Array ? input.subarray(this.start, this.end) : input.slice(this.start, this.end)
424
+ ) as Slice<I>
410
425
  }
411
426
 
412
427
  /** Whether this is an `ERROR` node. */
@@ -592,7 +607,7 @@ export class SyntaxNode<I extends Input = string> {
592
607
  return out
593
608
  }
594
609
 
595
- toJSON(): unknown {
610
+ toJSON(): SyntaxNodeJson {
596
611
  return { kind: this.kind, start: this.start, end: this.end }
597
612
  }
598
613
 
@@ -723,6 +738,8 @@ const run = <A, E, I extends Input>(config: Config, input: I, previous: Previous
723
738
  state.backtrack("Eof", expectedEof)
724
739
  fatal = { failure: state.reportedFailure(), mode: "Backtrack" }
725
740
  } else {
741
+ // SAFETY: `config.inner` is the `Parser<A, ...>` given to `parse` or the parser its root `node` wraps, which returns
742
+ // the same `A` (a `reparse` reuses the tree's config)
726
743
  value = Option.some(a as A)
727
744
  }
728
745
  const green = builder.finish(config.kind, Option.getOrUndefined(value), fatal, state.pos)
@@ -730,19 +747,12 @@ const run = <A, E, I extends Input>(config: Config, input: I, previous: Previous
730
747
  }
731
748
 
732
749
  /**
733
- * Parses an input into a syntax {@link Tree}. The grammar's output is the
734
- * tree's `value`, and its {@link node}s are the tree's nodes. When the
735
- * grammar is itself a {@link node}, that node is the root; otherwise the
736
- * root is a node of kind `options.kind` (by default `"document"`).
737
- *
738
- * The parse never fails: recovered failures (see `Parser.resumeAfter`), a
739
- * fatal failure and unparsed input at the end all become `ERROR` nodes, and
740
- * are listed in `tree.errors`. The parse is interpreted, never compiled.
750
+ * The overloads of {@link parse}.
741
751
  *
742
- * @since 0.2.0
752
+ * @since 0.5.0
743
753
  * @category parsing
744
754
  */
745
- export const parse: {
755
+ export interface ParseFn {
746
756
  <A, E, I extends Input>(
747
757
  grammar: Parser<A, E, never, I>,
748
758
  input: NoInfer<Source<I>>,
@@ -753,7 +763,22 @@ export const parse: {
753
763
  input: NoInfer<Source<I>>,
754
764
  options: ParseOptionsWithContext<R>
755
765
  ): Tree<A, E, I>
756
- } = <A, E, R, I extends Input>(
766
+ }
767
+
768
+ /**
769
+ * Parses an input into a syntax {@link Tree}. The grammar's output is the
770
+ * tree's `value`, and its {@link node}s are the tree's nodes. When the
771
+ * grammar is itself a {@link node}, that node is the root; otherwise the
772
+ * root is a node of kind `options.kind` (by default `"document"`).
773
+ *
774
+ * The parse never fails: recovered failures (see `Parser.resumeAfter`), a
775
+ * fatal failure and unparsed input at the end all become `ERROR` nodes, and
776
+ * are listed in `tree.errors`. The parse is interpreted, never compiled.
777
+ *
778
+ * @since 0.2.0
779
+ * @category parsing
780
+ */
781
+ export const parse: ParseFn = <A, E, R, I extends Input>(
757
782
  grammar: Parser<A, E, R, I>,
758
783
  input: I | Source<I>,
759
784
  options?: ParseOptions & { readonly context?: Context.Context<R> }
@@ -762,11 +787,12 @@ export const parse: {
762
787
  const isRoot = Predicate.isTagged(n, "Syntax") && n.kind !== undefined && n.named
763
788
  const config: Config = {
764
789
  kind: isRoot ? n.kind : (options?.kind ?? "document"),
790
+ // SAFETY: a `Syntax` node's `self` is the parser that `node` wrapped, a parser built by this library
765
791
  inner: isRoot ? (n.self as Parser.Any) : grammar,
766
792
  lookahead: options?.lookahead ?? 0,
767
- context: options?.context as Context.Context<never> | undefined
793
+ context: options?.context
768
794
  }
769
- return run(config, fromSource(input as Input) as I, undefined)
795
+ return run(config, fromSource<I>(input), undefined)
770
796
  }
771
797
 
772
798
  /**
@@ -803,13 +829,8 @@ export const reparse = <A, E, I extends Input>(
803
829
  input: NoInfer<Source<I>>,
804
830
  edits?: Edit | ReadonlyArray<Edit>
805
831
  ): Tree<A, E, I> => {
806
- const next = fromSource(input as Input) as I
807
- const list =
808
- edits === undefined
809
- ? diffList(tree.input, next)
810
- : "start" in edits
811
- ? [edits as Edit]
812
- : (edits as ReadonlyArray<Edit>)
832
+ const next = fromSource<I>(input)
833
+ const list = edits === undefined ? diffList(tree.input, next) : "start" in edits ? [edits] : edits
813
834
  const previous: Previous = {
814
835
  root: tree.green,
815
836
  oldLength: tree.input.length,
@@ -854,9 +875,12 @@ export const replace = <A, E>(
854
875
  * @category parsing
855
876
  */
856
877
  export const diff = <I extends Input>(before: I, after: I): Edit | undefined => {
857
- const a = before as any
858
- const b = after as any
859
- const at = Predicate.isString(a) ? (s: string, i: number) => s.charCodeAt(i) : (s: any, i: number) => s[i]
878
+ const a: Input = before
879
+ const b: Input = after
880
+ // SAFETY: the string reader is chosen only when `a` is a string, and `b` has the same type `I`
881
+ const at = Predicate.isString(a)
882
+ ? (s: Input, i: number) => (s as string).charCodeAt(i)
883
+ : (s: Input, i: number) => s[i]
860
884
  const max = Math.min(a.length, b.length)
861
885
  let prefix = 0
862
886
  while (prefix < max && at(a, prefix) === at(b, prefix)) prefix++
package/src/Text.ts CHANGED
@@ -39,13 +39,14 @@
39
39
  import * as Predicate from "effect/Predicate"
40
40
  import type { Encoding } from "./Encoding.js"
41
41
  import * as Encodings from "./Encoding.js"
42
- import type { Input, State } from "./Input.js"
42
+ import type { State } from "./Input.js"
43
43
  import { Fail } from "./Input.js"
44
44
  import { escapedImpl, overflow, takeEscapedImpl, toFloat } from "./Ascii.js"
45
45
  import { codePointPredicate, compile, indexOf, matchLiteral } from "./internal/tokens.js"
46
46
  import { floatText as markFloatText } from "./internal/numbers.js"
47
47
  import * as internal from "./internal/text.js"
48
48
  import type { Node } from "./internal/node.js"
49
+ import { bounds, checkCount, controlCode } from "./internal/node.js"
49
50
  import type { ErrorKind } from "./ParseError.js"
50
51
  import type { Parser, Range } from "./Parser.js"
51
52
  import * as P from "./Parser.js"
@@ -354,9 +355,8 @@ export interface TextParsers<I extends string | Uint8Array> {
354
355
  }
355
356
 
356
357
  const normalize = (r: Range | undefined): [number, number] => {
357
- if (r === undefined) return [0, Infinity]
358
- if (Predicate.isNumber(r)) return [r, r]
359
- return [r.min ?? 0, r.max ?? Infinity]
358
+ const { max, min } = bounds(r)
359
+ return [min, max]
360
360
  }
361
361
 
362
362
  const isAsciiDigit = /*#__PURE__*/ codePointPredicate("isAsciiDigit", (c: number): boolean => c >= 48 && c <= 57, [
@@ -392,7 +392,7 @@ const expectedIdentifier = ["identifier"]
392
392
  * @category constructors
393
393
  */
394
394
  export const make = <I extends string | Uint8Array>(encoding: Encoding<I>): TextParsers<I> => {
395
- const enc = encoding as Encoding<any>
395
+ const enc = encoding
396
396
  const fast = internal.fastLimit(enc)
397
397
 
398
398
  // Each parser records its encoding on byte input (`state.encoding`), so
@@ -410,7 +410,7 @@ export const make = <I extends string | Uint8Array>(encoding: Encoding<I>): Text
410
410
  ): string | Fail => {
411
411
  const count = internal.validate(enc, state, start, end)
412
412
  if (count < 0) return backtrack(state, kind, expected, -1 - count)
413
- return enc.text(state.input, start, end)
413
+ return internal.textIn(enc, state, start, end)
414
414
  }
415
415
 
416
416
  const takeWhileText = (
@@ -438,7 +438,7 @@ export const make = <I extends string | Uint8Array>(encoding: Encoding<I>): Text
438
438
  // More matching characters would have been accepted where we stopped
439
439
  if (hint && count < max) state.setHint(offset, expected)
440
440
  state.pos = offset
441
- return enc.text(state.input, start, offset)
441
+ return internal.textIn(enc, state, start, offset)
442
442
  },
443
443
  name,
444
444
  { _tag: "TakeWhile", set, negate, min, max, encoding: enc }
@@ -471,6 +471,7 @@ export const make = <I extends string | Uint8Array>(encoding: Encoding<I>): Text
471
471
  if (state.inputKind === 1) state.encoding = enc
472
472
  if (pos >= state.end) return state.eoi("Literal", expected, 1)
473
473
  const input = state.input
474
+ // SAFETY: a `Text` parser runs on strings or `Uint8Array`s, and `inputKind` 0 is set only for a string
474
475
  if ((state.inputKind === 0 ? (input as string).charCodeAt(pos) : (input as Uint8Array)[pos]) !== unit) {
475
476
  return backtrack(state, "Literal", expected)
476
477
  }
@@ -518,7 +519,7 @@ export const make = <I extends string | Uint8Array>(encoding: Encoding<I>): Text
518
519
  pos += internal.width
519
520
  }
520
521
  state.pos = pos
521
- return enc.text(state.input, start, pos)
522
+ return internal.textIn(enc, state, start, pos)
522
523
  },
523
524
  expected[0],
524
525
  { _tag: "Literal", literal: lit, caseless: true, encoding: enc }
@@ -546,6 +547,7 @@ export const make = <I extends string | Uint8Array>(encoding: Encoding<I>): Text
546
547
  }
547
548
 
548
549
  const take = (count: number): Parser<string, never, never, I> => {
550
+ checkCount(count)
549
551
  const expected = [count === 1 ? "1 character" : `${count} characters`]
550
552
  return P.described<string, never, never, I>(
551
553
  (state: State<any>) => {
@@ -559,7 +561,7 @@ export const make = <I extends string | Uint8Array>(encoding: Encoding<I>): Text
559
561
  pos += internal.width
560
562
  }
561
563
  state.pos = pos
562
- return enc.text(state.input, start, pos)
564
+ return internal.textIn(enc, state, start, pos)
563
565
  },
564
566
  "take",
565
567
  { _tag: "Take", count, encoding: enc }
@@ -575,9 +577,9 @@ export const make = <I extends string | Uint8Array>(encoding: Encoding<I>): Text
575
577
  (state: State<any>) => {
576
578
  if (state.inputKind === 1) state.encoding = enc
577
579
  const start = state.pos
578
- let idx = indexOf(state, needle as Input, start)
580
+ let idx = indexOf(state, needle, start)
579
581
  // Multi-unit encodings: only accept matches on a character boundary
580
- while (unit > 1 && idx >= 0 && (idx - start) % unit !== 0) idx = indexOf(state, needle as Input, idx + 1)
582
+ while (unit > 1 && idx >= 0 && (idx - start) % unit !== 0) idx = indexOf(state, needle, idx + 1)
581
583
  if (idx < 0) {
582
584
  if (state.partial) return state.incomplete(0, expected)
583
585
  return backtrack(state, "TakeUntil", expected, state.end)
@@ -590,7 +592,7 @@ export const make = <I extends string | Uint8Array>(encoding: Encoding<I>): Text
590
592
  if (count < min) return backtrack(state, "TakeUntil", expected, idx)
591
593
  if (count > max) return backtrack(state, "TakeUntil", expected)
592
594
  state.pos = idx
593
- return enc.text(state.input, start, idx)
595
+ return internal.textIn(enc, state, start, idx)
594
596
  },
595
597
  "takeUntil",
596
598
  { _tag: "TakeUntil", literal: lit, min, max, encoding: enc }
@@ -607,7 +609,7 @@ export const make = <I extends string | Uint8Array>(encoding: Encoding<I>): Text
607
609
  if (internal.scanStop === internal.Truncated) return state.incomplete(1, expectedAny)
608
610
  if (internal.scanStop === internal.Invalid) return backtrack(state, "Token", expectedAny, offset)
609
611
  state.pos = offset
610
- return enc.text(state.input, start, offset)
612
+ return internal.textIn(enc, state, start, offset)
611
613
  },
612
614
  "rest",
613
615
  { _tag: "Rest", encoding: enc }
@@ -628,7 +630,7 @@ export const make = <I extends string | Uint8Array>(encoding: Encoding<I>): Text
628
630
  }
629
631
 
630
632
  const cls = (test: CharPredicate, min: 0 | 1, description: string, kind: ErrorKind, hint = true) =>
631
- takeWhileText(test as any, { min }, false, `${kind.toLowerCase()}${min}`, [description], kind, hint)
633
+ takeWhileText(test, { min }, false, `${kind.toLowerCase()}${min}`, [description], kind, hint)
632
634
 
633
635
  const identifierStart = (cp: number) => cp === 95 || isIdStart(cp)
634
636
  const identifier: Parser<string, never, never, I> = P.described<string, never, never, I>(
@@ -638,13 +640,13 @@ export const make = <I extends string | Uint8Array>(encoding: Encoding<I>): Text
638
640
  const cp = internal.next(enc, state)
639
641
  if (cp < 0) return internal.failAt(state, cp, "TakeWhile", expectedIdentifier)
640
642
  if (!identifierStart(cp)) return state.backtrack("TakeWhile", expectedIdentifier)
641
- internal.scan(enc, state, isIdContinue as any, false, Infinity, start + internal.width, fast)
643
+ internal.scan(enc, state, isIdContinue, false, Infinity, start + internal.width, fast)
642
644
  const stop = internal.scanStop
643
645
  if (state.partial && (stop === internal.End || stop === internal.Truncated)) {
644
646
  return state.incomplete(1, expectedIdentifier)
645
647
  }
646
648
  state.pos = internal.scanOffset
647
- return enc.text(state.input, start, state.pos)
649
+ return internal.textIn(enc, state, start, state.pos)
648
650
  },
649
651
  "identifier",
650
652
  { _tag: "Identifier", encoding: enc }
@@ -691,7 +693,7 @@ export const make = <I extends string | Uint8Array>(encoding: Encoding<I>): Text
691
693
  if (after !== 10) return backtrack(state, "LineEnding", expectedLineEnding, offset)
692
694
  }
693
695
  state.pos = offset
694
- return enc.text(state.input, start, offset)
696
+ return internal.textIn(enc, state, start, offset)
695
697
  },
696
698
  "tillLineEnding",
697
699
  { _tag: "TillLineEnding", encoding: enc }
@@ -718,8 +720,7 @@ export const make = <I extends string | Uint8Array>(encoding: Encoding<I>): Text
718
720
  )
719
721
  const floatText = markFloatText(taken(P.alt(caseless("nan"), P.seq(sign, unsignedFloat))).pipe(P.expected("number")))
720
722
 
721
- const matchControl = (control: string) => {
722
- const ctrl = control.codePointAt(0)
723
+ const matchControl = (ctrl: number) => {
723
724
  return (state: State<any>): boolean => {
724
725
  if (internal.next(enc, state) !== ctrl) return false
725
726
  state.pos += internal.width
@@ -778,17 +779,21 @@ export const make = <I extends string | Uint8Array>(encoding: Encoding<I>): Text
778
779
  P.named("hexUint")
779
780
  ),
780
781
  float: floatText.pipe(P.map(toFloat), P.named("float")),
781
- takeEscaped: (normal, control, escapable) =>
782
- takeEscapedImpl(
782
+ takeEscaped: (normal, control, escapable) => {
783
+ const ctrl = controlCode(control, internal.firstCodePoint)
784
+ return takeEscapedImpl(
783
785
  normal,
784
- matchControl(control),
786
+ matchControl(ctrl),
785
787
  escapable,
786
- (state, start) => enc.text(state.input, start, state.pos),
787
- internal.firstCodePoint(control),
788
+ (state, start) => internal.textIn(enc, state, start, state.pos),
789
+ ctrl,
788
790
  enc
789
- ),
790
- escaped: (normal, control, escape) =>
791
- escapedImpl(normal, matchControl(control), escape, internal.firstCodePoint(control), enc)
791
+ )
792
+ },
793
+ escaped: (normal, control, escape) => {
794
+ const ctrl = controlCode(control, internal.firstCodePoint)
795
+ return escapedImpl(normal, matchControl(ctrl), escape, ctrl, enc)
796
+ }
792
797
  }
793
798
  }
794
799