@thomasfosterau/effect-parse 0.0.0 → 0.2.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 +247 -230
- package/dist/Ascii.d.ts +32 -53
- package/dist/Ascii.d.ts.map +1 -1
- package/dist/Ascii.js +576 -571
- package/dist/Ascii.js.map +1 -1
- package/dist/Binary.d.ts +6 -29
- package/dist/Binary.d.ts.map +1 -1
- package/dist/Binary.js +129 -116
- package/dist/Binary.js.map +1 -1
- package/dist/Bits.d.ts +4 -2
- package/dist/Bits.d.ts.map +1 -1
- package/dist/Bits.js +121 -123
- package/dist/Bits.js.map +1 -1
- package/dist/Compiler.d.ts +39 -0
- package/dist/Compiler.d.ts.map +1 -0
- package/dist/Compiler.js +48 -0
- package/dist/Compiler.js.map +1 -0
- package/dist/Encoding.d.ts +29 -46
- package/dist/Encoding.d.ts.map +1 -1
- package/dist/Encoding.js +76 -75
- package/dist/Encoding.js.map +1 -1
- package/dist/Expression.d.ts +15 -49
- package/dist/Expression.d.ts.map +1 -1
- package/dist/Expression.js +143 -131
- package/dist/Expression.js.map +1 -1
- package/dist/Input.d.ts +206 -177
- package/dist/Input.d.ts.map +1 -1
- package/dist/Input.js +317 -299
- package/dist/Input.js.map +1 -1
- package/dist/Nom.d.ts +44 -84
- package/dist/Nom.d.ts.map +1 -1
- package/dist/Nom.js +423 -453
- package/dist/Nom.js.map +1 -1
- package/dist/ParseError.d.ts +54 -49
- package/dist/ParseError.d.ts.map +1 -1
- package/dist/ParseError.js +233 -275
- package/dist/ParseError.js.map +1 -1
- package/dist/Parser.d.ts +345 -313
- package/dist/Parser.d.ts.map +1 -1
- package/dist/Parser.js +2010 -1802
- package/dist/Parser.js.map +1 -1
- package/dist/ParserSchema.d.ts +8 -7
- package/dist/ParserSchema.d.ts.map +1 -1
- package/dist/ParserSchema.js +49 -49
- package/dist/ParserSchema.js.map +1 -1
- package/dist/ParserStream.d.ts +26 -20
- package/dist/ParserStream.d.ts.map +1 -1
- package/dist/ParserStream.js +267 -255
- package/dist/ParserStream.js.map +1 -1
- package/dist/Syntax.d.ts +401 -0
- package/dist/Syntax.d.ts.map +1 -0
- package/dist/Syntax.js +717 -0
- package/dist/Syntax.js.map +1 -0
- package/dist/Text.d.ts +98 -134
- package/dist/Text.d.ts.map +1 -1
- package/dist/Text.js +534 -496
- package/dist/Text.js.map +1 -1
- package/dist/Token.d.ts +60 -42
- package/dist/Token.d.ts.map +1 -1
- package/dist/Token.js +331 -265
- package/dist/Token.js.map +1 -1
- package/dist/index.d.ts +16 -17
- package/dist/index.js +16 -17
- package/dist/internal/compiler/closure.d.ts +14 -16
- package/dist/internal/compiler/closure.d.ts.map +1 -1
- package/dist/internal/compiler/closure.js +1458 -1637
- package/dist/internal/compiler/closure.js.map +1 -1
- package/dist/internal/compiler/entries.d.ts +11 -11
- package/dist/internal/compiler/entries.d.ts.map +1 -1
- package/dist/internal/compiler/entries.js +36 -26
- package/dist/internal/compiler/entries.js.map +1 -1
- package/dist/internal/compiler/first.d.ts +19 -19
- package/dist/internal/compiler/first.d.ts.map +1 -1
- package/dist/internal/compiler/first.js +251 -227
- package/dist/internal/compiler/first.js.map +1 -1
- package/dist/internal/compiler/jit.d.ts +6 -17
- package/dist/internal/compiler/jit.d.ts.map +1 -1
- package/dist/internal/compiler/jit.js +860 -988
- package/dist/internal/compiler/jit.js.map +1 -1
- package/dist/internal/compiler/registry.d.ts +20 -21
- package/dist/internal/compiler/registry.d.ts.map +1 -1
- package/dist/internal/compiler/registry.js +21 -41
- package/dist/internal/compiler/registry.js.map +1 -1
- package/dist/internal/compiler/sets.d.ts +9 -13
- package/dist/internal/compiler/sets.d.ts.map +1 -1
- package/dist/internal/compiler/sets.js +76 -73
- package/dist/internal/compiler/sets.js.map +1 -1
- package/dist/internal/entries.d.ts +3 -3
- package/dist/internal/entries.d.ts.map +1 -1
- package/dist/internal/entries.js +38 -30
- package/dist/internal/entries.js.map +1 -1
- package/dist/internal/node.d.ts +177 -173
- package/dist/internal/node.d.ts.map +1 -1
- package/dist/internal/node.js +77 -66
- package/dist/internal/node.js.map +1 -1
- package/dist/internal/numbers.d.ts +7 -8
- package/dist/internal/numbers.d.ts.map +1 -1
- package/dist/internal/numbers.js +246 -276
- package/dist/internal/numbers.js.map +1 -1
- package/dist/internal/resume.d.ts +6 -24
- package/dist/internal/resume.d.ts.map +1 -1
- package/dist/internal/resume.js +30 -29
- package/dist/internal/resume.js.map +1 -1
- package/dist/internal/run.d.ts +15 -0
- package/dist/internal/run.d.ts.map +1 -0
- package/dist/internal/run.js +36 -0
- package/dist/internal/run.js.map +1 -0
- package/dist/internal/stack.d.ts +16 -0
- package/dist/internal/stack.d.ts.map +1 -0
- package/dist/internal/stack.js +26 -0
- package/dist/internal/stack.js.map +1 -0
- package/dist/internal/syntax.d.ts +146 -0
- package/dist/internal/syntax.d.ts.map +1 -0
- package/dist/internal/syntax.js +305 -0
- package/dist/internal/syntax.js.map +1 -0
- package/dist/internal/text.d.ts +10 -2
- package/dist/internal/text.d.ts.map +1 -1
- package/dist/internal/text.js +295 -345
- package/dist/internal/text.js.map +1 -1
- package/dist/internal/tokens.d.ts +25 -30
- package/dist/internal/tokens.d.ts.map +1 -1
- package/dist/internal/tokens.js +369 -363
- package/dist/internal/tokens.js.map +1 -1
- package/package.json +42 -28
- package/src/Ascii.ts +278 -187
- package/src/Binary.ts +150 -44
- package/src/Bits.ts +6 -3
- package/src/Compiler.ts +98 -0
- package/src/Expression.ts +10 -5
- package/src/Input.ts +106 -28
- package/src/Nom.ts +4 -3
- package/src/ParseError.ts +48 -51
- package/src/Parser.ts +1163 -795
- package/src/ParserStream.ts +104 -80
- package/src/Syntax.ts +900 -0
- package/src/Text.ts +272 -187
- package/src/Token.ts +180 -87
- package/src/index.ts +2 -0
- package/src/internal/compiler/closure.ts +121 -88
- package/src/internal/compiler/entries.ts +21 -8
- package/src/internal/compiler/first.ts +17 -15
- package/src/internal/compiler/jit.ts +360 -157
- package/src/internal/compiler/registry.ts +12 -33
- package/src/internal/compiler/sets.ts +17 -11
- package/src/internal/entries.ts +4 -2
- package/src/internal/node.ts +51 -37
- package/src/internal/numbers.ts +22 -20
- package/src/internal/resume.ts +8 -4
- package/src/internal/run.ts +41 -0
- package/src/internal/stack.ts +36 -0
- package/src/internal/syntax.ts +421 -0
- package/src/internal/text.ts +32 -25
- package/src/internal/tokens.ts +96 -51
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* Policy. Parsers that can't be compiled run their own (interpreted) steps
|
|
8
8
|
* on the same state.
|
|
9
9
|
*/
|
|
10
|
+
import * as Predicate from "effect/Predicate"
|
|
10
11
|
import type { Encoding } from "../../Encoding.js"
|
|
11
12
|
import type { ErrMode, State } from "../../Input.js"
|
|
12
13
|
import { Fail } from "../../Input.js"
|
|
@@ -15,11 +16,13 @@ import type { Node, NodeOf, ParserLike } from "../node.js"
|
|
|
15
16
|
import { addEntry, flushEntries, fromEntries, isPlainKey } from "../entries.js"
|
|
16
17
|
import { nodeOf } from "../node.js"
|
|
17
18
|
import { floatScan, floatTexts, scanFloatBytes, scanFloatString, toFloat } from "../numbers.js"
|
|
18
|
-
import { charOf, fastLimit, fold, validate } from "../text.js"
|
|
19
|
+
import { charOf, fastLimit, firstCodePoint, fold, validate } from "../text.js"
|
|
19
20
|
import { countTokens, indexOf } from "../tokens.js"
|
|
20
21
|
import type { AltPlan } from "./first.js"
|
|
21
22
|
import * as Resume from "../resume.js"
|
|
22
|
-
import {
|
|
23
|
+
import type { Backend } from "./registry.js"
|
|
24
|
+
import type { EntryPair } from "./entries.js"
|
|
25
|
+
import { buildsEntries, pairOf } from "./entries.js"
|
|
23
26
|
import { FirstSets, planAlt } from "./first.js"
|
|
24
27
|
import type { CharSet } from "./sets.js"
|
|
25
28
|
import { kindOfEncoding, TableSize, textSet, tokenSet } from "./sets.js"
|
|
@@ -34,7 +37,7 @@ export interface Fallback {
|
|
|
34
37
|
}
|
|
35
38
|
|
|
36
39
|
/** The maximum number of distinct parsers compiled for one root. */
|
|
37
|
-
|
|
40
|
+
const maxNodes = 2048
|
|
38
41
|
|
|
39
42
|
const BT: ErrMode = "Backtrack"
|
|
40
43
|
const CUT: ErrMode = "Cut"
|
|
@@ -48,7 +51,7 @@ const INC: ErrMode = "Incomplete"
|
|
|
48
51
|
*/
|
|
49
52
|
const Margin = 4
|
|
50
53
|
|
|
51
|
-
const lowerAscii = (c: number): number => c >= 65 && c <= 90 ? c + 32 : c
|
|
54
|
+
const lowerAscii = (c: number): number => (c >= 65 && c <= 90 ? c + 32 : c)
|
|
52
55
|
|
|
53
56
|
const isSuccess = (r: any): boolean => r._tag === "Success"
|
|
54
57
|
const isSome = (o: any): boolean => o._tag === "Some"
|
|
@@ -69,7 +72,10 @@ class Compiler {
|
|
|
69
72
|
* `resumable`: compile for streaming parses, which may be partial (see
|
|
70
73
|
* `state.partial`) and keep checkpoints (see `internal/resume.ts`).
|
|
71
74
|
*/
|
|
72
|
-
constructor(
|
|
75
|
+
constructor(
|
|
76
|
+
readonly kind: 0 | 1 | 2,
|
|
77
|
+
readonly resumable = false
|
|
78
|
+
) {
|
|
73
79
|
this.firsts = new FirstSets(kind)
|
|
74
80
|
}
|
|
75
81
|
|
|
@@ -100,7 +106,8 @@ class Compiler {
|
|
|
100
106
|
const slot = memo.get(p)
|
|
101
107
|
if (slot !== undefined) {
|
|
102
108
|
if (slot.fn !== undefined) return slot.fn
|
|
103
|
-
|
|
109
|
+
// A cycle through `suspend`: the slot is filled once the cycle is compiled, before any parse runs
|
|
110
|
+
return (s) => (slot.fn ?? p.step)(s)
|
|
104
111
|
}
|
|
105
112
|
const fresh: Slot = { fn: undefined }
|
|
106
113
|
memo.set(p, fresh)
|
|
@@ -192,7 +199,7 @@ class Compiler {
|
|
|
192
199
|
if (step !== undefined) return step
|
|
193
200
|
}
|
|
194
201
|
// Streaming builds keep the array, which their checkpoints hold
|
|
195
|
-
if (node.f === fromEntries && !this.resumable &&
|
|
202
|
+
if (node.f === fromEntries && !this.resumable && buildsEntries(node.self)) return this.entries(node.self)
|
|
196
203
|
const c = this.compile(node.self, true)
|
|
197
204
|
const f = node.f
|
|
198
205
|
return (s) => {
|
|
@@ -204,7 +211,7 @@ class Compiler {
|
|
|
204
211
|
const c = this.compile(node.self, false)
|
|
205
212
|
if (!used) return c
|
|
206
213
|
const value = node.value
|
|
207
|
-
return (s) => c(s) === Fail ? Fail : value
|
|
214
|
+
return (s) => (c(s) === Fail ? Fail : value)
|
|
208
215
|
}
|
|
209
216
|
case "Tap": {
|
|
210
217
|
const c = this.compile(node.self, true)
|
|
@@ -304,6 +311,7 @@ class Compiler {
|
|
|
304
311
|
case "MapError":
|
|
305
312
|
case "OrFail":
|
|
306
313
|
case "Trace":
|
|
314
|
+
case "Syntax":
|
|
307
315
|
case "RetryAfter":
|
|
308
316
|
// Diagnostics only, or inactive outside parseRecoverable / tracing
|
|
309
317
|
return this.compile(node.self, used)
|
|
@@ -362,9 +370,9 @@ class Compiler {
|
|
|
362
370
|
return (s) => {
|
|
363
371
|
const out: Record<string, unknown> = {}
|
|
364
372
|
for (let i = 0; i < n; i++) {
|
|
365
|
-
const a = steps[i]
|
|
373
|
+
const a = steps[i](s)
|
|
366
374
|
if (a === Fail) return Fail
|
|
367
|
-
out[keys[i]
|
|
375
|
+
out[keys[i]] = a
|
|
368
376
|
}
|
|
369
377
|
return out
|
|
370
378
|
}
|
|
@@ -404,13 +412,13 @@ class Compiler {
|
|
|
404
412
|
chain(steps: ReadonlyArray<Step>): Step {
|
|
405
413
|
const n = steps.length
|
|
406
414
|
if (n === 0) return () => undefined
|
|
407
|
-
if (n === 1) return steps[0]
|
|
415
|
+
if (n === 1) return steps[0]
|
|
408
416
|
if (n === 2) {
|
|
409
417
|
const [a, b] = steps as [Step, Step]
|
|
410
|
-
return (s) => a(s) === Fail ? Fail : b(s)
|
|
418
|
+
return (s) => (a(s) === Fail ? Fail : b(s))
|
|
411
419
|
}
|
|
412
420
|
return (s) => {
|
|
413
|
-
for (let i = 0; i < n; i++) if (steps[i]
|
|
421
|
+
for (let i = 0; i < n; i++) if (steps[i](s) === Fail) return Fail
|
|
414
422
|
return undefined
|
|
415
423
|
}
|
|
416
424
|
}
|
|
@@ -418,7 +426,7 @@ class Compiler {
|
|
|
418
426
|
seq(node: NodeOf<"Seq">, used: boolean): Step {
|
|
419
427
|
const output = node.output
|
|
420
428
|
const keep = (i: number) =>
|
|
421
|
-
used && (output === "tuple" || output === i || (
|
|
429
|
+
used && (output === "tuple" || output === i || (Array.isArray(output) && output.includes(i)))
|
|
422
430
|
const steps = node.parsers.map((q, i) => this.compile(q, keep(i)))
|
|
423
431
|
const n = steps.length
|
|
424
432
|
if (!used) return this.chain(steps)
|
|
@@ -426,28 +434,28 @@ class Compiler {
|
|
|
426
434
|
return (s) => {
|
|
427
435
|
const out = new Array(n)
|
|
428
436
|
for (let i = 0; i < n; i++) {
|
|
429
|
-
const a = steps[i]
|
|
437
|
+
const a = steps[i](s)
|
|
430
438
|
if (a === Fail) return Fail
|
|
431
439
|
out[i] = a
|
|
432
440
|
}
|
|
433
441
|
return out
|
|
434
442
|
}
|
|
435
443
|
}
|
|
436
|
-
if (
|
|
444
|
+
if (Predicate.isNumber(output)) {
|
|
437
445
|
if (n === 2) {
|
|
438
446
|
const [a, b] = steps as [Step, Step]
|
|
439
447
|
return output === 0
|
|
440
448
|
? (s) => {
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
: (s) => a(s) === Fail ? Fail : b(s)
|
|
449
|
+
const x = a(s)
|
|
450
|
+
if (x === Fail) return Fail
|
|
451
|
+
return b(s) === Fail ? Fail : x
|
|
452
|
+
}
|
|
453
|
+
: (s) => (a(s) === Fail ? Fail : b(s))
|
|
446
454
|
}
|
|
447
455
|
return (s) => {
|
|
448
456
|
let out: unknown
|
|
449
457
|
for (let i = 0; i < n; i++) {
|
|
450
|
-
const a = steps[i]
|
|
458
|
+
const a = steps[i](s)
|
|
451
459
|
if (a === Fail) return Fail
|
|
452
460
|
if (i === output) out = a
|
|
453
461
|
}
|
|
@@ -459,7 +467,7 @@ class Compiler {
|
|
|
459
467
|
let x: unknown
|
|
460
468
|
let y: unknown
|
|
461
469
|
for (let i = 0; i < n; i++) {
|
|
462
|
-
const a = steps[i]
|
|
470
|
+
const a = steps[i](s)
|
|
463
471
|
if (a === Fail) return Fail
|
|
464
472
|
if (i === i0) x = a
|
|
465
473
|
else if (i === i1) y = a
|
|
@@ -471,8 +479,8 @@ class Compiler {
|
|
|
471
479
|
/** The unit at the cursor, or -1 at the end of the input. */
|
|
472
480
|
private unitReader(): (s: State<any>) => number {
|
|
473
481
|
return this.kind === 0
|
|
474
|
-
? (s) => s.pos < s.end ? (s.input as string).charCodeAt(s.pos) : -1
|
|
475
|
-
: (s) => s.pos < s.end ? (s.input as Uint8Array)[s.pos]
|
|
482
|
+
? (s) => (s.pos < s.end ? (s.input as string).charCodeAt(s.pos) : -1)
|
|
483
|
+
: (s) => (s.pos < s.end ? (s.input as Uint8Array)[s.pos] : -1)
|
|
476
484
|
}
|
|
477
485
|
|
|
478
486
|
alt(node: NodeOf<"Alt">, used: boolean): Step {
|
|
@@ -484,15 +492,13 @@ class Compiler {
|
|
|
484
492
|
return Fail
|
|
485
493
|
}
|
|
486
494
|
}
|
|
487
|
-
if (n === 1) return steps[0]
|
|
488
|
-
const plan: AltPlan | undefined = this.kind === 2
|
|
489
|
-
? undefined
|
|
490
|
-
: planAlt(node.parsers.map((q) => this.firsts.of(q)))
|
|
495
|
+
if (n === 1) return steps[0]
|
|
496
|
+
const plan: AltPlan | undefined = this.kind === 2 ? undefined : planAlt(node.parsers.map((q) => this.firsts.of(q)))
|
|
491
497
|
if (plan === undefined) {
|
|
492
498
|
return (s) => {
|
|
493
499
|
const start = s.pos
|
|
494
500
|
for (let i = 0; i < n; i++) {
|
|
495
|
-
const a = steps[i]
|
|
501
|
+
const a = steps[i](s)
|
|
496
502
|
if (a !== Fail) return a
|
|
497
503
|
if (s.mode !== BT) return Fail
|
|
498
504
|
s.pos = start
|
|
@@ -501,17 +507,17 @@ class Compiler {
|
|
|
501
507
|
return Fail
|
|
502
508
|
}
|
|
503
509
|
}
|
|
504
|
-
const lists = plan.lists.map((l) => l.map((i) => steps[i]
|
|
510
|
+
const lists = plan.lists.map((l) => l.map((i) => steps[i]))
|
|
505
511
|
const { byUnit, end, high } = plan
|
|
506
512
|
const unit = this.unitReader()
|
|
507
513
|
const resumable = this.resumable
|
|
508
514
|
return (s) => {
|
|
509
515
|
// Near the end of a partial input, branches may be incomplete rather than fail
|
|
510
516
|
const u = resumable && s.partial && s.pos + Margin > s.end ? -2 : unit(s)
|
|
511
|
-
const candidates = u === -2 ? steps : lists[u < 0 ? end : u < TableSize ? byUnit[u]
|
|
517
|
+
const candidates = u === -2 ? steps : lists[u < 0 ? end : u < TableSize ? byUnit[u] : high]
|
|
512
518
|
const start = s.pos
|
|
513
519
|
for (let i = 0; i < candidates.length; i++) {
|
|
514
|
-
const a = candidates[i]
|
|
520
|
+
const a = candidates[i](s)
|
|
515
521
|
if (a !== Fail) return a
|
|
516
522
|
if (s.mode !== BT) return Fail
|
|
517
523
|
s.pos = start
|
|
@@ -527,7 +533,7 @@ class Compiler {
|
|
|
527
533
|
const compiled = new Map<ParserLike, Step>()
|
|
528
534
|
if (node.cases !== undefined) {
|
|
529
535
|
for (const key of Reflect.ownKeys(node.cases)) {
|
|
530
|
-
const q = node.cases[key as any]
|
|
536
|
+
const q = node.cases[key as any]
|
|
531
537
|
if (!compiled.has(q)) compiled.set(q, this.compile(q, used))
|
|
532
538
|
}
|
|
533
539
|
}
|
|
@@ -564,7 +570,7 @@ class Compiler {
|
|
|
564
570
|
for (let u = 0; u < size; u++) {
|
|
565
571
|
const key = enc === undefined && this.kind === 1 ? u : charOf(u)
|
|
566
572
|
const q = choose(key)
|
|
567
|
-
table.push(q === undefined ? null : compiled.get(q) ?? q.step)
|
|
573
|
+
table.push(q === undefined ? null : (compiled.get(q) ?? q.step))
|
|
568
574
|
}
|
|
569
575
|
const unit = this.unitReader()
|
|
570
576
|
const advance = peek ? 0 : 1
|
|
@@ -577,7 +583,7 @@ class Compiler {
|
|
|
577
583
|
return Fail
|
|
578
584
|
}
|
|
579
585
|
if (u >= size) return general(s)
|
|
580
|
-
const q = table[u]
|
|
586
|
+
const q = table[u]
|
|
581
587
|
if (q === null) {
|
|
582
588
|
s.mode = BT
|
|
583
589
|
return Fail
|
|
@@ -591,19 +597,21 @@ class Compiler {
|
|
|
591
597
|
const { max, min } = node
|
|
592
598
|
const checkLoop = max === Infinity
|
|
593
599
|
const isFold = node._tag === "Fold"
|
|
600
|
+
const cond = isFold ? (node as NodeOf<"Fold">).while : undefined
|
|
594
601
|
const c = this.compile(node.self, used)
|
|
595
602
|
const resumable = this.resumable
|
|
596
603
|
const key = {}
|
|
597
|
-
// The accumulator: an array, the fold's value, or nothing when unused
|
|
598
|
-
const
|
|
599
|
-
const
|
|
604
|
+
// The accumulator: an array, the fold's value, or nothing when unused (and unneeded by `while`)
|
|
605
|
+
const tracked = used || cond !== undefined
|
|
606
|
+
const init: () => unknown = !tracked ? () => undefined : isFold ? (node as NodeOf<"Fold">).init : () => []
|
|
607
|
+
const add: (acc: any, a: unknown) => unknown = !tracked
|
|
600
608
|
? (acc) => acc
|
|
601
609
|
: isFold
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
610
|
+
? (node as NodeOf<"Fold">).f
|
|
611
|
+
: (acc, a) => {
|
|
612
|
+
acc.push(a)
|
|
613
|
+
return acc
|
|
614
|
+
}
|
|
607
615
|
return (s) => {
|
|
608
616
|
const entry = s.pos
|
|
609
617
|
let acc: unknown
|
|
@@ -624,6 +632,7 @@ class Compiler {
|
|
|
624
632
|
}
|
|
625
633
|
if (!resumed) acc = init()
|
|
626
634
|
for (; count < max; count++) {
|
|
635
|
+
if (cond !== undefined && count >= min && !cond(acc)) break
|
|
627
636
|
const start = s.pos
|
|
628
637
|
const a = c(s)
|
|
629
638
|
if (a === Fail) {
|
|
@@ -643,7 +652,7 @@ class Compiler {
|
|
|
643
652
|
}
|
|
644
653
|
|
|
645
654
|
/**
|
|
646
|
-
* `map(self, Object.fromEntries)`, where `
|
|
655
|
+
* `map(self, Object.fromEntries)`, where `buildsEntries(self)`: builds the
|
|
647
656
|
* object directly (see the JIT).
|
|
648
657
|
*/
|
|
649
658
|
private entries(p: ParserLike): Step {
|
|
@@ -661,11 +670,11 @@ class Compiler {
|
|
|
661
670
|
}
|
|
662
671
|
case "Seq": {
|
|
663
672
|
const i = node.output as number
|
|
664
|
-
const steps = node.parsers.map((q, j) => j === i ? this.entries(q) : this.compile(q, false))
|
|
673
|
+
const steps = node.parsers.map((q, j) => (j === i ? this.entries(q) : this.compile(q, false)))
|
|
665
674
|
return (s) => {
|
|
666
675
|
let out: unknown
|
|
667
676
|
for (let j = 0; j < steps.length; j++) {
|
|
668
|
-
const a = steps[j]
|
|
677
|
+
const a = steps[j](s)
|
|
669
678
|
if (a === Fail) return Fail
|
|
670
679
|
if (j === i) out = a
|
|
671
680
|
}
|
|
@@ -673,15 +682,22 @@ class Compiler {
|
|
|
673
682
|
}
|
|
674
683
|
}
|
|
675
684
|
case "Repeat":
|
|
676
|
-
case "Separated":
|
|
677
|
-
|
|
685
|
+
case "Separated": {
|
|
686
|
+
const pair = pairOf(node.self)
|
|
687
|
+
if (pair !== undefined) return this.entriesLoop(node, pair)
|
|
688
|
+
// Not reached (`buildsEntries` found the pair): build the pairs, then the object
|
|
689
|
+
const c = this.compile(p, true)
|
|
690
|
+
return (s) => {
|
|
691
|
+
const a = c(s)
|
|
692
|
+
return a === Fail ? Fail : fromEntries(a as Iterable<readonly [PropertyKey, unknown]>)
|
|
693
|
+
}
|
|
694
|
+
}
|
|
678
695
|
default:
|
|
679
696
|
return this.entries((node as { readonly self: ParserLike }).self)
|
|
680
697
|
}
|
|
681
698
|
}
|
|
682
699
|
|
|
683
|
-
private entriesLoop(node: NodeOf<"Repeat"> | NodeOf<"Separated"
|
|
684
|
-
const pair = pairOf(node.self)!
|
|
700
|
+
private entriesLoop(node: NodeOf<"Repeat"> | NodeOf<"Separated">, pair: EntryPair): Step {
|
|
685
701
|
const parts = pair.parsers.map((q, j) => this.compile(q, j === pair.key || j === pair.value))
|
|
686
702
|
const { key: ki, value: vi } = pair
|
|
687
703
|
// Parses an entry and adds it to `acc`
|
|
@@ -689,7 +705,7 @@ class Compiler {
|
|
|
689
705
|
let key: unknown
|
|
690
706
|
let value: unknown
|
|
691
707
|
for (let j = 0; j < parts.length; j++) {
|
|
692
|
-
const a = parts[j]
|
|
708
|
+
const a = parts[j](s)
|
|
693
709
|
if (a === Fail) return false
|
|
694
710
|
if (j === ki) key = a
|
|
695
711
|
else if (j === vi) value = a
|
|
@@ -708,7 +724,7 @@ class Compiler {
|
|
|
708
724
|
let value: unknown
|
|
709
725
|
let ok = true
|
|
710
726
|
for (let j = 0; j < parts.length; j++) {
|
|
711
|
-
const a = parts[j]
|
|
727
|
+
const a = parts[j](s)
|
|
712
728
|
if (a === Fail) {
|
|
713
729
|
ok = false
|
|
714
730
|
break
|
|
@@ -803,7 +819,10 @@ class Compiler {
|
|
|
803
819
|
let count = 0
|
|
804
820
|
let resumed = false
|
|
805
821
|
if (resumable && s.resume !== undefined) {
|
|
806
|
-
const cp = Resume.take(s, key, entry) as
|
|
822
|
+
const cp = Resume.take(s, key, entry) as
|
|
823
|
+
| Resume.Done
|
|
824
|
+
| { acc: Array<unknown>; count: number; pos: number }
|
|
825
|
+
| undefined
|
|
807
826
|
if (cp instanceof Resume.Done) {
|
|
808
827
|
s.pos = cp.pos
|
|
809
828
|
return cp.value
|
|
@@ -976,7 +995,7 @@ class Compiler {
|
|
|
976
995
|
return (s) => {
|
|
977
996
|
const pos = s.pos
|
|
978
997
|
if (pos >= s.end) return fail(s)
|
|
979
|
-
const b = (s.input as Uint8Array)[pos]
|
|
998
|
+
const b = (s.input as Uint8Array)[pos]
|
|
980
999
|
if (accept[b] === 0) return fail(s)
|
|
981
1000
|
s.pos = pos + 1
|
|
982
1001
|
return b
|
|
@@ -1057,7 +1076,7 @@ class Compiler {
|
|
|
1057
1076
|
|
|
1058
1077
|
tokenLiteral(p: ParserLike, node: NodeOf<"Literal">): Step {
|
|
1059
1078
|
const lit = node.literal
|
|
1060
|
-
const literalKind =
|
|
1079
|
+
const literalKind = Predicate.isString(lit) ? 0 : lit instanceof Uint8Array ? 1 : 2
|
|
1061
1080
|
if (this.kind === 0) {
|
|
1062
1081
|
if (literalKind !== 0) return this.fallback(p, node, "byte or array literal on string input")
|
|
1063
1082
|
const str = lit as string
|
|
@@ -1078,7 +1097,7 @@ class Compiler {
|
|
|
1078
1097
|
return stringLiteral(str, str)
|
|
1079
1098
|
}
|
|
1080
1099
|
if (literalKind === 2) return this.fallback(p, node, "array literal on byte input")
|
|
1081
|
-
const bytes = literalKind === 0 ? new TextEncoder().encode(lit as string) : lit as Uint8Array
|
|
1100
|
+
const bytes = literalKind === 0 ? new TextEncoder().encode(lit as string) : (lit as Uint8Array)
|
|
1082
1101
|
const len = bytes.length
|
|
1083
1102
|
const sameKind = literalKind === 1 && !node.caseless
|
|
1084
1103
|
const expect = node.caseless ? Array.from(bytes, lowerAscii) : Array.from(bytes)
|
|
@@ -1088,7 +1107,7 @@ class Compiler {
|
|
|
1088
1107
|
if (s.end - pos < len) return fail(s)
|
|
1089
1108
|
const input = s.input as Uint8Array
|
|
1090
1109
|
for (let i = 0; i < len; i++) {
|
|
1091
|
-
const b = input[pos + i]
|
|
1110
|
+
const b = input[pos + i]
|
|
1092
1111
|
if ((caseless ? lowerAscii(b) : b) !== expect[i]) return fail(s)
|
|
1093
1112
|
}
|
|
1094
1113
|
s.pos = pos + len
|
|
@@ -1107,7 +1126,7 @@ class Compiler {
|
|
|
1107
1126
|
const start = s.pos
|
|
1108
1127
|
const limit = max === Infinity ? s.end : Math.min(s.end, start + max)
|
|
1109
1128
|
let i = start
|
|
1110
|
-
while (i < limit && accept[bytes[i]
|
|
1129
|
+
while (i < limit && accept[bytes[i]] === 1) i++
|
|
1111
1130
|
if (i - start < min) return failAt(s, i)
|
|
1112
1131
|
s.pos = i
|
|
1113
1132
|
return used ? bytes.subarray(start, i) : undefined
|
|
@@ -1155,9 +1174,8 @@ class Compiler {
|
|
|
1155
1174
|
const decode = enc.decode
|
|
1156
1175
|
const width = enc.width
|
|
1157
1176
|
const toText = enc.text
|
|
1158
|
-
const unitAt: (input: any, i: number) => number =
|
|
1159
|
-
? (input: string, i) => input.charCodeAt(i)
|
|
1160
|
-
: (input: Uint8Array, i) => input[i]!
|
|
1177
|
+
const unitAt: (input: any, i: number) => number =
|
|
1178
|
+
kind === 0 ? (input: string, i) => input.charCodeAt(i) : (input: Uint8Array, i) => input[i]
|
|
1161
1179
|
switch (node._tag) {
|
|
1162
1180
|
case "Any":
|
|
1163
1181
|
return (s) => {
|
|
@@ -1177,7 +1195,7 @@ class Compiler {
|
|
|
1177
1195
|
case "Literal": {
|
|
1178
1196
|
const lit = node.literal as string
|
|
1179
1197
|
if (node.caseless) {
|
|
1180
|
-
const folded = Array.from(lit, (c) => fold(c
|
|
1198
|
+
const folded = Array.from(lit, (c) => fold(firstCodePoint(c)))
|
|
1181
1199
|
const n = folded.length
|
|
1182
1200
|
return (s) => {
|
|
1183
1201
|
const start = s.pos
|
|
@@ -1203,11 +1221,11 @@ class Compiler {
|
|
|
1203
1221
|
}
|
|
1204
1222
|
}
|
|
1205
1223
|
const encoded = enc.encode(lit)
|
|
1206
|
-
if (
|
|
1224
|
+
if (Predicate.isString(encoded)) return stringLiteral(encoded, lit)
|
|
1207
1225
|
const bytes = encoded as Uint8Array
|
|
1208
1226
|
const len = bytes.length
|
|
1209
1227
|
if (len === 1) {
|
|
1210
|
-
const b0 = bytes[0]
|
|
1228
|
+
const b0 = bytes[0]
|
|
1211
1229
|
return (s) => {
|
|
1212
1230
|
const pos = s.pos
|
|
1213
1231
|
if (pos < s.end && (s.input as Uint8Array)[pos] === b0) {
|
|
@@ -1325,9 +1343,8 @@ class Compiler {
|
|
|
1325
1343
|
// `Text.taken` checks that the text is well formed, then decodes it
|
|
1326
1344
|
const fast = fastLimit(enc)
|
|
1327
1345
|
const toText = enc.text
|
|
1328
|
-
const unitAt: (input: any, i: number) => number =
|
|
1329
|
-
? (input: string, i) => input.charCodeAt(i)
|
|
1330
|
-
: (input: Uint8Array, i) => input[i]!
|
|
1346
|
+
const unitAt: (input: any, i: number) => number =
|
|
1347
|
+
this.kind === 0 ? (input: string, i) => input.charCodeAt(i) : (input: Uint8Array, i) => input[i]
|
|
1331
1348
|
return (s) => {
|
|
1332
1349
|
const start = s.pos
|
|
1333
1350
|
if (c(s) === Fail) return Fail
|
|
@@ -1353,7 +1370,11 @@ class Compiler {
|
|
|
1353
1370
|
const enc = taken.encoding
|
|
1354
1371
|
if (enc !== undefined && !(this.native(enc) && enc.unit === 1 && enc.asciiCompatible)) return undefined
|
|
1355
1372
|
const c = this.compile(node.self, true)
|
|
1356
|
-
const scan = (this.kind === 0 ? scanFloatString : scanFloatBytes) as (
|
|
1373
|
+
const scan = (this.kind === 0 ? scanFloatString : scanFloatBytes) as (
|
|
1374
|
+
input: unknown,
|
|
1375
|
+
i: number,
|
|
1376
|
+
end: number
|
|
1377
|
+
) => unknown
|
|
1357
1378
|
const resumable = this.resumable
|
|
1358
1379
|
return (s) => {
|
|
1359
1380
|
const v = scan(s.input, s.pos, s.end)
|
|
@@ -1378,21 +1399,22 @@ class Compiler {
|
|
|
1378
1399
|
// Matches the control character, advancing past it
|
|
1379
1400
|
let control: (s: State<any>) => boolean
|
|
1380
1401
|
if (enc === undefined || (ctrl < fastLimit(enc) && ctrl < TableSize)) {
|
|
1381
|
-
control =
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1402
|
+
control =
|
|
1403
|
+
kind === 0
|
|
1404
|
+
? (s) => {
|
|
1405
|
+
if (s.pos < s.end && (s.input as string).charCodeAt(s.pos) === ctrl) {
|
|
1406
|
+
s.pos++
|
|
1407
|
+
return true
|
|
1408
|
+
}
|
|
1409
|
+
return false
|
|
1410
|
+
}
|
|
1411
|
+
: (s) => {
|
|
1412
|
+
if (s.pos < s.end && (s.input as Uint8Array)[s.pos] === ctrl) {
|
|
1413
|
+
s.pos++
|
|
1414
|
+
return true
|
|
1415
|
+
}
|
|
1416
|
+
return false
|
|
1417
|
+
}
|
|
1396
1418
|
} else {
|
|
1397
1419
|
control = (s) => {
|
|
1398
1420
|
if (s.pos >= s.end) return false
|
|
@@ -1411,9 +1433,8 @@ class Compiler {
|
|
|
1411
1433
|
return Fail
|
|
1412
1434
|
}
|
|
1413
1435
|
if (raw) {
|
|
1414
|
-
const slice: (s: State<any>, start: number) => unknown =
|
|
1415
|
-
? (s, start) => s.slice(start, s.pos)
|
|
1416
|
-
: (s, start) => enc.text(s.input, start, s.pos)
|
|
1436
|
+
const slice: (s: State<any>, start: number) => unknown =
|
|
1437
|
+
enc === undefined ? (s, start) => s.slice(start, s.pos) : (s, start) => enc.text(s.input, start, s.pos)
|
|
1417
1438
|
return (s) => {
|
|
1418
1439
|
const start = s.pos
|
|
1419
1440
|
let resumed = false
|
|
@@ -1572,7 +1593,7 @@ export const createClosureCompiler = (kind: 0 | 1 | 2, resumable = false): Closu
|
|
|
1572
1593
|
}
|
|
1573
1594
|
|
|
1574
1595
|
/** Compiles a root parser for one input kind. */
|
|
1575
|
-
|
|
1596
|
+
const compileClosure = (
|
|
1576
1597
|
root: ParserLike,
|
|
1577
1598
|
kind: 0 | 1 | 2,
|
|
1578
1599
|
resumable = false
|
|
@@ -1581,3 +1602,15 @@ export const compileClosure = (
|
|
|
1581
1602
|
const step = compiler.compile(root, true)
|
|
1582
1603
|
return { step, fallbacks: compiler.fallbacks }
|
|
1583
1604
|
}
|
|
1605
|
+
|
|
1606
|
+
/** The closure compiler as a backend. */
|
|
1607
|
+
export const backend: Backend = {
|
|
1608
|
+
build: (p, kind, resumable) => {
|
|
1609
|
+
try {
|
|
1610
|
+
const { fallbacks, step } = compileClosure(p, kind, resumable)
|
|
1611
|
+
return { backend: "closure", step, fallbacks, error: undefined }
|
|
1612
|
+
} catch (error) {
|
|
1613
|
+
return { backend: undefined, step: undefined, fallbacks: [], error }
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1616
|
+
}
|
|
@@ -2,25 +2,38 @@
|
|
|
2
2
|
* The shapes of `map(p, Object.fromEntries)` that the compilers build
|
|
3
3
|
* directly (see `internal/entries.ts`).
|
|
4
4
|
*/
|
|
5
|
+
import * as Predicate from "effect/Predicate"
|
|
5
6
|
import type { Node, NodeOf, ParserLike } from "../node.js"
|
|
6
7
|
import { nodeOf } from "../node.js"
|
|
7
8
|
|
|
9
|
+
/** A sequence that yields an entry: its parsers, and which of them produce the key and the value. */
|
|
10
|
+
export interface EntryPair {
|
|
11
|
+
readonly parsers: ReadonlyArray<ParserLike>
|
|
12
|
+
readonly key: number
|
|
13
|
+
readonly value: number
|
|
14
|
+
}
|
|
15
|
+
|
|
8
16
|
/** A repeated pair for `Object.fromEntries`: the sequence and the indices of its key and value. */
|
|
9
|
-
export const pairOf = (p: ParserLike):
|
|
17
|
+
export const pairOf = (p: ParserLike): EntryPair | undefined => {
|
|
10
18
|
let node = nodeOf(p)
|
|
11
19
|
while (isDiagnostic(node)) node = nodeOf(node.self)
|
|
12
20
|
if (node._tag !== "Seq") return undefined
|
|
13
21
|
const output = node.output
|
|
14
22
|
if (output === "tuple") return node.parsers.length === 2 ? { parsers: node.parsers, key: 0, value: 1 } : undefined
|
|
15
|
-
if (
|
|
23
|
+
if (Predicate.isNumber(output) || output[0] === output[1]) return undefined
|
|
16
24
|
return { parsers: node.parsers, key: output[0], value: output[1] }
|
|
17
25
|
}
|
|
18
26
|
|
|
19
27
|
const isDiagnostic = (
|
|
20
28
|
node: Node
|
|
21
|
-
): node is NodeOf<"Context" | "Expected" | "MapError" | "OrFail" | "Trace" | "RetryAfter"> =>
|
|
22
|
-
node._tag === "Context" ||
|
|
23
|
-
node._tag === "
|
|
29
|
+
): node is NodeOf<"Context" | "Expected" | "MapError" | "OrFail" | "Trace" | "Syntax" | "RetryAfter"> =>
|
|
30
|
+
node._tag === "Context" ||
|
|
31
|
+
node._tag === "Expected" ||
|
|
32
|
+
node._tag === "MapError" ||
|
|
33
|
+
node._tag === "OrFail" ||
|
|
34
|
+
node._tag === "Trace" ||
|
|
35
|
+
node._tag === "Syntax" ||
|
|
36
|
+
node._tag === "RetryAfter"
|
|
24
37
|
|
|
25
38
|
/**
|
|
26
39
|
* Whether `map(p, Object.fromEntries)` can build its object directly: `p`
|
|
@@ -28,9 +41,9 @@ const isDiagnostic = (
|
|
|
28
41
|
* element of a sequence (`preceded`, `terminated`, `delimited`) and
|
|
29
42
|
* diagnostics.
|
|
30
43
|
*/
|
|
31
|
-
export const
|
|
44
|
+
export const buildsEntries = (p: ParserLike): boolean => {
|
|
32
45
|
const node = nodeOf(p)
|
|
33
|
-
if (isDiagnostic(node) || node._tag === "Mode") return
|
|
34
|
-
if (node._tag === "Seq") return
|
|
46
|
+
if (isDiagnostic(node) || node._tag === "Mode") return buildsEntries(node.self)
|
|
47
|
+
if (node._tag === "Seq") return Predicate.isNumber(node.output) && buildsEntries(node.parsers[node.output])
|
|
35
48
|
return (node._tag === "Repeat" || node._tag === "Separated") && pairOf(node.self) !== undefined
|
|
36
49
|
}
|