关于解析:如何使用Scala解析器组合器解析层次结构实体

How to parse hierarchical entities using Scala parser combinators

我正在尝试使用Scala解析器组合器解析实体以及组成该实体字段的实体。我想通过让每个子实体都知道如何解析自身来做到这一点。

我的问题可以由具有AddressCarPerson类重现。这是AddressCar类的外观以及它们的解析方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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);
  }

}

我遇到问题的地方是当我尝试组合解析器以解析Person

1
2
3
4
5
6
7
8
9
10
11
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);
  }

}

我得到的编译器错误是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[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]                                           ^

如何将两个解析器组合成可以解析完整的Person对象的解析器?


为了组合Parser,它们需要具有相同的type Elem定义。当具有AddressCarPerson伴随对象与JavaTokenParsers分开扩展时,编译器将无法推断出它们都是同一类型,因为它们将具有不同的Elem实例。

尝试将所有解析器放在同一个同伴对象下,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
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)
  }
}