@thomasfosterau/effect-parse 0.5.0 → 0.6.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/CHANGELOG.md +202 -0
- package/README.md +19 -1
- package/dist/Ascii.d.ts.map +1 -1
- package/dist/Ascii.js +5 -3
- package/dist/Ascii.js.map +1 -1
- package/dist/Binary.d.ts +5 -2
- package/dist/Binary.d.ts.map +1 -1
- package/dist/Binary.js +20 -3
- package/dist/Binary.js.map +1 -1
- package/dist/Bits.d.ts.map +1 -1
- package/dist/Bits.js +4 -0
- package/dist/Bits.js.map +1 -1
- package/dist/Input.d.ts +21 -3
- package/dist/Input.d.ts.map +1 -1
- package/dist/Input.js +31 -4
- package/dist/Input.js.map +1 -1
- package/dist/Nom.d.ts.map +1 -1
- package/dist/ParseError.d.ts +69 -11
- package/dist/ParseError.d.ts.map +1 -1
- package/dist/ParseError.js +129 -28
- package/dist/ParseError.js.map +1 -1
- package/dist/Parser.d.ts +10 -4
- package/dist/Parser.d.ts.map +1 -1
- package/dist/Parser.js +10 -24
- package/dist/Parser.js.map +1 -1
- package/dist/ParserSchema.d.ts.map +1 -1
- package/dist/ParserSchema.js +1 -2
- package/dist/ParserSchema.js.map +1 -1
- package/dist/ParserStream.d.ts +119 -12
- package/dist/ParserStream.d.ts.map +1 -1
- package/dist/ParserStream.js +282 -55
- package/dist/ParserStream.js.map +1 -1
- package/dist/Syntax.js +1 -1
- package/dist/Text.d.ts.map +1 -1
- package/dist/Text.js +13 -7
- package/dist/Text.js.map +1 -1
- package/dist/Token.d.ts +10 -1
- package/dist/Token.d.ts.map +1 -1
- package/dist/Token.js +14 -5
- package/dist/Token.js.map +1 -1
- package/dist/internal/compiler/closure.d.ts +1 -1
- package/dist/internal/compiler/closure.d.ts.map +1 -1
- package/dist/internal/compiler/closure.js +7 -17
- package/dist/internal/compiler/closure.js.map +1 -1
- package/dist/internal/compiler/first.d.ts.map +1 -1
- package/dist/internal/compiler/first.js +2 -1
- package/dist/internal/compiler/first.js.map +1 -1
- package/dist/internal/compiler/graph.d.ts +23 -1
- package/dist/internal/compiler/graph.d.ts.map +1 -1
- package/dist/internal/compiler/graph.js +27 -5
- package/dist/internal/compiler/graph.js.map +1 -1
- package/dist/internal/compiler/jit.d.ts.map +1 -1
- package/dist/internal/compiler/jit.js +26 -13
- package/dist/internal/compiler/jit.js.map +1 -1
- package/dist/internal/compiler/registry.d.ts +1 -1
- package/dist/internal/compiler/wasm.d.ts.map +1 -1
- package/dist/internal/compiler/wasm.js +105 -34
- package/dist/internal/compiler/wasm.js.map +1 -1
- package/dist/internal/node.d.ts +19 -1
- package/dist/internal/node.d.ts.map +1 -1
- package/dist/internal/node.js +42 -8
- package/dist/internal/node.js.map +1 -1
- package/dist/internal/run.d.ts +3 -1
- package/dist/internal/run.d.ts.map +1 -1
- package/dist/internal/run.js +4 -2
- package/dist/internal/run.js.map +1 -1
- package/dist/internal/stack.d.ts +8 -0
- package/dist/internal/stack.d.ts.map +1 -1
- package/dist/internal/stack.js +17 -1
- package/dist/internal/stack.js.map +1 -1
- package/dist/internal/tokens.d.ts +10 -3
- package/dist/internal/tokens.d.ts.map +1 -1
- package/dist/internal/tokens.js +22 -9
- package/dist/internal/tokens.js.map +1 -1
- package/dist/internal/tuple.d.ts +6 -0
- package/dist/internal/tuple.d.ts.map +1 -0
- package/dist/internal/tuple.js +170 -0
- package/dist/internal/tuple.js.map +1 -0
- package/package.json +17 -10
- package/src/Ascii.ts +5 -3
- package/src/Binary.ts +24 -3
- package/src/Bits.ts +4 -0
- package/src/Input.ts +37 -4
- package/src/ParseError.ts +206 -52
- package/src/Parser.ts +19 -29
- package/src/ParserSchema.ts +1 -2
- package/src/ParserStream.ts +336 -62
- package/src/Text.ts +16 -12
- package/src/Token.ts +14 -5
- package/src/internal/compiler/closure.ts +9 -18
- package/src/internal/compiler/first.ts +6 -0
- package/src/internal/compiler/graph.ts +32 -4
- package/src/internal/compiler/jit.ts +37 -17
- package/src/internal/compiler/wasm.ts +141 -68
- package/src/internal/node.ts +49 -3
- package/src/internal/run.ts +4 -2
- package/src/internal/stack.ts +17 -0
- package/src/internal/tokens.ts +20 -10
- package/src/internal/tuple.ts +141 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# @thomasfosterau/effect-parse
|
|
2
|
+
|
|
3
|
+
## 0.6.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#128](https://github.com/thomasfosterau/effect-parse/pull/128) [`8cf4008`](https://github.com/thomasfosterau/effect-parse/commit/8cf4008eaadd38fc85c6d0b09bff35cc225fdb0e) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - Every repetition checks progress, not only an unbounded one ([#115](https://github.com/thomasfosterau/effect-parse/issues/115)). `repeat`, `fold`, `separated`, `repeatTill` (and `Nom.count`, `Nom.manyMN`, `Binary.lengthRepeat`, which are built on them) now fail with an unrecoverable `Assert` failure when an element succeeds without consuming input, whatever the range, in the interpreter and in all three compilers. Before, a bounded repetition of such an element ran to its bound, and in `Binary.lengthRepeat` the bound comes from the input: three bytes made `lengthRepeat(beU24, succeed(0))` build an array of 16.7 M elements, and four bytes made `lengthRepeat(beU32, …)` throw a `RangeError` out of `Parser.parse`. A repetition now never runs more iterations than the input has tokens.
|
|
8
|
+
|
|
9
|
+
**Breaking:** `Parser.repeat(Parser.opt(x), 3)` and other bounded repetitions of a parser that can match empty are an error where the element matches nothing. Make the element consume (`repeat(x, { max: 3 })`), or write the optional parts out (`seq(opt(x), opt(x), opt(x))`).
|
|
10
|
+
|
|
11
|
+
- [#133](https://github.com/thomasfosterau/effect-parse/pull/133) [`6ff1607`](https://github.com/thomasfosterau/effect-parse/commit/6ff1607e10025b41c0dd84dd5194437c287ac67a) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - A `ParseError` no longer serialises the input it was parsing, and its message is bounded ([#117](https://github.com/thomasfosterau/effect-parse/issues/117)).
|
|
12
|
+
|
|
13
|
+
- `error.input` and `error.encoding` are still readable (and `position`, `message` and `ParseError.lineColumn` work as before), but they are now accessors over private fields rather than own properties, and `toJSON` leaves them out. `JSON.stringify(error)`, object spread, `Object.keys`, Node's `inspect`, Effect's `Cause` rendering and loggers that walk an error's own properties therefore no longer write out everything that was being parsed (a failed parse of a 1 MB `Uint8Array` used to serialise as 12.9 MB of JSON). **Breaking** for code that read `input` from a serialised or spread error (read `error.input` from the error itself); `input` is also no longer among the properties that `Equal.equals` and `Hash.hash` walk (they still compare an error's other own properties, its stack trace included). `toJSON` now returns a `ParseError.ParseErrorJson`: `_tag`, `offset`, `position`, `kind`, `mode`, `expected`, `context`, `cause`, `description` and `message`.
|
|
14
|
+
- `message` shows at most 60 characters on each side of the failure, marking what it leaves out with `…`, instead of the whole line: a failure at the end of a 5 MB line with no newline produced a 10 MB message, rebuilt on every access. Lines shorter than the window render exactly as before. Encoded byte input (`Text.utf8`, …) is bounded the same way, and a surrogate pair is never split at the window's edge.
|
|
15
|
+
|
|
16
|
+
- [#131](https://github.com/thomasfosterau/effect-parse/pull/131) [`a2da059`](https://github.com/thomasfosterau/effect-parse/commit/a2da05901f41b8474c71ee21feea0c86966878f0) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - The stream runners bound what they buffer, and `ParserStream.parseMany` no longer re-parses an unfinished value on every chunk ([#116](https://github.com/thomasfosterau/effect-parse/issues/116)).
|
|
17
|
+
|
|
18
|
+
- `maxBufferSize` (tokens: UTF-16 code units, bytes or array elements) is a new option of `parseMany`, `parseAll`, `parseReadable` and `parseResponse`, defaulting to 64 MiB (`ParserStream.defaultMaxBufferSize`); `Infinity` turns it off. `parseMany` counts the input it has not consumed yet (one unfinished value); the other three count the whole input. `parseResponse` also fails before reading the body when `Content-Length` is over the limit.
|
|
19
|
+
- Exceeding the limit fails with the new `ParserStream.BufferLimitError` (`limit`, `size`), not a `ParseError`. **Breaking:** it joins the error type of the four runners, so code that treats their error as a `ParseError` has to narrow it first (`Effect.catchTag("BufferLimitError", …)` or `error._tag === "ParseError"`), and a stream over 64 MiB that used to parse now fails unless it passes a larger `maxBufferSize`.
|
|
20
|
+
- `parseReadable` and `parseResponse` take an options argument (`ParserStream.BufferOptions`).
|
|
21
|
+
- `parseMany` was quadratic in the size of a value that had not completed: it copied the buffer and parsed the value again from its start on every chunk (4 MiB with no delimiter in 1 KiB chunks: 40 s). Its byte buffer now grows geometrically, and a value over 64 KiB is retried only once the buffer has grown by an eighth. **Behaviour change:** the chunk that completes a value larger than 64 KiB may not emit it until more input arrives or the stream ends; smaller values are emitted as soon as they complete, as before.
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- [#108](https://github.com/thomasfosterau/effect-parse/pull/108) [`a09a738`](https://github.com/thomasfosterau/effect-parse/commit/a09a7380412bf8efc9d281d014f92c57ac0812d3) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - Compiled `alt`s now dispatch on the first characters of a branch that starts with `not(p)`: the lookahead consumes nothing, so the branch can only start with `p`'s first characters or with those of what follows it, and is skipped on any other input without running the lookahead.
|
|
26
|
+
|
|
27
|
+
- [#142](https://github.com/thomasfosterau/effect-parse/pull/142) [`3dcc9f0`](https://github.com/thomasfosterau/effect-parse/commit/3dcc9f0a154bdbcc64b46a7e5e0b603d9af6bbdf) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - `Compiler.jit` and `Compiler.wasm` generate code in proportion to the grammar ([#122](https://github.com/thomasfosterau/effect-parse/issues/122)). A parser used twice by the same parent (`Parser.seq(p, p)`) counted as used once, so it was inlined at both places, and a grammar that did so at every level doubled its generated code per level: twenty lines compiled to 160 MB of JavaScript in 22 s, and ran the WebAssembly compiler out of memory. Uses are now counted, so such a parser becomes one rule that both places call. A grammar that is itself enormous (over 100 000 parsers to inline for one root, which no sharing can reduce) is no longer turned into source text at all: the closure compiler takes over, and `Compiler.fallbacks` / the registry record why.
|
|
28
|
+
|
|
29
|
+
- [#109](https://github.com/thomasfosterau/effect-parse/pull/109) [`82f57f0`](https://github.com/thomasfosterau/effect-parse/commit/82f57f09cf23c64b1e669e3a8ff6544b0bca74d5) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - Interpreted steps called from compiled code, such as a `Parser.make` guard, no longer allocate a `Failure` each time they backtrack or cut: a compiled run throws its failures away and the interpreter builds the error, so `State.backtrack` and `State.cut` record only the mode there.
|
|
30
|
+
|
|
31
|
+
- [#140](https://github.com/thomasfosterau/effect-parse/pull/140) [`c118e6a`](https://github.com/thomasfosterau/effect-parse/commit/c118e6ac8d83273fa3bac4e5a9c9415fff3bc770) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - `Input.State.reset` keeps, for string input, what the state has learnt about its input: where the stop characters of compiled `Token.takeTill` searches and the literals of `Token.takeUntilAny` occur ([#126](https://github.com/thomasfosterau/effect-parse/issues/126)). The positions are absolute and a string never changes, so they hold wherever the next run starts. Before, a lexer that reset one state before each token searched for a stop character that was rare or absent (`&` in ordinary XML text) to the end of the buffer again for every token, which made lexing a whole string quadratic (4 MB took about 4 s through effect-xml).
|
|
32
|
+
|
|
33
|
+
For byte and array input `reset` still drops what was remembered, because a caller may refill such a buffer in place between runs (a `Uint8Array` source is viewed, not copied): reuse a `State` over a buffer you overwrite and every run searches afresh, as before.
|
|
34
|
+
|
|
35
|
+
Also fixed: a `takeUntilAny` search that found nothing while a parser had narrowed the input's end was remembered as "not found" after the end widened again, so a literal further on could be missed within the same run. A miss is now remembered together with the end it was searched to.
|
|
36
|
+
|
|
37
|
+
- [#110](https://github.com/thomasfosterau/effect-parse/pull/110) [`2e24b10`](https://github.com/thomasfosterau/effect-parse/commit/2e24b102296d70329c4d09e58c2d36c4bf1952a1) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - `seq` builds its tuples with an array literal per arity (up to 8) in the interpreter and the closure compiler, as the JIT already did, so V8 can allocate tuples that a parse keeps straight into the old generation instead of copying them through scavenges.
|
|
38
|
+
|
|
39
|
+
- [#105](https://github.com/thomasfosterau/effect-parse/pull/105) [`62687e5`](https://github.com/thomasfosterau/effect-parse/commit/62687e5640ea3e209a93f4b61a918225ec4e3823) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - Include `CHANGELOG.md` in the published package, so the release notes can be read from `node_modules`.
|
|
40
|
+
|
|
41
|
+
- [#127](https://github.com/thomasfosterau/effect-parse/pull/127) [`fdd1cba`](https://github.com/thomasfosterau/effect-parse/commit/fdd1cbadacda7dcc76875586959ef1b4c082939a) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - Counts and repetition bounds are validated when a parser is built, and a length read from the input is validated when it is read ([#114](https://github.com/thomasfosterau/effect-parse/issues/114), [#121](https://github.com/thomasfosterau/effect-parse/issues/121)). `Token.take`, `Text.*.take`, `Bits.take` / `takeBig` / `pattern` and every combinator that takes a `Range` (`repeat`, `fold`, `repeatTill`, `separated`, `takeWhile`, `takeTill`, `takeUntil`, `takeUntilAny` and their `Text` and `Nom` forms) now throw a `RangeError` unless the count, `min` and `max` are non-negative integers (`max` may be `Infinity`) with `min <= max`; `escaped` / `takeEscaped` throw unless the control character is a character or its code. Before, a negative or fractional count moved the cursor backwards (`Parser.repeat(Binary.lengthTake(Binary.i8))` on the single byte `0xfe` never terminated and ran the process out of memory), and the JIT wrote a bound into the source it compiles as given, so a bound that was a string at runtime (one read from JSON without a `Number()`) ran as code. `Binary.lengthTake`, `lengthRepeat` and `lengthAndThen` now fail the parse at the length, with kind `Verify`, when it is negative, fractional, `NaN` or above `Number.MAX_SAFE_INTEGER`. The JIT also writes every number through one helper that refuses anything but a non-negative integer.
|
|
42
|
+
|
|
43
|
+
- [#138](https://github.com/thomasfosterau/effect-parse/pull/138) [`90ed4ab`](https://github.com/thomasfosterau/effect-parse/commit/90ed4abefd4ad390abee441f0b9a22e486fc614c) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - `Compiler.wasm` stays within its memory and agrees with the interpreter at the limits ([#123](https://github.com/thomasfosterau/effect-parse/issues/123)):
|
|
44
|
+
|
|
45
|
+
- A parse whose input and trace need more linear memory than the engine will give, or more than 2 GiB, now runs on the JIT (which parses the input in place) instead of throwing `RangeError: WebAssembly.Memory.grow()` out of `Parser.parse`. This holds when the trace runs out part-way through a parse as well.
|
|
46
|
+
- After a parse that grew a module's memory past 128 MiB, the module gets a new memory, so one large input no longer holds five to ten times its size for the life of the process (a `WebAssembly.Memory` cannot shrink), nor keeps the last string parsed alive.
|
|
47
|
+
- Repetition bounds of 2^32 or more were truncated to their low 32 bits: `repeat(p, { min: 2 ** 32 })` succeeded where the interpreter fails, and `{ max: 2 ** 32 }` matched nothing. A minimum that large can now never be met and a maximum that large is no limit, as in the other backends.
|
|
48
|
+
- Trace offsets are read unsigned.
|
|
49
|
+
|
|
50
|
+
## 0.5.0
|
|
51
|
+
|
|
52
|
+
### Minor Changes
|
|
53
|
+
|
|
54
|
+
- [#85](https://github.com/thomasfosterau/effect-parse/pull/85) [`7287ad5`](https://github.com/thomasfosterau/effect-parse/commit/7287ad556f688dbb71267c422869e77a4149f313) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - Add `Parser.failAt(offset, error)`, a parser that fails with a user error reported at a chosen offset. A check that can only run once a construct has parsed (`tryMap`, `filterOrFail`) can only fail where the construct started; returned from a `flatMap` continuation, `failAt` points the error at the part at fault instead, such as a mismatched end tag. Interpreted and compiled parsers report the same position ([#73](https://github.com/thomasfosterau/effect-parse/issues/73)).
|
|
55
|
+
|
|
56
|
+
- [#85](https://github.com/thomasfosterau/effect-parse/pull/85) [`7287ad5`](https://github.com/thomasfosterau/effect-parse/commit/7287ad556f688dbb71267c422869e77a4149f313) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - Add `Parser.withFastPath(grammar, fast)`, a supported way to put a hand-written scanner in front of a grammar. Compiled code calls `fast(state)` first; it returns the grammar's value with `state.pos` where the grammar would stop, or `Parser.Defer` to run the grammar from the same offset. Interpreted runs use the grammar alone, so every error, `Syntax` tree and trace is exactly the grammar's. `Parser.verifyFastPath(grammar, fast, inputs)` runs both at every offset of every input, complete and partial, and returns the places where they disagree ([#78](https://github.com/thomasfosterau/effect-parse/issues/78)).
|
|
57
|
+
|
|
58
|
+
- [#85](https://github.com/thomasfosterau/effect-parse/pull/85) [`7287ad5`](https://github.com/thomasfosterau/effect-parse/commit/7287ad556f688dbb71267c422869e77a4149f313) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - Add `Parser.mapOrFail(p, f, orFailWith?)`, the allocation-free form of `tryMap` and `filterMap`: `f` returns `Input.Fail` to reject a value, and compiled code compares the result with the sentinel instead of allocating and unwrapping a `Result` or `Option` on every success. `orFailWith` builds the user error (the `ParseError`'s `cause`) only on failure; without it, the failure has no cause, as with `filterMap`. Where V8 does not inline the callback and remove the wrapper (a large grammar that exhausts its inlining budget), a check on every token runs about 1.3× faster than with `tryMap` ([#66](https://github.com/thomasfosterau/effect-parse/issues/66)).
|
|
59
|
+
|
|
60
|
+
- [#85](https://github.com/thomasfosterau/effect-parse/pull/85) [`7287ad5`](https://github.com/thomasfosterau/effect-parse/commit/7287ad556f688dbb71267c422869e77a4149f313) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - Add `Parser.mapSpan(p, (a, start, end) => b)` and `Parser.seqWith(parsers, (a, b, ...) => c)`, the allocation-free spellings of `map(withSpan(p), ...)` and `map(seq(...), ...)`: compiled code passes the offsets, or one value per parser, straight to the callback instead of building a tuple and a span object on every success. V8 often removes those allocations itself when it inlines the callback; in a large grammar that exhausts its inlining budget, a lexer that records spans runs about 10% faster with `mapSpan` ([#64](https://github.com/thomasfosterau/effect-parse/issues/64)).
|
|
61
|
+
|
|
62
|
+
- [#85](https://github.com/thomasfosterau/effect-parse/pull/85) [`7287ad5`](https://github.com/thomasfosterau/effect-parse/commit/7287ad556f688dbb71267c422869e77a4149f313) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - The overloaded exports have named types: `Parser.ParseFn`, `ParseSyncFn`, `ParsePeekFn`, `ParsePartialFn`, `ParseRecoverableFn` and `DispatchFn`, `Input.FromSourceFn`, `Token.LiteralFn` and `TakeUntilFn`, `Ascii.CaselessFn` and `Syntax.ParseFn`, each holding the same call signatures as before, so calls infer the same types. `SyntaxNode.toJSON()` returns the new `Syntax.SyntaxNodeJson` (`{ kind, start, end }`) instead of `unknown` ([#77](https://github.com/thomasfosterau/effect-parse/issues/77)).
|
|
63
|
+
|
|
64
|
+
- [#85](https://github.com/thomasfosterau/effect-parse/pull/85) [`7287ad5`](https://github.com/thomasfosterau/effect-parse/commit/7287ad556f688dbb71267c422869e77a4149f313) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - Add `Compiler.runner(p, options?)`, a prepared runner for drivers that run one compiled grammar many times on states they own, such as a lexer reading a token per run. It returns a function of the state that returns exactly what `Parser.run(p, state, options)` returns, with the compiled form looked up once (and again only when the input kind, or complete versus partial, changes) instead of on every run.
|
|
65
|
+
|
|
66
|
+
The JIT's generated entry now checks the state's end and reports a call-stack overflow as the same `TooDeep` failure itself, so every runner calls it directly instead of through a separate guard and a closure. On the drivers benchmark's lexer (240 K tokens, one per run), `Parser.run` takes 13.7 ms instead of 14.5, and `Compiler.runner` 11.0 ms: about 46 ns per token against 60 before ([#65](https://github.com/thomasfosterau/effect-parse/issues/65)).
|
|
67
|
+
|
|
68
|
+
- [#85](https://github.com/thomasfosterau/effect-parse/pull/85) [`7287ad5`](https://github.com/thomasfosterau/effect-parse/commit/7287ad556f688dbb71267c422869e77a4149f313) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - Add `Parser.combinator(parsers, build, name?)`, for writing combinators whose inner parsers compile. `build` makes the combinator's step from the parsers' steps, which `Parser.Steps<Ps>` types. Interpreted, it receives their own steps; compiled, their compiled steps. A combinator written with `Parser.make` is opaque to the compilers, so it and every parser it runs stay interpreted ([#83](https://github.com/thomasfosterau/effect-parse/issues/83)).
|
|
69
|
+
|
|
70
|
+
- [#85](https://github.com/thomasfosterau/effect-parse/pull/85) [`7287ad5`](https://github.com/thomasfosterau/effect-parse/commit/7287ad556f688dbb71267c422869e77a4149f313) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - Add `Parser.quiet(p)`, which runs a parser without letting it add to the expectations of later errors. A whitespace or comment skipper that matches zero or more times stops by failing, and what it would have accepted (`" "`, `"(:"`, ...) used to be listed in every error raised after it; wrapped in `quiet`, errors expect only what can actually fail there. When the parser succeeds, its hints and furthest failure are forgotten; when it fails recoverably without consuming input, its failure expects nothing. Compiled parsers treat it as an identity ([#74](https://github.com/thomasfosterau/effect-parse/issues/74)).
|
|
71
|
+
|
|
72
|
+
- [#100](https://github.com/thomasfosterau/effect-parse/pull/100) [`0a0f3b0`](https://github.com/thomasfosterau/effect-parse/commit/0a0f3b051319f7e5dc42ebdec14316dca695d2bc) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - `Token.takeUntilAny(literals)`: takes input up to the first occurrence of any of several literals, the search a multi-pattern prefilter makes. On byte input `Compiler.wasm` now compiles it, and `Token.takeUntil`, natively with WebAssembly SIMD: Teddy (as in ripgrep), which tests the first three bytes of every literal at sixteen positions at once with nibble-table lookups and checks each candidate in full. Elsewhere successive searches over one input remember where each literal next occurs, so each is searched for once per occurrence. Results are unchanged.
|
|
73
|
+
|
|
74
|
+
When each of the first three positions holds at most three distinct bytes across the literals (one literal, or the case variants of a few), the search compares with `i8x16.eq` instead of nibble tables, and a candidate is checked with the widest loads its literals fill.
|
|
75
|
+
|
|
76
|
+
- [#80](https://github.com/thomasfosterau/effect-parse/pull/80) [`60c1810`](https://github.com/thomasfosterau/effect-parse/commit/60c1810c7f45281460559601e107d86c27717df6) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - Add `Compiler.wasm`, a third parser compiler. It scans the input in WebAssembly, with code generated from the grammar, and builds the value with a generated JavaScript function that reads what the scan recorded, so results and errors are those of the interpreter, as with the other compilers. On the JSON benchmarks it parses strings, UTF-8 and UTF-16 bytes faster than `Compiler.jit`. It copies input into WebAssembly memory with standard `ArrayBuffer` views and `TextEncoder`, so it runs the same everywhere. Array input, streaming builds, and environments without `WebAssembly` or `new Function` use the JIT.
|
|
77
|
+
|
|
78
|
+
### Patch Changes
|
|
79
|
+
|
|
80
|
+
- [#85](https://github.com/thomasfosterau/effect-parse/pull/85) [`7287ad5`](https://github.com/thomasfosterau/effect-parse/commit/7287ad556f688dbb71267c422869e77a4149f313) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - `Binary` integers of up to 32 bits are read from the bytes directly, without a `DataView`, and `lengthTake` and `lengthRepeat` reuse the parser they build for each length instead of building one per value: length-prefixed records parse 15–40% faster.
|
|
81
|
+
|
|
82
|
+
- [#85](https://github.com/thomasfosterau/effect-parse/pull/85) [`7287ad5`](https://github.com/thomasfosterau/effect-parse/commit/7287ad556f688dbb71267c422869e77a4149f313) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - `Binary`'s fixed-size numbers compile: the JIT reads them inline on byte input instead of calling their step, about 3× faster for a sequence of mixed numbers and level with a hand-written `DataView` loop for a run of one kind.
|
|
83
|
+
|
|
84
|
+
- [#85](https://github.com/thomasfosterau/effect-parse/pull/85) [`7287ad5`](https://github.com/thomasfosterau/effect-parse/commit/7287ad556f688dbb71267c422869e77a4149f313) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - `Binary` parsers no longer allocate a `DataView` per number: the view is created once per parse state. Parsing a run of 32-bit integers is 3–4× faster, and of floats or a `fold` of 16-bit integers up to 10× when compiled.
|
|
85
|
+
|
|
86
|
+
- [#85](https://github.com/thomasfosterau/effect-parse/pull/85) [`7287ad5`](https://github.com/thomasfosterau/effect-parse/commit/7287ad556f688dbb71267c422869e77a4149f313) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - `Bits.take` and the other bit parsers read as many bits as each byte holds at once rather than one bit at a time: 16-bit fields parse about 2.5× faster, 3-bit fields about 15%.
|
|
87
|
+
|
|
88
|
+
- [#85](https://github.com/thomasfosterau/effect-parse/pull/85) [`7287ad5`](https://github.com/thomasfosterau/effect-parse/commit/7287ad556f688dbb71267c422869e77a4149f313) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - The parsers inside `Expression.make`, `Parser.permutation` and `Binary.lengthTake` now compile with the grammar around them instead of running interpreted: compiled expression grammars run about twice as fast.
|
|
89
|
+
|
|
90
|
+
- [#85](https://github.com/thomasfosterau/effect-parse/pull/85) [`7287ad5`](https://github.com/thomasfosterau/effect-parse/commit/7287ad556f688dbb71267c422869e77a4149f313) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - The `Compiler` module's doc comment no longer says that `ParserStream.parseMany` is always interpreted: it runs a compiled parser's resumable build, and parses a value again, interpreted, only when it fails or needs more input ([#76](https://github.com/thomasfosterau/effect-parse/issues/76)).
|
|
91
|
+
|
|
92
|
+
- [#85](https://github.com/thomasfosterau/effect-parse/pull/85) [`7287ad5`](https://github.com/thomasfosterau/effect-parse/commit/7287ad556f688dbb71267c422869e77a4149f313) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - Internal type cleanups from bringing every Effect lint rule to `error`: casts replaced by generics and narrowing, and the remaining type assertions documented. No behaviour changes; the emitted `.d.ts` prints `Nom.lineEnding`'s union in a different order ([#68](https://github.com/thomasfosterau/effect-parse/issues/68)).
|
|
93
|
+
|
|
94
|
+
- [#85](https://github.com/thomasfosterau/effect-parse/pull/85) [`7287ad5`](https://github.com/thomasfosterau/effect-parse/commit/7287ad556f688dbb71267c422869e77a4149f313) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - Interpreted parses merge expected-token lists through a small cache of recent merges instead of allocating a new list each time a hint meets a failure: 2–13% faster on the JSON benchmarks.
|
|
95
|
+
|
|
96
|
+
- [#85](https://github.com/thomasfosterau/effect-parse/pull/85) [`7287ad5`](https://github.com/thomasfosterau/effect-parse/commit/7287ad556f688dbb71267c422869e77a4149f313) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - `Parser.parsePartial` returns a compiled parser's `Incomplete` without re-running the parser interpreted: compiled code now records the interpreter's `Incomplete` failure (`needed` included) where it reports it itself, at `eof` and at the end of an `escaped` text. Results are unchanged; a whole document parsed as partial input (ending in whitespace, say) no longer parses twice: 5× faster on a 2.4 MB JSON document.
|
|
97
|
+
|
|
98
|
+
`ParserStream.parseMany` likewise no longer parses a value cut short by its chunk a second time, interpreted; only a value that fails is.
|
|
99
|
+
|
|
100
|
+
- [#85](https://github.com/thomasfosterau/effect-parse/pull/85) [`7287ad5`](https://github.com/thomasfosterau/effect-parse/commit/7287ad556f688dbb71267c422869e77a4149f313) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - The JIT compiles a repetition of a character set whose values are unused (under `taken`, `asVoid`, `peek` or a dropped element) as one scan of the run: `repeat(oneOf(S))` as `takeWhile(S)`, and `repeat(alt(oneOf(S), ...rest))` (with `min` at most 1 and no `max`) with a `takeWhile` run as its first branch. A name written as a repetition of a shared `alt(nameChar, escape)` no longer calls that alternative once per character: about 20% faster on the drivers benchmark's names. The closure compiler compiles `repeat(oneOf(S))` with unused values as `takeWhile(S)` too: 2.2× faster on runs of 30–70 characters. Results are unchanged ([#79](https://github.com/thomasfosterau/effect-parse/issues/79)).
|
|
101
|
+
|
|
102
|
+
- [#85](https://github.com/thomasfosterau/effect-parse/pull/85) [`7287ad5`](https://github.com/thomasfosterau/effect-parse/commit/7287ad556f688dbb71267c422869e77a4149f313) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - Compiled streaming parses (`Parser.parsePartial`, `ParserStream.parseAll` and `parseMany`) build `Parser.fromEntries` objects directly, as ordinary compiled parses do, rather than building the array of pairs first: about 1.5× faster on a JSON document with the JIT.
|
|
103
|
+
|
|
104
|
+
- [#85](https://github.com/thomasfosterau/effect-parse/pull/85) [`7287ad5`](https://github.com/thomasfosterau/effect-parse/commit/7287ad556f688dbb71267c422869e77a4149f313) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - Interpreted `Token.takeWhile` / `takeTill` and the `Ascii` classes no longer allocate a result record per match: the shared token scanner fills one record that its caller reads at once. The interpreted JSON benchmark (`json.ts`, Token/Ascii) runs 4–7% faster.
|
|
105
|
+
|
|
106
|
+
- [#85](https://github.com/thomasfosterau/effect-parse/pull/85) [`7287ad5`](https://github.com/thomasfosterau/effect-parse/commit/7287ad556f688dbb71267c422869e77a4149f313) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - `Syntax.parse` allocates less per node: leaves share one empty array of children, and nodes are built from the builder's stack without copying their children off it first (about 3% faster on a JSON document).
|
|
107
|
+
|
|
108
|
+
- [#85](https://github.com/thomasfosterau/effect-parse/pull/85) [`7287ad5`](https://github.com/thomasfosterau/effect-parse/commit/7287ad556f688dbb71267c422869e77a4149f313) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - Compiled `Token.takeTill` of one to three characters, on string input, finds the end of its run with `indexOf` once the run is longer than a few characters, with a per-state cache of where each stop character next occurs. On CSV-shaped input, runs of 64 characters parse about 3× as fast and runs of 256 characters up to 9× (JIT) and 14× (closure compiler); short runs are unchanged or faster. Results are unchanged ([#75](https://github.com/thomasfosterau/effect-parse/issues/75)).
|
|
109
|
+
|
|
110
|
+
- [#85](https://github.com/thomasfosterau/effect-parse/pull/85) [`7287ad5`](https://github.com/thomasfosterau/effect-parse/commit/7287ad556f688dbb71267c422869e77a4149f313) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - `Text.utf8` parsers decode long strings that lie in a run of ASCII bytes by slicing them from the run's text, decoded once per parse, instead of making one `TextDecoder` call per string: a JSON document of ASCII strings parses about 27% faster from bytes.
|
|
111
|
+
|
|
112
|
+
- [#85](https://github.com/thomasfosterau/effect-parse/pull/85) [`7287ad5`](https://github.com/thomasfosterau/effect-parse/commit/7287ad556f688dbb71267c422869e77a4149f313) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - `Text.utf8` builds short strings from bytes eight ASCII bytes at a time, and by hand up to 40 bytes (was 24) before calling `TextDecoder`: JSON with escaped strings parses about 25% faster from bytes, and records about 5%.
|
|
113
|
+
|
|
114
|
+
- [#85](https://github.com/thomasfosterau/effect-parse/pull/85) [`7287ad5`](https://github.com/thomasfosterau/effect-parse/commit/7287ad556f688dbb71267c422869e77a4149f313) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - `Compiler.wasm` scans `Binary`'s fixed-size numbers itself instead of calling out to JavaScript for each one: binary formats parse 3–12× faster with it, level with the JIT.
|
|
115
|
+
|
|
116
|
+
- [#100](https://github.com/thomasfosterau/effect-parse/pull/100) [`93d25ad`](https://github.com/thomasfosterau/effect-parse/commit/93d25add25894e877aa0b07cb13ce93b1d98f06a) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - `Compiler.wasm` vectorises `takeWhile` and `takeTill` on bytes (`Token` and Latin-1 text) with WebAssembly SIMD: sixteen bytes per step, then thirty-two once a run is that long, tested against at most three stop bytes with `i8x16.eq` or against nibble tables with `i8x16.swizzle`; the first byte that does not belong ends the run without a scalar step. A run of 8.5 MB scans about 3.7× as fast (1.6 GB/s to 5.8 GB/s with the copy into WebAssembly memory). Results are unchanged.
|
|
117
|
+
|
|
118
|
+
Where relaxed SIMD validates, the nibble-table lookups (in these runs and in `takeUntil`'s Teddy search) use `i8x16.relaxed_swizzle`, which is exact for their indices and skips `swizzle`'s fix-up for indices from 16 up.
|
|
119
|
+
|
|
120
|
+
- [#100](https://github.com/thomasfosterau/effect-parse/pull/100) [`09da6aa`](https://github.com/thomasfosterau/effect-parse/commit/09da6aa57fde2db66f3d8456ab93145e3992a700) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - `Compiler.wasm` compares a literal many bytes at a time: sixteen with a SIMD `v128` load, then eight, four, two and one with `i64` and `i32` loads (a caseless letter's byte ORed with 0x20 first), instead of one unit at a time. Results are unchanged.
|
|
121
|
+
|
|
122
|
+
## 0.4.1
|
|
123
|
+
|
|
124
|
+
### Patch Changes
|
|
125
|
+
|
|
126
|
+
- [#69](https://github.com/thomasfosterau/effect-parse/pull/69) [`9d72a0f`](https://github.com/thomasfosterau/effect-parse/commit/9d72a0f63efcf1de4b2e29b8ce81eb1d95359544) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - Fixes from type-aware linting. `Parser` now declares the `toString()` it already had (`Parser(<name>)`), and `tryMapUnknown` spells its error type `unknown` rather than the equivalent `E | unknown`. An unexpected token that `JSON.stringify` cannot render (a cycle, a `BigInt`) is now shown as its elements joined (arrays) or its object tag such as `[object Map]`, without calling a user `toString`.
|
|
127
|
+
|
|
128
|
+
## 0.4.0
|
|
129
|
+
|
|
130
|
+
### Minor Changes
|
|
131
|
+
|
|
132
|
+
- [#58](https://github.com/thomasfosterau/effect-parse/pull/58) [`4e8f5fb`](https://github.com/thomasfosterau/effect-parse/commit/4e8f5fb8cc509c263ca7ecfce49e7cab08747d14) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - Breaking: a parser step that moves the cursor backwards (to retry an alternative, or after a lookahead) must call the new `state.rewind(offset)` instead of assigning `state.pos`; moving forward is still an assignment. `Syntax` trees are now built by a separate builder rather than a `State` subclass whose `pos` was an accessor, so every parser sees one state shape. In a program that also builds syntax trees, ordinary interpreted parses no longer slow down by about 20%. Built-in encodings also share one object shape.
|
|
133
|
+
|
|
134
|
+
### Patch Changes
|
|
135
|
+
|
|
136
|
+
- [#55](https://github.com/thomasfosterau/effect-parse/pull/55) [`42e115d`](https://github.com/thomasfosterau/effect-parse/commit/42e115d13d0984ac76bb190e751c6359a03fdf01) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - The closure compiler writes the `Text` `takeWhile` loop once per kind of unit read (string, bytes, UTF-16 bytes), so it keeps inlining its reads in a program that parses more than one input kind or encoding: about 17-20% faster on the JSON benchmark's `Text` grammars.
|
|
137
|
+
|
|
138
|
+
- [#55](https://github.com/thomasfosterau/effect-parse/pull/55) [`d9c3410`](https://github.com/thomasfosterau/effect-parse/commit/d9c341008772f5c0117fe40fdd528c1cca81ed80) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - The closure compiler reads UTF-16 bytes a code unit at a time, as the JIT does, instead of decoding every code point: compiled `Text.utf16le` / `Text.utf16be` parsers run about 1.75× faster on the JSON benchmark when `new Function` is unavailable.
|
|
139
|
+
|
|
140
|
+
- [#57](https://github.com/thomasfosterau/effect-parse/pull/57) [`f1ac841`](https://github.com/thomasfosterau/effect-parse/commit/f1ac84175d7411cfa1fe76cb5f1ada98dc064b0f) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - Streaming parses with a JIT-compiled parser run escapes (`escaped`, `takeEscaped`) as generated code that keeps checkpoints, instead of calling the closure compiler's: about 13% faster on a JSON document, within 5% of an ordinary compiled parse.
|
|
141
|
+
|
|
142
|
+
- [#56](https://github.com/thomasfosterau/effect-parse/pull/56) [`459f8fe`](https://github.com/thomasfosterau/effect-parse/commit/459f8fe12dedad0988ce67b372d46904ebe2706e) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - `ParserStream.parseAll` (and `parseReadable` / `parseResponse`) parse an input that arrives in a single chunk, such as most small response bodies, once instead of twice: the first partial attempt waits for a second chunk, and a stream that ends first is parsed as an ordinary compiled parse. On a 2 MB JSON document in one chunk this takes 60 ms instead of 147 ms.
|
|
143
|
+
|
|
144
|
+
## 0.3.0
|
|
145
|
+
|
|
146
|
+
### Minor Changes
|
|
147
|
+
|
|
148
|
+
- [#41](https://github.com/thomasfosterau/effect-parse/pull/41) [`2a57d83`](https://github.com/thomasfosterau/effect-parse/commit/2a57d836303e8f5453112c8df89cf4ef59f01608) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - Add parsers and printers derived from Effect `Schema`s. `ParserSchema.toParser(schema)` derives a parser from a schema, guided by annotations (`ParserSchema.annotate`, under the key `ParserSchema.annotationKey`) that give a node's `prefix`, `suffix`, `separator`, `keySeparator` and `whitespace`, or a `parser` and `print` that replace the derived ones. Structs, tuples, arrays, records, unions, literals, enums, template literals and recursive schemas are derived; the schema's checks and transformations run on the result. `ParserSchema.toPrinter(schema)` derives the printer of the same text. `ParserSchema.fromSchema(schema)` wraps both as a `Schema` from `string`, whose encoding checks that the text reads back as the value.
|
|
149
|
+
|
|
150
|
+
The annotation key is declared on `Schema.Annotations.Annotations` by module augmentation.
|
|
151
|
+
|
|
152
|
+
### Patch Changes
|
|
153
|
+
|
|
154
|
+
- [#43](https://github.com/thomasfosterau/effect-parse/pull/43) [`6e69d9e`](https://github.com/thomasfosterau/effect-parse/commit/6e69d9ebe6c787430858192ff8eac5e96feb2db6) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - Interpreted `Parser.alt` no longer merges the failures of branches that fail at the same offset until the merged failure is read. A nested `alt` hands its tied failures to the enclosing one unmerged, so an `alt` whose next branch consumes input never pays for the merge: about 30% faster on a token-heavy interpreted grammar. Error results are unchanged. `Input.State`'s `failure` and `deepest` are now accessors (reads and writes behave as before).
|
|
155
|
+
|
|
156
|
+
- [#46](https://github.com/thomasfosterau/effect-parse/pull/46) [`37bd245`](https://github.com/thomasfosterau/effect-parse/commit/37bd245604ea64a0236b844e933e91881c0be072) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - `Parser.permutation` and `Expression.make`'s operator loop no longer merge the failures of attempts that fail at the same offset until the merged failure is read, as `Parser.alt` already does. A round of a permutation in which some parser matches, or an operator round in which some operator matches, discards its tied failures without merging them, and a nested `alt`'s ties are taken over unmerged. Error results are unchanged.
|
|
157
|
+
|
|
158
|
+
## 0.2.0
|
|
159
|
+
|
|
160
|
+
### Minor Changes
|
|
161
|
+
|
|
162
|
+
- [#39](https://github.com/thomasfosterau/effect-parse/pull/39) [`bb8efed`](https://github.com/thomasfosterau/effect-parse/commit/bb8efed7a31c4ca413cb43ba2f51dc66f3cc10fd) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - Add `Parser.run(parser, state)`, which runs a parser on an `Input.State` you own and returns its output or `Fail`, like `parser.step(state)` but using the parser's compiled form when it has one. A lexer that keeps one state and `reset`s it before each token now runs its token parser compiled without allocating a state, a `Result` or a slice per token: about 1.9 times as fast as calling `step` on a reused state, and 15% faster than `parsePartial` with an `offset`. On failure the parser runs again interpreted from the same position, so the state holds the interpreter's failure; partial states run the build that handles partial input. A driver that only needs to know that a parser failed (it tries another, or skips a character) can pass `{ diagnostics: false }` to skip that re-run, keeping just the failure's `mode`: about 2.3 times as fast on a scan where most runs fail.
|
|
163
|
+
|
|
164
|
+
`ParserStream.parseMany` now runs a compiled parser compiled, with one state per buffer, instead of always interpreting it: about 2.8 times as fast on a stream of CSV-like rows.
|
|
165
|
+
|
|
166
|
+
- [#34](https://github.com/thomasfosterau/effect-parse/pull/34) [`53764ff`](https://github.com/thomasfosterau/effect-parse/commit/53764ffd7e612084b113f44c25408835405bcb39) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - **Breaking:** compile parsers with the new `Compiler` module (`@thomasfosterau/effect-parse/Compiler`) instead of `Parser.compile`. `Compiler.jit(p)` replaces `Parser.compile(p)` and `Parser.compile(p, { backend: "auto" })`, and `Compiler.closure(p)` replaces `Parser.compile(p, { backend: "closure" })`. `Parser.compile` and `Parser.CompileOptions` are removed.
|
|
167
|
+
|
|
168
|
+
The two backends are now separate functions, so bundles contain only the compilers a program uses ([#15](https://github.com/thomasfosterau/effect-parse/issues/15)). `Parser` and its runners no longer import a compiler. A program that never compiles a parser no longer bundles about 45 KB of minified compiler code. A program that uses only `Compiler.closure` contains no `new Function`, which Content Security Policy and supply-chain scanners flag even when it never runs.
|
|
169
|
+
|
|
170
|
+
- [#33](https://github.com/thomasfosterau/effect-parse/pull/33) [`737afc1`](https://github.com/thomasfosterau/effect-parse/commit/737afc15b3ff9e6f244cf107ab298a109a250651) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - Add a `while` option to `Parser.fold`, a predicate on the accumulator that stops the repetition, successfully and without consuming more input, once it is false. It is checked before each element once `range.min` elements are folded, and compiles to a loop-condition check, so a fold can stop at "N kept items" instead of scanning the rest of the input ([#16](https://github.com/thomasfosterau/effect-parse/issues/16)).
|
|
171
|
+
|
|
172
|
+
- [#27](https://github.com/thomasfosterau/effect-parse/pull/27) [`b6c5a94`](https://github.com/thomasfosterau/effect-parse/commit/b6c5a9469062bbfe56e963d94cf0b357ce615508) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - Add an `offset` option to every `Parser` runner (`parse`, `parseSync`, `parsePeek`, `parsePartial`, `parseEffect`, `parseRecoverable`), so an incremental driver such as a lexer can parse one token at a time from a buffer without slicing it. The result is that of parsing `input.slice(offset)`, with offsets (`Done`'s `offset`, spans, `ParseError` offsets, lines and columns) counted in the whole input. `parsePartial` now runs compiled parsers compiled, re-running the interpreter only to report `Incomplete` or an error, so a lexer loop over `parsePartial` runs compiled code from any offset ([#19](https://github.com/thomasfosterau/effect-parse/issues/19)).
|
|
173
|
+
|
|
174
|
+
- [#31](https://github.com/thomasfosterau/effect-parse/pull/31) [`3318a75`](https://github.com/thomasfosterau/effect-parse/commit/3318a751673fc3857f5dfd83cc714bf83e3576fe) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - Deeply nested input no longer makes the runners throw `RangeError: Maximum call stack size exceeded`. When a recursive grammar (`Parser.suspend`) exhausts the call stack, interpreted or compiled, `parse`, `parsePeek`, `parsePartial`, `parseEffect`, `parseRecoverable`, `ParserStream.parseMany`, `ParserStream.parseAll` and `Syntax.parse` now fail with an unrecoverable `ParseError` of the new kind `"TooDeep"` at the offset reached, so untrusted input can't crash the caller. `Parser.tryMapUnknown` no longer catches the overflow as a user error ([#14](https://github.com/thomasfosterau/effect-parse/issues/14)).
|
|
175
|
+
|
|
176
|
+
- [#24](https://github.com/thomasfosterau/effect-parse/pull/24) [`da7891e`](https://github.com/thomasfosterau/effect-parse/commit/da7891ee50854c53fa737f1c90776bb0259e156a) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - Add `Input.State.reset(offset, options?)`, which prepares a state for another run over the same input, so that drivers making many small runs over one buffer (one per token, say) don't allocate a new `State` each time. It resets every per-run field, so callers no longer need to know which ones those are. After a reset the state behaves exactly like `new State(state.input, { ...options, offset })`, including after a run that failed or returned `Incomplete` ([#20](https://github.com/thomasfosterau/effect-parse/issues/20)).
|
|
177
|
+
|
|
178
|
+
- [#29](https://github.com/thomasfosterau/effect-parse/pull/29) [`2527c14`](https://github.com/thomasfosterau/effect-parse/commit/2527c1429a8d0e26b46555ad4979fabbe5ae3d1e) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - Add the `Syntax` module: Tree-sitter-style concrete syntax trees and incremental parsing. Mark a grammar's rules with `Syntax.node` (plus `Syntax.token` for anonymous nodes and `Syntax.field` for field names), and `Syntax.parse` returns a tree of nodes with spans, values, parents and siblings, to search by offset (`descendantAt`) or walk with a `TreeCursor`. Recovered and fatal failures become `ERROR` nodes. After an edit, `Syntax.reparse` and `Syntax.replace` parse again, reusing every node whose input is unchanged, and return the same tree a fresh parse would. Outside `Syntax.parse` the annotations change nothing, and compiled parsers compile them away.
|
|
179
|
+
|
|
180
|
+
- [#26](https://github.com/thomasfosterau/effect-parse/pull/26) [`9dba9e3`](https://github.com/thomasfosterau/effect-parse/commit/9dba9e3e066fffc94dc2681226da729621df5b90) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - Add `Token.codePoints(name, predicate, ranges?)`, which declares a character class as a predicate over code points. In token sets on string, `Text` and byte input it receives each character as a number, so testing a character allocates nothing, and with `ranges` compiled parsers test the ranges instead of calling it. Plain `(c: string) => boolean` predicates still receive whole characters, now built with `String.fromCharCode` below U+10000 instead of `String.fromCodePoint`. The README says which token sets are the fast path. Closes [#22](https://github.com/thomasfosterau/effect-parse/issues/22).
|
|
181
|
+
|
|
182
|
+
### Patch Changes
|
|
183
|
+
|
|
184
|
+
- [#39](https://github.com/thomasfosterau/effect-parse/pull/39) [`bb8efed`](https://github.com/thomasfosterau/effect-parse/commit/bb8efed7a31c4ca413cb43ba2f51dc66f3cc10fd) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - The JIT compiles two more shapes of grammar inline. A `Parser.dispatch` with a record of cases and a selector other than `Token.any` or `Parser.peek(Token.any)` now runs the chosen case inline, through a switch on its index, instead of calling its closure-compiled step. On token arrays, `Token.anyToken`, `Token.oneOf`, `Token.noneOf`, `Token.takeWhile` and `Token.takeTill` call their predicate (or membership test) inline instead of running their interpreted steps, which also recorded a failure on every miss: a grammar over 200 K tokens matched with `Token.oneOf(predicate)` runs about 3 times as fast. Results and errors are unchanged. The `Parser.dispatch` docs and the README now say which ways of writing a grammar compile best.
|
|
185
|
+
|
|
186
|
+
- [#36](https://github.com/thomasfosterau/effect-parse/pull/36) [`b54e94e`](https://github.com/thomasfosterau/effect-parse/commit/b54e94e71198be09202ed4e12dea16a5ab780e19) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - `Parser.separated` has its doc comment again: it sat above an internal declaration, so the emitted `.d.ts` and editor hovers showed none.
|
|
187
|
+
|
|
188
|
+
- [#36](https://github.com/thomasfosterau/effect-parse/pull/36) [`b54e94e`](https://github.com/thomasfosterau/effect-parse/commit/b54e94e71198be09202ed4e12dea16a5ab780e19) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - The package is now built with `vp pack` (tsdown) instead of `tsc`. `dist/` keeps the same layout, entry points and runtime exports, and every top-level call stays marked `/*#__PURE__*/`; the declaration files spell some types out where they used to write `typeof Token.take` and the like, and `Parser.Do` is typed `Parser<Record<never, never>, …>` (the same type as `Parser<{}, …>`). The root entry's `index.js` no longer ships a source map.
|
|
189
|
+
|
|
190
|
+
- [#25](https://github.com/thomasfosterau/effect-parse/pull/25) [`9b3ecc0`](https://github.com/thomasfosterau/effect-parse/commit/9b3ecc0ae7653d6652e866ae1e66b4ac411343ec) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - Report a committed (`cut`) failure where it happened. The furthest-failure heuristic no longer replaces it with a deeper failure from a branch or lookahead tried before the commit; failures inside the `cut` parser itself still count. Failures inside a lookahead that succeeded (`peek`, or the parser given to `not`) are no longer reported as the furthest failure either. Ordinary backtracking (`alt`, `opt`, `separated`, ...) reports the same errors as before.
|
|
191
|
+
|
|
192
|
+
- [#28](https://github.com/thomasfosterau/effect-parse/pull/28) [`03313ed`](https://github.com/thomasfosterau/effect-parse/commit/03313ed7ecf11ff0065c29dd43cd27c9bef4ce55) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - Make parsers cheaper to build, for those written inside a `Parser.gen` body, which are rebuilt on every run. Compiled token sets given as strings (`Token.oneOf("+-")`, `Token.takeWhile(" \t")`, ...) and the descriptions of string literals are now cached by value, so building `Token.oneOf("+-")` takes about 30 ns instead of 4 µs, and `Token.literal(",")` about 30 ns instead of 90 ns. Results and error messages are unchanged. The `Parser.gen` docs now show how to hoist parsers out of the body on hot paths.
|
|
193
|
+
|
|
194
|
+
- [#17](https://github.com/thomasfosterau/effect-parse/pull/17) [`ff2e2a5`](https://github.com/thomasfosterau/effect-parse/commit/ff2e2a5efcc964e07cff909dca1c48b88c5dbe03) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - Mark every parser, predicate and table built at module load `/*#__PURE__*/`, so bundlers drop the ones a program doesn't use. Importing only `decInt` from `@thomasfosterau/effect-parse/Ascii` now bundles about 7 KB of effect-parse instead of 24 KB.
|
|
195
|
+
|
|
196
|
+
- [#32](https://github.com/thomasfosterau/effect-parse/pull/32) [`bfad13b`](https://github.com/thomasfosterau/effect-parse/commit/bfad13bf7086175bcd508a7fb94d198314c6c565) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - `Token.takeUntil` and `Text.<encoding>.takeUntil` now stop at `State.end`, like the other token parsers, in interpreted and compiled code. A literal only counts as found when it lies wholly within the input up to `end`, so a parser run over a narrowed region no longer matches past it, returns text from outside it, or leaves `pos` past `end` ([#30](https://github.com/thomasfosterau/effect-parse/issues/30)).
|
|
197
|
+
|
|
198
|
+
## 0.1.0
|
|
199
|
+
|
|
200
|
+
### Minor Changes
|
|
201
|
+
|
|
202
|
+
- [#11](https://github.com/thomasfosterau/effect-parse/pull/11) [`8f77dad`](https://github.com/thomasfosterau/effect-parse/commit/8f77dad2cd9ca1afe000b9dfe8b370b94b06460f) Thanks [@thomasfosterau](https://github.com/thomasfosterau)! - First release of `@thomasfosterau/effect-parse` (developed as `effect-nom`): parser combinators for Effect, ported from Rust's nom and winnow. Text, byte, bit and token-stream input; `Backtrack` / `Cut` / `Incomplete` error modes; streaming input through `ParserStream`; compiled parsers through `Parser.compile`; `Schema` integration through `ParserSchema`; and `ParseError` diagnostics with line and column. Requires `effect` 4.x as a peer.
|
package/README.md
CHANGED
|
@@ -321,6 +321,8 @@ while parsing array
|
|
|
321
321
|
expected value, found ","
|
|
322
322
|
```
|
|
323
323
|
|
|
324
|
+
An error is safe to log. It keeps the input (`error.input`, which `position` and `message` read, and which stays alive as long as the error does), but not as one of its own properties, and `toJSON` leaves it out: `JSON.stringify(error)`, Effect's `Cause` rendering and structured loggers write the offset, position, kind, expectations and message, not what was being parsed. The message shows at most 60 characters on each side of the failure (`…` marks the rest), so a failure in a 5 MB line of minified JSON is still a four-line message.
|
|
325
|
+
|
|
324
326
|
effect-parse tries hard to produce good messages without annotations:
|
|
325
327
|
|
|
326
328
|
- `alt` merges the expectations of failed branches: `expected "true", "false" or "null"`.
|
|
@@ -385,6 +387,21 @@ const value = await Effect.runPromise(ParserStream.parseResponse(await fetch(url
|
|
|
385
387
|
|
|
386
388
|
The result, and any error, is the same as parsing the whole body at once. Compiled parsers stream compiled. With the JSON example on a 2 MB document, `parseResponse` returns about 1 ms after the last byte at 10 MB/s, and keeps pace with `Response.json()` at 25 MB/s; on faster connections the native parser is quicker (`vp run bench:stream`).
|
|
387
389
|
|
|
390
|
+
### Untrusted streams
|
|
391
|
+
|
|
392
|
+
Every stream runner bounds what it buffers. `maxBufferSize` (in tokens: UTF-16 code units, bytes or array elements) defaults to 64 MiB (`ParserStream.defaultMaxBufferSize`) on `parseMany`, `parseAll`, `parseReadable` and `parseResponse`; a stream that exceeds it fails with a `ParserStream.BufferLimitError` (`limit`, `size`), a different tagged error from `ParseError`, so "too large" and "malformed" can be answered differently:
|
|
393
|
+
|
|
394
|
+
```ts
|
|
395
|
+
import { Effect } from "effect"
|
|
396
|
+
import { ParserStream } from "@thomasfosterau/effect-parse"
|
|
397
|
+
|
|
398
|
+
const body = ParserStream.parseResponse(await fetch(url), json, { maxBufferSize: 8 * 1024 * 1024 }).pipe(
|
|
399
|
+
Effect.catchTag("BufferLimitError", (e) => Effect.fail(`payload too large: ${e.size} > ${e.limit} bytes`))
|
|
400
|
+
)
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
`parseMany` counts the input it has not consumed yet (one unfinished value, so a missing delimiter is caught); the other three hold the whole input and count all of it, and `parseResponse` fails before reading the body when `Content-Length` is already over the limit. Pass `Infinity` to turn the limit off for input you trust.
|
|
404
|
+
|
|
388
405
|
## Services
|
|
389
406
|
|
|
390
407
|
Parsers can require Effect services. These replace winnow's `Stateful` input: configuration, symbol tables, indentation stacks and so on.
|
|
@@ -603,6 +620,7 @@ The `Nom` module provides the nom names directly, with nom's argument orders, fo
|
|
|
603
620
|
- [`json.ts`](examples/json.ts): JSON with `dispatch`, `cut` and escapes
|
|
604
621
|
- [`json-text.ts`](examples/json-text.ts): the same grammar written once against `Text.TextParsers`, for strings, UTF-8 and UTF-16
|
|
605
622
|
- [`json-fast.ts`](examples/json-fast.ts): the same grammar written for compiled parsers, with `Parser.fromEntries`
|
|
623
|
+
- [`json-tape.ts`](examples/json-tape.ts): the same grammar building no values at all: it appends 16-byte records to memory from [effect-ext](https://github.com/thomasfosterau/effect-ext)'s `Allocator`, and strings are read as views of the input's bytes. On UTF-8 input it parses about 1.4 times as fast as `TextDecoder` and `JSON.parse`, and leaves no garbage ([DESIGN.md](docs/DESIGN.md#zero-copy-output))
|
|
606
624
|
- [`arithmetic.ts`](examples/arithmetic.ts): direct evaluation, an AST via the Pratt parser, and a lexer plus a parser over the token array
|
|
607
625
|
- [`ini.ts`](examples/ini.ts): INI files with a generator-style parser
|
|
608
626
|
- [`http.ts`](examples/http.ts): HTTP requests over bytes, complete and streamed
|
|
@@ -630,7 +648,7 @@ vp run check:dist # check dist/ as a consumer imports it
|
|
|
630
648
|
vp run bench # JSON example: interpreted vs compiled, per encoding
|
|
631
649
|
```
|
|
632
650
|
|
|
633
|
-
The other benchmarks (`bench:native`, `bench:stream`, `bench:gen`, `bench:syntax`) and single checks are listed in [CONTRIBUTING.md](CONTRIBUTING.md). Repository conventions are in [AGENTS.md](AGENTS.md), the release pipeline in [PUBLISHING.md](PUBLISHING.md) and the vulnerability-reporting policy in [SECURITY.md](SECURITY.md).
|
|
651
|
+
The other benchmarks (`bench:native`, `bench:stream`, `bench:gen`, `bench:syntax`, `bench:downstream`, which times the libraries built on this package, and `bench:zero-copy`) and single checks are listed in [CONTRIBUTING.md](CONTRIBUTING.md). Repository conventions are in [AGENTS.md](AGENTS.md), the release pipeline in [PUBLISHING.md](PUBLISHING.md) and the vulnerability-reporting policy in [SECURITY.md](SECURITY.md).
|
|
634
652
|
|
|
635
653
|
## License
|
|
636
654
|
|
package/dist/Ascii.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Ascii.d.ts","names":[],"sources":["../src/Ascii.ts"],"mappings":";;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"Ascii.d.ts","names":[],"sources":["../src/Ascii.ts"],"mappings":"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"}
|
package/dist/Ascii.js
CHANGED
|
@@ -4,6 +4,7 @@ import { Fail } from "./Input.js";
|
|
|
4
4
|
import * as P from "./Parser.js";
|
|
5
5
|
import * as numbers from "./internal/numbers.js";
|
|
6
6
|
import { Key } from "./internal/key.js";
|
|
7
|
+
import { controlCode } from "./internal/node.js";
|
|
7
8
|
import * as Resume from "./internal/resume.js";
|
|
8
9
|
import { codePointPredicate } from "./internal/tokens.js";
|
|
9
10
|
import * as Token$1 from "./Token.js";
|
|
@@ -372,7 +373,8 @@ const float = /*#__PURE__*/ floatText$1.pipe(/*#__PURE__*/ P.map(toFloat), /*#__
|
|
|
372
373
|
* @category literals
|
|
373
374
|
*/
|
|
374
375
|
const caseless = (lit) => literalImpl(lit, true);
|
|
375
|
-
|
|
376
|
+
/** The first UTF-16 unit of a control character: what `atControl` compares with a string's units. */
|
|
377
|
+
const firstUnit = (s) => s.charCodeAt(0);
|
|
376
378
|
const atControl = (state, control) => {
|
|
377
379
|
if (state.pos >= state.end) return false;
|
|
378
380
|
const input = state.input;
|
|
@@ -398,7 +400,7 @@ const atControl = (state, control) => {
|
|
|
398
400
|
* @category escapes
|
|
399
401
|
*/
|
|
400
402
|
const takeEscaped = (normal, control, escapable) => {
|
|
401
|
-
const ctrl = controlCode(control);
|
|
403
|
+
const ctrl = controlCode(control, firstUnit);
|
|
402
404
|
return takeEscapedImpl(normal, (state) => {
|
|
403
405
|
if (!atControl(state, ctrl)) return false;
|
|
404
406
|
state.pos++;
|
|
@@ -489,7 +491,7 @@ const takeEscapedImpl = (normal, matchControl, escapable, slice, control, encodi
|
|
|
489
491
|
* @category escapes
|
|
490
492
|
*/
|
|
491
493
|
const escaped = (normal, control, escape) => {
|
|
492
|
-
const ctrl = controlCode(control);
|
|
494
|
+
const ctrl = controlCode(control, firstUnit);
|
|
493
495
|
return escapedImpl(normal, (state) => {
|
|
494
496
|
if (!atControl(state, ctrl)) return false;
|
|
495
497
|
state.pos++;
|
package/dist/Ascii.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Ascii.js","names":["floatText","Token"],"sources":["../src/Ascii.ts"],"sourcesContent":["/**\n * Parsers for ASCII text: character classes, line endings, numbers and\n * escaped strings (winnow's `ascii` module, nom's `character` module).\n *\n * The parsers are typed for `string` input. Each also works on\n * `Uint8Array` input (treating bytes as ASCII), and `Ascii.bytes` gives the\n * same parsers typed for bytes:\n *\n * ```ts\n * import { Ascii, Parser } from \"@thomasfosterau/effect-parse\"\n *\n * Parser.parse(Ascii.decUint, \"42\") // 42\n * Parser.parse(Ascii.bytes.decUint, new TextEncoder().encode(\"42\")) // 42\n * ```\n *\n * Partial (streaming) input is supported: for example `digit1` on the\n * partial input `\"123\"` reports `Incomplete`, since more digits may follow.\n *\n * For Unicode character classes, or for text in other encodings (UTF-8,\n * UTF-16), use the `Text` module.\n *\n * @since 0.1.0\n */\nimport * as Predicate from \"effect/Predicate\"\nimport * as Result from \"effect/Result\"\nimport type { Encoding } from \"./Encoding.js\"\nimport type { Input, Slice, State } from \"./Input.js\"\nimport { Fail } from \"./Input.js\"\nimport type { ErrorKind } from \"./ParseError.js\"\nimport type { Parser } from \"./Parser.js\"\nimport * as P from \"./Parser.js\"\nimport * as numbers from \"./internal/numbers.js\"\nimport { Key } from \"./internal/key.js\"\nimport * as Resume from \"./internal/resume.js\"\nimport { codePointPredicate } from \"./internal/tokens.js\"\nimport { literalImpl, range, takeWhileImpl } from \"./Token.js\"\nimport * as Token from \"./Token.js\"\n\n// -----------------------------------------------------------------------------\n// Character predicates\n// -----------------------------------------------------------------------------\n\nconst code = (c: string | number): number => (Predicate.isNumber(c) ? c : c.charCodeAt(0))\n\n/**\n * `[a-zA-Z]`\n *\n * @since 0.1.0\n * @category predicates\n */\nexport const isAlpha: (c: string | number) => boolean = /*#__PURE__*/ codePointPredicate(\n \"isAlpha\",\n (c: string | number): boolean => {\n const x = code(c)\n return (x >= 65 && x <= 90) || (x >= 97 && x <= 122)\n },\n [\n [65, 90],\n [97, 122]\n ]\n)\n\n/**\n * `[0-9]`\n *\n * @since 0.1.0\n * @category predicates\n */\nexport const isDigit: (c: string | number) => boolean = /*#__PURE__*/ codePointPredicate(\n \"isDigit\",\n (c: string | number): boolean => {\n const x = code(c)\n return x >= 48 && x <= 57\n },\n [[48, 57]]\n)\n\n/**\n * `[0-9a-fA-F]`\n *\n * @since 0.1.0\n * @category predicates\n */\nexport const isHexDigit: (c: string | number) => boolean = /*#__PURE__*/ codePointPredicate(\n \"isHexDigit\",\n (c: string | number): boolean => {\n const x = code(c)\n return (x >= 48 && x <= 57) || (x >= 65 && x <= 70) || (x >= 97 && x <= 102)\n },\n [\n [48, 57],\n [65, 70],\n [97, 102]\n ]\n)\n\n/**\n * `[0-7]`\n *\n * @since 0.1.0\n * @category predicates\n */\nexport const isOctDigit: (c: string | number) => boolean = /*#__PURE__*/ codePointPredicate(\n \"isOctDigit\",\n (c: string | number): boolean => {\n const x = code(c)\n return x >= 48 && x <= 55\n },\n [[48, 55]]\n)\n\n/**\n * `[0-9a-zA-Z]`\n *\n * @since 0.1.0\n * @category predicates\n */\nexport const isAlphanumeric: (c: string | number) => boolean = /*#__PURE__*/ codePointPredicate(\n \"isAlphanumeric\",\n (c: string | number): boolean => isAlpha(c) || isDigit(c),\n [\n [48, 57],\n [65, 90],\n [97, 122]\n ]\n)\n\n/**\n * `[ \\t]`\n *\n * @since 0.1.0\n * @category predicates\n */\nexport const isSpace: (c: string | number) => boolean = /*#__PURE__*/ codePointPredicate(\n \"isSpace\",\n (c: string | number): boolean => {\n const x = code(c)\n return x === 32 || x === 9\n },\n [\n [9, 9],\n [32, 32]\n ]\n)\n\n/**\n * `[ \\t\\r\\n]`\n *\n * @since 0.1.0\n * @category predicates\n */\nexport const isMultispace: (c: string | number) => boolean = /*#__PURE__*/ codePointPredicate(\n \"isMultispace\",\n (c: string | number): boolean => {\n const x = code(c)\n return x === 32 || x === 9 || x === 10 || x === 13\n },\n [\n [9, 10],\n [13, 13],\n [32, 32]\n ]\n)\n\n/**\n * `\\n`\n *\n * @since 0.1.0\n * @category predicates\n */\nexport const isNewline: (c: string | number) => boolean = /*#__PURE__*/ codePointPredicate(\n \"isNewline\",\n (c: string | number): boolean => code(c) === 10,\n [[10, 10]]\n)\n\n// Token sets usable for both string and byte input\nconst alphaSet = [/*#__PURE__*/ range(\"a\", \"z\"), /*#__PURE__*/ range(\"A\", \"Z\")]\nconst digitSet = /*#__PURE__*/ range(\"0\", \"9\")\nconst hexSet = [/*#__PURE__*/ range(\"0\", \"9\"), /*#__PURE__*/ range(\"a\", \"f\"), /*#__PURE__*/ range(\"A\", \"F\")]\nconst octSet = /*#__PURE__*/ range(\"0\", \"7\")\nconst alnumSet = [/*#__PURE__*/ range(\"a\", \"z\"), /*#__PURE__*/ range(\"A\", \"Z\"), /*#__PURE__*/ range(\"0\", \"9\")]\nconst spaceSet = \" \\t\"\nconst multispaceSet = \" \\t\\r\\n\"\n\nconst cls = (\n set: Token.StringTokenSet,\n min: 0 | 1,\n description: string,\n kind: ErrorKind,\n hint = true\n): Parser<string> => takeWhileImpl<string>(set, { min }, false, `${kind.toLowerCase()}${min}`, description, kind, hint)\n\n// -----------------------------------------------------------------------------\n// Character classes\n// -----------------------------------------------------------------------------\n\n/**\n * Zero or more ASCII letters, `[a-zA-Z]*`.\n *\n * @since 0.1.0\n * @category character classes\n */\nexport const alpha0: Parser<string> = /*#__PURE__*/ cls(alphaSet, 0, \"letter\", \"Alpha\")\n\n/**\n * One or more ASCII letters, `[a-zA-Z]+`.\n *\n * @since 0.1.0\n * @category character classes\n */\nexport const alpha1: Parser<string> = /*#__PURE__*/ cls(alphaSet, 1, \"letter\", \"Alpha\")\n\n/**\n * Zero or more ASCII digits, `[0-9]*`.\n *\n * @since 0.1.0\n * @category character classes\n */\nexport const digit0: Parser<string> = /*#__PURE__*/ cls(digitSet, 0, \"digit\", \"Digit\")\n\n/**\n * One or more ASCII digits, `[0-9]+`.\n *\n * @since 0.1.0\n * @category character classes\n */\nexport const digit1: Parser<string> = /*#__PURE__*/ cls(digitSet, 1, \"digit\", \"Digit\")\n\n/**\n * Zero or more hexadecimal digits, `[0-9a-fA-F]*`.\n *\n * @since 0.1.0\n * @category character classes\n */\nexport const hexDigit0: Parser<string> = /*#__PURE__*/ cls(hexSet, 0, \"hexadecimal digit\", \"HexDigit\")\n\n/**\n * One or more hexadecimal digits, `[0-9a-fA-F]+`.\n *\n * @since 0.1.0\n * @category character classes\n */\nexport const hexDigit1: Parser<string> = /*#__PURE__*/ cls(hexSet, 1, \"hexadecimal digit\", \"HexDigit\")\n\n/**\n * Zero or more octal digits, `[0-7]*`.\n *\n * @since 0.1.0\n * @category character classes\n */\nexport const octDigit0: Parser<string> = /*#__PURE__*/ cls(octSet, 0, \"octal digit\", \"OctDigit\")\n\n/**\n * One or more octal digits, `[0-7]+`.\n *\n * @since 0.1.0\n * @category character classes\n */\nexport const octDigit1: Parser<string> = /*#__PURE__*/ cls(octSet, 1, \"octal digit\", \"OctDigit\")\n\n/**\n * Zero or more ASCII letters or digits, `[0-9a-zA-Z]*`.\n *\n * @since 0.1.0\n * @category character classes\n */\nexport const alphanumeric0: Parser<string> = /*#__PURE__*/ cls(alnumSet, 0, \"letter or digit\", \"AlphaNumeric\")\n\n/**\n * One or more ASCII letters or digits, `[0-9a-zA-Z]+`.\n *\n * @since 0.1.0\n * @category character classes\n */\nexport const alphanumeric1: Parser<string> = /*#__PURE__*/ cls(alnumSet, 1, \"letter or digit\", \"AlphaNumeric\")\n\n/**\n * Zero or more spaces and tabs, `[ \\t]*`.\n *\n * @since 0.1.0\n * @category character classes\n */\nexport const space0: Parser<string> = /*#__PURE__*/ cls(spaceSet, 0, \"space\", \"Space\", false)\n\n/**\n * One or more spaces and tabs, `[ \\t]+`.\n *\n * @since 0.1.0\n * @category character classes\n */\nexport const space1: Parser<string> = /*#__PURE__*/ cls(spaceSet, 1, \"space\", \"Space\", false)\n\n/**\n * Zero or more spaces, tabs, carriage returns and line feeds,\n * `[ \\t\\r\\n]*`.\n *\n * @since 0.1.0\n * @category character classes\n */\nexport const multispace0: Parser<string> = /*#__PURE__*/ cls(multispaceSet, 0, \"whitespace\", \"MultiSpace\", false)\n\n/**\n * One or more spaces, tabs, carriage returns and line feeds,\n * `[ \\t\\r\\n]+`.\n *\n * @since 0.1.0\n * @category character classes\n */\nexport const multispace1: Parser<string> = /*#__PURE__*/ cls(multispaceSet, 1, \"whitespace\", \"MultiSpace\", false)\n\n// -----------------------------------------------------------------------------\n// Line endings\n// -----------------------------------------------------------------------------\n\n/**\n * A carriage return followed by a line feed, `\\r\\n`.\n *\n * @since 0.1.0\n * @category line endings\n */\nexport const crlf: Parser<\"\\r\\n\"> = /*#__PURE__*/ Token.literal(\"\\r\\n\")\n\n/**\n * A line feed, `\\n` (nom's `newline`).\n *\n * @since 0.1.0\n * @category line endings\n */\nexport const newline: Parser<\"\\n\"> = /*#__PURE__*/ Token.literal(\"\\n\")\n\n/**\n * A tab, `\\t`.\n *\n * @since 0.1.0\n * @category line endings\n */\nexport const tab: Parser<\"\\t\"> = /*#__PURE__*/ Token.literal(\"\\t\")\n\n/**\n * A line ending: `\\n` or `\\r\\n`.\n *\n * @since 0.1.0\n * @category line endings\n */\nexport const lineEnding: Parser<\"\\n\" | \"\\r\\n\"> = /*#__PURE__*/ P.alt(newline, crlf).pipe(\n /*#__PURE__*/ P.expected(\"line ending\")\n)\n\nconst expectedLineEnding = [\"line ending\"]\n\n/**\n * Everything up to (not including) a line ending, `[^\\r\\n]*` (winnow's\n * `till_line_ending`, nom's `not_line_ending`). A carriage return that is\n * not followed by a line feed is an error.\n *\n * @since 0.1.0\n * @category line endings\n */\nexport const tillLineEnding: Parser<string> = /*#__PURE__*/ P.described<string>(\n (state: State<any>) => {\n const start = state.pos\n const input = state.input\n const isString = state.inputKind === 0\n let i = start\n while (i < state.end) {\n // SAFETY: `Ascii` parsers run on strings or `Uint8Array`s, and `isString` is `inputKind === 0`, set only for a string\n const c = isString ? (input as string).charCodeAt(i) : (input as Uint8Array)[i]\n if (c === 10) break\n if (c === 13) {\n // The line feed after it is read, not consumed\n state.syntax?.read(i + 2)\n if (i + 1 >= state.end) {\n if (state.partial) return state.incomplete(1, expectedLineEnding)\n return state.backtrack(\"LineEnding\", expectedLineEnding, i)\n }\n // SAFETY: `Ascii` parsers run on strings or `Uint8Array`s, and `isString` is `inputKind === 0`, set only for a string\n const d = isString ? (input as string).charCodeAt(i + 1) : (input as Uint8Array)[i + 1]\n if (d === 10) break\n return state.backtrack(\"LineEnding\", expectedLineEnding, i)\n }\n i++\n }\n if (i >= state.end && state.partial) return state.incomplete(1, expectedLineEnding)\n state.pos = i\n // SAFETY: on string input, the input type of a `Parser<string>`, the slice is a string (`bytes` retypes it for bytes)\n return state.slice(start, i) as string\n },\n \"tillLineEnding\",\n { _tag: \"TillLineEnding\", encoding: undefined }\n)\n\n// -----------------------------------------------------------------------------\n// Numbers\n// -----------------------------------------------------------------------------\n\n/** @internal */\nexport const overflow = (value: number): Result.Result<number, string> =>\n Number.isSafeInteger(value) ? Result.succeed(value) : Result.fail(\"integer overflow\")\n\n/**\n * An unsigned decimal integer: one or more digits (winnow's `dec_uint`,\n * nom's `u32`/`u64`). Fails if the value is not a safe integer.\n *\n * @since 0.1.0\n * @category numbers\n */\nexport const decUint: Parser<number, string> = /*#__PURE__*/ digit1.pipe(\n /*#__PURE__*/ P.tryMap((s) => overflow(Number(numbers.toText(s)))),\n /*#__PURE__*/ P.named(\"decUint\")\n)\n\n/**\n * A signed decimal integer: an optional `+` or `-` followed by one or more\n * digits (winnow's `dec_int`, nom's `i32`/`i64`). Fails if the value is not\n * a safe integer.\n *\n * @since 0.1.0\n * @category numbers\n */\nexport const decInt: Parser<number, string> = /*#__PURE__*/ P.taken(\n /*#__PURE__*/ P.seq(/*#__PURE__*/ P.opt(/*#__PURE__*/ Token.oneOf(\"+-\")), digit1)\n).pipe(\n /*#__PURE__*/ P.tryMap((s) => overflow(Number(numbers.toText(s)))),\n /*#__PURE__*/ P.named(\"decInt\")\n)\n\n/**\n * An unsigned decimal integer as a `bigint`, of any size.\n *\n * @since 0.1.0\n * @category numbers\n */\nexport const decBigUint: Parser<bigint> = /*#__PURE__*/ digit1.pipe(\n /*#__PURE__*/ P.map((s) => BigInt(numbers.toText(s)))\n)\n\n/**\n * A signed decimal integer as a `bigint`, of any size.\n *\n * @since 0.1.0\n * @category numbers\n */\nexport const decBigInt: Parser<bigint> = /*#__PURE__*/ P.taken(\n /*#__PURE__*/ P.seq(/*#__PURE__*/ P.opt(/*#__PURE__*/ Token.oneOf(\"+-\")), digit1)\n).pipe(\n /*#__PURE__*/ P.map((s) => {\n const t = numbers.toText(s)\n return BigInt(t.startsWith(\"+\") ? t.slice(1) : t)\n })\n)\n\n/**\n * A hexadecimal unsigned integer, without prefix (winnow's `hex_uint`, nom's\n * `hex_u32`). Fails if the value is not a safe integer.\n *\n * @since 0.1.0\n * @category numbers\n */\nexport const hexUint: Parser<number, string> = /*#__PURE__*/ hexDigit1.pipe(\n /*#__PURE__*/ P.tryMap((s) => overflow(parseInt(numbers.toText(s), 16))),\n /*#__PURE__*/ P.named(\"hexUint\")\n)\n\nconst sign = /*#__PURE__*/ P.opt(/*#__PURE__*/ Token.oneOf(\"+-\"))\nconst exponent = /*#__PURE__*/ P.opt(/*#__PURE__*/ P.seq(/*#__PURE__*/ Token.oneOf(\"eE\"), sign, digit1))\nconst unsignedFloat = /*#__PURE__*/ P.alt(\n /*#__PURE__*/ P.seq(\n /*#__PURE__*/ literalImpl(\"inf\", true),\n /*#__PURE__*/ P.opt(/*#__PURE__*/ literalImpl(\"inity\", true))\n ),\n /*#__PURE__*/ P.seq(/*#__PURE__*/ Token.literal(\".\"), digit1, exponent),\n /*#__PURE__*/ P.seq(\n digit1,\n /*#__PURE__*/ P.opt(/*#__PURE__*/ P.seq(/*#__PURE__*/ Token.literal(\".\"), /*#__PURE__*/ P.opt(digit1))),\n exponent\n )\n)\nconst floatText = /*#__PURE__*/ numbers.floatText(\n /*#__PURE__*/ P.taken(\n /*#__PURE__*/ P.alt(/*#__PURE__*/ literalImpl(\"nan\", true), /*#__PURE__*/ P.seq(sign, unsignedFloat))\n ).pipe(/*#__PURE__*/ P.expected(\"number\"))\n)\n\n/** @internal */\nexport const toFloat: (s: Input) => number = numbers.toFloat\n\n/**\n * A floating point number in decimal or scientific notation, including\n * `inf`, `infinity` and `nan` (case insensitive), as accepted by winnow's\n * `float` and nom's `double`.\n *\n * @example\n * ```ts\n * import { Ascii, Parser } from \"@thomasfosterau/effect-parse\"\n *\n * Parser.parse(Ascii.float, \"-1.5e3\") // Result.succeed(-1500)\n * ```\n *\n * @since 0.1.0\n * @category numbers\n */\nexport const float: Parser<number> = /*#__PURE__*/ floatText.pipe(\n /*#__PURE__*/ P.map(toFloat),\n /*#__PURE__*/ P.named(\"float\")\n)\n\n// -----------------------------------------------------------------------------\n// Literals\n// -----------------------------------------------------------------------------\n\n/**\n * The overloads of {@link caseless}.\n *\n * @since 0.5.0\n * @category literals\n */\nexport interface CaselessFn {\n (literal: string): Parser<string>\n (literal: Uint8Array): Parser<Uint8Array, never, never, Uint8Array>\n}\n\n/**\n * Matches a literal ignoring ASCII case (winnow's `Caseless`, nom's\n * `tag_no_case`). Returns the input as written.\n *\n * @since 0.1.0\n * @category literals\n */\nexport const caseless: CaselessFn = (lit: string | Uint8Array): any => literalImpl(lit, true)\n\n// -----------------------------------------------------------------------------\n// Escapes\n// -----------------------------------------------------------------------------\n\nconst controlCode = (c: string | number): number => (Predicate.isNumber(c) ? c : c.charCodeAt(0))\n\nconst atControl = (state: State<Input>, control: number): boolean => {\n if (state.pos >= state.end) return false\n const input = state.input\n // SAFETY: escapes are read from strings or `Uint8Array`s, and `inputKind` 0 is set only for a string\n const c = state.inputKind === 0 ? (input as string).charCodeAt(state.pos) : (input as Uint8Array)[state.pos]\n return c === control\n}\n\n/**\n * Recognizes a string containing escape sequences, returning the raw slice\n * (winnow's `take_escaped`, nom's `escaped`).\n *\n * - `normal` matches runs of ordinary characters (it must consume input)\n * - `control` is the escape character, e.g. `\"\\\\\"`\n * - `escapable` matches what may follow the control character\n *\n * @example\n * ```ts\n * import { Ascii, Parser, Token } from \"@thomasfosterau/effect-parse\"\n *\n * const raw = Ascii.takeEscaped(Ascii.alpha1, \"\\\\\", Token.oneOf(\"\\\"n\\\\\"))\n * Parser.parse(raw, \"ab\\\\\\\"cd\") // Result.succeed(\"ab\\\\\\\"cd\")\n * ```\n *\n * @since 0.1.0\n * @category escapes\n */\nexport const takeEscaped = <A, E, R, I extends Input, B, E2, R2, I2 extends Input>(\n normal: Parser<A, E, R, I>,\n control: string | number,\n escapable: Parser<B, E2, R2, I2>\n): Parser<Slice<I & I2>, E | E2, R | R2, I & I2> => {\n const ctrl = controlCode(control)\n return takeEscapedImpl(\n normal,\n (state) => {\n if (!atControl(state, ctrl)) return false\n state.pos++\n return true\n },\n escapable,\n // SAFETY: the parser runs on input of type `I & I2`, and `State.slice` returns that input's own slice type\n (state, start) => state.slice(start, state.pos) as Slice<I & I2>,\n ctrl,\n undefined\n )\n}\n\nconst isIncomplete = (state: State<any>): boolean => state.mode === \"Incomplete\"\n\n/**\n * Fails with the current (`Incomplete`) failure, recording a checkpoint\n * first in a streaming parse.\n */\nconst suspendAt = (state: State<any>, key: Key, start: number, checkpoint: unknown): Fail => {\n if (state.resume !== undefined) Resume.save(state, key, start, checkpoint)\n return Fail\n}\n\n/** @internal */\nexport const takeEscapedImpl = <A, E, R, I extends Input, B, E2, R2, I2 extends Input, S>(\n normal: Parser<A, E, R, I>,\n matchControl: (state: State<any>) => boolean,\n escapable: Parser<B, E2, R2, I2>,\n slice: (state: State<any>, start: number) => S,\n control: number,\n encoding: Encoding<any> | undefined\n): Parser<S, E | E2, R | R2, I & I2> => {\n const normalStep = normal.step\n const escStep = escapable.step\n const key = new Key()\n return P.described(\n (state: State<any>) => {\n const start = state.pos\n let resumed = false\n if (state.resume !== undefined) {\n // SAFETY: under its own `key`, this parser saves only a resume offset (`suspendAt`) or a `Done`\n const checkpoint = Resume.take(state, key, start) as number | Resume.Done | undefined\n if (checkpoint instanceof Resume.Done) {\n state.pos = checkpoint.pos\n // SAFETY: a `Done` saved under this parser's `key` holds the `S` it returned\n return checkpoint.value as S\n }\n if (checkpoint !== undefined) {\n state.pos = checkpoint\n resumed = true\n }\n }\n while (state.pos < state.end) {\n const before = state.pos\n const a = normalStep(state)\n if (a !== Fail) {\n if (state.pos === before)\n return state.failMessage(\"Cut\", \"Assert\", \"`takeEscaped` parsers must always consume\")\n continue\n }\n if (state.mode === \"Incomplete\") return suspendAt(state, key, start, before)\n if (state.mode !== \"Backtrack\") return Fail\n state.rewind(before)\n if (matchControl(state)) {\n if (escStep(state) === Fail) return isIncomplete(state) ? suspendAt(state, key, start, before) : Fail\n } else {\n return Resume.done(state, key, start, resumed, slice(state, start))\n }\n }\n if (state.partial) {\n state.incomplete(0)\n return suspendAt(state, key, start, state.pos)\n }\n return Resume.done(state, key, start, resumed, slice(state, start))\n },\n \"takeEscaped\",\n { _tag: \"Escaped\", normal, control, escape: escapable, raw: true, encoding }\n )\n}\n\n/**\n * Parses a string containing escape sequences, returning the *unescaped*\n * string (winnow's `escaped`, nom's `escaped_transform`).\n *\n * - `normal` matches runs of ordinary characters, returning them\n * - `control` is the escape character, e.g. `\"\\\\\"`\n * - `escape` parses what follows the control character, returning its\n * replacement\n *\n * @example\n * ```ts\n * import { Ascii, Parser, Token } from \"@thomasfosterau/effect-parse\"\n *\n * const unescaped = Ascii.escaped(\n * Token.takeTill(\"\\\\\\\"\"),\n * \"\\\\\",\n * Parser.alt(\n * Token.literal(\"n\").pipe(Parser.as(\"\\n\")),\n * Token.literal(\"\\\\\"),\n * Token.literal(\"\\\"\")\n * )\n * )\n * Parser.parse(unescaped, \"a\\\\nb\") // Result.succeed(\"a\\nb\")\n * ```\n *\n * @since 0.1.0\n * @category escapes\n */\nexport const escaped = <E, R, I extends Input, E2, R2, I2 extends Input>(\n normal: Parser<string, E, R, I>,\n control: string | number,\n escape: Parser<string, E2, R2, I2>\n): Parser<string, E | E2, R | R2, I & I2> => {\n const ctrl = controlCode(control)\n return escapedImpl(\n normal,\n (state) => {\n if (!atControl(state, ctrl)) return false\n state.pos++\n return true\n },\n escape,\n ctrl,\n undefined\n )\n}\n\n/** How far `escaped` got: the text so far, and where to carry on. */\ninterface EscapedCheckpoint {\n readonly out: string\n readonly pos: number\n}\n\n/** @internal */\nexport const escapedImpl = <E, R, I extends Input, E2, R2, I2 extends Input>(\n normal: Parser<string, E, R, I>,\n matchControl: (state: State<any>) => boolean,\n escape: Parser<string, E2, R2, I2>,\n control: number,\n encoding: Encoding<any> | undefined\n): Parser<string, E | E2, R | R2, I & I2> => {\n const normalStep = normal.step\n const escStep = escape.step\n const key = new Key()\n return P.described(\n (state: State<any>) => {\n const start = state.pos\n let out = \"\"\n let resumed = false\n if (state.resume !== undefined) {\n // SAFETY: under its own `key`, this parser saves only an `EscapedCheckpoint` (`suspendAt`) or a `Done`\n const checkpoint = Resume.take(state, key, start) as EscapedCheckpoint | Resume.Done | undefined\n if (checkpoint instanceof Resume.Done) {\n state.pos = checkpoint.pos\n // SAFETY: a `Done` saved under this parser's `key` holds the string it returned\n return checkpoint.value as string\n }\n if (checkpoint !== undefined) {\n out = checkpoint.out\n state.pos = checkpoint.pos\n resumed = true\n }\n }\n while (state.pos < state.end) {\n const before = state.pos\n const a = normalStep(state)\n if (a !== Fail) {\n if (state.pos !== before) {\n out += a\n continue\n }\n // `normal` matched nothing: fall through to the control character\n } else {\n if (state.mode === \"Incomplete\") return suspendAt(state, key, start, { out, pos: before })\n if (state.mode !== \"Backtrack\") return Fail\n state.rewind(before)\n }\n if (matchControl(state)) {\n const b = escStep(state)\n if (b === Fail) return isIncomplete(state) ? suspendAt(state, key, start, { out, pos: before }) : Fail\n out += b\n } else {\n return Resume.done(state, key, start, resumed, out)\n }\n }\n if (state.partial) {\n state.incomplete(0)\n return suspendAt(state, key, start, { out, pos: state.pos })\n }\n return Resume.done(state, key, start, resumed, out)\n },\n \"escaped\",\n { _tag: \"Escaped\", normal, control, escape, raw: false, encoding }\n )\n}\n\n// -----------------------------------------------------------------------------\n// Byte views\n// -----------------------------------------------------------------------------\n\ntype Bytes<P> =\n P extends Parser<infer A, infer E, infer R, infer _I>\n ? Parser<A extends string ? Uint8Array : A, E, R, Uint8Array>\n : never\n\n/**\n * Gives a value the type of another view of the same parsers (see\n * {@link bytes}).\n */\nconst retype = <T>(value: unknown): T =>\n // SAFETY: callers pass the byte views' parsers, which are the string parsers themselves (below)\n value as T\n\n/**\n * The parsers of this module, typed for `Uint8Array` input. Slices are\n * returned as `Uint8Array`s.\n *\n * @example\n * ```ts\n * import { Ascii, Parser, Token } from \"@thomasfosterau/effect-parse\"\n *\n * const encode = (s: string) => new TextEncoder().encode(s)\n * const header = Parser.separatedPair(\n * Ascii.bytes.alpha1,\n * Token.literal(encode(\": \")),\n * Ascii.bytes.tillLineEnding\n * )\n * ```\n *\n * @since 0.1.0\n * @category byte views\n */\nexport const bytes: {\n readonly alpha0: Bytes<typeof alpha0>\n readonly alpha1: Bytes<typeof alpha1>\n readonly digit0: Bytes<typeof digit0>\n readonly digit1: Bytes<typeof digit1>\n readonly hexDigit0: Bytes<typeof hexDigit0>\n readonly hexDigit1: Bytes<typeof hexDigit1>\n readonly octDigit0: Bytes<typeof octDigit0>\n readonly octDigit1: Bytes<typeof octDigit1>\n readonly alphanumeric0: Bytes<typeof alphanumeric0>\n readonly alphanumeric1: Bytes<typeof alphanumeric1>\n readonly space0: Bytes<typeof space0>\n readonly space1: Bytes<typeof space1>\n readonly multispace0: Bytes<typeof multispace0>\n readonly multispace1: Bytes<typeof multispace1>\n readonly crlf: Parser<Uint8Array, never, never, Uint8Array>\n readonly newline: Parser<Uint8Array, never, never, Uint8Array>\n readonly tab: Parser<Uint8Array, never, never, Uint8Array>\n readonly lineEnding: Parser<Uint8Array, never, never, Uint8Array>\n readonly tillLineEnding: Bytes<typeof tillLineEnding>\n readonly decUint: Parser<number, string, never, Uint8Array>\n readonly decInt: Parser<number, string, never, Uint8Array>\n readonly decBigUint: Parser<bigint, never, never, Uint8Array>\n readonly decBigInt: Parser<bigint, never, never, Uint8Array>\n readonly hexUint: Parser<number, string, never, Uint8Array>\n readonly float: Parser<number, never, never, Uint8Array>\n} = /*#__PURE__*/ (() => {\n const lit = (s: string) => Token.literal(new TextEncoder().encode(s))\n const crlfB = lit(\"\\r\\n\")\n const newlineB = lit(\"\\n\")\n const views = {\n alpha0,\n alpha1,\n digit0,\n digit1,\n hexDigit0,\n hexDigit1,\n octDigit0,\n octDigit1,\n alphanumeric0,\n alphanumeric1,\n space0,\n space1,\n multispace0,\n multispace1,\n crlf: crlfB,\n newline: newlineB,\n tab: lit(\"\\t\"),\n lineEnding: P.alt(newlineB, crlfB).pipe(P.expected(\"line ending\")),\n tillLineEnding,\n decUint,\n decInt,\n decBigUint,\n decBigInt,\n hexUint,\n float\n }\n // SAFETY: the string parsers run on byte input unchanged (their slices of a `Uint8Array` are `Uint8Array`s),\n // so only their declared input and slice types differ from the byte views'\n return retype<typeof bytes>(views)\n})()\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Ascii.js","names":["floatText","Token"],"sources":["../src/Ascii.ts"],"sourcesContent":["/**\n * Parsers for ASCII text: character classes, line endings, numbers and\n * escaped strings (winnow's `ascii` module, nom's `character` module).\n *\n * The parsers are typed for `string` input. Each also works on\n * `Uint8Array` input (treating bytes as ASCII), and `Ascii.bytes` gives the\n * same parsers typed for bytes:\n *\n * ```ts\n * import { Ascii, Parser } from \"@thomasfosterau/effect-parse\"\n *\n * Parser.parse(Ascii.decUint, \"42\") // 42\n * Parser.parse(Ascii.bytes.decUint, new TextEncoder().encode(\"42\")) // 42\n * ```\n *\n * Partial (streaming) input is supported: for example `digit1` on the\n * partial input `\"123\"` reports `Incomplete`, since more digits may follow.\n *\n * For Unicode character classes, or for text in other encodings (UTF-8,\n * UTF-16), use the `Text` module.\n *\n * @since 0.1.0\n */\nimport * as Predicate from \"effect/Predicate\"\nimport * as Result from \"effect/Result\"\nimport type { Encoding } from \"./Encoding.js\"\nimport type { Input, Slice, State } from \"./Input.js\"\nimport { Fail } from \"./Input.js\"\nimport type { ErrorKind } from \"./ParseError.js\"\nimport type { Parser } from \"./Parser.js\"\nimport * as P from \"./Parser.js\"\nimport * as numbers from \"./internal/numbers.js\"\nimport { Key } from \"./internal/key.js\"\nimport { controlCode } from \"./internal/node.js\"\nimport * as Resume from \"./internal/resume.js\"\nimport { codePointPredicate } from \"./internal/tokens.js\"\nimport { literalImpl, range, takeWhileImpl } from \"./Token.js\"\nimport * as Token from \"./Token.js\"\n\n// -----------------------------------------------------------------------------\n// Character predicates\n// -----------------------------------------------------------------------------\n\nconst code = (c: string | number): number => (Predicate.isNumber(c) ? c : c.charCodeAt(0))\n\n/**\n * `[a-zA-Z]`\n *\n * @since 0.1.0\n * @category predicates\n */\nexport const isAlpha: (c: string | number) => boolean = /*#__PURE__*/ codePointPredicate(\n \"isAlpha\",\n (c: string | number): boolean => {\n const x = code(c)\n return (x >= 65 && x <= 90) || (x >= 97 && x <= 122)\n },\n [\n [65, 90],\n [97, 122]\n ]\n)\n\n/**\n * `[0-9]`\n *\n * @since 0.1.0\n * @category predicates\n */\nexport const isDigit: (c: string | number) => boolean = /*#__PURE__*/ codePointPredicate(\n \"isDigit\",\n (c: string | number): boolean => {\n const x = code(c)\n return x >= 48 && x <= 57\n },\n [[48, 57]]\n)\n\n/**\n * `[0-9a-fA-F]`\n *\n * @since 0.1.0\n * @category predicates\n */\nexport const isHexDigit: (c: string | number) => boolean = /*#__PURE__*/ codePointPredicate(\n \"isHexDigit\",\n (c: string | number): boolean => {\n const x = code(c)\n return (x >= 48 && x <= 57) || (x >= 65 && x <= 70) || (x >= 97 && x <= 102)\n },\n [\n [48, 57],\n [65, 70],\n [97, 102]\n ]\n)\n\n/**\n * `[0-7]`\n *\n * @since 0.1.0\n * @category predicates\n */\nexport const isOctDigit: (c: string | number) => boolean = /*#__PURE__*/ codePointPredicate(\n \"isOctDigit\",\n (c: string | number): boolean => {\n const x = code(c)\n return x >= 48 && x <= 55\n },\n [[48, 55]]\n)\n\n/**\n * `[0-9a-zA-Z]`\n *\n * @since 0.1.0\n * @category predicates\n */\nexport const isAlphanumeric: (c: string | number) => boolean = /*#__PURE__*/ codePointPredicate(\n \"isAlphanumeric\",\n (c: string | number): boolean => isAlpha(c) || isDigit(c),\n [\n [48, 57],\n [65, 90],\n [97, 122]\n ]\n)\n\n/**\n * `[ \\t]`\n *\n * @since 0.1.0\n * @category predicates\n */\nexport const isSpace: (c: string | number) => boolean = /*#__PURE__*/ codePointPredicate(\n \"isSpace\",\n (c: string | number): boolean => {\n const x = code(c)\n return x === 32 || x === 9\n },\n [\n [9, 9],\n [32, 32]\n ]\n)\n\n/**\n * `[ \\t\\r\\n]`\n *\n * @since 0.1.0\n * @category predicates\n */\nexport const isMultispace: (c: string | number) => boolean = /*#__PURE__*/ codePointPredicate(\n \"isMultispace\",\n (c: string | number): boolean => {\n const x = code(c)\n return x === 32 || x === 9 || x === 10 || x === 13\n },\n [\n [9, 10],\n [13, 13],\n [32, 32]\n ]\n)\n\n/**\n * `\\n`\n *\n * @since 0.1.0\n * @category predicates\n */\nexport const isNewline: (c: string | number) => boolean = /*#__PURE__*/ codePointPredicate(\n \"isNewline\",\n (c: string | number): boolean => code(c) === 10,\n [[10, 10]]\n)\n\n// Token sets usable for both string and byte input\nconst alphaSet = [/*#__PURE__*/ range(\"a\", \"z\"), /*#__PURE__*/ range(\"A\", \"Z\")]\nconst digitSet = /*#__PURE__*/ range(\"0\", \"9\")\nconst hexSet = [/*#__PURE__*/ range(\"0\", \"9\"), /*#__PURE__*/ range(\"a\", \"f\"), /*#__PURE__*/ range(\"A\", \"F\")]\nconst octSet = /*#__PURE__*/ range(\"0\", \"7\")\nconst alnumSet = [/*#__PURE__*/ range(\"a\", \"z\"), /*#__PURE__*/ range(\"A\", \"Z\"), /*#__PURE__*/ range(\"0\", \"9\")]\nconst spaceSet = \" \\t\"\nconst multispaceSet = \" \\t\\r\\n\"\n\nconst cls = (\n set: Token.StringTokenSet,\n min: 0 | 1,\n description: string,\n kind: ErrorKind,\n hint = true\n): Parser<string> => takeWhileImpl<string>(set, { min }, false, `${kind.toLowerCase()}${min}`, description, kind, hint)\n\n// -----------------------------------------------------------------------------\n// Character classes\n// -----------------------------------------------------------------------------\n\n/**\n * Zero or more ASCII letters, `[a-zA-Z]*`.\n *\n * @since 0.1.0\n * @category character classes\n */\nexport const alpha0: Parser<string> = /*#__PURE__*/ cls(alphaSet, 0, \"letter\", \"Alpha\")\n\n/**\n * One or more ASCII letters, `[a-zA-Z]+`.\n *\n * @since 0.1.0\n * @category character classes\n */\nexport const alpha1: Parser<string> = /*#__PURE__*/ cls(alphaSet, 1, \"letter\", \"Alpha\")\n\n/**\n * Zero or more ASCII digits, `[0-9]*`.\n *\n * @since 0.1.0\n * @category character classes\n */\nexport const digit0: Parser<string> = /*#__PURE__*/ cls(digitSet, 0, \"digit\", \"Digit\")\n\n/**\n * One or more ASCII digits, `[0-9]+`.\n *\n * @since 0.1.0\n * @category character classes\n */\nexport const digit1: Parser<string> = /*#__PURE__*/ cls(digitSet, 1, \"digit\", \"Digit\")\n\n/**\n * Zero or more hexadecimal digits, `[0-9a-fA-F]*`.\n *\n * @since 0.1.0\n * @category character classes\n */\nexport const hexDigit0: Parser<string> = /*#__PURE__*/ cls(hexSet, 0, \"hexadecimal digit\", \"HexDigit\")\n\n/**\n * One or more hexadecimal digits, `[0-9a-fA-F]+`.\n *\n * @since 0.1.0\n * @category character classes\n */\nexport const hexDigit1: Parser<string> = /*#__PURE__*/ cls(hexSet, 1, \"hexadecimal digit\", \"HexDigit\")\n\n/**\n * Zero or more octal digits, `[0-7]*`.\n *\n * @since 0.1.0\n * @category character classes\n */\nexport const octDigit0: Parser<string> = /*#__PURE__*/ cls(octSet, 0, \"octal digit\", \"OctDigit\")\n\n/**\n * One or more octal digits, `[0-7]+`.\n *\n * @since 0.1.0\n * @category character classes\n */\nexport const octDigit1: Parser<string> = /*#__PURE__*/ cls(octSet, 1, \"octal digit\", \"OctDigit\")\n\n/**\n * Zero or more ASCII letters or digits, `[0-9a-zA-Z]*`.\n *\n * @since 0.1.0\n * @category character classes\n */\nexport const alphanumeric0: Parser<string> = /*#__PURE__*/ cls(alnumSet, 0, \"letter or digit\", \"AlphaNumeric\")\n\n/**\n * One or more ASCII letters or digits, `[0-9a-zA-Z]+`.\n *\n * @since 0.1.0\n * @category character classes\n */\nexport const alphanumeric1: Parser<string> = /*#__PURE__*/ cls(alnumSet, 1, \"letter or digit\", \"AlphaNumeric\")\n\n/**\n * Zero or more spaces and tabs, `[ \\t]*`.\n *\n * @since 0.1.0\n * @category character classes\n */\nexport const space0: Parser<string> = /*#__PURE__*/ cls(spaceSet, 0, \"space\", \"Space\", false)\n\n/**\n * One or more spaces and tabs, `[ \\t]+`.\n *\n * @since 0.1.0\n * @category character classes\n */\nexport const space1: Parser<string> = /*#__PURE__*/ cls(spaceSet, 1, \"space\", \"Space\", false)\n\n/**\n * Zero or more spaces, tabs, carriage returns and line feeds,\n * `[ \\t\\r\\n]*`.\n *\n * @since 0.1.0\n * @category character classes\n */\nexport const multispace0: Parser<string> = /*#__PURE__*/ cls(multispaceSet, 0, \"whitespace\", \"MultiSpace\", false)\n\n/**\n * One or more spaces, tabs, carriage returns and line feeds,\n * `[ \\t\\r\\n]+`.\n *\n * @since 0.1.0\n * @category character classes\n */\nexport const multispace1: Parser<string> = /*#__PURE__*/ cls(multispaceSet, 1, \"whitespace\", \"MultiSpace\", false)\n\n// -----------------------------------------------------------------------------\n// Line endings\n// -----------------------------------------------------------------------------\n\n/**\n * A carriage return followed by a line feed, `\\r\\n`.\n *\n * @since 0.1.0\n * @category line endings\n */\nexport const crlf: Parser<\"\\r\\n\"> = /*#__PURE__*/ Token.literal(\"\\r\\n\")\n\n/**\n * A line feed, `\\n` (nom's `newline`).\n *\n * @since 0.1.0\n * @category line endings\n */\nexport const newline: Parser<\"\\n\"> = /*#__PURE__*/ Token.literal(\"\\n\")\n\n/**\n * A tab, `\\t`.\n *\n * @since 0.1.0\n * @category line endings\n */\nexport const tab: Parser<\"\\t\"> = /*#__PURE__*/ Token.literal(\"\\t\")\n\n/**\n * A line ending: `\\n` or `\\r\\n`.\n *\n * @since 0.1.0\n * @category line endings\n */\nexport const lineEnding: Parser<\"\\n\" | \"\\r\\n\"> = /*#__PURE__*/ P.alt(newline, crlf).pipe(\n /*#__PURE__*/ P.expected(\"line ending\")\n)\n\nconst expectedLineEnding = [\"line ending\"]\n\n/**\n * Everything up to (not including) a line ending, `[^\\r\\n]*` (winnow's\n * `till_line_ending`, nom's `not_line_ending`). A carriage return that is\n * not followed by a line feed is an error.\n *\n * @since 0.1.0\n * @category line endings\n */\nexport const tillLineEnding: Parser<string> = /*#__PURE__*/ P.described<string>(\n (state: State<any>) => {\n const start = state.pos\n const input = state.input\n const isString = state.inputKind === 0\n let i = start\n while (i < state.end) {\n // SAFETY: `Ascii` parsers run on strings or `Uint8Array`s, and `isString` is `inputKind === 0`, set only for a string\n const c = isString ? (input as string).charCodeAt(i) : (input as Uint8Array)[i]\n if (c === 10) break\n if (c === 13) {\n // The line feed after it is read, not consumed\n state.syntax?.read(i + 2)\n if (i + 1 >= state.end) {\n if (state.partial) return state.incomplete(1, expectedLineEnding)\n return state.backtrack(\"LineEnding\", expectedLineEnding, i)\n }\n // SAFETY: `Ascii` parsers run on strings or `Uint8Array`s, and `isString` is `inputKind === 0`, set only for a string\n const d = isString ? (input as string).charCodeAt(i + 1) : (input as Uint8Array)[i + 1]\n if (d === 10) break\n return state.backtrack(\"LineEnding\", expectedLineEnding, i)\n }\n i++\n }\n if (i >= state.end && state.partial) return state.incomplete(1, expectedLineEnding)\n state.pos = i\n // SAFETY: on string input, the input type of a `Parser<string>`, the slice is a string (`bytes` retypes it for bytes)\n return state.slice(start, i) as string\n },\n \"tillLineEnding\",\n { _tag: \"TillLineEnding\", encoding: undefined }\n)\n\n// -----------------------------------------------------------------------------\n// Numbers\n// -----------------------------------------------------------------------------\n\n/** @internal */\nexport const overflow = (value: number): Result.Result<number, string> =>\n Number.isSafeInteger(value) ? Result.succeed(value) : Result.fail(\"integer overflow\")\n\n/**\n * An unsigned decimal integer: one or more digits (winnow's `dec_uint`,\n * nom's `u32`/`u64`). Fails if the value is not a safe integer.\n *\n * @since 0.1.0\n * @category numbers\n */\nexport const decUint: Parser<number, string> = /*#__PURE__*/ digit1.pipe(\n /*#__PURE__*/ P.tryMap((s) => overflow(Number(numbers.toText(s)))),\n /*#__PURE__*/ P.named(\"decUint\")\n)\n\n/**\n * A signed decimal integer: an optional `+` or `-` followed by one or more\n * digits (winnow's `dec_int`, nom's `i32`/`i64`). Fails if the value is not\n * a safe integer.\n *\n * @since 0.1.0\n * @category numbers\n */\nexport const decInt: Parser<number, string> = /*#__PURE__*/ P.taken(\n /*#__PURE__*/ P.seq(/*#__PURE__*/ P.opt(/*#__PURE__*/ Token.oneOf(\"+-\")), digit1)\n).pipe(\n /*#__PURE__*/ P.tryMap((s) => overflow(Number(numbers.toText(s)))),\n /*#__PURE__*/ P.named(\"decInt\")\n)\n\n/**\n * An unsigned decimal integer as a `bigint`, of any size.\n *\n * @since 0.1.0\n * @category numbers\n */\nexport const decBigUint: Parser<bigint> = /*#__PURE__*/ digit1.pipe(\n /*#__PURE__*/ P.map((s) => BigInt(numbers.toText(s)))\n)\n\n/**\n * A signed decimal integer as a `bigint`, of any size.\n *\n * @since 0.1.0\n * @category numbers\n */\nexport const decBigInt: Parser<bigint> = /*#__PURE__*/ P.taken(\n /*#__PURE__*/ P.seq(/*#__PURE__*/ P.opt(/*#__PURE__*/ Token.oneOf(\"+-\")), digit1)\n).pipe(\n /*#__PURE__*/ P.map((s) => {\n const t = numbers.toText(s)\n return BigInt(t.startsWith(\"+\") ? t.slice(1) : t)\n })\n)\n\n/**\n * A hexadecimal unsigned integer, without prefix (winnow's `hex_uint`, nom's\n * `hex_u32`). Fails if the value is not a safe integer.\n *\n * @since 0.1.0\n * @category numbers\n */\nexport const hexUint: Parser<number, string> = /*#__PURE__*/ hexDigit1.pipe(\n /*#__PURE__*/ P.tryMap((s) => overflow(parseInt(numbers.toText(s), 16))),\n /*#__PURE__*/ P.named(\"hexUint\")\n)\n\nconst sign = /*#__PURE__*/ P.opt(/*#__PURE__*/ Token.oneOf(\"+-\"))\nconst exponent = /*#__PURE__*/ P.opt(/*#__PURE__*/ P.seq(/*#__PURE__*/ Token.oneOf(\"eE\"), sign, digit1))\nconst unsignedFloat = /*#__PURE__*/ P.alt(\n /*#__PURE__*/ P.seq(\n /*#__PURE__*/ literalImpl(\"inf\", true),\n /*#__PURE__*/ P.opt(/*#__PURE__*/ literalImpl(\"inity\", true))\n ),\n /*#__PURE__*/ P.seq(/*#__PURE__*/ Token.literal(\".\"), digit1, exponent),\n /*#__PURE__*/ P.seq(\n digit1,\n /*#__PURE__*/ P.opt(/*#__PURE__*/ P.seq(/*#__PURE__*/ Token.literal(\".\"), /*#__PURE__*/ P.opt(digit1))),\n exponent\n )\n)\nconst floatText = /*#__PURE__*/ numbers.floatText(\n /*#__PURE__*/ P.taken(\n /*#__PURE__*/ P.alt(/*#__PURE__*/ literalImpl(\"nan\", true), /*#__PURE__*/ P.seq(sign, unsignedFloat))\n ).pipe(/*#__PURE__*/ P.expected(\"number\"))\n)\n\n/** @internal */\nexport const toFloat: (s: Input) => number = numbers.toFloat\n\n/**\n * A floating point number in decimal or scientific notation, including\n * `inf`, `infinity` and `nan` (case insensitive), as accepted by winnow's\n * `float` and nom's `double`.\n *\n * @example\n * ```ts\n * import { Ascii, Parser } from \"@thomasfosterau/effect-parse\"\n *\n * Parser.parse(Ascii.float, \"-1.5e3\") // Result.succeed(-1500)\n * ```\n *\n * @since 0.1.0\n * @category numbers\n */\nexport const float: Parser<number> = /*#__PURE__*/ floatText.pipe(\n /*#__PURE__*/ P.map(toFloat),\n /*#__PURE__*/ P.named(\"float\")\n)\n\n// -----------------------------------------------------------------------------\n// Literals\n// -----------------------------------------------------------------------------\n\n/**\n * The overloads of {@link caseless}.\n *\n * @since 0.5.0\n * @category literals\n */\nexport interface CaselessFn {\n (literal: string): Parser<string>\n (literal: Uint8Array): Parser<Uint8Array, never, never, Uint8Array>\n}\n\n/**\n * Matches a literal ignoring ASCII case (winnow's `Caseless`, nom's\n * `tag_no_case`). Returns the input as written.\n *\n * @since 0.1.0\n * @category literals\n */\nexport const caseless: CaselessFn = (lit: string | Uint8Array): any => literalImpl(lit, true)\n\n// -----------------------------------------------------------------------------\n// Escapes\n// -----------------------------------------------------------------------------\n\n/** The first UTF-16 unit of a control character: what `atControl` compares with a string's units. */\nconst firstUnit = (s: string): number => s.charCodeAt(0)\n\nconst atControl = (state: State<Input>, control: number): boolean => {\n if (state.pos >= state.end) return false\n const input = state.input\n // SAFETY: escapes are read from strings or `Uint8Array`s, and `inputKind` 0 is set only for a string\n const c = state.inputKind === 0 ? (input as string).charCodeAt(state.pos) : (input as Uint8Array)[state.pos]\n return c === control\n}\n\n/**\n * Recognizes a string containing escape sequences, returning the raw slice\n * (winnow's `take_escaped`, nom's `escaped`).\n *\n * - `normal` matches runs of ordinary characters (it must consume input)\n * - `control` is the escape character, e.g. `\"\\\\\"`\n * - `escapable` matches what may follow the control character\n *\n * @example\n * ```ts\n * import { Ascii, Parser, Token } from \"@thomasfosterau/effect-parse\"\n *\n * const raw = Ascii.takeEscaped(Ascii.alpha1, \"\\\\\", Token.oneOf(\"\\\"n\\\\\"))\n * Parser.parse(raw, \"ab\\\\\\\"cd\") // Result.succeed(\"ab\\\\\\\"cd\")\n * ```\n *\n * @since 0.1.0\n * @category escapes\n */\nexport const takeEscaped = <A, E, R, I extends Input, B, E2, R2, I2 extends Input>(\n normal: Parser<A, E, R, I>,\n control: string | number,\n escapable: Parser<B, E2, R2, I2>\n): Parser<Slice<I & I2>, E | E2, R | R2, I & I2> => {\n const ctrl = controlCode(control, firstUnit)\n return takeEscapedImpl(\n normal,\n (state) => {\n if (!atControl(state, ctrl)) return false\n state.pos++\n return true\n },\n escapable,\n // SAFETY: the parser runs on input of type `I & I2`, and `State.slice` returns that input's own slice type\n (state, start) => state.slice(start, state.pos) as Slice<I & I2>,\n ctrl,\n undefined\n )\n}\n\nconst isIncomplete = (state: State<any>): boolean => state.mode === \"Incomplete\"\n\n/**\n * Fails with the current (`Incomplete`) failure, recording a checkpoint\n * first in a streaming parse.\n */\nconst suspendAt = (state: State<any>, key: Key, start: number, checkpoint: unknown): Fail => {\n if (state.resume !== undefined) Resume.save(state, key, start, checkpoint)\n return Fail\n}\n\n/** @internal */\nexport const takeEscapedImpl = <A, E, R, I extends Input, B, E2, R2, I2 extends Input, S>(\n normal: Parser<A, E, R, I>,\n matchControl: (state: State<any>) => boolean,\n escapable: Parser<B, E2, R2, I2>,\n slice: (state: State<any>, start: number) => S,\n control: number,\n encoding: Encoding<any> | undefined\n): Parser<S, E | E2, R | R2, I & I2> => {\n const normalStep = normal.step\n const escStep = escapable.step\n const key = new Key()\n return P.described(\n (state: State<any>) => {\n const start = state.pos\n let resumed = false\n if (state.resume !== undefined) {\n // SAFETY: under its own `key`, this parser saves only a resume offset (`suspendAt`) or a `Done`\n const checkpoint = Resume.take(state, key, start) as number | Resume.Done | undefined\n if (checkpoint instanceof Resume.Done) {\n state.pos = checkpoint.pos\n // SAFETY: a `Done` saved under this parser's `key` holds the `S` it returned\n return checkpoint.value as S\n }\n if (checkpoint !== undefined) {\n state.pos = checkpoint\n resumed = true\n }\n }\n while (state.pos < state.end) {\n const before = state.pos\n const a = normalStep(state)\n if (a !== Fail) {\n if (state.pos === before)\n return state.failMessage(\"Cut\", \"Assert\", \"`takeEscaped` parsers must always consume\")\n continue\n }\n if (state.mode === \"Incomplete\") return suspendAt(state, key, start, before)\n if (state.mode !== \"Backtrack\") return Fail\n state.rewind(before)\n if (matchControl(state)) {\n if (escStep(state) === Fail) return isIncomplete(state) ? suspendAt(state, key, start, before) : Fail\n } else {\n return Resume.done(state, key, start, resumed, slice(state, start))\n }\n }\n if (state.partial) {\n state.incomplete(0)\n return suspendAt(state, key, start, state.pos)\n }\n return Resume.done(state, key, start, resumed, slice(state, start))\n },\n \"takeEscaped\",\n { _tag: \"Escaped\", normal, control, escape: escapable, raw: true, encoding }\n )\n}\n\n/**\n * Parses a string containing escape sequences, returning the *unescaped*\n * string (winnow's `escaped`, nom's `escaped_transform`).\n *\n * - `normal` matches runs of ordinary characters, returning them\n * - `control` is the escape character, e.g. `\"\\\\\"`\n * - `escape` parses what follows the control character, returning its\n * replacement\n *\n * @example\n * ```ts\n * import { Ascii, Parser, Token } from \"@thomasfosterau/effect-parse\"\n *\n * const unescaped = Ascii.escaped(\n * Token.takeTill(\"\\\\\\\"\"),\n * \"\\\\\",\n * Parser.alt(\n * Token.literal(\"n\").pipe(Parser.as(\"\\n\")),\n * Token.literal(\"\\\\\"),\n * Token.literal(\"\\\"\")\n * )\n * )\n * Parser.parse(unescaped, \"a\\\\nb\") // Result.succeed(\"a\\nb\")\n * ```\n *\n * @since 0.1.0\n * @category escapes\n */\nexport const escaped = <E, R, I extends Input, E2, R2, I2 extends Input>(\n normal: Parser<string, E, R, I>,\n control: string | number,\n escape: Parser<string, E2, R2, I2>\n): Parser<string, E | E2, R | R2, I & I2> => {\n const ctrl = controlCode(control, firstUnit)\n return escapedImpl(\n normal,\n (state) => {\n if (!atControl(state, ctrl)) return false\n state.pos++\n return true\n },\n escape,\n ctrl,\n undefined\n )\n}\n\n/** How far `escaped` got: the text so far, and where to carry on. */\ninterface EscapedCheckpoint {\n readonly out: string\n readonly pos: number\n}\n\n/** @internal */\nexport const escapedImpl = <E, R, I extends Input, E2, R2, I2 extends Input>(\n normal: Parser<string, E, R, I>,\n matchControl: (state: State<any>) => boolean,\n escape: Parser<string, E2, R2, I2>,\n control: number,\n encoding: Encoding<any> | undefined\n): Parser<string, E | E2, R | R2, I & I2> => {\n const normalStep = normal.step\n const escStep = escape.step\n const key = new Key()\n return P.described(\n (state: State<any>) => {\n const start = state.pos\n let out = \"\"\n let resumed = false\n if (state.resume !== undefined) {\n // SAFETY: under its own `key`, this parser saves only an `EscapedCheckpoint` (`suspendAt`) or a `Done`\n const checkpoint = Resume.take(state, key, start) as EscapedCheckpoint | Resume.Done | undefined\n if (checkpoint instanceof Resume.Done) {\n state.pos = checkpoint.pos\n // SAFETY: a `Done` saved under this parser's `key` holds the string it returned\n return checkpoint.value as string\n }\n if (checkpoint !== undefined) {\n out = checkpoint.out\n state.pos = checkpoint.pos\n resumed = true\n }\n }\n while (state.pos < state.end) {\n const before = state.pos\n const a = normalStep(state)\n if (a !== Fail) {\n if (state.pos !== before) {\n out += a\n continue\n }\n // `normal` matched nothing: fall through to the control character\n } else {\n if (state.mode === \"Incomplete\") return suspendAt(state, key, start, { out, pos: before })\n if (state.mode !== \"Backtrack\") return Fail\n state.rewind(before)\n }\n if (matchControl(state)) {\n const b = escStep(state)\n if (b === Fail) return isIncomplete(state) ? suspendAt(state, key, start, { out, pos: before }) : Fail\n out += b\n } else {\n return Resume.done(state, key, start, resumed, out)\n }\n }\n if (state.partial) {\n state.incomplete(0)\n return suspendAt(state, key, start, { out, pos: state.pos })\n }\n return Resume.done(state, key, start, resumed, out)\n },\n \"escaped\",\n { _tag: \"Escaped\", normal, control, escape, raw: false, encoding }\n )\n}\n\n// -----------------------------------------------------------------------------\n// Byte views\n// -----------------------------------------------------------------------------\n\ntype Bytes<P> =\n P extends Parser<infer A, infer E, infer R, infer _I>\n ? Parser<A extends string ? Uint8Array : A, E, R, Uint8Array>\n : never\n\n/**\n * Gives a value the type of another view of the same parsers (see\n * {@link bytes}).\n */\nconst retype = <T>(value: unknown): T =>\n // SAFETY: callers pass the byte views' parsers, which are the string parsers themselves (below)\n value as T\n\n/**\n * The parsers of this module, typed for `Uint8Array` input. Slices are\n * returned as `Uint8Array`s.\n *\n * @example\n * ```ts\n * import { Ascii, Parser, Token } from \"@thomasfosterau/effect-parse\"\n *\n * const encode = (s: string) => new TextEncoder().encode(s)\n * const header = Parser.separatedPair(\n * Ascii.bytes.alpha1,\n * Token.literal(encode(\": \")),\n * Ascii.bytes.tillLineEnding\n * )\n * ```\n *\n * @since 0.1.0\n * @category byte views\n */\nexport const bytes: {\n readonly alpha0: Bytes<typeof alpha0>\n readonly alpha1: Bytes<typeof alpha1>\n readonly digit0: Bytes<typeof digit0>\n readonly digit1: Bytes<typeof digit1>\n readonly hexDigit0: Bytes<typeof hexDigit0>\n readonly hexDigit1: Bytes<typeof hexDigit1>\n readonly octDigit0: Bytes<typeof octDigit0>\n readonly octDigit1: Bytes<typeof octDigit1>\n readonly alphanumeric0: Bytes<typeof alphanumeric0>\n readonly alphanumeric1: Bytes<typeof alphanumeric1>\n readonly space0: Bytes<typeof space0>\n readonly space1: Bytes<typeof space1>\n readonly multispace0: Bytes<typeof multispace0>\n readonly multispace1: Bytes<typeof multispace1>\n readonly crlf: Parser<Uint8Array, never, never, Uint8Array>\n readonly newline: Parser<Uint8Array, never, never, Uint8Array>\n readonly tab: Parser<Uint8Array, never, never, Uint8Array>\n readonly lineEnding: Parser<Uint8Array, never, never, Uint8Array>\n readonly tillLineEnding: Bytes<typeof tillLineEnding>\n readonly decUint: Parser<number, string, never, Uint8Array>\n readonly decInt: Parser<number, string, never, Uint8Array>\n readonly decBigUint: Parser<bigint, never, never, Uint8Array>\n readonly decBigInt: Parser<bigint, never, never, Uint8Array>\n readonly hexUint: Parser<number, string, never, Uint8Array>\n readonly float: Parser<number, never, never, Uint8Array>\n} = /*#__PURE__*/ (() => {\n const lit = (s: string) => Token.literal(new TextEncoder().encode(s))\n const crlfB = lit(\"\\r\\n\")\n const newlineB = lit(\"\\n\")\n const views = {\n alpha0,\n alpha1,\n digit0,\n digit1,\n hexDigit0,\n hexDigit1,\n octDigit0,\n octDigit1,\n alphanumeric0,\n alphanumeric1,\n space0,\n space1,\n multispace0,\n multispace1,\n crlf: crlfB,\n newline: newlineB,\n tab: lit(\"\\t\"),\n lineEnding: P.alt(newlineB, crlfB).pipe(P.expected(\"line ending\")),\n tillLineEnding,\n decUint,\n decInt,\n decBigUint,\n decBigInt,\n hexUint,\n float\n }\n // SAFETY: the string parsers run on byte input unchanged (their slices of a `Uint8Array` are `Uint8Array`s),\n // so only their declared input and slice types differ from the byte views'\n return retype<typeof bytes>(views)\n})()\n"],"mappings":"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"}
|
package/dist/Binary.d.ts
CHANGED
|
@@ -101,7 +101,9 @@ export declare const f32: (endian: Endianness) => Parser<number, never, never, U
|
|
|
101
101
|
export declare const f64: (endian: Endianness) => Parser<number, never, never, Uint8Array>;
|
|
102
102
|
/**
|
|
103
103
|
* Parses a length with `count`, then takes that many tokens (winnow's
|
|
104
|
-
* `length_take`, nom's `length_data`).
|
|
104
|
+
* `length_take`, nom's `length_data`). A length that is not a non-negative
|
|
105
|
+
* integer (a negative `i8`, a fractional float) fails the parse at the
|
|
106
|
+
* length.
|
|
105
107
|
*
|
|
106
108
|
* @since 0.1.0
|
|
107
109
|
* @category length-prefixed
|
|
@@ -109,7 +111,8 @@ export declare const f64: (endian: Endianness) => Parser<number, never, never, U
|
|
|
109
111
|
export declare const lengthTake: <E, R, I extends Input = Uint8Array>(count: Parser<number | bigint, E, R, I>) => Parser<Slice<I>, E, R, I>;
|
|
110
112
|
/**
|
|
111
113
|
* Parses a length with `count`, then applies `parser` that many times
|
|
112
|
-
* (winnow's `length_repeat`, nom's `length_count`).
|
|
114
|
+
* (winnow's `length_repeat`, nom's `length_count`). A length that is not a
|
|
115
|
+
* non-negative integer fails the parse at the length.
|
|
113
116
|
*
|
|
114
117
|
* @since 0.1.0
|
|
115
118
|
* @category length-prefixed
|
package/dist/Binary.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Binary.d.ts","names":[],"sources":["../src/Binary.ts"],"mappings":";;;;;;;;;YA0CY;;;;;;;qBAmEC,IAAI,6BAA6B;;;;;;;qBAQjC,IAAI,6BAA6B;;qBAGjC,OAAO,6BAA6B;;qBAMpC,OAAO,6BAA6B;;qBAMpC,OAAO,6BAA6B;;qBAMpC,OAAO,6BAA6B;;qBAMpC,OAAO,6BAA6B;;qBAMpC,OAAO,6BAA6B;;qBAMpC,OAAO,6BAA6B;;qBAMpC,OAAO,6BAA6B;;qBAMpC,OAAO,6BAA6B;;qBAMpC,OAAO,6BAA6B;;qBAMpC,OAAO,6BAA6B;;qBAMpC,OAAO,6BAA6B;;qBAMpC,OAAO,6BAA6B;;qBAMpC,OAAO,6BAA6B;;qBAMpC,OAAO,6BAA6B;;qBAMpC,OAAO,6BAA6B;;qBAMpC,QAAQ,6BAA6B;;qBAMrC,QAAQ,6BAA6B;;qBAMrC,QAAQ,6BAA6B;;qBAMrC,QAAQ,6BAA6B;;qBAOrC,OAAO,6BAA6B;;qBAMpC,OAAO,6BAA6B;;qBAMpC,OAAO,6BAA6B;;qBAMpC,OAAO,6BAA6B;;;;;;;qBAiBpC,MAAM,QAAQ,eAAe,6BAA6B;;qBAK1D,MAAM,QAAQ,eAAe,6BAA6B;;qBAK1D,MAAM,QAAQ,eAAe,6BAA6B;;qBAK1D,MAAM,QAAQ,eAAe,6BAA6B;;qBAK1D,MAAM,QAAQ,eAAe,6BAA6B;;qBAK1D,MAAM,QAAQ,eAAe,6BAA6B;;qBAK1D,MAAM,QAAQ,eAAe,6BAA6B;;qBAK1D,MAAM,QAAQ,eAAe,6BAA6B;;qBAK1D,OAAO,QAAQ,eAAe,6BAA6B;;qBAK3D,OAAO,QAAQ,eAAe,6BAA6B;;qBAK3D,MAAM,QAAQ,eAAe,6BAA6B;;qBAK1D,MAAM,QAAQ,eAAe,6BAA6B
|
|
1
|
+
{"version":3,"file":"Binary.d.ts","names":[],"sources":["../src/Binary.ts"],"mappings":";;;;;;;;;YA0CY;;;;;;;qBAmEC,IAAI,6BAA6B;;;;;;;qBAQjC,IAAI,6BAA6B;;qBAGjC,OAAO,6BAA6B;;qBAMpC,OAAO,6BAA6B;;qBAMpC,OAAO,6BAA6B;;qBAMpC,OAAO,6BAA6B;;qBAMpC,OAAO,6BAA6B;;qBAMpC,OAAO,6BAA6B;;qBAMpC,OAAO,6BAA6B;;qBAMpC,OAAO,6BAA6B;;qBAMpC,OAAO,6BAA6B;;qBAMpC,OAAO,6BAA6B;;qBAMpC,OAAO,6BAA6B;;qBAMpC,OAAO,6BAA6B;;qBAMpC,OAAO,6BAA6B;;qBAMpC,OAAO,6BAA6B;;qBAMpC,OAAO,6BAA6B;;qBAMpC,OAAO,6BAA6B;;qBAMpC,QAAQ,6BAA6B;;qBAMrC,QAAQ,6BAA6B;;qBAMrC,QAAQ,6BAA6B;;qBAMrC,QAAQ,6BAA6B;;qBAOrC,OAAO,6BAA6B;;qBAMpC,OAAO,6BAA6B;;qBAMpC,OAAO,6BAA6B;;qBAMpC,OAAO,6BAA6B;;;;;;;qBAiBpC,MAAM,QAAQ,eAAe,6BAA6B;;qBAK1D,MAAM,QAAQ,eAAe,6BAA6B;;qBAK1D,MAAM,QAAQ,eAAe,6BAA6B;;qBAK1D,MAAM,QAAQ,eAAe,6BAA6B;;qBAK1D,MAAM,QAAQ,eAAe,6BAA6B;;qBAK1D,MAAM,QAAQ,eAAe,6BAA6B;;qBAK1D,MAAM,QAAQ,eAAe,6BAA6B;;qBAK1D,MAAM,QAAQ,eAAe,6BAA6B;;qBAK1D,OAAO,QAAQ,eAAe,6BAA6B;;qBAK3D,OAAO,QAAQ,eAAe,6BAA6B;;qBAK3D,MAAM,QAAQ,eAAe,6BAA6B;;qBAK1D,MAAM,QAAQ,eAAe,6BAA6B;;;;;;;;;;qBAiD1D,aAAc,GAAG,GAAG,UAAU,QAAQ,YACjD,OAAO,wBAAwB,GAAG,GAAG,OACpC,OAAO,MAAM,IAAI,GAAG,GAAG;;;;;;;;;qBA8Bb,eAAgB,GAAG,GAAG,UAAU,OAAO,GAAG,IAAI,IAAI,WAAW,OACxE,OAAO,wBAAwB,GAAG,GAAG,IACrC,QAAQ,OAAO,GAAG,IAAI,IAAI,QACzB,OAAO,MAAM,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI;;;;;;;;;qBAc3B,gBAAiB,GAAG,GAAG,UAAU,OAAO,GAAG,IAAI,IAC1D,OAAO,wBAAwB,GAAG,GAAG,IACrC,QAAQ,OAAO,GAAG,IAAI,IAAI,MAAM,KAAK,WACpC,OAAO,GAAG,IAAI,IAAI,IAAI,IAAI"}
|