@thomasfosterau/effect-parse 0.5.0 → 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 (99) hide show
  1. package/CHANGELOG.md +202 -0
  2. package/README.md +19 -1
  3. package/dist/Ascii.d.ts.map +1 -1
  4. package/dist/Ascii.js +5 -3
  5. package/dist/Ascii.js.map +1 -1
  6. package/dist/Binary.d.ts +5 -2
  7. package/dist/Binary.d.ts.map +1 -1
  8. package/dist/Binary.js +20 -3
  9. package/dist/Binary.js.map +1 -1
  10. package/dist/Bits.d.ts.map +1 -1
  11. package/dist/Bits.js +4 -0
  12. package/dist/Bits.js.map +1 -1
  13. package/dist/Input.d.ts +21 -3
  14. package/dist/Input.d.ts.map +1 -1
  15. package/dist/Input.js +31 -4
  16. package/dist/Input.js.map +1 -1
  17. package/dist/Nom.d.ts.map +1 -1
  18. package/dist/ParseError.d.ts +69 -11
  19. package/dist/ParseError.d.ts.map +1 -1
  20. package/dist/ParseError.js +129 -28
  21. package/dist/ParseError.js.map +1 -1
  22. package/dist/Parser.d.ts +10 -4
  23. package/dist/Parser.d.ts.map +1 -1
  24. package/dist/Parser.js +10 -24
  25. package/dist/Parser.js.map +1 -1
  26. package/dist/ParserSchema.d.ts.map +1 -1
  27. package/dist/ParserSchema.js +1 -2
  28. package/dist/ParserSchema.js.map +1 -1
  29. package/dist/ParserStream.d.ts +119 -12
  30. package/dist/ParserStream.d.ts.map +1 -1
  31. package/dist/ParserStream.js +282 -55
  32. package/dist/ParserStream.js.map +1 -1
  33. package/dist/Syntax.js +1 -1
  34. package/dist/Text.d.ts.map +1 -1
  35. package/dist/Text.js +13 -7
  36. package/dist/Text.js.map +1 -1
  37. package/dist/Token.d.ts +10 -1
  38. package/dist/Token.d.ts.map +1 -1
  39. package/dist/Token.js +14 -5
  40. package/dist/Token.js.map +1 -1
  41. package/dist/internal/compiler/closure.d.ts +1 -1
  42. package/dist/internal/compiler/closure.d.ts.map +1 -1
  43. package/dist/internal/compiler/closure.js +7 -17
  44. package/dist/internal/compiler/closure.js.map +1 -1
  45. package/dist/internal/compiler/first.d.ts.map +1 -1
  46. package/dist/internal/compiler/first.js +2 -1
  47. package/dist/internal/compiler/first.js.map +1 -1
  48. package/dist/internal/compiler/graph.d.ts +23 -1
  49. package/dist/internal/compiler/graph.d.ts.map +1 -1
  50. package/dist/internal/compiler/graph.js +27 -5
  51. package/dist/internal/compiler/graph.js.map +1 -1
  52. package/dist/internal/compiler/jit.d.ts.map +1 -1
  53. package/dist/internal/compiler/jit.js +26 -13
  54. package/dist/internal/compiler/jit.js.map +1 -1
  55. package/dist/internal/compiler/registry.d.ts +1 -1
  56. package/dist/internal/compiler/wasm.d.ts.map +1 -1
  57. package/dist/internal/compiler/wasm.js +105 -34
  58. package/dist/internal/compiler/wasm.js.map +1 -1
  59. package/dist/internal/node.d.ts +19 -1
  60. package/dist/internal/node.d.ts.map +1 -1
  61. package/dist/internal/node.js +42 -8
  62. package/dist/internal/node.js.map +1 -1
  63. package/dist/internal/run.d.ts +3 -1
  64. package/dist/internal/run.d.ts.map +1 -1
  65. package/dist/internal/run.js +4 -2
  66. package/dist/internal/run.js.map +1 -1
  67. package/dist/internal/stack.d.ts +8 -0
  68. package/dist/internal/stack.d.ts.map +1 -1
  69. package/dist/internal/stack.js +17 -1
  70. package/dist/internal/stack.js.map +1 -1
  71. package/dist/internal/tokens.d.ts +10 -3
  72. package/dist/internal/tokens.d.ts.map +1 -1
  73. package/dist/internal/tokens.js +22 -9
  74. package/dist/internal/tokens.js.map +1 -1
  75. package/dist/internal/tuple.d.ts +6 -0
  76. package/dist/internal/tuple.d.ts.map +1 -0
  77. package/dist/internal/tuple.js +170 -0
  78. package/dist/internal/tuple.js.map +1 -0
  79. package/package.json +17 -10
  80. package/src/Ascii.ts +5 -3
  81. package/src/Binary.ts +24 -3
  82. package/src/Bits.ts +4 -0
  83. package/src/Input.ts +37 -4
  84. package/src/ParseError.ts +206 -52
  85. package/src/Parser.ts +19 -29
  86. package/src/ParserSchema.ts +1 -2
  87. package/src/ParserStream.ts +336 -62
  88. package/src/Text.ts +16 -12
  89. package/src/Token.ts +14 -5
  90. package/src/internal/compiler/closure.ts +9 -18
  91. package/src/internal/compiler/first.ts +6 -0
  92. package/src/internal/compiler/graph.ts +32 -4
  93. package/src/internal/compiler/jit.ts +37 -17
  94. package/src/internal/compiler/wasm.ts +141 -68
  95. package/src/internal/node.ts +49 -3
  96. package/src/internal/run.ts +4 -2
  97. package/src/internal/stack.ts +17 -0
  98. package/src/internal/tokens.ts +20 -10
  99. package/src/internal/tuple.ts +141 -0
@@ -0,0 +1,170 @@
1
+ import { Fail } from "../Input.js";
2
+ // src/internal/tuple.ts
3
+ /**
4
+ * Tuple steps: run steps in sequence and collect their outputs in an array.
5
+ *
6
+ * V8 pretenures by allocation site, and only array and object literals have
7
+ * one: an array from `new Array(n)` starts young, so tuples that a parse keeps
8
+ * (a `repeat(seq(...))`, a tree) are copied by a scavenge or two before they
9
+ * are promoted. A literal's site learns that its arrays survive, and V8 then
10
+ * allocates them straight into the old generation. So arities up to
11
+ * {@link maxLiteral} build their tuple with a literal of that arity, each its
12
+ * own site; longer tuples fall back to `new Array(n)` (#86).
13
+ */
14
+ /** The longest tuple built with a literal. */
15
+ const maxLiteral = 8;
16
+ /** A step that runs `steps` in order and returns their outputs as an array, or {@link Fail}. */
17
+ const tupleStep = (steps) => {
18
+ const n = steps.length;
19
+ if (n <= maxLiteral) return literals[n](steps);
20
+ return (state) => {
21
+ const out = new Array(n);
22
+ for (let i = 0; i < n; i++) {
23
+ const a = steps[i](state);
24
+ if (a === Fail) return Fail;
25
+ out[i] = a;
26
+ }
27
+ return out;
28
+ };
29
+ };
30
+ const literals = [
31
+ () => () => [],
32
+ ([s0]) => (state) => {
33
+ const a0 = s0(state);
34
+ if (a0 === Fail) return Fail;
35
+ return [a0];
36
+ },
37
+ ([s0, s1]) => (state) => {
38
+ const a0 = s0(state);
39
+ if (a0 === Fail) return Fail;
40
+ const a1 = s1(state);
41
+ if (a1 === Fail) return Fail;
42
+ return [a0, a1];
43
+ },
44
+ ([s0, s1, s2]) => (state) => {
45
+ const a0 = s0(state);
46
+ if (a0 === Fail) return Fail;
47
+ const a1 = s1(state);
48
+ if (a1 === Fail) return Fail;
49
+ const a2 = s2(state);
50
+ if (a2 === Fail) return Fail;
51
+ return [
52
+ a0,
53
+ a1,
54
+ a2
55
+ ];
56
+ },
57
+ ([s0, s1, s2, s3]) => (state) => {
58
+ const a0 = s0(state);
59
+ if (a0 === Fail) return Fail;
60
+ const a1 = s1(state);
61
+ if (a1 === Fail) return Fail;
62
+ const a2 = s2(state);
63
+ if (a2 === Fail) return Fail;
64
+ const a3 = s3(state);
65
+ if (a3 === Fail) return Fail;
66
+ return [
67
+ a0,
68
+ a1,
69
+ a2,
70
+ a3
71
+ ];
72
+ },
73
+ ([s0, s1, s2, s3, s4]) => (state) => {
74
+ const a0 = s0(state);
75
+ if (a0 === Fail) return Fail;
76
+ const a1 = s1(state);
77
+ if (a1 === Fail) return Fail;
78
+ const a2 = s2(state);
79
+ if (a2 === Fail) return Fail;
80
+ const a3 = s3(state);
81
+ if (a3 === Fail) return Fail;
82
+ const a4 = s4(state);
83
+ if (a4 === Fail) return Fail;
84
+ return [
85
+ a0,
86
+ a1,
87
+ a2,
88
+ a3,
89
+ a4
90
+ ];
91
+ },
92
+ ([s0, s1, s2, s3, s4, s5]) => (state) => {
93
+ const a0 = s0(state);
94
+ if (a0 === Fail) return Fail;
95
+ const a1 = s1(state);
96
+ if (a1 === Fail) return Fail;
97
+ const a2 = s2(state);
98
+ if (a2 === Fail) return Fail;
99
+ const a3 = s3(state);
100
+ if (a3 === Fail) return Fail;
101
+ const a4 = s4(state);
102
+ if (a4 === Fail) return Fail;
103
+ const a5 = s5(state);
104
+ if (a5 === Fail) return Fail;
105
+ return [
106
+ a0,
107
+ a1,
108
+ a2,
109
+ a3,
110
+ a4,
111
+ a5
112
+ ];
113
+ },
114
+ ([s0, s1, s2, s3, s4, s5, s6]) => (state) => {
115
+ const a0 = s0(state);
116
+ if (a0 === Fail) return Fail;
117
+ const a1 = s1(state);
118
+ if (a1 === Fail) return Fail;
119
+ const a2 = s2(state);
120
+ if (a2 === Fail) return Fail;
121
+ const a3 = s3(state);
122
+ if (a3 === Fail) return Fail;
123
+ const a4 = s4(state);
124
+ if (a4 === Fail) return Fail;
125
+ const a5 = s5(state);
126
+ if (a5 === Fail) return Fail;
127
+ const a6 = s6(state);
128
+ if (a6 === Fail) return Fail;
129
+ return [
130
+ a0,
131
+ a1,
132
+ a2,
133
+ a3,
134
+ a4,
135
+ a5,
136
+ a6
137
+ ];
138
+ },
139
+ ([s0, s1, s2, s3, s4, s5, s6, s7]) => (state) => {
140
+ const a0 = s0(state);
141
+ if (a0 === Fail) return Fail;
142
+ const a1 = s1(state);
143
+ if (a1 === Fail) return Fail;
144
+ const a2 = s2(state);
145
+ if (a2 === Fail) return Fail;
146
+ const a3 = s3(state);
147
+ if (a3 === Fail) return Fail;
148
+ const a4 = s4(state);
149
+ if (a4 === Fail) return Fail;
150
+ const a5 = s5(state);
151
+ if (a5 === Fail) return Fail;
152
+ const a6 = s6(state);
153
+ if (a6 === Fail) return Fail;
154
+ const a7 = s7(state);
155
+ if (a7 === Fail) return Fail;
156
+ return [
157
+ a0,
158
+ a1,
159
+ a2,
160
+ a3,
161
+ a4,
162
+ a5,
163
+ a6,
164
+ a7
165
+ ];
166
+ }
167
+ ];
168
+ export { tupleStep };
169
+
170
+ //# sourceMappingURL=tuple.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tuple.js","names":[],"sources":["../../src/internal/tuple.ts"],"sourcesContent":["/**\n * Tuple steps: run steps in sequence and collect their outputs in an array.\n *\n * V8 pretenures by allocation site, and only array and object literals have\n * one: an array from `new Array(n)` starts young, so tuples that a parse keeps\n * (a `repeat(seq(...))`, a tree) are copied by a scavenge or two before they\n * are promoted. A literal's site learns that its arrays survive, and V8 then\n * allocates them straight into the old generation. So arities up to\n * {@link maxLiteral} build their tuple with a literal of that arity, each its\n * own site; longer tuples fall back to `new Array(n)` (#86).\n */\nimport { Fail } from \"../Input.js\"\nimport type { State } from \"../Input.js\"\n\ntype Step = (state: State<any>) => unknown\n\n/** The longest tuple built with a literal. */\nconst maxLiteral = 8\n\n/** A step that runs `steps` in order and returns their outputs as an array, or {@link Fail}. */\nexport const tupleStep = (steps: ReadonlyArray<Step>): ((state: State<any>) => Array<unknown> | Fail) => {\n const n = steps.length\n if (n <= maxLiteral) return literals[n](steps)\n return (state) => {\n const out = new Array<unknown>(n)\n for (let i = 0; i < n; i++) {\n const a = steps[i](state)\n if (a === Fail) return Fail\n out[i] = a\n }\n return out\n }\n}\n\nconst literals: ReadonlyArray<(steps: ReadonlyArray<Step>) => (state: State<any>) => Array<unknown> | Fail> = [\n () => () => [],\n ([s0]) =>\n (state) => {\n const a0 = s0(state)\n if (a0 === Fail) return Fail\n return [a0]\n },\n ([s0, s1]) =>\n (state) => {\n const a0 = s0(state)\n if (a0 === Fail) return Fail\n const a1 = s1(state)\n if (a1 === Fail) return Fail\n return [a0, a1]\n },\n ([s0, s1, s2]) =>\n (state) => {\n const a0 = s0(state)\n if (a0 === Fail) return Fail\n const a1 = s1(state)\n if (a1 === Fail) return Fail\n const a2 = s2(state)\n if (a2 === Fail) return Fail\n return [a0, a1, a2]\n },\n ([s0, s1, s2, s3]) =>\n (state) => {\n const a0 = s0(state)\n if (a0 === Fail) return Fail\n const a1 = s1(state)\n if (a1 === Fail) return Fail\n const a2 = s2(state)\n if (a2 === Fail) return Fail\n const a3 = s3(state)\n if (a3 === Fail) return Fail\n return [a0, a1, a2, a3]\n },\n ([s0, s1, s2, s3, s4]) =>\n (state) => {\n const a0 = s0(state)\n if (a0 === Fail) return Fail\n const a1 = s1(state)\n if (a1 === Fail) return Fail\n const a2 = s2(state)\n if (a2 === Fail) return Fail\n const a3 = s3(state)\n if (a3 === Fail) return Fail\n const a4 = s4(state)\n if (a4 === Fail) return Fail\n return [a0, a1, a2, a3, a4]\n },\n ([s0, s1, s2, s3, s4, s5]) =>\n (state) => {\n const a0 = s0(state)\n if (a0 === Fail) return Fail\n const a1 = s1(state)\n if (a1 === Fail) return Fail\n const a2 = s2(state)\n if (a2 === Fail) return Fail\n const a3 = s3(state)\n if (a3 === Fail) return Fail\n const a4 = s4(state)\n if (a4 === Fail) return Fail\n const a5 = s5(state)\n if (a5 === Fail) return Fail\n return [a0, a1, a2, a3, a4, a5]\n },\n ([s0, s1, s2, s3, s4, s5, s6]) =>\n (state) => {\n const a0 = s0(state)\n if (a0 === Fail) return Fail\n const a1 = s1(state)\n if (a1 === Fail) return Fail\n const a2 = s2(state)\n if (a2 === Fail) return Fail\n const a3 = s3(state)\n if (a3 === Fail) return Fail\n const a4 = s4(state)\n if (a4 === Fail) return Fail\n const a5 = s5(state)\n if (a5 === Fail) return Fail\n const a6 = s6(state)\n if (a6 === Fail) return Fail\n return [a0, a1, a2, a3, a4, a5, a6]\n },\n ([s0, s1, s2, s3, s4, s5, s6, s7]) =>\n (state) => {\n const a0 = s0(state)\n if (a0 === Fail) return Fail\n const a1 = s1(state)\n if (a1 === Fail) return Fail\n const a2 = s2(state)\n if (a2 === Fail) return Fail\n const a3 = s3(state)\n if (a3 === Fail) return Fail\n const a4 = s4(state)\n if (a4 === Fail) return Fail\n const a5 = s5(state)\n if (a5 === Fail) return Fail\n const a6 = s6(state)\n if (a6 === Fail) return Fail\n const a7 = s7(state)\n if (a7 === Fail) return Fail\n return [a0, a1, a2, a3, a4, a5, a6, a7]\n }\n]\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://www.schemastore.org/package",
3
3
  "name": "@thomasfosterau/effect-parse",
4
- "version": "0.5.0",
4
+ "version": "0.6.0",
5
5
  "description": "Parser combinators for Effect, ported from Rust's nom and winnow: text, bytes, bits and token streams, streaming input, compiled parsers and Schema integration",
6
6
  "keywords": [
7
7
  "effect",
@@ -24,7 +24,8 @@
24
24
  "files": [
25
25
  "dist",
26
26
  "src",
27
- "!dist/**/*.tsbuildinfo"
27
+ "!dist/**/*.tsbuildinfo",
28
+ "CHANGELOG.md"
28
29
  ],
29
30
  "type": "module",
30
31
  "sideEffects": false,
@@ -102,19 +103,25 @@
102
103
  "@changesets/changelog-github": "^1.0.1",
103
104
  "@changesets/cli": "^3.0.3",
104
105
  "@effect/language-service": "^0.87.5",
105
- "@effect/platform-node-shared": "4.1.1",
106
- "@effect/tsgo": "0.63.0",
106
+ "@effect/platform-node-shared": "4.1.4",
107
+ "@effect/tsgo": "0.67.7",
107
108
  "@enfect/oxlint": "^0.10.0",
109
+ "@thomasfosterau/effect-bib": "0.1.0",
110
+ "@thomasfosterau/effect-ext": "0.2.0",
111
+ "@thomasfosterau/effect-ical": "0.1.0",
112
+ "@thomasfosterau/effect-parse": "0.6.0",
113
+ "@thomasfosterau/effect-rdf": "0.2.0",
114
+ "@thomasfosterau/effect-xml": "0.1.0",
108
115
  "@types/node": "^26.6.5",
109
116
  "@typescript/native": "npm:typescript@7.0.2",
110
- "@vitest/coverage-istanbul": "5.0.5",
111
- "effect": "4.1.1",
112
- "fallow": "3.40.0",
117
+ "@vitest/coverage-istanbul": "5.1.0",
118
+ "effect": "4.1.4",
119
+ "fallow": "3.42.0",
113
120
  "rolldown": "^1.2.14",
114
121
  "typescript": "npm:@typescript/typescript6@6.0.2",
115
- "vite": "npm:@voidzero-dev/vite-plus-core@1.4.0",
116
- "vite-plus": "1.4.0",
117
- "vitest": "5.0.5"
122
+ "vite": "npm:@voidzero-dev/vite-plus-core@1.6.0",
123
+ "vite-plus": "1.6.0",
124
+ "vitest": "5.1.0"
118
125
  },
119
126
  "peerDependencies": {
120
127
  "effect": "^4.0.0"
package/src/Ascii.ts CHANGED
@@ -31,6 +31,7 @@ import type { Parser } from "./Parser.js"
31
31
  import * as P from "./Parser.js"
32
32
  import * as numbers from "./internal/numbers.js"
33
33
  import { Key } from "./internal/key.js"
34
+ import { controlCode } from "./internal/node.js"
34
35
  import * as Resume from "./internal/resume.js"
35
36
  import { codePointPredicate } from "./internal/tokens.js"
36
37
  import { literalImpl, range, takeWhileImpl } from "./Token.js"
@@ -533,7 +534,8 @@ export const caseless: CaselessFn = (lit: string | Uint8Array): any => literalIm
533
534
  // Escapes
534
535
  // -----------------------------------------------------------------------------
535
536
 
536
- const controlCode = (c: string | number): number => (Predicate.isNumber(c) ? c : c.charCodeAt(0))
537
+ /** The first UTF-16 unit of a control character: what `atControl` compares with a string's units. */
538
+ const firstUnit = (s: string): number => s.charCodeAt(0)
537
539
 
538
540
  const atControl = (state: State<Input>, control: number): boolean => {
539
541
  if (state.pos >= state.end) return false
@@ -567,7 +569,7 @@ export const takeEscaped = <A, E, R, I extends Input, B, E2, R2, I2 extends Inpu
567
569
  control: string | number,
568
570
  escapable: Parser<B, E2, R2, I2>
569
571
  ): Parser<Slice<I & I2>, E | E2, R | R2, I & I2> => {
570
- const ctrl = controlCode(control)
572
+ const ctrl = controlCode(control, firstUnit)
571
573
  return takeEscapedImpl(
572
574
  normal,
573
575
  (state) => {
@@ -684,7 +686,7 @@ export const escaped = <E, R, I extends Input, E2, R2, I2 extends Input>(
684
686
  control: string | number,
685
687
  escape: Parser<string, E2, R2, I2>
686
688
  ): Parser<string, E | E2, R | R2, I & I2> => {
687
- const ctrl = controlCode(control)
689
+ const ctrl = controlCode(control, firstUnit)
688
690
  return escapedImpl(
689
691
  normal,
690
692
  (state) => {
package/src/Binary.ts CHANGED
@@ -334,6 +334,18 @@ export const f64: (endian: Endianness) => Parser<number, never, never, Uint8Arra
334
334
  leF64
335
335
  )
336
336
 
337
+ const MaxCount = /*#__PURE__*/ BigInt(Number.MAX_SAFE_INTEGER)
338
+
339
+ /**
340
+ * Whether a length read from the input is a count: a non-negative integer
341
+ * of at most `Number.MAX_SAFE_INTEGER`. A signed, fractional or `NaN`
342
+ * length is the input's to choose, so it fails the parse where it was read
343
+ * (as `Parser.filter` does) and never reaches `Token.take` or
344
+ * `Parser.repeat`, which throw on one.
345
+ */
346
+ const isCount = (n: number | bigint): boolean =>
347
+ Predicate.isBigInt(n) ? n >= 0n && n <= MaxCount : Number.isSafeInteger(n) && n >= 0
348
+
337
349
  const toCount = (n: number | bigint): number => (Predicate.isBigInt(n) ? Number(n) : n)
338
350
 
339
351
  /** How many counts {@link byCount} keeps the parsers of. */
@@ -359,7 +371,9 @@ const byCount = <A>(build: (n: number) => A): ((n: number | bigint) => A) => {
359
371
 
360
372
  /**
361
373
  * Parses a length with `count`, then takes that many tokens (winnow's
362
- * `length_take`, nom's `length_data`).
374
+ * `length_take`, nom's `length_data`). A length that is not a non-negative
375
+ * integer (a negative `i8`, a fractional float) fails the parse at the
376
+ * length.
363
377
  *
364
378
  * @since 0.1.0
365
379
  * @category length-prefixed
@@ -373,9 +387,15 @@ export const lengthTake = <E, R, I extends Input = Uint8Array>(
373
387
  [count],
374
388
  ([countStep]) =>
375
389
  (state: State<I>) => {
390
+ const start = state.pos
376
391
  // SAFETY: the count parser's step, interpreted or compiled, returns its output (a number or bigint) or `Fail`
377
392
  const n = countStep(state) as number | bigint | Fail
378
393
  if (n === Fail) return Fail
394
+ // As `Parser.filter` fails: at the length, backtracking
395
+ if (!isCount(n)) {
396
+ state.rewind(start)
397
+ return state.backtrack("Verify")
398
+ }
379
399
  return take(n)(state)
380
400
  },
381
401
  "lengthTake"
@@ -384,7 +404,8 @@ export const lengthTake = <E, R, I extends Input = Uint8Array>(
384
404
 
385
405
  /**
386
406
  * Parses a length with `count`, then applies `parser` that many times
387
- * (winnow's `length_repeat`, nom's `length_count`).
407
+ * (winnow's `length_repeat`, nom's `length_count`). A length that is not a
408
+ * non-negative integer fails the parse at the length.
388
409
  *
389
410
  * @since 0.1.0
390
411
  * @category length-prefixed
@@ -394,7 +415,7 @@ export const lengthRepeat = <E, R, I extends Input, A, E2, R2, I2 extends Input>
394
415
  parser: Parser<A, E2, R2, I2>
395
416
  ): Parser<Array<A>, E | E2, R | R2, I & I2> =>
396
417
  P.flatMap(
397
- count,
418
+ P.filter(count, isCount),
398
419
  byCount((n) => P.repeat(parser, n))
399
420
  )
400
421
 
package/src/Bits.ts CHANGED
@@ -24,6 +24,7 @@ import type { State } from "./Input.js"
24
24
  import { Fail, Failure } from "./Input.js"
25
25
  import type { Parser } from "./Parser.js"
26
26
  import { make } from "./Parser.js"
27
+ import { checkCount } from "./internal/node.js"
27
28
 
28
29
  declare const BitInputBrand: unique symbol
29
30
 
@@ -136,6 +137,7 @@ const readBits = (state: State<any>, count: number): number => {
136
137
  * @category parsers
137
138
  */
138
139
  export const take = (count: number): Parser<number, never, never, BitInput> => {
140
+ checkCount(count)
139
141
  if (count > 53) throw new RangeError("Bits.take: use Bits.takeBig for more than 53 bits")
140
142
  const expected = [`${count} bits`]
141
143
  return make((state: State<any>) => {
@@ -152,6 +154,7 @@ export const take = (count: number): Parser<number, never, never, BitInput> => {
152
154
  * @category parsers
153
155
  */
154
156
  export const takeBig = (count: number): Parser<bigint, never, never, BitInput> => {
157
+ checkCount(count)
155
158
  const expected = [`${count} bits`]
156
159
  return make((state: State<any>) => {
157
160
  const avail = state.end - state.pos
@@ -175,6 +178,7 @@ export const takeBig = (count: number): Parser<bigint, never, never, BitInput> =
175
178
  * @category parsers
176
179
  */
177
180
  export const pattern = (pattern: number, count: number): Parser<number, never, never, BitInput> => {
181
+ checkCount(count)
178
182
  const expected = [`bit pattern ${pattern.toString(2).padStart(count, "0")}`]
179
183
  return make((state: State<any>) => {
180
184
  const start = state.pos
package/src/Input.ts CHANGED
@@ -276,6 +276,18 @@ export class State<I extends Input = Input> {
276
276
  this.deepestIsLatest = false
277
277
  this.deepestFailure = failure
278
278
  }
279
+ /**
280
+ * Whether compiled code is running on this state. A compiled run that fails
281
+ * is thrown away (the interpreter runs again to build the error) and one
282
+ * that succeeds records no diagnostics, so interpreted steps called from it
283
+ * (an opaque `Parser.make`, a leaf near the end of a partial input) record
284
+ * a `Backtrack` or `Cut` failure's mode only, without building its
285
+ * {@link Failure} (#82). `Incomplete` failures are still built: a compiled
286
+ * run's `Incomplete` is reported as it stands.
287
+ *
288
+ * @internal
289
+ */
290
+ compiledRun = false
279
291
  /** When defined, `Parser.resumeAfter`/`retryAfter` record failures here. */
280
292
  recovered: Array<Failure> | undefined = undefined
281
293
  /** When defined, `Parser.trace` reports events here. */
@@ -304,8 +316,10 @@ export class State<I extends Input = Input> {
304
316
  /**
305
317
  * Where the stop characters of compiled `takeTill`s next occur in this
306
318
  * state's input, by search site; created on first use. It lives as long
307
- * as the state (whose input never changes), and `reset` clears it with
308
- * the other per-run fields.
319
+ * as the state. `reset` keeps it for string input (a string never
320
+ * changes, and the positions are absolute, so they hold wherever the next
321
+ * run starts) and drops it for bytes and arrays, which a caller may
322
+ * refill in place between runs.
309
323
  *
310
324
  * @internal
311
325
  */
@@ -383,7 +397,11 @@ export class State<I extends Input = Input> {
383
397
  *
384
398
  * Every per-run field is reset: the cursor and end, the latest failure,
385
399
  * hints and furthest failure, recorded recoveries, the tracer and tracing
386
- * depth, the recorded encoding and streaming checkpoints. Like the
400
+ * depth, the recorded encoding and streaming checkpoints. For string
401
+ * input, what the state has learnt about the string (where the stop
402
+ * characters of `takeTill` and the literals of `takeUntilAny` occur) is
403
+ * kept, as a string cannot change; for bytes and arrays it is dropped, so
404
+ * a buffer refilled in place between runs is searched afresh. Like the
387
405
  * constructor, `partial` defaults to `false` and `context` to the empty
388
406
  * context, so pass them again on every reset.
389
407
  *
@@ -422,12 +440,19 @@ export class State<I extends Input = Input> {
422
440
  this.hintExpected = empty
423
441
  this.deepestFailure = undefined
424
442
  this.deepestIsLatest = false
443
+ this.compiledRun = false
425
444
  this.recovered = undefined
426
445
  this.tracer = undefined
427
446
  this.depth = 0
428
447
  this.encoding = undefined
429
448
  this.resume = undefined
430
- this.searches = undefined
449
+ // For a string, `searches` is kept: it remembers where stop characters
450
+ // and literals occur by absolute position, and a string never changes,
451
+ // so it holds at any offset. A lexer that resets before each token
452
+ // otherwise searched to the end of the buffer again for every token
453
+ // (#126). Bytes and arrays can be refilled in place between runs (a
454
+ // `Uint8Array` source is viewed, not copied), so theirs is dropped.
455
+ if (this.inputKind !== 0) this.searches = undefined
431
456
  this.asciiRun = undefined
432
457
  return this
433
458
  }
@@ -503,6 +528,10 @@ export class State<I extends Input = Input> {
503
528
  * Records a recoverable failure at the current offset and returns {@link Fail}.
504
529
  */
505
530
  backtrack(kind: ErrorKind, expected: ReadonlyArray<string> = empty, offset: number = this.pos): Fail {
531
+ if (this.compiledRun) {
532
+ this.mode = "Backtrack"
533
+ return Fail
534
+ }
506
535
  return this.failWith("Backtrack", this.makeFailure(offset, kind, expected))
507
536
  }
508
537
 
@@ -510,6 +539,10 @@ export class State<I extends Input = Input> {
510
539
  * Records an unrecoverable failure at the current offset and returns {@link Fail}.
511
540
  */
512
541
  cut(kind: ErrorKind, expected: ReadonlyArray<string> = empty, offset: number = this.pos): Fail {
542
+ if (this.compiledRun) {
543
+ this.mode = "Cut"
544
+ return Fail
545
+ }
513
546
  return this.failWith("Cut", this.makeFailure(offset, kind, expected))
514
547
  }
515
548