@thomasfosterau/effect-parse 0.4.1 → 0.5.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.
- package/README.md +37 -13
- package/dist/Ascii.d.ts +11 -4
- package/dist/Ascii.d.ts.map +1 -1
- package/dist/Ascii.js +7 -1
- package/dist/Ascii.js.map +1 -1
- package/dist/Binary.d.ts.map +1 -1
- package/dist/Binary.js +64 -35
- package/dist/Binary.js.map +1 -1
- package/dist/Bits.d.ts.map +1 -1
- package/dist/Bits.js +7 -4
- package/dist/Bits.js.map +1 -1
- package/dist/Compiler.d.ts +74 -2
- package/dist/Compiler.d.ts.map +1 -1
- package/dist/Compiler.js +78 -1
- package/dist/Compiler.js.map +1 -1
- package/dist/Expression.d.ts.map +1 -1
- package/dist/Expression.js +86 -74
- package/dist/Expression.js.map +1 -1
- package/dist/Input.d.ts +37 -4
- package/dist/Input.d.ts.map +1 -1
- package/dist/Input.js +42 -0
- package/dist/Input.js.map +1 -1
- package/dist/Nom.d.ts +5 -15
- package/dist/Nom.d.ts.map +1 -1
- package/dist/Nom.js.map +1 -1
- package/dist/ParseError.d.ts.map +1 -1
- package/dist/ParseError.js.map +1 -1
- package/dist/Parser.d.ts +366 -26
- package/dist/Parser.d.ts.map +1 -1
- package/dist/Parser.js +390 -19
- package/dist/Parser.js.map +1 -1
- package/dist/ParserSchema.js +1 -1
- package/dist/ParserStream.d.ts +3 -2
- package/dist/ParserStream.d.ts.map +1 -1
- package/dist/ParserStream.js +13 -9
- package/dist/ParserStream.js.map +1 -1
- package/dist/Syntax.d.ts +23 -5
- package/dist/Syntax.d.ts.map +1 -1
- package/dist/Syntax.js.map +1 -1
- package/dist/Text.d.ts.map +1 -1
- package/dist/Text.js +9 -9
- package/dist/Text.js.map +1 -1
- package/dist/Token.d.ts +55 -10
- package/dist/Token.d.ts.map +1 -1
- package/dist/Token.js +59 -21
- package/dist/Token.js.map +1 -1
- package/dist/internal/compiler/closure.d.ts.map +1 -1
- package/dist/internal/compiler/closure.js +257 -97
- package/dist/internal/compiler/closure.js.map +1 -1
- package/dist/internal/compiler/entries.d.ts +3 -1
- package/dist/internal/compiler/entries.d.ts.map +1 -1
- package/dist/internal/compiler/entries.js +3 -2
- package/dist/internal/compiler/entries.js.map +1 -1
- package/dist/internal/compiler/first.d.ts.map +1 -1
- package/dist/internal/compiler/first.js +7 -1
- package/dist/internal/compiler/first.js.map +1 -1
- package/dist/internal/compiler/graph.d.ts +17 -0
- package/dist/internal/compiler/graph.d.ts.map +1 -0
- package/dist/internal/compiler/graph.js +56 -0
- package/dist/internal/compiler/graph.js.map +1 -0
- package/dist/internal/compiler/jit.d.ts +5 -0
- package/dist/internal/compiler/jit.d.ts.map +1 -1
- package/dist/internal/compiler/jit.js +185 -96
- package/dist/internal/compiler/jit.js.map +1 -1
- package/dist/internal/compiler/registry.d.ts +10 -2
- package/dist/internal/compiler/registry.d.ts.map +1 -1
- package/dist/internal/compiler/registry.js.map +1 -1
- package/dist/internal/compiler/search.d.ts +32 -0
- package/dist/internal/compiler/search.d.ts.map +1 -0
- package/dist/internal/compiler/search.js +68 -0
- package/dist/internal/compiler/search.js.map +1 -0
- package/dist/internal/compiler/sets.d.ts.map +1 -1
- package/dist/internal/compiler/sets.js +1 -1
- package/dist/internal/compiler/sets.js.map +1 -1
- package/dist/internal/compiler/wasm.d.ts +8 -0
- package/dist/internal/compiler/wasm.d.ts.map +1 -0
- package/dist/internal/compiler/wasm.js +2769 -0
- package/dist/internal/compiler/wasm.js.map +1 -0
- package/dist/internal/compiler/wasmAsm.d.ts +199 -0
- package/dist/internal/compiler/wasmAsm.d.ts.map +1 -0
- package/dist/internal/compiler/wasmAsm.js +427 -0
- package/dist/internal/compiler/wasmAsm.js.map +1 -0
- package/dist/internal/entries.d.ts +3 -1
- package/dist/internal/entries.d.ts.map +1 -1
- package/dist/internal/entries.js.map +1 -1
- package/dist/internal/node.d.ts +58 -2
- package/dist/internal/node.d.ts.map +1 -1
- package/dist/internal/node.js +13 -3
- package/dist/internal/node.js.map +1 -1
- package/dist/internal/numbers.d.ts.map +1 -1
- package/dist/internal/numbers.js.map +1 -1
- package/dist/internal/run.d.ts +12 -0
- package/dist/internal/run.d.ts.map +1 -1
- package/dist/internal/run.js +51 -11
- package/dist/internal/run.js.map +1 -1
- package/dist/internal/stack.d.ts +6 -0
- package/dist/internal/stack.d.ts.map +1 -1
- package/dist/internal/stack.js +8 -2
- package/dist/internal/stack.js.map +1 -1
- package/dist/internal/syntax.d.ts +4 -4
- package/dist/internal/syntax.d.ts.map +1 -1
- package/dist/internal/syntax.js +18 -10
- package/dist/internal/syntax.js.map +1 -1
- package/dist/internal/text.d.ts +32 -0
- package/dist/internal/text.d.ts.map +1 -1
- package/dist/internal/text.js +68 -14
- package/dist/internal/text.js.map +1 -1
- package/dist/internal/tokens.d.ts +13 -0
- package/dist/internal/tokens.d.ts.map +1 -1
- package/dist/internal/tokens.js +59 -39
- package/dist/internal/tokens.js.map +1 -1
- package/package.json +5 -4
- package/src/Ascii.ts +42 -9
- package/src/Binary.ts +151 -71
- package/src/Bits.ts +12 -6
- package/src/Compiler.ts +101 -10
- package/src/Expression.ts +94 -81
- package/src/Input.ts +65 -6
- package/src/Nom.ts +15 -5
- package/src/ParseError.ts +3 -0
- package/src/Parser.ts +678 -127
- package/src/ParserStream.ts +37 -18
- package/src/Syntax.ts +60 -36
- package/src/Text.ts +16 -15
- package/src/Token.ts +138 -29
- package/src/internal/compiler/closure.ts +362 -135
- package/src/internal/compiler/entries.ts +4 -2
- package/src/internal/compiler/first.ts +10 -0
- package/src/internal/compiler/graph.ts +68 -0
- package/src/internal/compiler/jit.ts +284 -154
- package/src/internal/compiler/registry.ts +10 -2
- package/src/internal/compiler/search.ts +68 -0
- package/src/internal/compiler/sets.ts +7 -3
- package/src/internal/compiler/wasm.ts +3203 -0
- package/src/internal/compiler/wasmAsm.ts +484 -0
- package/src/internal/entries.ts +8 -2
- package/src/internal/node.ts +54 -4
- package/src/internal/numbers.ts +3 -1
- package/src/internal/run.ts +71 -12
- package/src/internal/stack.ts +8 -1
- package/src/internal/syntax.ts +39 -18
- package/src/internal/text.ts +97 -9
- package/src/internal/tokens.ts +96 -14
package/src/Expression.ts
CHANGED
|
@@ -38,7 +38,10 @@ import * as Predicate from "effect/Predicate"
|
|
|
38
38
|
import type { Input, State } from "./Input.js"
|
|
39
39
|
import { Fail } from "./Input.js"
|
|
40
40
|
import type { Parser } from "./Parser.js"
|
|
41
|
-
import {
|
|
41
|
+
import { combinator } from "./Parser.js"
|
|
42
|
+
|
|
43
|
+
/** A parser's step, interpreted or compiled. */
|
|
44
|
+
type Step = (state: State<any>) => unknown
|
|
42
45
|
import { TiedFailures } from "./internal/ties.js"
|
|
43
46
|
|
|
44
47
|
/**
|
|
@@ -154,101 +157,111 @@ export const make = <A, E, R, I extends Input, const Ops extends ReadonlyArray<O
|
|
|
154
157
|
readonly operand: Parser<A, E, R, I>
|
|
155
158
|
readonly operators: Ops
|
|
156
159
|
}): Parser<A, E | OpError<Ops[number]>, R | OpServices<Ops[number]>, I & OpInput<Ops[number]>> => {
|
|
157
|
-
const operand = options.operand.step
|
|
158
160
|
const prefixes = options.operators.filter((o): o is Prefix<A, any, any, any> => Predicate.isTagged(o, "Prefix"))
|
|
159
161
|
const postfixes = options.operators.filter((o): o is Postfix<A, any, any, any> => Predicate.isTagged(o, "Postfix"))
|
|
160
162
|
const infixes = options.operators.filter((o): o is Infix<A, any, any, any> => Predicate.isTagged(o, "Infix"))
|
|
163
|
+
const operators = [...prefixes, ...postfixes, ...infixes]
|
|
164
|
+
const parsers = [options.operand, ...operators.map((o) => o.parser)]
|
|
165
|
+
// Builds the step from the operand's and the operators' steps, in that
|
|
166
|
+
// order: their own steps when interpreted, compiled ones when compiled
|
|
167
|
+
const build = (steps: ReadonlyArray<Step>) => {
|
|
168
|
+
const operand = steps[0]
|
|
169
|
+
const prefixSteps = steps.slice(1, 1 + prefixes.length)
|
|
170
|
+
const postfixSteps = steps.slice(1 + prefixes.length, 1 + prefixes.length + postfixes.length)
|
|
171
|
+
const infixSteps = steps.slice(1 + prefixes.length + postfixes.length)
|
|
161
172
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
173
|
+
// Attempts each operator in turn. Returns the index of the first match
|
|
174
|
+
// (with its output in `matched`), -1 if none matched, or -2 on a fatal
|
|
175
|
+
// failure. Failed attempts are folded into `failures`, merged only when
|
|
176
|
+
// read (#44): a round in which an operator matches discards them unmerged.
|
|
177
|
+
// Like `matched`, it is shared by nested expressions, which clear it.
|
|
178
|
+
let matched: unknown
|
|
179
|
+
const failures = new TiedFailures()
|
|
180
|
+
const tryOps = (state: State<any>, ops: ReadonlyArray<Step>, mustConsume: boolean): number => {
|
|
181
|
+
const start = state.pos
|
|
182
|
+
for (let i = 0; i < ops.length; i++) {
|
|
183
|
+
const out = ops[i](state)
|
|
184
|
+
if (out !== Fail) {
|
|
185
|
+
// A prefix or postfix operator matching nothing would apply forever
|
|
186
|
+
if (mustConsume && state.pos === start) {
|
|
187
|
+
state.failMessage("Cut", "Assert", "prefix and postfix operators must always consume")
|
|
188
|
+
return -2
|
|
189
|
+
}
|
|
190
|
+
matched = out
|
|
191
|
+
return i
|
|
178
192
|
}
|
|
179
|
-
|
|
180
|
-
|
|
193
|
+
if (state.mode !== "Backtrack") return -2
|
|
194
|
+
state.rewind(start)
|
|
195
|
+
failures.add(state)
|
|
181
196
|
}
|
|
182
|
-
|
|
183
|
-
state.rewind(start)
|
|
184
|
-
failures.add(state)
|
|
197
|
+
return -1
|
|
185
198
|
}
|
|
186
|
-
return -1
|
|
187
|
-
}
|
|
188
199
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
if (
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
200
|
+
const expr = (state: State<any>, minPower: number): A | Fail => {
|
|
201
|
+
let lhs: A | Fail
|
|
202
|
+
failures.clear()
|
|
203
|
+
const p = tryOps(state, prefixSteps, true)
|
|
204
|
+
if (p === -2) return Fail
|
|
205
|
+
if (p >= 0) {
|
|
206
|
+
const op = prefixes[p]
|
|
207
|
+
const opOut = matched
|
|
208
|
+
const operandValue = expr(state, op.precedence * 2)
|
|
209
|
+
if (operandValue === Fail) return Fail
|
|
210
|
+
lhs = op.fold(opOut, operandValue)
|
|
211
|
+
} else {
|
|
212
|
+
const prefixFailure = failures.failure
|
|
213
|
+
const prefixTie1 = failures.tie1
|
|
214
|
+
const prefixTie2 = failures.tie2
|
|
215
|
+
// SAFETY: the operand's step, interpreted or compiled, returns its output (an `A`) or `Fail`
|
|
216
|
+
lhs = operand(state) as A | Fail
|
|
217
|
+
if (lhs === Fail) {
|
|
218
|
+
if (prefixFailure !== undefined && state.mode === "Backtrack") {
|
|
219
|
+
// The operand may have parsed nested expressions, which reuse `failures`
|
|
220
|
+
failures.failure = prefixFailure
|
|
221
|
+
failures.tie1 = prefixTie1
|
|
222
|
+
failures.tie2 = prefixTie2
|
|
223
|
+
failures.add(state)
|
|
224
|
+
failures.fail(state)
|
|
225
|
+
}
|
|
226
|
+
return Fail
|
|
213
227
|
}
|
|
214
|
-
return Fail
|
|
215
228
|
}
|
|
216
|
-
}
|
|
217
229
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
230
|
+
while (true) {
|
|
231
|
+
const start = state.pos
|
|
232
|
+
failures.clear()
|
|
233
|
+
const q = tryOps(state, postfixSteps, true)
|
|
234
|
+
if (q === -2) return Fail
|
|
235
|
+
if (q >= 0) {
|
|
236
|
+
const op = postfixes[q]
|
|
237
|
+
if (op.precedence * 2 < minPower) {
|
|
238
|
+
state.rewind(start)
|
|
239
|
+
break
|
|
240
|
+
}
|
|
241
|
+
lhs = op.fold(lhs, matched)
|
|
242
|
+
continue
|
|
243
|
+
}
|
|
244
|
+
// The infix attempts are folded on top of the postfix ones
|
|
245
|
+
const i = tryOps(state, infixSteps, false)
|
|
246
|
+
if (i === -2) return Fail
|
|
247
|
+
if (i < 0) {
|
|
248
|
+
failures.hint(state)
|
|
249
|
+
break
|
|
250
|
+
}
|
|
251
|
+
const op = infixes[i]
|
|
252
|
+
const leftPower = op.precedence * 2
|
|
253
|
+
if (leftPower < minPower) {
|
|
226
254
|
state.rewind(start)
|
|
227
255
|
break
|
|
228
256
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
const i = tryOps(state, infixes, false)
|
|
234
|
-
if (i === -2) return Fail
|
|
235
|
-
if (i < 0) {
|
|
236
|
-
failures.hint(state)
|
|
237
|
-
break
|
|
257
|
+
const opOut = matched
|
|
258
|
+
const rhs = expr(state, op.associativity === "left" ? leftPower + 1 : leftPower)
|
|
259
|
+
if (rhs === Fail) return Fail
|
|
260
|
+
lhs = op.fold(lhs, opOut, rhs)
|
|
238
261
|
}
|
|
239
|
-
|
|
240
|
-
const leftPower = op.precedence * 2
|
|
241
|
-
if (leftPower < minPower) {
|
|
242
|
-
state.rewind(start)
|
|
243
|
-
break
|
|
244
|
-
}
|
|
245
|
-
const opOut = matched
|
|
246
|
-
const rhs = expr(state, op.associativity === "left" ? leftPower + 1 : leftPower)
|
|
247
|
-
if (rhs === Fail) return Fail
|
|
248
|
-
lhs = op.fold(lhs, opOut, rhs)
|
|
262
|
+
return lhs
|
|
249
263
|
}
|
|
250
|
-
return
|
|
264
|
+
return (state: State<any>) => expr(state, 0)
|
|
251
265
|
}
|
|
252
|
-
|
|
253
|
-
return makeParser((state: State<any>) => expr(state, 0), "expression")
|
|
266
|
+
return combinator(parsers, build, "expression")
|
|
254
267
|
}
|
package/src/Input.ts
CHANGED
|
@@ -19,6 +19,7 @@ import * as Context from "effect/Context"
|
|
|
19
19
|
import type { Encoding } from "./Encoding.js"
|
|
20
20
|
import type { ErrorKind } from "./ParseError.js"
|
|
21
21
|
import type { Builder as SyntaxBuilder } from "./internal/syntax.js"
|
|
22
|
+
import type { AsciiRun } from "./internal/text.js"
|
|
22
23
|
|
|
23
24
|
/**
|
|
24
25
|
* The kinds of input a parser can consume.
|
|
@@ -56,6 +57,17 @@ export type BinaryInput = ArrayBufferLike | ArrayBufferView
|
|
|
56
57
|
*/
|
|
57
58
|
export type Source<I> = I | ([I] extends [Uint8Array] ? BinaryInput : never)
|
|
58
59
|
|
|
60
|
+
/**
|
|
61
|
+
* The overloads of {@link fromSource}.
|
|
62
|
+
*
|
|
63
|
+
* @since 0.5.0
|
|
64
|
+
* @category constructors
|
|
65
|
+
*/
|
|
66
|
+
export interface FromSourceFn {
|
|
67
|
+
(source: BinaryInput): Uint8Array
|
|
68
|
+
<I extends Input>(source: Source<I>): I
|
|
69
|
+
}
|
|
70
|
+
|
|
59
71
|
/**
|
|
60
72
|
* Converts a {@link Source} to the input parsers read: binary data becomes a
|
|
61
73
|
* `Uint8Array` view of the same memory, everything else is returned as is.
|
|
@@ -70,10 +82,7 @@ export type Source<I> = I | ([I] extends [Uint8Array] ? BinaryInput : never)
|
|
|
70
82
|
* @since 0.1.0
|
|
71
83
|
* @category constructors
|
|
72
84
|
*/
|
|
73
|
-
export const fromSource: {
|
|
74
|
-
(source: BinaryInput): Uint8Array
|
|
75
|
-
<I extends Input>(source: Source<I>): I
|
|
76
|
-
} = (source: Input | BinaryInput): any => {
|
|
85
|
+
export const fromSource: FromSourceFn = (source: Input | BinaryInput): any => {
|
|
77
86
|
if (Predicate.isString(source) || source instanceof Uint8Array || Array.isArray(source)) return source
|
|
78
87
|
if (ArrayBuffer.isView(source)) return new Uint8Array(source.buffer, source.byteOffset, source.byteLength)
|
|
79
88
|
// An explicit length fixes the view's size even for a resizable buffer
|
|
@@ -292,6 +301,31 @@ export class State<I extends Input = Input> {
|
|
|
292
301
|
* @internal
|
|
293
302
|
*/
|
|
294
303
|
syntax: SyntaxBuilder | undefined = undefined
|
|
304
|
+
/**
|
|
305
|
+
* Where the stop characters of compiled `takeTill`s next occur in this
|
|
306
|
+
* 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.
|
|
309
|
+
*
|
|
310
|
+
* @internal
|
|
311
|
+
*/
|
|
312
|
+
searches: Map<object, Array<number>> | undefined = undefined
|
|
313
|
+
/**
|
|
314
|
+
* A run of ASCII bytes of this state's UTF-8 input, decoded once, from
|
|
315
|
+
* which `Text.utf8` slices the long strings it decodes (see
|
|
316
|
+
* `internal/text.ts`); `reset` clears it with the other per-run fields.
|
|
317
|
+
*
|
|
318
|
+
* @internal
|
|
319
|
+
*/
|
|
320
|
+
asciiRun: AsciiRun | undefined = undefined
|
|
321
|
+
/**
|
|
322
|
+
* A `DataView` of this state's byte input, for the `Binary` parsers;
|
|
323
|
+
* created on first use. It lives as long as the state, whose input never
|
|
324
|
+
* changes: one per read cost most of a number's time.
|
|
325
|
+
*
|
|
326
|
+
* @internal
|
|
327
|
+
*/
|
|
328
|
+
view: DataView | undefined = undefined
|
|
295
329
|
|
|
296
330
|
constructor(
|
|
297
331
|
source: I | Source<I>,
|
|
@@ -301,7 +335,7 @@ export class State<I extends Input = Input> {
|
|
|
301
335
|
readonly offset?: number | undefined
|
|
302
336
|
}
|
|
303
337
|
) {
|
|
304
|
-
const input = fromSource(source
|
|
338
|
+
const input = fromSource<I>(source)
|
|
305
339
|
this.input = input
|
|
306
340
|
this.end = input.length
|
|
307
341
|
this.pos = options?.offset ?? 0
|
|
@@ -393,6 +427,8 @@ export class State<I extends Input = Input> {
|
|
|
393
427
|
this.depth = 0
|
|
394
428
|
this.encoding = undefined
|
|
395
429
|
this.resume = undefined
|
|
430
|
+
this.searches = undefined
|
|
431
|
+
this.asciiRun = undefined
|
|
396
432
|
return this
|
|
397
433
|
}
|
|
398
434
|
|
|
@@ -445,7 +481,14 @@ export class State<I extends Input = Input> {
|
|
|
445
481
|
* Extracts the slice `[start, end)` of the input.
|
|
446
482
|
*/
|
|
447
483
|
slice(start: number, end: number): Slice<I> {
|
|
448
|
-
|
|
484
|
+
// SAFETY: `inputKind` 1 is a `Uint8Array`, whose `subarray` returns a
|
|
485
|
+
// `Uint8Array` view (its `Slice`); 0 and 2 are a string and an array, whose
|
|
486
|
+
// `slice` returns a string and an array of the same elements (their
|
|
487
|
+
// `Slice`). `subarray` is only called for kind 1
|
|
488
|
+
const input = this.input as {
|
|
489
|
+
slice(start: number, end: number): Slice<I>
|
|
490
|
+
subarray(start: number, end: number): Slice<I>
|
|
491
|
+
} & I
|
|
449
492
|
switch (this.inputKind) {
|
|
450
493
|
case 0:
|
|
451
494
|
return input.slice(start, end)
|
|
@@ -598,14 +641,30 @@ export class State<I extends Input = Input> {
|
|
|
598
641
|
}
|
|
599
642
|
}
|
|
600
643
|
|
|
644
|
+
/**
|
|
645
|
+
* The last merges {@link mergeExpected} made, as `[a, b, merged]` triples. A
|
|
646
|
+
* parse merges the same few pairs of expectation arrays over and over (a
|
|
647
|
+
* whitespace skipper's hint with a repetition's, then with the failure of
|
|
648
|
+
* the token after them), and expectation arrays are never mutated, so a
|
|
649
|
+
* merge seen recently returns its earlier result, which in turn keeps the
|
|
650
|
+
* next merge's input the same array.
|
|
651
|
+
*/
|
|
652
|
+
const merges: Array<ReadonlyArray<string>> = /*#__PURE__*/ new Array(12).fill(empty)
|
|
653
|
+
let mergeSlot = 0
|
|
654
|
+
|
|
601
655
|
/** @internal */
|
|
602
656
|
export const mergeExpected = (a: ReadonlyArray<string>, b: ReadonlyArray<string>): ReadonlyArray<string> => {
|
|
603
657
|
if (Arr.isReadonlyArrayEmpty(a)) return b
|
|
604
658
|
if (Arr.isReadonlyArrayEmpty(b)) return a
|
|
659
|
+
for (let i = 0; i < 12; i += 3) if (merges[i] === a && merges[i + 1] === b) return merges[i + 2]
|
|
605
660
|
const out = a.slice()
|
|
606
661
|
for (const e of b) {
|
|
607
662
|
if (!out.includes(e)) out.push(e)
|
|
608
663
|
}
|
|
664
|
+
merges[mergeSlot] = a
|
|
665
|
+
merges[mergeSlot + 1] = b
|
|
666
|
+
merges[mergeSlot + 2] = out
|
|
667
|
+
mergeSlot = mergeSlot === 9 ? 0 : mergeSlot + 3
|
|
609
668
|
return out
|
|
610
669
|
}
|
|
611
670
|
|
package/src/Nom.ts
CHANGED
|
@@ -132,7 +132,9 @@ export const take = Token.take
|
|
|
132
132
|
*/
|
|
133
133
|
export const takeWhile = <I extends Input = string>(
|
|
134
134
|
predicate: (token: TokenOf<I>) => boolean
|
|
135
|
-
): Parser<Slice<NoInfer<I>>, never, never, NoInfer<I>> =>
|
|
135
|
+
): Parser<Slice<NoInfer<I>>, never, never, NoInfer<I>> =>
|
|
136
|
+
// SAFETY: a predicate over the input's tokens is a member of `TokenSet<I>` for each input kind
|
|
137
|
+
Token.takeWhile<I>(predicate as Token.TokenSet<I>)
|
|
136
138
|
|
|
137
139
|
/**
|
|
138
140
|
* @since 0.1.0
|
|
@@ -140,7 +142,9 @@ export const takeWhile = <I extends Input = string>(
|
|
|
140
142
|
*/
|
|
141
143
|
export const takeWhile1 = <I extends Input = string>(
|
|
142
144
|
predicate: (token: TokenOf<I>) => boolean
|
|
143
|
-
): Parser<Slice<NoInfer<I>>, never, never, NoInfer<I>> =>
|
|
145
|
+
): Parser<Slice<NoInfer<I>>, never, never, NoInfer<I>> =>
|
|
146
|
+
// SAFETY: a predicate over the input's tokens is a member of `TokenSet<I>` for each input kind
|
|
147
|
+
Token.takeWhile<I>(predicate as Token.TokenSet<I>, { min: 1 })
|
|
144
148
|
|
|
145
149
|
/**
|
|
146
150
|
* @since 0.1.0
|
|
@@ -150,7 +154,9 @@ export const takeWhileMN = <I extends Input = string>(
|
|
|
150
154
|
m: number,
|
|
151
155
|
n: number,
|
|
152
156
|
predicate: (token: TokenOf<I>) => boolean
|
|
153
|
-
): Parser<Slice<NoInfer<I>>, never, never, NoInfer<I>> =>
|
|
157
|
+
): Parser<Slice<NoInfer<I>>, never, never, NoInfer<I>> =>
|
|
158
|
+
// SAFETY: a predicate over the input's tokens is a member of `TokenSet<I>` for each input kind
|
|
159
|
+
Token.takeWhile<I>(predicate as Token.TokenSet<I>, { min: m, max: n })
|
|
154
160
|
|
|
155
161
|
/**
|
|
156
162
|
* @since 0.1.0
|
|
@@ -158,7 +164,9 @@ export const takeWhileMN = <I extends Input = string>(
|
|
|
158
164
|
*/
|
|
159
165
|
export const takeTill = <I extends Input = string>(
|
|
160
166
|
predicate: (token: TokenOf<I>) => boolean
|
|
161
|
-
): Parser<Slice<NoInfer<I>>, never, never, NoInfer<I>> =>
|
|
167
|
+
): Parser<Slice<NoInfer<I>>, never, never, NoInfer<I>> =>
|
|
168
|
+
// SAFETY: a predicate over the input's tokens is a member of `TokenSet<I>` for each input kind
|
|
169
|
+
Token.takeTill<I>(predicate as Token.TokenSet<I>)
|
|
162
170
|
|
|
163
171
|
/**
|
|
164
172
|
* @since 0.1.0
|
|
@@ -166,7 +174,9 @@ export const takeTill = <I extends Input = string>(
|
|
|
166
174
|
*/
|
|
167
175
|
export const takeTill1 = <I extends Input = string>(
|
|
168
176
|
predicate: (token: TokenOf<I>) => boolean
|
|
169
|
-
): Parser<Slice<NoInfer<I>>, never, never, NoInfer<I>> =>
|
|
177
|
+
): Parser<Slice<NoInfer<I>>, never, never, NoInfer<I>> =>
|
|
178
|
+
// SAFETY: a predicate over the input's tokens is a member of `TokenSet<I>` for each input kind
|
|
179
|
+
Token.takeTill<I>(predicate as Token.TokenSet<I>, { min: 1 })
|
|
170
180
|
|
|
171
181
|
/**
|
|
172
182
|
* @since 0.1.0
|
package/src/ParseError.ts
CHANGED
|
@@ -167,6 +167,9 @@ export const fromFailure = <E = never>(
|
|
|
167
167
|
mode,
|
|
168
168
|
expected: failure.expected,
|
|
169
169
|
context: failure.context,
|
|
170
|
+
// SAFETY: `E` is the user error type of the parser whose run recorded
|
|
171
|
+
// `failure`; a failure with `hasCause` carries a cause raised by that
|
|
172
|
+
// parser's `fail` / `mapError`
|
|
170
173
|
cause: failure.hasCause ? (failure.cause as E) : undefined,
|
|
171
174
|
description: failure.message,
|
|
172
175
|
encoding: input instanceof Uint8Array ? encoding : undefined
|