0

I'm trying to parse an entity and the entities that make up that entity's fields using Scala parser combinators. I'd like to do this by having each sub entity know how to parse itself.

My problem can be reproduced by a Person class that has an Address and a Car. Here's what the Address and Car classes look like and how they're parsed.

import scala.util.parsing.combinator._

case class Address(val street: String, val postCode: String) {

}

object Address extends JavaTokenParsers {

  def parse: Parser[Address] = (streetPattern ~ postCodePattern) ^^ {
    case street ~ postCode => Address(street, postCode)
  }

}

case class Car(val make: String, val model: String) {

}

object Car extends JavaTokenParsers {

  def parse: Parser[Car] = (stringLiteral ~ ":" ~ stringLiteral) ^^ {
    case make ~ ":" ~ model => Car(make, model);
  }

}

Where I run into problems is when I try to combine the parsers to parse Person:

case class Person(val address: Address, val car: Car) {

}

object Person extends JavaTokenParsers {

  def parse: Parser[Person] = (Address.parse ~ Car.parse) ^^ {
    case address ~ car => Person(address, car);
  }

}

The compiler error that I get is this:

[error] Parser.scala:38: type mismatch;
[error]  found   : Car.Parser[Car]
[error]  required: Address.Parser[?]
[error]   def parse: Parser[Person] = (Address.parse ~ Car.parse) ^^ {
[error]                                                    ^
[error] Parser.scala:39: type mismatch;
[error]  found   : Any
[error]  required: Address
[error]     case address ~ car => Person(address, car);
[error]                                  ^
[error] Parser.scala:39: type mismatch;
[error]  found   : Any
[error]  required: Car
[error]     case address ~ car => Person(address, car);
[error]                                           ^

How can I combine the two parsers into a parser that can parse a complete Person object?

2
  • You may find this answer helpful...? Commented Mar 22, 2015 at 0:12
  • And this. Commented Mar 22, 2015 at 0:17

1 Answer 1

1

In order to combine Parsers they need to have the same type Elem definition. When you have Address, Car and Person companion objects extend separately from JavaTokenParsers the compiler is unable to deduce that they all the same type since they'll have different instances of Elem.

Try to put all parsers under the same companion object like:

object Person extends JavaTokenParsers {
  def address: Parser[Address] = (streetPattern ~ postCodePattern) ^^ {
    case street ~ postCode => Address(street, postCode)
  }

  def car: Parser[Car] = (stringLiteral ~ ":" ~ stringLiteral) ^^ {
    case make ~ ":" ~ model => Car(make, model)
  }

  def parse: Parser[Person] = address ~ car ^^ {
    case a ~ c => Person(a, c)
  }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, I got it to work like this. But I guess that it's not really possible to have object oriented entities that know how to parse themselves and then combine several of these together. And sharing parsers in libraries (other than very generic parsers) would also be quite awkward. Right?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.