pointfreeco/swift-parsing

Unable to start a line with an Int parser

sbeitzel opened this issue · 1 comments

Given that I want to parse an input line that looks like this: (AoC 2022, number 4)
2-4,6-8

I reckon that what I want to wind up with is four integers: the starting and ending points for Elf A and Elf B.

Let's define ElfPair as:

    struct ElfPair {
        let firstA: Int
        let firstB: Int
        let secondA: Int
        let secondB: Int
  }

Now, let's try to parse it:

        let pairParser = Parse(ElfPair.init) {
            Int.parser()
            "-"
            Int.parser()
            ","
            Int.parser()
            "-"
            Int.parser()
        }

The compiler complains on the first Int.parser(), saying, "Ambiguous use of buildExpression"

I can make the compiler shut up by adding an initial literal parser for the empty string, but this seems ... icky:

        let pairParser = Parse(ElfPair.init) {
            ""
            Int.parser()
            "-"
            Int.parser()
            ","
            Int.parser()
            "-"
            Int.parser()
        }

You need to supply more type information due to certain limitations of result builders in Swift. This was detailed in this discussion.

To fix you can either do this:

let pairParser = Parse.init(input: Substring.self, ElfPair.init) {
  Int.parser()
  "-"
  Int.parser()
  ","
  Int.parser()
  "-"
  Int.parser()
}

Or you can define a whole new parser type using the body-style of parsing, which can be easier for the compiler to process for large, complex parsers:

struct ElfPairParser: Parser {
  var body: some Parser<Substring, ElfPair> {
    Parse(ElfPair.init) {
      Int.parser()
      "-"
      Int.parser()
      ","
      Int.parser()
      "-"
      Int.parser()
    }
  }
}

Also this is not an issue with the library so I am going to convert this to a discussion.