2010-04-16 4 views
15

Biorąc pod uwagę rodzinę obiektów, które implementują kombinatory parserów, jak połączyć parsery? Od Parsers.Parser jest klasą wewnętrzną, a w Scala inner classes are bound to the outer object historia staje się nieco skomplikowana.Scala: Jak łączyć kombinatory parserów z różnych obiektów

Oto przykład, który próbuje połączyć dwa parsery z różnych obiektów.

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))) 
    } 
} 

Wynika to z następującego błędu:

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

Znalazłem rozwiązanie tego problemu już, ale ponieważ została wychowana niedawno na scala użytkowników ml (Problem injecting one parser into another), to prawdopodobnie warto to tutaj umieścić.

Odpowiedz

17

Szybka odpowiedź jest użycie trait S zamiast gospodarzem Parsery w object s:

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))) 
    } 
} 

Ponieważ operatorzy COMBINATOR jak ~ i | są zapisywane na wewnętrznej klasy, eskalacji odniesień parser klasie -pozostawiając, że BinaryParser#Parser[_] nic ci nie daje. Korzystanie z cech rozwiązuje wszystkie problemy z klasą wewnętrzną, ponieważ zarówno Parser[Any] z i ShortChainParser odnoszą się teraz do wewnętrznej klasy obiektu ExampleParser.

+1

Dziękujemy za opublikowanie tego pytania i oczywiście za udzielenie odpowiedzi! Właśnie tego szukałem. –