Scala: cómo combinar combinadores de parser de diferentes objetos
parsing parser-combinators (1)
La respuesta rápida es usar el trait
s en lugar de alojar los analizadores en el 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) ))
}
}
Debido a que los operadores combinator como ~
y |
están escritas contra la clase interna, escalando las referencias del analizador a nivel de clase diciendo que BinaryParser#Parser[_]
no le hace ningún bien. El uso de rasgos resuelve todos los problemas de clase interna, ya que tanto el Parser[Any]
de LongChainParser
como el de ShortChainParser
se refieren a la clase interna del objeto ExampleParser
.
Dada una familia de objetos que implementan combinadores de analizadores, ¿cómo combino los analizadores? Como Parsers.Parser
es una clase interna, y en Scala las clases internas están vinculadas al objeto externo , la historia se vuelve un poco complicada.
Aquí hay un ejemplo que intenta combinar dos analizadores de diferentes objetos.
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) ))
}
}
Esto da lugar al siguiente error:
<console>:11: error: type mismatch;
found : ShortChainParser.Parser[Any]
required: LongChainParser.Parser[?]
def parser: Parser[Any] = (LongChainParser.parser1
||| ShortChainParser.parser2) ~ anyrep
Ya he encontrado la solución a este problema, pero como se mencionó recientemente en scala-user ML ( Problema al inyectar un analizador en otro ), probablemente también valga la pena ponerlo aquí.