Releases: pointfreeco/swift-parsing
0.8.0
-
Added: A case-iterable, raw-representable parser. Simply tack
.parser()
onto any conforming type: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 asDouble.init
'sLosslessStringConvertible
functionality. -
Optimized:
Peek
andNot
will only backtrack when they are successful (i.e., ifPeek
's upstream parser successfully parses a value, or ifNot
's upstream parser fails to parse a value). Backtracking on failure is now delegated to any upstreamOneOf
s. -
Optimized:
OneOfMany
no longer backtracks its final failure, bringing it in line with the behavior of the variadicOneOf
s. -
Breaking change: The non-
inout
overloads ofParser.parse
now attempt to fully consumeCollection
-based inputs.// 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 ofparse
, or explicitly describe how the input should be ignored in the parser, for example usingOptionally { Rest() }.map { _ in () }
. -
Breaking change: The
Rest
parser now fails when the rest of input is empty.// 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 anOptionally
parser, or usereplaceError(with:)
to provide a default value of""
. -
Breaking change:
Peek
is now aVoid
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 ofInt.parser()
has been removed.Int.parser()
will now always parse a sign ifFixedWidthInteger.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.: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 toBinaryFloatingPoint
, includingFloat16
. -
Updated:
Many
'supdateAccumulatingResult
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).
0.7.1
- 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.
0.7.0
-
Breaking change:
Parser.parse
's method signature has changed from optional-returning to throwing:-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:
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 callparse
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.
-
Added:
Parser.replaceError(with:)
, a parser modifier that transforms a throwing parser into a non-throwing parser by providing a default output.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 anError
for custom error messaging. -
Deprecated:
Conditional
as a top-level parser has been deprecated. Useif
-else
builder syntax instead, which usesConditional
parsers under the hood, or reference the nestedParsers.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).
0.6.0
-
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 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
, andPrefixUpTo
.Note:
Peek
andNot
preserve their backtracking behavior, as they are designed to never consume any input. -
Infrastructure: Add tests for
CharacterSet.parse
(thanks @andrewjl).
0.5.0
- Added: New result builder syntax for creating parsers! Use the
Parse
andOneOf
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 anInt
(notSelf
) 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.
0.4.1
- Changed:
Many
andOptionalParser
'sUpstream
generic has been deprecated and renamed toElement
andWrapped
. - Infrastructure: benchmarks and documentation cleanup.
0.4.0
- Added: initializer overloads of
Prefix
and other parsers that aid in type inference. E.g., the following now type-checks:Prefix { $0 == " " } // Inferred to be "Prefix<Substring>" Prefix { $0 == .init(ascii: " ") } // Inferred to be "Prefix<Substring.UTF8View>"
- Added:
CharacterSet
now conforms toParser
. - 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 generalDouble
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).
0.3.1
What's Changed
- Disfavor overloads of standard library methods by @mbrandonw in #58 /ht to @MaxDesiatov for the report!
Full Changelog: 0.3.0...0.3.1
0.3.0
-
Added:
UUID.parser()
, which incrementally parses a hexadecimal UUID from a substring or collection of bytes. -
Added:
Parser
conformances forString
,String.UnicodeScalarView
,String.UTF8View
, and[UInt8]
.These conformances can clean up a lot of
StartsWith
noise that can accumulate in string parsing. For example:let user = Int.parser() - .skip(StartsWith(",")) + .skip(",") .take(Prefix { $0 != "," }) - .skip(StartsWith(",")) + .skip(",") .take(Bool.parser())
0.2.0
- Added: additional
Take
parsers to support up to 11 values (thanks @ryanbooker). - Updated: swift-parsing now uses swift-package-tools 5.3.
- Fixed:
Int.parser()
no longer consumes a leading-
or+
even when parsing fails (thanks @mortigenus). - Fixed:
Prefix
no longer fails if it matches past its maximum specified length. - Fixed: Windows support (thanks @MaxDesiatov).
- Fixed: documentation typo (thanks @tevelee).
- Deprecated:
FirstWhere
has been deprecated in favor of using more explicit methods. This was done to avoid confusion around differences between the standard library's collection behavior and the behavior of the parser. Migration path: useFirst().filter(predicate)
for the behavior ofFirstWhere
. - Infrastructure: renamed Zip.swift to Take.swift to make navigating the project easier (thanks @jasdev).
- Infrastructure: fixed float parser test (thanks @tgrapperon).
- Infrastructure: DocC support.
- Infrastructure: Fixed JSON parser example.