2010-04-16 1 views
15

Учитывая, что существует множество объектов, реализующих комбинаторы парсеров, как объединить парсеры? Поскольку Parsers.Parser является внутренним классом, а в Scala inner classes are bound to the outer object история становится немного сложной.Scala: Как совместить комбинаторы парсеров от разных объектов?

Вот пример, который пытается объединить два парсера из разных объектов.

import scala.util.parsing.combinator._ 

class BinaryParser extends JavaTokenParsers { 
    def anyrep: Parser[Any] = rep(any) 
    def any: Parser[Any] = zero | one 
    def zero: Parser[Any] = "0" 
    def one: Parser[Any] = "1" 
} 

object LongChainParser extends BinaryParser { 
    def parser1: Parser[Any] = zero~zero~one~one 
} 

object ShortChainParser extends BinaryParser { 
    def parser2: Parser[Any] = zero~zero 
} 

object ExampleParser extends BinaryParser { 
    def parser: Parser[Any] = (LongChainParser.parser1 
    ||| ShortChainParser.parser2) ~ anyrep 

    def main(args: Array[String]) { 
    println(parseAll(parser, args(0))) 
    } 
} 

Это приводит к следующей ошибке:

<console>:11: error: type mismatch; 
found : ShortChainParser.Parser[Any] 
required: LongChainParser.Parser[?] 
     def parser: Parser[Any] = (LongChainParser.parser1 
      ||| ShortChainParser.parser2) ~ anyrep 

Я нашел решение этой проблемы уже, но так как он был воспитан недавно на Scala-пользователя ML (Problem injecting one parser into another), это вероятно, стоит поставить его здесь тоже.

ответ

17

Быстрый ответ использовать trait S вместо хостинга Парсеров в object с:

import scala.util.parsing.combinator._ 

trait BinaryParser extends JavaTokenParsers { 
    def anyrep: Parser[Any] = rep(any) 
    def any: Parser[Any] = zero | one 
    def zero: Parser[Any] = "0" 
    def one: Parser[Any] = "1" 
} 

trait LongChainParser extends BinaryParser { 
    def parser1: Parser[Any] = zero~zero~one~one 
} 

trait ShortChainParser extends BinaryParser { 
    def parser2: Parser[Any] = zero~zero 
} 

object ExampleParser extends LongChainParser with ShortChainParser { 
    def parser: Parser[Any] = (parser1 ||| parser2) ~ anyrep 

    def main(args: Array[String]) { 
    println(parseAll(parser, args(0))) 
    } 
} 

Поскольку операторы Combinator как ~ и | написаны против внутреннего класса, наращивание ссылок синтаксического анализатора класса -level, говоря, что BinaryParser#Parser[_] вам не приносит пользы. Использование признаков решает все проблемы внутреннего класса, поскольку оба Parser[Any] от LongChainParser и ShortChainParser теперь относятся к внутреннему классу объекта ExampleParser.

+1

Спасибо, что ответили на этот вопрос и, конечно, ответили! Это именно то, что я искал. –