Given a family of objects that implement parser combinators, how do I combine the parsers? Since Parsers.Parser
is an inner class, and in Scala inner classes are bound to the outer object , the story becomes slightly complicated.
Here's an example that attempts to combine two parsers from different objects.
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) ))
}
}
This results to the following error:
<console>:11: error: type mismatch;
found : ShortChainParser.Parser[Any]
required: LongChainParser.Parser[?]
def parser: Parser[Any] = (LongChainParser.parser1
||| ShortChainParser.parser2) ~ anyrep
I've found the solution to this problem already, but since it was brought up recently on scala-user ML ( Problem injecting one parser into another ), it's probably worth putting it here too.
The quick answer is to use the trait
s instead of hosting the parsers in 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) ))
}
}
Because the combinator operators like ~
and |
are written against the inner class, escalating the parser references to class-level by saying BinaryParser#Parser[_]
doesn't do you any good. Using traits solves all that inner-class issues since both Parser[Any]
from LongChainParser
and ShortChainParser
now refer to the inner class of ExampleParser
object.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.