Skip to content

Releases: pointfreeco/swift-parsing

0.8.0

10 Mar 18:53
Compare
Choose a tag to compare
  • 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 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 OneOfs.

  • Optimized: OneOfMany no longer backtracks its final failure, bringing it in line with the behavior of the variadic OneOfs.

  • Breaking change: The non-inout overloads of Parser.parse now attempt to fully consume Collection-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 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.

    // 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.:

    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).

0.7.1

17 Feb 21:23
Compare
Choose a tag to compare
  • 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

14 Feb 16:15
Compare
Choose a tag to compare
  • 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 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.

  • 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 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).

0.6.0

09 Feb 19:20
Compare
Choose a tag to compare
  • 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, 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).

0.5.0

24 Jan 18:10
Compare
Choose a tag to compare
  • 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.

0.4.1

06 Jan 15:12
b91a41b
Compare
Choose a tag to compare
  • Changed: Many and OptionalParser's Upstream generic has been deprecated and renamed to Element and Wrapped.
  • Infrastructure: benchmarks and documentation cleanup.

0.4.0

06 Dec 22:51
Compare
Choose a tag to compare
  • 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 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).

0.3.1

27 Oct 21:43
0f539b4
Compare
Choose a tag to compare

What's Changed

Full Changelog: 0.3.0...0.3.1

0.3.0

27 Oct 17:38
0e4f1bf
Compare
Choose a tag to compare
  • Added: UUID.parser(), which incrementally parses a hexadecimal UUID from a substring or collection of bytes.

  • Added: Parser conformances for String, 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

20 Sep 18:09
28433d9
Compare
Choose a tag to compare
  • 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: use First().filter(predicate) for the behavior of FirstWhere.
  • 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.