2010-04-16 3 views
15

Bei einer Familie von Objekten, die Parser-Kombinatoren implementieren, wie kombiniere ich die Parser? Da Parsers.Parser eine innere Klasse ist, und in Scala inner classes are bound to the outer object, wird die Geschichte etwas kompliziert.Scala: Kombinieren von Parser-Kombinatoren aus verschiedenen Objekten

Hier ist ein Beispiel, das versucht, zwei Parser aus verschiedenen Objekten zu kombinieren.

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

Dies führt zu dem folgenden Fehler:

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

ich die Lösung für dieses Problem bereits gefunden habe, aber da es bis kürzlich auf scala-Benutzer ML (Problem injecting one parser into another) gebracht wurde, ist es wahrscheinlich lohnt es sich auch hier zu platzieren.

Antwort

17

Die schnelle Antwort ist die trait s zu verwenden, anstatt die Parser in object s Hosting:

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

Da die combinator Operatoren wie ~ und | gegen die innere Klasse geschrieben werden, eskaliert die Parser Verweise auf Klasse -Ebene mit dem Sprichwort BinaryParser#Parser[_] tut dir nichts Gutes. Die Verwendung von Merkmalen löst all diese inneren Klassenprobleme, da sich sowohl Parser[Any] von LongChainParser als auch ShortChainParser jetzt auf die innere Klasse von ExampleParser beziehen.

+1

Danke für das Posten dieser Frage und natürlich für die Beantwortung! Genau das habe ich gesucht. –