@thomasfosterau/effect-parse 0.4.0 → 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 +40 -14
- 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 +2 -2
- package/dist/ParseError.d.ts.map +1 -1
- package/dist/ParseError.js +1 -1
- package/dist/ParseError.js.map +1 -1
- package/dist/Parser.d.ts +370 -28
- 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 +2 -2
- package/dist/ParserSchema.js.map +1 -1
- package/dist/ParserStream.d.ts +3 -2
- package/dist/ParserStream.d.ts.map +1 -1
- package/dist/ParserStream.js +15 -10
- 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 +1 -2
- 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 +9 -4
- package/src/Parser.ts +682 -129
- package/src/ParserSchema.ts +1 -1
- package/src/ParserStream.ts +40 -19
- 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 +10 -4
- 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/internal/tokens.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
// fallow-ignore-file duplicate-export -- `End` and `scan` here are the token-set versions of the text
|
|
2
|
-
// helpers in ./text.ts; both are internal modules, imported by path, never re-exported from one barrel.
|
|
3
1
|
import * as Predicate from "effect/Predicate"
|
|
4
2
|
import * as Result from "effect/Result"
|
|
5
3
|
import type { Input, State } from "../Input.js"
|
|
@@ -22,7 +20,7 @@ export interface TokenRangeLike {
|
|
|
22
20
|
readonly to: string | number
|
|
23
21
|
}
|
|
24
22
|
|
|
25
|
-
const isRange = (u: unknown): u is TokenRangeLike => Predicate.isObjectOrArray(u) && (u
|
|
23
|
+
const isRange = (u: unknown): u is TokenRangeLike => Predicate.isObjectOrArray(u) && Predicate.isTagged(u, "TokenRange")
|
|
26
24
|
|
|
27
25
|
const toCode = (u: string | number): number => (Predicate.isNumber(u) ? u : firstCodePoint(u))
|
|
28
26
|
|
|
@@ -67,7 +65,10 @@ const compileCode = (u: unknown): ((code: number) => boolean) => {
|
|
|
67
65
|
return bitmap(codes)
|
|
68
66
|
}
|
|
69
67
|
if (Predicate.isNumber(u)) return (x) => x === u
|
|
70
|
-
if (Predicate.isFunction(u))
|
|
68
|
+
if (Predicate.isFunction(u)) {
|
|
69
|
+
// SAFETY: a predicate compiled for codes is a byte, code point or `codePoints` predicate (`compile` wraps string predicates first)
|
|
70
|
+
return u as (code: number) => boolean
|
|
71
|
+
}
|
|
71
72
|
if (u instanceof Uint8Array) return bitmap(Array.from(u))
|
|
72
73
|
if (isRange(u)) {
|
|
73
74
|
const from = toCode(u.from)
|
|
@@ -98,7 +99,10 @@ const bitmap = (codes: ReadonlyArray<number>): ((code: number) => boolean) => {
|
|
|
98
99
|
}
|
|
99
100
|
|
|
100
101
|
const compileToken = (u: unknown): ((token: unknown) => boolean) => {
|
|
101
|
-
if (Predicate.isFunction(u))
|
|
102
|
+
if (Predicate.isFunction(u)) {
|
|
103
|
+
// SAFETY: a predicate in an array input's token set takes the array's elements, the tokens tested here
|
|
104
|
+
return u as (token: unknown) => boolean
|
|
105
|
+
}
|
|
102
106
|
if (Array.isArray(u)) {
|
|
103
107
|
const set = new Set(u)
|
|
104
108
|
return (t) => set.has(t)
|
|
@@ -130,8 +134,13 @@ export const codePointPredicate = <F extends (c: never) => boolean>(
|
|
|
130
134
|
ranges?: ReadonlyArray<readonly [number, number]>
|
|
131
135
|
): F => {
|
|
132
136
|
Object.defineProperty(f, "name", { value: name })
|
|
133
|
-
|
|
134
|
-
|
|
137
|
+
// SAFETY: `f` is a function object, which takes new properties; the intersection only names the two markers set here
|
|
138
|
+
const marked = f as F & {
|
|
139
|
+
[CodePointPredicate]?: true
|
|
140
|
+
[PredicateRanges]?: ReadonlyArray<readonly [number, number]>
|
|
141
|
+
}
|
|
142
|
+
marked[CodePointPredicate] = true
|
|
143
|
+
if (ranges !== undefined) marked[PredicateRanges] = ranges
|
|
135
144
|
return f
|
|
136
145
|
}
|
|
137
146
|
|
|
@@ -144,6 +153,7 @@ export const compile = (set: unknown, kind: "string" | "code" = "code"): Matcher
|
|
|
144
153
|
const description = describeSet(set)
|
|
145
154
|
let code: (code: number) => boolean
|
|
146
155
|
if (Predicate.isFunction(set) && kind === "string" && !(CodePointPredicate in set)) {
|
|
156
|
+
// SAFETY: an unmarked predicate in a string token set takes each character as a string (`StringTokenSet`)
|
|
147
157
|
const pred = set as (c: string) => boolean
|
|
148
158
|
code = (x) => pred(charOf(x))
|
|
149
159
|
} else {
|
|
@@ -227,6 +237,7 @@ const compileAnyImpl = (set: unknown): AnyMatcher => {
|
|
|
227
237
|
*/
|
|
228
238
|
export const splitSurrogate = (state: State<Input>, i: number): boolean => {
|
|
229
239
|
if (!state.partial || i !== state.end - 1) return false
|
|
240
|
+
// SAFETY: called only on string input (the `inputKind === 0` paths of `nextIf`, `scan`, `advance` and `Token.any`)
|
|
230
241
|
const c = (state.input as string).charCodeAt(i)
|
|
231
242
|
return c >= 0xd800 && c <= 0xdbff
|
|
232
243
|
}
|
|
@@ -253,6 +264,7 @@ export const nextIf = (state: State<Input>, m: AnyMatcher, negate: boolean): unk
|
|
|
253
264
|
if (pos >= state.end) return End
|
|
254
265
|
switch (state.inputKind) {
|
|
255
266
|
case 0: {
|
|
267
|
+
// SAFETY: `inputKind` 0 is set only for a string input
|
|
256
268
|
const s = state.input as string
|
|
257
269
|
if (splitSurrogate(state, pos)) return End
|
|
258
270
|
const cp = codePointAt(s, pos)
|
|
@@ -262,12 +274,14 @@ export const nextIf = (state: State<Input>, m: AnyMatcher, negate: boolean): unk
|
|
|
262
274
|
return len === 1 ? s[pos] : s.slice(pos, pos + 2)
|
|
263
275
|
}
|
|
264
276
|
case 1: {
|
|
277
|
+
// SAFETY: `inputKind` 1 is set only for a `Uint8Array` input
|
|
265
278
|
const b = (state.input as Uint8Array)[pos]
|
|
266
279
|
if (m.forCode.code(b) === negate) return NoMatch
|
|
267
280
|
state.pos = pos + 1
|
|
268
281
|
return b
|
|
269
282
|
}
|
|
270
283
|
default: {
|
|
284
|
+
// SAFETY: `inputKind` 2 is set for every input that is neither a string nor a `Uint8Array`, an array
|
|
271
285
|
const t = (state.input as ReadonlyArray<unknown>)[pos]
|
|
272
286
|
if (m.forCode.token(t) === negate) return NoMatch
|
|
273
287
|
state.pos = pos + 1
|
|
@@ -282,10 +296,32 @@ export interface Scanned extends Advanced {
|
|
|
282
296
|
readonly hitEnd: boolean
|
|
283
297
|
}
|
|
284
298
|
|
|
299
|
+
/** The one record {@link scan} fills; see there. */
|
|
300
|
+
class ScanResult implements Scanned {
|
|
301
|
+
offset = 0
|
|
302
|
+
count = 0
|
|
303
|
+
hitEnd = false
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const scanned = /*#__PURE__*/ new ScanResult()
|
|
307
|
+
|
|
308
|
+
/** Fills {@link scanned} and returns it. */
|
|
309
|
+
const scannedAt = (offset: number, count: number, hitEnd: boolean): Scanned => {
|
|
310
|
+
scanned.offset = offset
|
|
311
|
+
scanned.count = count
|
|
312
|
+
scanned.hitEnd = hitEnd
|
|
313
|
+
return scanned
|
|
314
|
+
}
|
|
315
|
+
|
|
285
316
|
/**
|
|
286
317
|
* Scans forward while tokens satisfy the matcher (xor `negate`), up to `max`
|
|
287
318
|
* tokens. Returns the offset reached, the number of tokens matched, and
|
|
288
319
|
* whether the end of input was hit before `max` tokens.
|
|
320
|
+
*
|
|
321
|
+
* The result is one shared record, overwritten by the next scan: read it
|
|
322
|
+
* before running anything else. Allocating one per call cost the
|
|
323
|
+
* interpreter a record per token, since `scan` (shared by every `takeWhile`)
|
|
324
|
+
* is too polymorphic for V8 to inline and remove it.
|
|
289
325
|
*/
|
|
290
326
|
export const scan = (state: State<Input>, m: AnyMatcher, negate: boolean, max: number): Scanned => {
|
|
291
327
|
let i = state.pos
|
|
@@ -293,45 +329,48 @@ export const scan = (state: State<Input>, m: AnyMatcher, negate: boolean, max: n
|
|
|
293
329
|
let count = 0
|
|
294
330
|
switch (state.inputKind) {
|
|
295
331
|
case 0: {
|
|
332
|
+
// SAFETY: `inputKind` 0 is set only for a string input
|
|
296
333
|
const s = state.input as string
|
|
297
334
|
const test = m.forString.code
|
|
298
335
|
while (count < max) {
|
|
299
|
-
if (i >= end) return
|
|
336
|
+
if (i >= end) return scannedAt(i, count, true)
|
|
300
337
|
const c = s.charCodeAt(i)
|
|
301
338
|
if (c < 0xd800 || c > 0xdbff) {
|
|
302
339
|
if (test(c) === negate) break
|
|
303
340
|
i++
|
|
304
341
|
} else {
|
|
305
|
-
if (splitSurrogate(state, i)) return
|
|
342
|
+
if (splitSurrogate(state, i)) return scannedAt(i, count, true)
|
|
306
343
|
const cp = codePointAt(s, i)
|
|
307
344
|
if (test(cp) === negate) break
|
|
308
345
|
i += cp > 0xffff ? 2 : 1
|
|
309
346
|
}
|
|
310
347
|
count++
|
|
311
348
|
}
|
|
312
|
-
return
|
|
349
|
+
return scannedAt(i, count, false)
|
|
313
350
|
}
|
|
314
351
|
case 1: {
|
|
352
|
+
// SAFETY: `inputKind` 1 is set only for a `Uint8Array` input
|
|
315
353
|
const bytes = state.input as Uint8Array
|
|
316
354
|
const test = m.forCode.code
|
|
317
355
|
while (count < max) {
|
|
318
|
-
if (i >= end) return
|
|
356
|
+
if (i >= end) return scannedAt(i, count, true)
|
|
319
357
|
if (test(bytes[i]) === negate) break
|
|
320
358
|
i++
|
|
321
359
|
count++
|
|
322
360
|
}
|
|
323
|
-
return
|
|
361
|
+
return scannedAt(i, count, false)
|
|
324
362
|
}
|
|
325
363
|
default: {
|
|
364
|
+
// SAFETY: `inputKind` 2 is set for every input that is neither a string nor a `Uint8Array`, an array
|
|
326
365
|
const arr = state.input as ReadonlyArray<unknown>
|
|
327
366
|
const test = m.forCode.token
|
|
328
367
|
while (count < max) {
|
|
329
|
-
if (i >= end) return
|
|
368
|
+
if (i >= end) return scannedAt(i, count, true)
|
|
330
369
|
if (test(arr[i]) === negate) break
|
|
331
370
|
i++
|
|
332
371
|
count++
|
|
333
372
|
}
|
|
334
|
-
return
|
|
373
|
+
return scannedAt(i, count, false)
|
|
335
374
|
}
|
|
336
375
|
}
|
|
337
376
|
}
|
|
@@ -348,6 +387,7 @@ export const advance = (state: State<Input>, start: number, n: number): Advanced
|
|
|
348
387
|
const offset = Math.min(state.end, start + n)
|
|
349
388
|
return { offset, count: offset - start }
|
|
350
389
|
}
|
|
390
|
+
// SAFETY: the other input kinds returned above, and `inputKind` 0 is set only for a string input
|
|
351
391
|
const s = state.input as string
|
|
352
392
|
let i = start
|
|
353
393
|
let count = 0
|
|
@@ -363,6 +403,7 @@ export const advance = (state: State<Input>, start: number, n: number): Advanced
|
|
|
363
403
|
/** Counts tokens between two offsets. */
|
|
364
404
|
export const countTokens = (state: State<Input>, start: number, end: number): number => {
|
|
365
405
|
if (state.inputKind !== 0) return end - start
|
|
406
|
+
// SAFETY: the other input kinds returned above, and `inputKind` 0 is set only for a string input
|
|
366
407
|
const s = state.input as string
|
|
367
408
|
let count = 0
|
|
368
409
|
for (let i = start; i < end; i++) {
|
|
@@ -373,6 +414,36 @@ export const countTokens = (state: State<Input>, start: number, end: number): nu
|
|
|
373
414
|
return count
|
|
374
415
|
}
|
|
375
416
|
|
|
417
|
+
/**
|
|
418
|
+
* The first index at or after `from` of any of `needles` within
|
|
419
|
+
* `[from, state.end)`, or -1. The state remembers, under `needles`, where
|
|
420
|
+
* each one next occurs (`[from, at]` at `2 * i`), so successive searches
|
|
421
|
+
* forwards over one input search each needle once per occurrence rather
|
|
422
|
+
* than once per call (as `nextStop` does for `takeTill`).
|
|
423
|
+
*/
|
|
424
|
+
export const indexOfAny = (state: State<Input>, needles: ReadonlyArray<Input>, from: number): number => {
|
|
425
|
+
const searches = (state.searches ??= new Map())
|
|
426
|
+
let memo = searches.get(needles)
|
|
427
|
+
if (memo === undefined) {
|
|
428
|
+
memo = needles.flatMap(() => [-1, -1])
|
|
429
|
+
searches.set(needles, memo)
|
|
430
|
+
}
|
|
431
|
+
let best = -1
|
|
432
|
+
for (let i = 0; i < needles.length; i++) {
|
|
433
|
+
const known = memo[2 * i] ?? -1
|
|
434
|
+
let at = memo[2 * i + 1] ?? -1
|
|
435
|
+
const needle = needles[i] ?? ""
|
|
436
|
+
// Searched again when the input's end moved before a remembered occurrence
|
|
437
|
+
if (known < 0 || from < known || (at >= 0 && (at < from || at > state.end - needle.length))) {
|
|
438
|
+
at = indexOf(state, needle, from)
|
|
439
|
+
memo[2 * i] = from
|
|
440
|
+
memo[2 * i + 1] = at
|
|
441
|
+
}
|
|
442
|
+
if (at >= 0 && (best < 0 || at < best)) best = at
|
|
443
|
+
}
|
|
444
|
+
return best
|
|
445
|
+
}
|
|
446
|
+
|
|
376
447
|
/** Finds `needle` within `[from, state.end)`; returns -1 if absent. */
|
|
377
448
|
export const indexOf = (state: State<Input>, needle: Input, from: number): number => {
|
|
378
449
|
// The whole needle must lie before `state.end`, which may narrow the input
|
|
@@ -380,11 +451,14 @@ export const indexOf = (state: State<Input>, needle: Input, from: number): numbe
|
|
|
380
451
|
if (from > last) return -1
|
|
381
452
|
switch (state.inputKind) {
|
|
382
453
|
case 0: {
|
|
454
|
+
// SAFETY: `inputKind` 0 is set only for a string input, and the callers' types give the needle the input's kind
|
|
383
455
|
const i = (state.input as string).indexOf(needle as string, from)
|
|
384
456
|
return i <= last ? i : -1
|
|
385
457
|
}
|
|
386
458
|
case 1: {
|
|
459
|
+
// SAFETY: `inputKind` 1 is set only for a `Uint8Array` input
|
|
387
460
|
const hay = state.input as Uint8Array
|
|
461
|
+
// SAFETY: the callers' types give the needle the input's kind (`Text` encodes it for byte input)
|
|
388
462
|
const n = needle as Uint8Array
|
|
389
463
|
if (n.byteLength === 0) return from
|
|
390
464
|
const first = n[0]
|
|
@@ -398,7 +472,9 @@ export const indexOf = (state: State<Input>, needle: Input, from: number): numbe
|
|
|
398
472
|
return -1
|
|
399
473
|
}
|
|
400
474
|
default: {
|
|
475
|
+
// SAFETY: `inputKind` 2 is set for every input that is neither a string nor a `Uint8Array`, an array
|
|
401
476
|
const hay = state.input as ReadonlyArray<unknown>
|
|
477
|
+
// SAFETY: the callers' types give the needle the input's kind, an array of the same element type
|
|
402
478
|
const n = needle as ReadonlyArray<unknown>
|
|
403
479
|
outer: for (let i = from; i <= last; i++) {
|
|
404
480
|
for (let j = 0; j < n.length; j++) if (hay[i + j] !== n[j]) continue outer
|
|
@@ -428,7 +504,9 @@ const match = (state: State<Input>, lit: Input, caseless: boolean): number => {
|
|
|
428
504
|
const n = Math.min(len, avail)
|
|
429
505
|
switch (state.inputKind) {
|
|
430
506
|
case 0: {
|
|
507
|
+
// SAFETY: `inputKind` 0 is set only for a string input
|
|
431
508
|
const s = state.input as string
|
|
509
|
+
// SAFETY: the callers' types give the literal the input's kind (`Token.literal` encodes a string literal for byte input)
|
|
432
510
|
const l = lit as string
|
|
433
511
|
if (!caseless) {
|
|
434
512
|
if (avail >= len) return s.startsWith(l, pos) ? len : -1
|
|
@@ -440,7 +518,9 @@ const match = (state: State<Input>, lit: Input, caseless: boolean): number => {
|
|
|
440
518
|
return n === len ? len : -2
|
|
441
519
|
}
|
|
442
520
|
case 1: {
|
|
521
|
+
// SAFETY: `inputKind` 1 is set only for a `Uint8Array` input
|
|
443
522
|
const b = state.input as Uint8Array
|
|
523
|
+
// SAFETY: the callers' types give the literal the input's kind (`Token.literal` and `Text` encode string literals for byte input)
|
|
444
524
|
const l = lit as Uint8Array
|
|
445
525
|
for (let i = 0; i < n; i++) {
|
|
446
526
|
const x = b[pos + i]
|
|
@@ -450,7 +530,9 @@ const match = (state: State<Input>, lit: Input, caseless: boolean): number => {
|
|
|
450
530
|
return n === len ? len : -2
|
|
451
531
|
}
|
|
452
532
|
default: {
|
|
533
|
+
// SAFETY: `inputKind` 2 is set for every input that is neither a string nor a `Uint8Array`, an array
|
|
453
534
|
const a = state.input as ReadonlyArray<unknown>
|
|
535
|
+
// SAFETY: the callers' types give the literal the input's kind, an array of the same element type
|
|
454
536
|
const l = lit as ReadonlyArray<unknown>
|
|
455
537
|
for (let i = 0; i < n; i++) if (a[pos + i] !== l[i]) return -1
|
|
456
538
|
return n === len ? len : -2
|