The markdown parsing is broken/disabled for release notes. Sorry about that, I'm chasing the source of a crash that's been bringing this website down for the last couple of days.
- Fixed: Added a missing `ParserPrinter` conformance to `OptionalOneOf`, which prevented parsers that used `if` statements in `@OneOfBuilder` blocks from being printers.
The following changes have been made to the more experimental `_URLRouting` module:
- Added: A `Body()` initializer that takes no arguments. It simply parses the entire body as `Data`.
- Infrastructure: documentation changes.
- Fixed: A `Double.parser()` overflow bug has been fixed (thanks @tgrapperon).
The following changes have been made to the more experimental `_URLRouting` module:
- Added: A `URLRoutingClient` for wrapping a router and URL session into an HTTP client.
- Fixed: A few potential bugs around `Field` and `Body` being empty.
Introduced the `ParserPrinter` protocol for invertible parsing.
- Added: A case-iterable, raw-representable parser. Simply tack `.parser()` onto any conforming type:
```swift
enum Role: String, CaseIterable {
case admin
case guest
case member
}
try Role.parser().parse("admin") // Role.admin
```
- Fixed: An Xcode 13.3 compiler error has been fixed.
- Fixed: `Optionally` will now backtrack if the parser fails (thanks @randomeizer).
- Fixed: `Double.parser()` now parses as freely as `Double.init`'s `LosslessStringConvertible` functionality.
- Optimized: `Peek` and `Not` will only backtrack when they are successful (_i.e._, if `Peek`'s upstream parser successfully parses a value, or if `Not`'s upstream parser fails to parse a value). Backtracking on failure is now delegated to any upstream `OneOf`s.
- Optimized: `OneOfMany` no longer backtracks its final failure, bringing it in line with the behavior of the variadic `OneOf`s.
- Breaking change: The non-`inout` overloads of `Parser.parse` now attempt to fully consume `Collection`-based inputs.
```swift
// Before:
try Int.parser().parse("42hello") // 42
// After:
try Int.parser().parse("42hello")
// error: unexpected input
// --> input:1:13
// 1 | 42hello
// | ^ expected end of input
```
This change makes parsing a bit more strict by default in order to catch potential issues with input.
If you want to ignore trailing output, use the `inout` version of `parse`, or explicitly describe how the input should be ignored in the parser, for example using `Optionally { Rest() }.map { _ in () }`.
- Breaking change: The `Rest` parser now fails when the rest of input is empty.
```swift
// Before:
try Rest().parse("") // ""
// After:
try Rest().parse("")
/// error: unexpected input
/// --> input:1:1
/// 1 |
/// | ^ expected a non-empty input
```
If your use of `Rest` should not fail on empty input, wrap it explicitly in an `Optionally` parser, or use `replaceError(with:)` to provide a default value of `""`.
- Breaking change: `Peek` is now a `Void` parser. It can be used to inspect a value in order to test that a parser should be successful, but capturing any data is now the responsible for the parsers that comes afterward (thanks @randomeizer).
- Breaking change: The `isSigned` parameter of `Int.parser()` has been removed. `Int.parser()` will now always parse a sign if `FixedWidthInteger.isSigned` returns true (_e.g._, `Int.parser()` will parse a sign, `UInt.parser()` will not.).
If you want to parse a number without a sign, use a more explicit parser, or test for the sign before using `Int.parser()`. _E.g._:
```swift
let digits = Prefix { $0.isNumber }.compactMap(Int.init)
// ...or...
let digits = Parse {
Not { OneOf { "-"; "+" } }
Int.parser()
}
```
- Updated: `Double.parser()` can now be used on any type that conforms to `BinaryFloatingPoint`, including `Float16`.
- Updated: `Many`'s `updateAccumulatingResult` can now throw.
- Updated: Documentation has been revamped, including a new DocC-based static site with articles that cover common topics.
- Infrastructure: Documentation fixes (thanks @haikusw).
- Improved: Error messages that occur at the same input range are now coalesced into a single error (thanks @mayoff).
- Fixed: `Prefix` now eagerly consumes input.
- Fixed: `Prefix` with a minimum length now throws an error at the correct input location, rather than the input location of that minimum length.
- Infrastructure: README and documentation updates.
* Breaking change: `Parser.parse`'s method signature has changed from optional-returning to throwing:
```diff
-func parse(_ input: inout Input) -> Output?
+func parse(_ input: inout Input) throws -> Output
```
All of the parsers the library ships with now include error messages and context alongside failure, which can be printed:
```swift
do {
let output = users.parse(&input)
} catch {
print(error)
}
// error: multiple failures occurred
//
// error: unexpected input
// --> input:3:11
// 3 | 3,Blob Jr,tru
// | ^ expected "true" or "false"
//
// error: unexpected input
// --> input:2:16
// 2 | 2,Blob Sr,false
// | ^ expected end of input"
```
This is unfortunately a breaking change. It does not seem possible to support both throwing and optional-returning at the same time without requiring alternate breaking changes, so we opted for a clean break that requires upgrading existing parsers to throwing parsers. For most of our users, it will hopefully be a matter of prepending `try?` to lines that call `parse` to get things building again, though we hope folks will take full advantage of the new error messages. For users with custom parser conformances, they will need to do a little more work to make these parsers throwing.
For more information about the release and migration strategies, see [our announcement](https://www.pointfree.co/blog/posts/73-parser-errors).
* Added: `Parser.replaceError(with:)`, a parser modifier that transforms a throwing parser into a non-throwing parser by providing a default output.
```swift
let sign = OneOf {
"+".map { 1 }
"-".map { -1 }
}
.replaceError(with: 1)
var input = "-123"[...]
// No `try` required:
sign.parse(&input) // -1
input // "123"
// Simply returns the default when parsing fails:
sign.parse(&input) // 1
```
* Added: the `Fail` parser has a new `.init(throwing:)` initializer that takes an `Error` for custom error messaging.
* Deprecated: `Conditional` as a top-level parser has been deprecated. Use `if`-`else` builder syntax instead, which uses `Conditional` parsers under the hood, or reference the nested `Parsers.Conditional` type.
* Infrastructure: documentation has been rewritten and expanded to reflect throwing parsers.
* Infrastructure: Swift Package Index configuration was fixed so that our supported platform are better communicated (thanks @finestructure).
* Breaking change: many parsers that used to explicitly revert changes made to `input` when parsing fails (a process known as "backtracking") no longer do.
See [our announcement](https://www.pointfree.co/blog/posts/72-backtracking-parsers) and pull request #108 for more information about the change and its motivation.
`OneOf`, which previously did no backtracking whatsoever and trusted other parsers to do the work, is now the main entry point into backtracking behavior.
Backtracking has been removed from `Double.parser()`, `Parser.filter`, `Parser.flatMap`, `Many` (with the exception of backtracking a trailing separator), `Parser.pipe`, `PrefixThrough`, and `PrefixUpTo`.
Note: `Peek` and `Not` preserve their backtracking behavior, as they are designed to never consume any input.
* Infrastructure: Add tests for `CharacterSet.parse` (thanks @andrewjl).
- Added: New result builder syntax for creating parsers! Use the `Parse` and `OneOf` entry points into `@ParserBuilder` and `@OneOfBuilder` blocks.
- Added: A `Peek` parser: for running a parser and checking its result _without_ consuming input (thanks @randomeizer).
- Added: A `Not` parser: for running a parser and succeeding if it fails (or failing if it succeeds) (thanks @randomeizer).
- Changed: Many parsers have been updated to work with builder syntax, including `Skip`, `Many`, etc.
- Changed: `Int.parser()` now takes an `Int` (not `Self`) as its radix.
- Deprecated: Older, non-parser builder interfaces have been soft-deprecated.
- Deprecated: Swift 5.3 support has been removed.
- Performance: `Many`'s performance has been improved.
- Changed: `Many` and `OptionalParser`'s `Upstream` generic has been deprecated and renamed to `Element` and `Wrapped`.
- Infrastructure: benchmarks and documentation cleanup.
- Added: initializer overloads of `Prefix` and other parsers that aid in type inference. _E.g._, the following now type-checks:
```swift
Prefix { $0 == " " }
// Inferred to be "Prefix<Substring>"
Prefix { $0 == .init(ascii: " ") }
// Inferred to be "Prefix<Substring.UTF8View>"
```
- Added: `CharacterSet` now conforms to `Parser`.
- Changed: `Many` will now trigger a warning breakpoint when its upstream parser succeeds but fails to consume any data, which can cause an infinite loop.
- Fixed: `Double.parser()` exponent parsing (thanks @bradhowes) and general `Double` parsing edge cases.
- Infrastructure: documentation fixes (thanks @igor1309).
- Infrastructure: improved "arithmetic" demo parser to use more ergonomic/performant `InfixOperator` parser.
- Infrastructure: benchmarks now better reflect typical parsing (substring UTF8 views vs. unsafe buffer pointers).