简体   繁体   中英

How to parse hierarchical entities using Scala parser combinators

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?

In order to combine Parser s 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)
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM