@thomasfosterau/effect-parse 0.0.0-stage → 0.0.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/LICENSE +21 -0
- package/README.md +550 -2
- package/dist/Ascii.d.ts +392 -0
- package/dist/Ascii.d.ts.map +1 -0
- package/dist/Ascii.js +610 -0
- package/dist/Ascii.js.map +1 -0
- package/dist/Binary.d.ts +153 -0
- package/dist/Binary.d.ts.map +1 -0
- package/dist/Binary.js +171 -0
- package/dist/Binary.js.map +1 -0
- package/dist/Bits.d.ts +60 -0
- package/dist/Bits.d.ts.map +1 -0
- package/dist/Bits.js +144 -0
- package/dist/Bits.js.map +1 -0
- package/dist/Encoding.d.ts +116 -0
- package/dist/Encoding.d.ts.map +1 -0
- package/dist/Encoding.js +85 -0
- package/dist/Encoding.js.map +1 -0
- package/dist/Expression.d.ts +124 -0
- package/dist/Expression.d.ts.map +1 -0
- package/dist/Expression.js +139 -0
- package/dist/Expression.js.map +1 -0
- package/dist/Input.d.ts +301 -0
- package/dist/Input.d.ts.map +1 -0
- package/dist/Input.js +312 -0
- package/dist/Input.js.map +1 -0
- package/dist/Nom.d.ts +518 -0
- package/dist/Nom.d.ts.map +1 -0
- package/dist/Nom.js +519 -0
- package/dist/Nom.js.map +1 -0
- package/dist/ParseError.d.ts +120 -0
- package/dist/ParseError.d.ts.map +1 -0
- package/dist/ParseError.js +301 -0
- package/dist/ParseError.js.map +1 -0
- package/dist/Parser.d.ts +1312 -0
- package/dist/Parser.d.ts.map +1 -0
- package/dist/Parser.js +1936 -0
- package/dist/Parser.js.map +1 -0
- package/dist/ParserSchema.d.ts +31 -0
- package/dist/ParserSchema.d.ts.map +1 -0
- package/dist/ParserSchema.js +56 -0
- package/dist/ParserSchema.js.map +1 -0
- package/dist/ParserStream.d.ts +127 -0
- package/dist/ParserStream.d.ts.map +1 -0
- package/dist/ParserStream.js +270 -0
- package/dist/ParserStream.js.map +1 -0
- package/dist/Text.d.ts +330 -0
- package/dist/Text.d.ts.map +1 -0
- package/dist/Text.js +529 -0
- package/dist/Text.js.map +1 -0
- package/dist/Token.d.ts +225 -0
- package/dist/Token.d.ts.map +1 -0
- package/dist/Token.js +294 -0
- package/dist/Token.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/compiler/closure.d.ts +25 -0
- package/dist/internal/compiler/closure.d.ts.map +1 -0
- package/dist/internal/compiler/closure.js +1668 -0
- package/dist/internal/compiler/closure.js.map +1 -0
- package/dist/internal/compiler/entries.d.ts +19 -0
- package/dist/internal/compiler/entries.d.ts.map +1 -0
- package/dist/internal/compiler/entries.js +32 -0
- package/dist/internal/compiler/entries.js.map +1 -0
- package/dist/internal/compiler/first.d.ts +33 -0
- package/dist/internal/compiler/first.d.ts.map +1 -0
- package/dist/internal/compiler/first.js +235 -0
- package/dist/internal/compiler/first.js.map +1 -0
- package/dist/internal/compiler/jit.d.ts +20 -0
- package/dist/internal/compiler/jit.d.ts.map +1 -0
- package/dist/internal/compiler/jit.js +1030 -0
- package/dist/internal/compiler/jit.js.map +1 -0
- package/dist/internal/compiler/registry.d.ts +34 -0
- package/dist/internal/compiler/registry.d.ts.map +1 -0
- package/dist/internal/compiler/registry.js +46 -0
- package/dist/internal/compiler/registry.js.map +1 -0
- package/dist/internal/compiler/sets.d.ts +29 -0
- package/dist/internal/compiler/sets.d.ts.map +1 -0
- package/dist/internal/compiler/sets.js +85 -0
- package/dist/internal/compiler/sets.js.map +1 -0
- package/dist/internal/entries.d.ts +27 -0
- package/dist/internal/entries.d.ts.map +1 -0
- package/dist/internal/entries.js +42 -0
- package/dist/internal/entries.js.map +1 -0
- package/dist/internal/node.d.ts +251 -0
- package/dist/internal/node.d.ts.map +1 -0
- package/dist/internal/node.js +73 -0
- package/dist/internal/node.js.map +1 -0
- package/dist/internal/numbers.d.ts +41 -0
- package/dist/internal/numbers.d.ts.map +1 -0
- package/dist/internal/numbers.js +302 -0
- package/dist/internal/numbers.js.map +1 -0
- package/dist/internal/resume.d.ts +39 -0
- package/dist/internal/resume.d.ts.map +1 -0
- package/dist/internal/resume.js +37 -0
- package/dist/internal/resume.js.map +1 -0
- package/dist/internal/text.d.ts +72 -0
- package/dist/internal/text.d.ts.map +1 -0
- package/dist/internal/text.js +391 -0
- package/dist/internal/text.js.map +1 -0
- package/dist/internal/tokens.d.ts +93 -0
- package/dist/internal/tokens.d.ts.map +1 -0
- package/dist/internal/tokens.js +400 -0
- package/dist/internal/tokens.js.map +1 -0
- package/package.json +115 -3
- package/src/Ascii.ts +741 -0
- package/src/Binary.ts +228 -0
- package/src/Bits.ts +192 -0
- package/src/Encoding.ts +128 -0
- package/src/Expression.ts +245 -0
- package/src/Input.ts +429 -0
- package/src/Nom.ts +642 -0
- package/src/ParseError.ts +378 -0
- package/src/Parser.ts +2763 -0
- package/src/ParserSchema.ts +87 -0
- package/src/ParserStream.ts +390 -0
- package/src/Text.ts +757 -0
- package/src/Token.ts +416 -0
- package/src/index.ts +16 -0
- package/src/internal/compiler/closure.ts +1583 -0
- package/src/internal/compiler/entries.ts +36 -0
- package/src/internal/compiler/first.ts +252 -0
- package/src/internal/compiler/jit.ts +1091 -0
- package/src/internal/compiler/registry.ts +79 -0
- package/src/internal/compiler/sets.ts +100 -0
- package/src/internal/entries.ts +51 -0
- package/src/internal/node.ts +207 -0
- package/src/internal/numbers.ts +291 -0
- package/src/internal/resume.ts +55 -0
- package/src/internal/text.ts +411 -0
- package/src/internal/tokens.ts +409 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shapes of `map(p, Object.fromEntries)` that the compilers build
|
|
3
|
+
* directly (see `internal/entries.ts`).
|
|
4
|
+
*/
|
|
5
|
+
import type { Node, NodeOf, ParserLike } from "../node.js"
|
|
6
|
+
import { nodeOf } from "../node.js"
|
|
7
|
+
|
|
8
|
+
/** A repeated pair for `Object.fromEntries`: the sequence and the indices of its key and value. */
|
|
9
|
+
export const pairOf = (p: ParserLike): { readonly parsers: ReadonlyArray<ParserLike>; readonly key: number; readonly value: number } | undefined => {
|
|
10
|
+
let node = nodeOf(p)
|
|
11
|
+
while (isDiagnostic(node)) node = nodeOf(node.self)
|
|
12
|
+
if (node._tag !== "Seq") return undefined
|
|
13
|
+
const output = node.output
|
|
14
|
+
if (output === "tuple") return node.parsers.length === 2 ? { parsers: node.parsers, key: 0, value: 1 } : undefined
|
|
15
|
+
if (typeof output === "number" || output[0] === output[1]) return undefined
|
|
16
|
+
return { parsers: node.parsers, key: output[0], value: output[1] }
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const isDiagnostic = (
|
|
20
|
+
node: Node
|
|
21
|
+
): node is NodeOf<"Context" | "Expected" | "MapError" | "OrFail" | "Trace" | "RetryAfter"> =>
|
|
22
|
+
node._tag === "Context" || node._tag === "Expected" || node._tag === "MapError" || node._tag === "OrFail" ||
|
|
23
|
+
node._tag === "Trace" || node._tag === "RetryAfter"
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Whether `map(p, Object.fromEntries)` can build its object directly: `p`
|
|
27
|
+
* is a `repeat` or `separated` of a pair, possibly inside `cut`, the kept
|
|
28
|
+
* element of a sequence (`preceded`, `terminated`, `delimited`) and
|
|
29
|
+
* diagnostics.
|
|
30
|
+
*/
|
|
31
|
+
export const entriesShape = (p: ParserLike): boolean => {
|
|
32
|
+
const node = nodeOf(p)
|
|
33
|
+
if (isDiagnostic(node) || node._tag === "Mode") return entriesShape(node.self)
|
|
34
|
+
if (node._tag === "Seq") return typeof node.output === "number" && entriesShape(node.parsers[node.output]!)
|
|
35
|
+
return (node._tag === "Repeat" || node._tag === "Separated") && pairOf(node.self) !== undefined
|
|
36
|
+
}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* First sets: which input units can start a match of a parser.
|
|
3
|
+
*
|
|
4
|
+
* A first set has a mode:
|
|
5
|
+
*
|
|
6
|
+
* - `Strict`: when the next unit is not in `units` (or the input has
|
|
7
|
+
* ended), the parser fails with `Backtrack`.
|
|
8
|
+
* - `Optional`: in that case, the parser either fails with `Backtrack` or
|
|
9
|
+
* succeeds without consuming input.
|
|
10
|
+
* - `Unknown`: no guarantee.
|
|
11
|
+
*
|
|
12
|
+
* Units are UTF-16 code units for strings and bytes for byte inputs; units
|
|
13
|
+
* from `TableSize` up are summarized by `high`. Array inputs have no units.
|
|
14
|
+
*
|
|
15
|
+
* Skipping a parser that is certain to fail also skips the callbacks it
|
|
16
|
+
* would have run before failing, which is why callbacks must be pure.
|
|
17
|
+
*/
|
|
18
|
+
import type { Encoding } from "../../Encoding.js"
|
|
19
|
+
import type { Node, ParserLike } from "../node.js"
|
|
20
|
+
import { nodeOf } from "../node.js"
|
|
21
|
+
import { fastLimit } from "../text.js"
|
|
22
|
+
import type { CharSet } from "./sets.js"
|
|
23
|
+
import { kindOfEncoding, reachesAbove, TableSize, textSet, tokenSet } from "./sets.js"
|
|
24
|
+
|
|
25
|
+
export const Strict = 0
|
|
26
|
+
export const Optional = 1
|
|
27
|
+
export const Unknown = 2
|
|
28
|
+
|
|
29
|
+
export interface First {
|
|
30
|
+
readonly mode: 0 | 1 | 2
|
|
31
|
+
readonly units: Uint8Array
|
|
32
|
+
readonly high: boolean
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const none = new Uint8Array(TableSize)
|
|
36
|
+
const all = new Uint8Array(TableSize).fill(1)
|
|
37
|
+
|
|
38
|
+
const unknown: First = { mode: Unknown, units: all, high: true }
|
|
39
|
+
const emptyOptional: First = { mode: Optional, units: none, high: false }
|
|
40
|
+
const failing: First = { mode: Strict, units: none, high: false }
|
|
41
|
+
const anyUnit: First = { mode: Strict, units: all, high: true }
|
|
42
|
+
|
|
43
|
+
const union = (a: First, b: First, mode: 0 | 1 | 2): First => {
|
|
44
|
+
const units = new Uint8Array(TableSize)
|
|
45
|
+
for (let i = 0; i < TableSize; i++) units[i] = a.units[i]! | b.units[i]!
|
|
46
|
+
return { mode, units, high: a.high || b.high }
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const withMode = (f: First, mode: 0 | 1 | 2): First => f.mode === mode ? f : { ...f, mode }
|
|
50
|
+
|
|
51
|
+
const lowerAscii = (c: number): number => c >= 65 && c <= 90 ? c + 32 : c
|
|
52
|
+
const upperAscii = (c: number): number => c >= 97 && c <= 122 ? c - 32 : c
|
|
53
|
+
|
|
54
|
+
const ofUnits = (codes: ReadonlyArray<number>, mode: 0 | 1 | 2 = Strict): First => {
|
|
55
|
+
const units = new Uint8Array(TableSize)
|
|
56
|
+
let high = false
|
|
57
|
+
for (const c of codes) {
|
|
58
|
+
if (c < TableSize) units[c] = 1
|
|
59
|
+
else high = true
|
|
60
|
+
}
|
|
61
|
+
return { mode, units, high }
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export class FirstSets {
|
|
65
|
+
private readonly memo = new Map<ParserLike, First | undefined>()
|
|
66
|
+
constructor(readonly kind: 0 | 1 | 2) {}
|
|
67
|
+
|
|
68
|
+
of(p: ParserLike): First {
|
|
69
|
+
if (this.kind === 2) return unknown
|
|
70
|
+
if (this.memo.has(p)) return this.memo.get(p) ?? unknown // in progress: a cycle
|
|
71
|
+
this.memo.set(p, undefined)
|
|
72
|
+
const f = this.compute(nodeOf(p))
|
|
73
|
+
this.memo.set(p, f)
|
|
74
|
+
return f
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Units of the code points of a set, as an encoding (or `Token`) reads them. */
|
|
78
|
+
private setUnits(set: CharSet, enc: Encoding<any> | undefined, mode: 0 | 1): First | undefined {
|
|
79
|
+
if (enc === undefined || kindOfEncoding(enc) === 0) {
|
|
80
|
+
if (this.kind === 1) return { mode, units: set.table, high: false }
|
|
81
|
+
return { mode, units: set.table, high: reachesAbove(set, TableSize) }
|
|
82
|
+
}
|
|
83
|
+
if (enc.unit !== 1) return undefined
|
|
84
|
+
const fast = fastLimit(enc)
|
|
85
|
+
if (fast === 0) return undefined
|
|
86
|
+
const units = set.table.slice()
|
|
87
|
+
// Multi-unit sequences start with a unit at or above `fast`
|
|
88
|
+
if (fast < TableSize) units.fill(reachesAbove(set, fast) ? 1 : 0, fast)
|
|
89
|
+
return { mode, units, high: false }
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
private compute(node: Node): First {
|
|
93
|
+
const kind = this.kind as 0 | 1
|
|
94
|
+
switch (node._tag) {
|
|
95
|
+
case "Succeed":
|
|
96
|
+
case "Sync":
|
|
97
|
+
case "Location":
|
|
98
|
+
case "RestLen":
|
|
99
|
+
case "Eof":
|
|
100
|
+
return emptyOptional
|
|
101
|
+
case "Fail":
|
|
102
|
+
return node.mode === "Backtrack" ? failing : unknown
|
|
103
|
+
case "Any":
|
|
104
|
+
return node.encoding !== undefined && kindOfEncoding(node.encoding) !== kind ? unknown : anyUnit
|
|
105
|
+
case "Take":
|
|
106
|
+
return node.count === 0 ? emptyOptional : anyUnit
|
|
107
|
+
case "Literal": {
|
|
108
|
+
const lit = node.literal
|
|
109
|
+
if (node.encoding !== undefined) {
|
|
110
|
+
if (kindOfEncoding(node.encoding) !== kind) return unknown
|
|
111
|
+
if (node.caseless) return lit.length === 0 ? unknown : anyUnit
|
|
112
|
+
const encoded = node.encoding.encode(lit as string)
|
|
113
|
+
if (encoded.length === 0) return emptyOptional
|
|
114
|
+
return ofUnits([typeof encoded === "string" ? encoded.charCodeAt(0) : encoded[0]!])
|
|
115
|
+
}
|
|
116
|
+
if (lit.length === 0) return emptyOptional
|
|
117
|
+
let first: number
|
|
118
|
+
if (typeof lit === "string") {
|
|
119
|
+
first = kind === 0 ? lit.charCodeAt(0) : new TextEncoder().encode(lit)[0]!
|
|
120
|
+
} else if (lit instanceof Uint8Array && kind === 1) {
|
|
121
|
+
first = lit[0]!
|
|
122
|
+
} else {
|
|
123
|
+
return unknown
|
|
124
|
+
}
|
|
125
|
+
return ofUnits(node.caseless ? [first, lowerAscii(first), upperAscii(first)] : [first])
|
|
126
|
+
}
|
|
127
|
+
case "OneOf":
|
|
128
|
+
case "TakeWhile": {
|
|
129
|
+
if (node.encoding !== undefined && kindOfEncoding(node.encoding) !== kind) return unknown
|
|
130
|
+
const min = node._tag === "OneOf" ? 1 : node.min
|
|
131
|
+
if (node._tag === "TakeWhile" && node.max === 0) return emptyOptional
|
|
132
|
+
const mode = min > 0 ? Strict : Optional
|
|
133
|
+
if (node.negate) return mode === Strict ? anyUnit : withMode(anyUnit, Optional)
|
|
134
|
+
const set = node.encoding === undefined ? tokenSet(node.set, kind) : textSet(node.set)
|
|
135
|
+
return this.setUnits(set, node.encoding, mode) ?? (mode === Strict ? anyUnit : unknown)
|
|
136
|
+
}
|
|
137
|
+
case "Map":
|
|
138
|
+
case "As":
|
|
139
|
+
case "Tap":
|
|
140
|
+
case "TryMap":
|
|
141
|
+
case "FilterMap":
|
|
142
|
+
case "Filter":
|
|
143
|
+
case "Taken":
|
|
144
|
+
case "WithTaken":
|
|
145
|
+
case "Span":
|
|
146
|
+
case "WithSpan":
|
|
147
|
+
case "Context":
|
|
148
|
+
case "Expected":
|
|
149
|
+
case "MapError":
|
|
150
|
+
case "OrFail":
|
|
151
|
+
case "Peek":
|
|
152
|
+
case "Trace":
|
|
153
|
+
case "ResumeAfter":
|
|
154
|
+
case "RetryAfter":
|
|
155
|
+
return this.of(node.self)
|
|
156
|
+
case "FlatMap":
|
|
157
|
+
case "SeparatedFold":
|
|
158
|
+
case "Dispatch": {
|
|
159
|
+
const f = this.of(node._tag === "Dispatch" ? node.selector : node.self)
|
|
160
|
+
return f.mode === Strict ? f : unknown
|
|
161
|
+
}
|
|
162
|
+
case "Mode": {
|
|
163
|
+
const f = this.of(node.self)
|
|
164
|
+
return node.from === "Backtrack" ? (f.mode === Unknown ? f : unknown) : f
|
|
165
|
+
}
|
|
166
|
+
case "Opt":
|
|
167
|
+
case "OrElseSucceed": {
|
|
168
|
+
const f = this.of(node.self)
|
|
169
|
+
return f.mode === Unknown ? f : withMode(f, Optional)
|
|
170
|
+
}
|
|
171
|
+
case "Seq":
|
|
172
|
+
case "Struct":
|
|
173
|
+
return this.sequence(node.parsers)
|
|
174
|
+
case "ZipWith":
|
|
175
|
+
return this.sequence([node.self, node.that])
|
|
176
|
+
case "Alt": {
|
|
177
|
+
if (node.parsers.length === 0) return failing
|
|
178
|
+
let acc: First | undefined
|
|
179
|
+
let mode: 0 | 1 | 2 = Strict
|
|
180
|
+
for (const p of node.parsers) {
|
|
181
|
+
const f = this.of(p)
|
|
182
|
+
if (f.mode === Unknown) return unknown
|
|
183
|
+
if (f.mode === Optional) mode = Optional
|
|
184
|
+
acc = acc === undefined ? f : union(acc, f, mode)
|
|
185
|
+
}
|
|
186
|
+
return withMode(acc!, mode)
|
|
187
|
+
}
|
|
188
|
+
case "Repeat":
|
|
189
|
+
case "Fold":
|
|
190
|
+
case "Separated": {
|
|
191
|
+
if (node.max === 0) return emptyOptional
|
|
192
|
+
const f = this.of(node.self)
|
|
193
|
+
if (f.mode !== Strict) return unknown
|
|
194
|
+
return node.min === 0 ? withMode(f, Optional) : f
|
|
195
|
+
}
|
|
196
|
+
case "Suspend":
|
|
197
|
+
return this.of(node.resolve())
|
|
198
|
+
default:
|
|
199
|
+
return unknown
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
private sequence(parsers: ReadonlyArray<ParserLike>): First {
|
|
204
|
+
let acc: First | undefined
|
|
205
|
+
for (const p of parsers) {
|
|
206
|
+
const f = this.of(p)
|
|
207
|
+
if (f.mode === Unknown) return unknown
|
|
208
|
+
acc = acc === undefined ? f : union(acc, f, f.mode)
|
|
209
|
+
if (f.mode === Strict) return acc
|
|
210
|
+
}
|
|
211
|
+
return acc ?? emptyOptional
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* For an `Alt`: the branches worth trying for each next unit, each next
|
|
217
|
+
* high unit, and at the end of the input, or `undefined` when pruning
|
|
218
|
+
* would never skip a branch.
|
|
219
|
+
*/
|
|
220
|
+
export interface AltPlan {
|
|
221
|
+
/** Indexed by unit: indexes into `lists`. */
|
|
222
|
+
readonly byUnit: Uint8Array
|
|
223
|
+
readonly high: number
|
|
224
|
+
readonly end: number
|
|
225
|
+
readonly lists: ReadonlyArray<ReadonlyArray<number>>
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export const planAlt = (firsts: ReadonlyArray<First>): AltPlan | undefined => {
|
|
229
|
+
const n = firsts.length
|
|
230
|
+
if (n < 2 || n > 64) return undefined
|
|
231
|
+
const lists: Array<ReadonlyArray<number>> = []
|
|
232
|
+
const index = new Map<string, number>()
|
|
233
|
+
const listOf = (keep: (f: First) => boolean): number => {
|
|
234
|
+
const list: Array<number> = []
|
|
235
|
+
for (let i = 0; i < n; i++) if (keep(firsts[i]!)) list.push(i)
|
|
236
|
+
const key = list.join(",")
|
|
237
|
+
let k = index.get(key)
|
|
238
|
+
if (k === undefined) {
|
|
239
|
+
k = lists.length
|
|
240
|
+
lists.push(list)
|
|
241
|
+
index.set(key, k)
|
|
242
|
+
}
|
|
243
|
+
return k
|
|
244
|
+
}
|
|
245
|
+
const byUnit = new Uint8Array(TableSize)
|
|
246
|
+
for (let u = 0; u < TableSize; u++) byUnit[u] = listOf((f) => f.mode !== Strict || f.units[u] === 1)
|
|
247
|
+
const high = listOf((f) => f.mode !== Strict || f.high)
|
|
248
|
+
const end = listOf((f) => f.mode !== Strict)
|
|
249
|
+
if (lists.length === 1 && lists[0]!.length === n) return undefined
|
|
250
|
+
if (lists.length > 255) return undefined
|
|
251
|
+
return { byUnit, high, end, lists }
|
|
252
|
+
}
|