@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/dist/Input.js CHANGED
@@ -1,312 +1,422 @@
1
- /**
2
- * Input types and the mutable parse {@link State} cursor.
3
- *
4
- * Like winnow, effect-parse parsers advance a mutable cursor rather than
5
- * returning the remaining input. A {@link State} wraps the original input
6
- * together with the current offset, the streaming (partial) flag, the
7
- * services available to the parser, and the details of the most recent
8
- * failure.
9
- *
10
- * Most users never touch `State` directly. It is exposed for writing custom
11
- * low-level parsers with `Parser.make`.
12
- *
13
- * @since 0.1.0
14
- */
1
+ import * as Predicate from "effect/Predicate";
15
2
  import * as Context from "effect/Context";
3
+ //#region src/Input.ts
4
+ /**
5
+ * Input types and the mutable parse {@link State} cursor.
6
+ *
7
+ * Like winnow, effect-parse parsers advance a mutable cursor rather than
8
+ * returning the remaining input. A {@link State} wraps the original input
9
+ * together with the current offset, the streaming (partial) flag, the
10
+ * services available to the parser, and the details of the most recent
11
+ * failure.
12
+ *
13
+ * Most users never touch `State` directly. It is exposed for writing custom
14
+ * low-level parsers with `Parser.make`, and for drivers that run a parser's
15
+ * `step` many times over one input, reusing a state with {@link State.reset}.
16
+ *
17
+ * @since 0.1.0
18
+ */
16
19
  /**
17
- * Converts a {@link Source} to the input parsers read: binary data becomes a
18
- * `Uint8Array` view of the same memory, everything else is returned as is.
19
- *
20
- * @example
21
- * ```ts
22
- * import { Input } from "@thomasfosterau/effect-parse"
23
- *
24
- * Input.fromSource(new Uint16Array([0x41]).buffer) // Uint8Array [0x41, 0x00]
25
- * ```
26
- *
27
- * @since 0.1.0
28
- * @category constructors
29
- */
30
- export const fromSource = (source) => {
31
- if (typeof source === "string" || source instanceof Uint8Array || Array.isArray(source))
32
- return source;
33
- if (ArrayBuffer.isView(source))
34
- return new Uint8Array(source.buffer, source.byteOffset, source.byteLength);
35
- // An explicit length fixes the view's size even for a resizable buffer
36
- if (isArrayBufferLike(source))
37
- return new Uint8Array(source, 0, source.byteLength);
38
- return source;
20
+ * Converts a {@link Source} to the input parsers read: binary data becomes a
21
+ * `Uint8Array` view of the same memory, everything else is returned as is.
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * import { Input } from "@thomasfosterau/effect-parse"
26
+ *
27
+ * Input.fromSource(new Uint16Array([0x41]).buffer) // Uint8Array [0x41, 0x00]
28
+ * ```
29
+ *
30
+ * @since 0.1.0
31
+ * @category constructors
32
+ */
33
+ const fromSource = (source) => {
34
+ if (Predicate.isString(source) || source instanceof Uint8Array || Array.isArray(source)) return source;
35
+ if (ArrayBuffer.isView(source)) return new Uint8Array(source.buffer, source.byteOffset, source.byteLength);
36
+ if (isArrayBufferLike(source)) return new Uint8Array(source, 0, source.byteLength);
37
+ return source;
39
38
  };
40
- const isArrayBufferLike = (u) => u instanceof ArrayBuffer || (typeof SharedArrayBuffer !== "undefined" && u instanceof SharedArrayBuffer);
39
+ const isArrayBufferLike = (u) => u instanceof ArrayBuffer || globalThis.SharedArrayBuffer !== void 0 && u instanceof SharedArrayBuffer;
41
40
  /**
42
- * Sentinel returned by a parser step to signal failure. The failure details
43
- * are stored on the {@link State}.
44
- *
45
- * @since 0.1.0
46
- * @category failure
47
- */
48
- export const Fail = Symbol.for("effect-parse/Fail");
41
+ * Sentinel returned by a parser step to signal failure. The failure details
42
+ * are stored on the {@link State}.
43
+ *
44
+ * @since 0.1.0
45
+ * @category failure
46
+ */
47
+ const Fail = /*#__PURE__*/ Symbol.for("effect-parse/Fail");
49
48
  /**
50
- * The details of a parse failure.
51
- *
52
- * @since 0.1.0
53
- * @category failure
54
- */
55
- export class Failure {
56
- offset;
57
- kind;
58
- expected;
59
- context;
60
- hasCause;
61
- cause;
62
- message;
63
- needed;
64
- constructor(
65
- /** Offset into the input where the failure occurred. */
66
- offset,
67
- /** The kind of parser that failed. */
68
- kind,
69
- /** Rendered descriptions of what was expected at `offset`. */
70
- expected,
71
- /** Context labels added by `Parser.context`, innermost first. */
72
- context,
73
- /** Whether a user supplied cause is present. */
74
- hasCause,
75
- /** A user supplied (typed) cause. */
76
- cause,
77
- /** An optional free-form message. */
78
- message,
79
- /** For `Incomplete` failures, how many more tokens are needed (0 if unknown). */
80
- needed) {
81
- this.offset = offset;
82
- this.kind = kind;
83
- this.expected = expected;
84
- this.context = context;
85
- this.hasCause = hasCause;
86
- this.cause = cause;
87
- this.message = message;
88
- this.needed = needed;
89
- }
90
- }
49
+ * The details of a parse failure.
50
+ *
51
+ * @since 0.1.0
52
+ * @category failure
53
+ */
54
+ var Failure = class {
55
+ offset;
56
+ kind;
57
+ expected;
58
+ context;
59
+ hasCause;
60
+ cause;
61
+ message;
62
+ needed;
63
+ constructor(offset, kind, expected, context, hasCause, cause, message, needed) {
64
+ this.offset = offset;
65
+ this.kind = kind;
66
+ this.expected = expected;
67
+ this.context = context;
68
+ this.hasCause = hasCause;
69
+ this.cause = cause;
70
+ this.message = message;
71
+ this.needed = needed;
72
+ }
73
+ };
91
74
  const empty = [];
75
+ /** The failure a {@link State} starts with, before any step has failed. */
76
+ const initialFailure = /*#__PURE__*/ new Failure(0, "Fail", empty, empty, false, void 0, void 0, 0);
92
77
  /** @internal */
93
- export const emptyStrings = empty;
78
+ const emptyStrings = empty;
94
79
  /**
95
- * The mutable parsing cursor.
96
- *
97
- * @since 0.1.0
98
- * @category models
99
- */
100
- export class State {
101
- /** The full input being parsed. */
102
- input;
103
- /** The current offset. Advanced by parsers, rewound on backtracking. */
104
- pos;
105
- /** The end offset (the input's length; in bits inside `Bits.bits`). */
106
- end;
107
- /** 0 = string, 1 = Uint8Array, 2 = array. */
108
- inputKind;
109
- /** Whether the input is partial (streaming): running out yields `Incomplete`. */
110
- partial;
111
- /** Services available to `Parser.service`. */
112
- context;
113
- /** Mode of the latest failure. Only meaningful after a step returned {@link Fail}. */
114
- mode = "Backtrack";
115
- /** Details of the latest failure. Only meaningful after a step returned {@link Fail}. */
116
- failure;
117
- /**
118
- * The offset of a recoverable failure that occurred without consuming
119
- * input (for example the last attempt of a `repeat`). Its
120
- * expectations are merged into new failures at the same offset, producing
121
- * messages like `expected digit or ")"`.
122
- */
123
- hintOffset = -1;
124
- /** The expectations of the hint at {@link hintOffset}. */
125
- hintExpected = empty;
126
- /**
127
- * The furthest recoverable failure seen so far, including failures that
128
- * were later swallowed by backtracking (for example a trailing separator
129
- * followed by an invalid element). It is reported instead of the final
130
- * failure when it lies further into the input. This is the classic PEG
131
- * "farthest failure" heuristic.
132
- */
133
- deepest = undefined;
134
- /** When defined, `Parser.resumeAfter`/`retryAfter` record failures here. */
135
- recovered = undefined;
136
- /** When defined, `Parser.trace` reports events here. */
137
- tracer = undefined;
138
- /** Current tracing depth. */
139
- depth = 0;
140
- /**
141
- * The text encoding of a byte input, recorded by `Text` parsers when they
142
- * fail so that errors can show the input as text.
143
- */
144
- encoding = undefined;
145
- /**
146
- * The checkpoints of a resumable streaming parse (see
147
- * `ParserStream.parseAll`); `undefined` otherwise.
148
- *
149
- * @internal
150
- */
151
- resume = undefined;
152
- constructor(source, options) {
153
- const input = fromSource(source);
154
- this.input = input;
155
- this.end = input.length;
156
- this.pos = options?.offset ?? 0;
157
- this.partial = options?.partial ?? false;
158
- this.context = options?.context ?? Context.empty();
159
- this.inputKind = typeof input === "string" ? 0 : input instanceof Uint8Array ? 1 : 2;
160
- this.failure = new Failure(0, "Fail", empty, empty, false, undefined, undefined, 0);
161
- }
162
- /**
163
- * The number of input units (code units, bytes or elements) remaining.
164
- */
165
- remaining() {
166
- return this.end - this.pos;
167
- }
168
- /**
169
- * Whether the cursor is at the end of the input.
170
- */
171
- atEnd() {
172
- return this.pos >= this.end;
173
- }
174
- /**
175
- * Extracts the slice `[start, end)` of the input.
176
- */
177
- slice(start, end) {
178
- const input = this.input;
179
- switch (this.inputKind) {
180
- case 0:
181
- return input.slice(start, end);
182
- case 1:
183
- return input.subarray(start, end);
184
- default:
185
- return input.slice(start, end);
186
- }
187
- }
188
- /**
189
- * Records a recoverable failure at the current offset and returns {@link Fail}.
190
- */
191
- backtrack(kind, expected = empty, offset = this.pos) {
192
- return this.failWith("Backtrack", this.makeFailure(offset, kind, expected));
193
- }
194
- /**
195
- * Records an unrecoverable failure at the current offset and returns {@link Fail}.
196
- */
197
- cut(kind, expected = empty, offset = this.pos) {
198
- return this.failWith("Cut", this.makeFailure(offset, kind, expected));
199
- }
200
- /**
201
- * Records an `Incomplete` failure (only meaningful for partial input) and
202
- * returns {@link Fail}.
203
- */
204
- incomplete(needed, expected = empty) {
205
- return this.failWith("Incomplete", new Failure(this.pos, "Incomplete", expected, empty, false, undefined, undefined, needed));
206
- }
207
- /**
208
- * Fails because the input ended: `Incomplete` for partial input, otherwise
209
- * a `Backtrack` failure of the given kind.
210
- */
211
- eoi(kind, expected, needed) {
212
- return this.partial ? this.incomplete(needed, expected) : this.backtrack(kind, expected);
213
- }
214
- /**
215
- * Records a failure carrying a user supplied cause.
216
- */
217
- failCause(mode, kind, cause, offset = this.pos) {
218
- return this.failWith(mode, new Failure(offset, kind, empty, empty, true, cause, undefined, 0));
219
- }
220
- /**
221
- * Records a failure carrying a message.
222
- */
223
- failMessage(mode, kind, message, offset = this.pos) {
224
- return this.failWith(mode, new Failure(offset, kind, empty, empty, false, undefined, message, 0));
225
- }
226
- /**
227
- * Records the given failure and returns {@link Fail}.
228
- */
229
- failWith(mode, failure) {
230
- this.mode = mode;
231
- this.failure = failure;
232
- if (mode === "Backtrack" && (this.deepest === undefined || failure.offset >= this.deepest.offset)) {
233
- this.deepest = failure;
234
- }
235
- return Fail;
236
- }
237
- /**
238
- * Replaces the details of the current failure (for example to add context),
239
- * keeping the record of the furthest failure consistent.
240
- */
241
- replaceFailure(failure) {
242
- if (this.deepest === this.failure)
243
- this.deepest = failure;
244
- this.failure = failure;
245
- }
246
- /**
247
- * The failure to report to the user: the current failure, or the furthest
248
- * failure if it lies beyond the current one and the current failure is a
249
- * plain syntax error (no user cause or message).
250
- */
251
- reportedFailure() {
252
- const f = this.failure;
253
- const d = this.deepest;
254
- if (d === undefined || d === f || d.offset <= f.offset || this.mode === "Incomplete" ||
255
- f.hasCause || f.message !== undefined) {
256
- return f;
257
- }
258
- const context = d.context.length === 0 ? f.context : [...d.context, ...f.context.filter((l) => !d.context.includes(l))];
259
- return new Failure(d.offset, d.kind, d.expected, context, d.hasCause, d.cause, d.message, d.needed);
260
- }
261
- /**
262
- * Records that, at `offset`, any of `expected` could also have been
263
- * accepted. Used by parsers that stop without failing, such as `opt`,
264
- * `repeat` and `Ascii.digit1`.
265
- */
266
- setHint(offset, expected) {
267
- if (this.hintOffset === offset) {
268
- this.hintExpected = mergeExpected(this.hintExpected, expected);
269
- }
270
- else {
271
- this.hintOffset = offset;
272
- this.hintExpected = expected;
273
- }
274
- }
275
- /** @internal */
276
- makeFailure(offset, kind, expected) {
277
- if (this.hintOffset === offset && this.hintExpected.length > 0) {
278
- expected = mergeExpected(this.hintExpected, expected);
279
- }
280
- return new Failure(offset, kind, expected, empty, false, undefined, undefined, 0);
281
- }
282
- }
80
+ * The mutable parsing cursor.
81
+ *
82
+ * @since 0.1.0
83
+ * @category models
84
+ */
85
+ var State = class {
86
+ /** The full input being parsed. */
87
+ input;
88
+ /** The end offset (the input's length; in bits inside `Bits.bits`). */
89
+ end;
90
+ /** 0 = string, 1 = Uint8Array, 2 = array. */
91
+ inputKind;
92
+ /** Whether the input is partial (streaming): running out yields `Incomplete`. */
93
+ partial;
94
+ /** Services available to `Parser.service`. */
95
+ context;
96
+ /** Mode of the latest failure. Only meaningful after a step returned {@link Fail}. */
97
+ mode = "Backtrack";
98
+ /**
99
+ * The latest failure, kept unmerged: the failure is `failureHead` merged
100
+ * (as `mergeFailures` does) with `failureTie1` and then `failureTie2`, all
101
+ * at the same offset. `Parser.alt` records its tied branch failures here
102
+ * with {@link failTies} instead of merging them, so that an enclosing `alt`
103
+ * whose next branch succeeds never pays for the merge. Reading
104
+ * {@link failure} performs the merge, once.
105
+ *
106
+ * @internal
107
+ */
108
+ failureHead;
109
+ /** @internal */
110
+ failureTie1 = void 0;
111
+ /** @internal */
112
+ failureTie2 = void 0;
113
+ /** Backs {@link deepest}. @internal */
114
+ deepestFailure = void 0;
115
+ /**
116
+ * Whether the furthest failure is the latest failure, still unmerged, so
117
+ * that {@link deepest} is that failure once merged. Only set while
118
+ * `failureTie1` is.
119
+ *
120
+ * @internal
121
+ */
122
+ deepestIsLatest = false;
123
+ /**
124
+ * The offset of a recoverable failure that occurred without consuming
125
+ * input (for example the last attempt of a `repeat`). Its
126
+ * expectations are merged into new failures at the same offset, producing
127
+ * messages like `expected digit or ")"`.
128
+ */
129
+ hintOffset = -1;
130
+ /** The expectations of the hint at {@link hintOffset}. */
131
+ hintExpected = empty;
132
+ /**
133
+ * The furthest recoverable failure seen so far, including failures that
134
+ * were later swallowed by backtracking (for example a trailing separator
135
+ * followed by an invalid element). It is reported instead of the final
136
+ * failure when it lies further into the input. This is the classic PEG
137
+ * "farthest failure" heuristic. `Parser.cut` keeps only the failures
138
+ * recorded inside it when it commits, and `Parser.peek` and `Parser.not`
139
+ * forget the failures of a lookahead that succeeded.
140
+ */
141
+ get deepest() {
142
+ if (this.deepestIsLatest) this.settleFailure();
143
+ return this.deepestFailure;
144
+ }
145
+ set deepest(failure) {
146
+ this.deepestIsLatest = false;
147
+ this.deepestFailure = failure;
148
+ }
149
+ /** When defined, `Parser.resumeAfter`/`retryAfter` record failures here. */
150
+ recovered = void 0;
151
+ /** When defined, `Parser.trace` reports events here. */
152
+ tracer = void 0;
153
+ /** Current tracing depth. */
154
+ depth = 0;
155
+ /**
156
+ * The text encoding of a byte input, recorded by `Text` parsers when they
157
+ * fail so that errors can show the input as text.
158
+ */
159
+ encoding = void 0;
160
+ /**
161
+ * The checkpoints of a resumable streaming parse (see
162
+ * `ParserStream.parseAll`); `undefined` otherwise.
163
+ *
164
+ * @internal
165
+ */
166
+ resume = void 0;
167
+ /**
168
+ * The tree builder of a `Syntax` parse; `undefined` otherwise.
169
+ *
170
+ * @internal
171
+ */
172
+ syntax = void 0;
173
+ constructor(source, options) {
174
+ const input = fromSource(source);
175
+ this.input = input;
176
+ this.end = input.length;
177
+ this.pos = options?.offset ?? 0;
178
+ this.partial = options?.partial ?? false;
179
+ this.context = options?.context ?? Context.empty();
180
+ this.inputKind = Predicate.isString(input) ? 0 : input instanceof Uint8Array ? 1 : 2;
181
+ this.failureHead = initialFailure;
182
+ }
183
+ /** Details of the latest failure. Only meaningful after a step returned {@link Fail}. */
184
+ get failure() {
185
+ if (this.failureTie1 !== void 0) this.settleFailure();
186
+ return this.failureHead;
187
+ }
188
+ set failure(failure) {
189
+ if (this.deepestIsLatest) this.settleFailure();
190
+ this.failureHead = failure;
191
+ this.failureTie1 = void 0;
192
+ this.failureTie2 = void 0;
193
+ }
194
+ /** Merges the latest failure's ties into it (see {@link failureHead}). */
195
+ settleFailure() {
196
+ let failure = this.failureHead;
197
+ const tie1 = this.failureTie1;
198
+ if (tie1 !== void 0) {
199
+ failure = mergeTiedFailures(failure, tie1, mergeExpected(failure.expected, tie1.expected));
200
+ const tie2 = this.failureTie2;
201
+ if (tie2 !== void 0) failure = mergeTiedFailures(failure, tie2, mergeExpected(failure.expected, tie2.expected));
202
+ this.failureHead = failure;
203
+ this.failureTie1 = void 0;
204
+ this.failureTie2 = void 0;
205
+ }
206
+ if (this.deepestIsLatest) {
207
+ this.deepestFailure = failure;
208
+ this.deepestIsLatest = false;
209
+ }
210
+ }
211
+ /**
212
+ * Prepares the state for another run over the same input, starting at
213
+ * `offset`: afterwards it behaves exactly like
214
+ * `new State(state.input, { ...options, offset })`, without allocating a
215
+ * new state.
216
+ *
217
+ * Every per-run field is reset: the cursor and end, the latest failure,
218
+ * hints and furthest failure, recorded recoveries, the tracer and tracing
219
+ * depth, the recorded encoding and streaming checkpoints. Like the
220
+ * constructor, `partial` defaults to `false` and `context` to the empty
221
+ * context, so pass them again on every reset.
222
+ *
223
+ * Use it to run many small parses over one buffer, for example one per
224
+ * token, with `parser.step`. A state can be reused after any run,
225
+ * including one that failed, returned `Incomplete` or threw.
226
+ *
227
+ * @example
228
+ * ```ts
229
+ * import { Ascii, Input } from "@thomasfosterau/effect-parse"
230
+ *
231
+ * const state = new Input.State("12 34")
232
+ * Ascii.decUint.step(state) // 12
233
+ * state.reset(3)
234
+ * Ascii.decUint.step(state) // 34
235
+ * ```
236
+ *
237
+ * @since 0.2.0
238
+ */
239
+ reset(offset = 0, options) {
240
+ this.pos = offset;
241
+ this.end = this.input.length;
242
+ this.partial = options?.partial ?? false;
243
+ this.context = options?.context ?? Context.empty();
244
+ this.mode = "Backtrack";
245
+ this.failureHead = initialFailure;
246
+ this.failureTie1 = void 0;
247
+ this.failureTie2 = void 0;
248
+ this.hintOffset = -1;
249
+ this.hintExpected = empty;
250
+ this.deepestFailure = void 0;
251
+ this.deepestIsLatest = false;
252
+ this.recovered = void 0;
253
+ this.tracer = void 0;
254
+ this.depth = 0;
255
+ this.encoding = void 0;
256
+ this.resume = void 0;
257
+ return this;
258
+ }
259
+ /**
260
+ * The number of input units (code units, bytes or elements) remaining.
261
+ */
262
+ remaining() {
263
+ return this.end - this.pos;
264
+ }
265
+ /**
266
+ * Whether the cursor is at the end of the input.
267
+ */
268
+ atEnd() {
269
+ return this.pos >= this.end;
270
+ }
271
+ /**
272
+ * Extracts the slice `[start, end)` of the input.
273
+ */
274
+ slice(start, end) {
275
+ const input = this.input;
276
+ switch (this.inputKind) {
277
+ case 0: return input.slice(start, end);
278
+ case 1: return input.subarray(start, end);
279
+ default: return input.slice(start, end);
280
+ }
281
+ }
282
+ /**
283
+ * Records a recoverable failure at the current offset and returns {@link Fail}.
284
+ */
285
+ backtrack(kind, expected = empty, offset = this.pos) {
286
+ return this.failWith("Backtrack", this.makeFailure(offset, kind, expected));
287
+ }
288
+ /**
289
+ * Records an unrecoverable failure at the current offset and returns {@link Fail}.
290
+ */
291
+ cut(kind, expected = empty, offset = this.pos) {
292
+ return this.failWith("Cut", this.makeFailure(offset, kind, expected));
293
+ }
294
+ /**
295
+ * Records an `Incomplete` failure (only meaningful for partial input) and
296
+ * returns {@link Fail}.
297
+ */
298
+ incomplete(needed, expected = empty) {
299
+ return this.failWith("Incomplete", new Failure(this.pos, "Incomplete", expected, empty, false, void 0, void 0, needed));
300
+ }
301
+ /**
302
+ * Fails because the input ended: `Incomplete` for partial input, otherwise
303
+ * a `Backtrack` failure of the given kind.
304
+ */
305
+ eoi(kind, expected, needed) {
306
+ return this.partial ? this.incomplete(needed, expected) : this.backtrack(kind, expected);
307
+ }
308
+ /**
309
+ * Records a failure carrying a user supplied cause.
310
+ */
311
+ failCause(mode, kind, cause, offset = this.pos) {
312
+ return this.failWith(mode, new Failure(offset, kind, empty, empty, true, cause, void 0, 0));
313
+ }
314
+ /**
315
+ * Records a failure carrying a message.
316
+ */
317
+ failMessage(mode, kind, message, offset = this.pos) {
318
+ return this.failWith(mode, new Failure(offset, kind, empty, empty, false, void 0, message, 0));
319
+ }
320
+ /**
321
+ * Records the given failure and returns {@link Fail}.
322
+ */
323
+ failWith(mode, failure) {
324
+ this.mode = mode;
325
+ if (this.deepestIsLatest) {
326
+ if (mode === "Backtrack" && failure.offset >= this.failureHead.offset) this.deepestIsLatest = false;
327
+ else this.settleFailure();
328
+ }
329
+ this.failureHead = failure;
330
+ this.failureTie1 = void 0;
331
+ this.failureTie2 = void 0;
332
+ if (mode === "Backtrack" && (this.deepestFailure === void 0 || failure.offset >= this.deepestFailure.offset)) this.deepestFailure = failure;
333
+ return Fail;
334
+ }
335
+ /**
336
+ * Records a recoverable failure made of tied failures, merged only when
337
+ * read: `failWith("Backtrack", f)` where `f` merges `head` with `tie1`
338
+ * and then `tie2` (all at the same offset), as `mergeFailures` would.
339
+ *
340
+ * @internal
341
+ */
342
+ failTies(head, tie1, tie2) {
343
+ this.mode = "Backtrack";
344
+ if (this.deepestIsLatest && head.offset < this.failureHead.offset) this.settleFailure();
345
+ this.failureHead = head;
346
+ this.failureTie1 = tie1;
347
+ this.failureTie2 = tie2;
348
+ this.deepestIsLatest = this.deepestFailure === void 0 || head.offset >= this.deepestFailure.offset;
349
+ return Fail;
350
+ }
351
+ /**
352
+ * Replaces the details of the current failure (for example to add context),
353
+ * keeping the record of the furthest failure consistent.
354
+ */
355
+ replaceFailure(failure) {
356
+ if (this.deepest === this.failure) this.deepest = failure;
357
+ this.failure = failure;
358
+ }
359
+ /**
360
+ * The failure to report to the user: the current failure, or the furthest
361
+ * failure if it lies beyond the current one and the current failure is a
362
+ * plain syntax error (no user cause or message).
363
+ */
364
+ reportedFailure() {
365
+ const f = this.failure;
366
+ const d = this.deepest;
367
+ if (d === void 0 || d === f || d.offset <= f.offset || this.mode === "Incomplete" || f.hasCause || f.message !== void 0) return f;
368
+ const context = d.context.length === 0 ? f.context : [...d.context, ...f.context.filter((l) => !d.context.includes(l))];
369
+ return new Failure(d.offset, d.kind, d.expected, context, d.hasCause, d.cause, d.message, d.needed);
370
+ }
371
+ /**
372
+ * Records that, at `offset`, any of `expected` could also have been
373
+ * accepted. Used by parsers that stop without failing, such as `opt`,
374
+ * `repeat` and `Ascii.digit1`.
375
+ */
376
+ setHint(offset, expected) {
377
+ if (this.hintOffset === offset) this.hintExpected = mergeExpected(this.hintExpected, expected);
378
+ else {
379
+ this.hintOffset = offset;
380
+ this.hintExpected = expected;
381
+ }
382
+ }
383
+ /** @internal */
384
+ makeFailure(offset, kind, expected) {
385
+ if (this.hintOffset === offset && this.hintExpected.length > 0) expected = mergeExpected(this.hintExpected, expected);
386
+ return new Failure(offset, kind, expected, empty, false, void 0, void 0, 0);
387
+ }
388
+ };
283
389
  /** @internal */
284
- export const mergeExpected = (a, b) => {
285
- if (a.length === 0)
286
- return b;
287
- if (b.length === 0)
288
- return a;
289
- const out = a.slice();
290
- for (const e of b) {
291
- if (!out.includes(e))
292
- out.push(e);
293
- }
294
- return out;
390
+ const mergeExpected = (a, b) => {
391
+ if (a.length === 0) return b;
392
+ if (b.length === 0) return a;
393
+ const out = a.slice();
394
+ for (const e of b) if (!out.includes(e)) out.push(e);
395
+ return out;
396
+ };
397
+ /**
398
+ * Combines the failures of two alternatives: the furthest failure wins, and
399
+ * failures at the same offset have their expectations merged.
400
+ *
401
+ * @internal
402
+ */
403
+ const mergeFailures = (a, b) => {
404
+ if (a.offset > b.offset) return a;
405
+ if (b.offset > a.offset) return b;
406
+ return mergeTiedFailures(a, b, mergeExpected(a.expected, b.expected));
295
407
  };
296
408
  /**
297
- * Combines the failures of two alternatives: the furthest failure wins, and
298
- * failures at the same offset have their expectations merged.
299
- *
300
- * @internal
301
- */
302
- export const mergeFailures = (a, b) => {
303
- if (a.offset > b.offset)
304
- return a;
305
- if (b.offset > a.offset)
306
- return b;
307
- const expected = mergeExpected(a.expected, b.expected);
308
- if (expected === b.expected)
309
- return b;
310
- return new Failure(b.offset, b.kind, expected, b.context.length > 0 ? b.context : a.context, b.hasCause || a.hasCause, b.hasCause ? b.cause : a.cause, b.message ?? a.message, b.needed);
409
+ * {@link mergeFailures} for two failures at the same offset, given their
410
+ * merged expectations (`mergeExpected(a.expected, b.expected)`, possibly
411
+ * memoised by the caller).
412
+ *
413
+ * @internal
414
+ */
415
+ const mergeTiedFailures = (a, b, expected) => {
416
+ if (expected === b.expected) return b;
417
+ return new Failure(b.offset, b.kind, expected, b.context.length > 0 ? b.context : a.context, b.hasCause || a.hasCause, b.hasCause ? b.cause : a.cause, b.message ?? a.message, b.needed);
311
418
  };
419
+ //#endregion
420
+ export { Fail, Failure, State, emptyStrings, fromSource, mergeExpected, mergeFailures, mergeTiedFailures };
421
+
312
422
  //# sourceMappingURL=Input.js.map