I have the following code being compiled against scala 2.8.0:
import scala.util.parsing.combinator.{syntacti开发者_C百科cal,PackratParsers}
import syntactical.StandardTokenParsers
object MyParser extends StandardTokenParsers with PackratParsers{
lexical.reserved ++= Set("int","char","boolean")
lazy val primitiveType:PackratParser[PrimitiveType[_]] = primitiveChar | primitiveInt | primitiveBool
lazy val primitiveInt:PackratParser[PrimitiveType[Int]] = "int" ^^ { _ => PrimitiveType[Int]() }
lazy val primitiveChar:PackratParser[PrimitiveType[Char]] = "char" ^^ { _ => PrimitiveType[Char]() }
lazy val primitiveBool:PackratParser[PrimitiveType[Boolean]] = "boolean" ^^ { _ => PrimitiveType[Boolean]() }
}
object MyParser2 extends StandardTokenParsers with PackratParsers{
lexical.reserved ++= Set("int","char","boolean")
lazy val primitiveType:PackratParser[PrimitiveType[_]] = primitiveChar | primitiveIntOrBool
lazy val primitiveIntOrBool:PackratParser[PrimitiveType[_]] = "int" ^^ { _ => PrimitiveType[Int]() } | "boolean" ^^ {_ => PrimitiveType[Boolean]()}
lazy val primitiveChar:PackratParser[PrimitiveType[Char]] = "char" ^^ { _ => PrimitiveType[Char]()}
}
case class PrimitiveType[T]()
Compiling MyParser1 gives:
error: inferred type arguments [this.PrimitiveType[_ >: _1 with Boolean <: AnyVal]] do not conform to method |'s type parameter bounds [U >: this.PrimitiveType[_ >: Char with Int <: AnyVal]]
I believe it fails because of the | method type signature, defined as:
def | [U >: T](q: => Parser[U]): Parser[U]
why does U have to be a supertype of T? What should be the return value of "primitiveType"?
You need to change your last line into
case class PrimitiveType[+T]()
This allows for PrimitiveType[Int] <: PrimitiveType[AnyVal] which is needed when you want to merge the results of PrimitiveType[Boolean] and PrimitiveType[Int] parsers via |.
BTW, I would also suggest to write
PrimitiveType[AnyVal]
instead of
PrimitiveType[_]
since this is more precise in your case.
You might be better changing your generic case class PrimitiveType[T]
to a class hierarchy. The generic type parameters aren't available at runtime, so you won't be able to do much with your parse results...
This would give you the following (untested code now tested):
object MyParser extends StandardTokenParsers with PackratParsers{
lexical.reserved ++= Set("int","char","boolean")
lazy val primitiveType:Parser[PrimitiveType] = primitiveChar | primitiveInt | primitiveBool
lazy val primitiveInt:PackratParser[PrimitiveType] = "int" ^^^ PrimitiveInt
lazy val primitiveChar:PackratParser[PrimitiveType] = "char" ^^^ PrimitiveChar
lazy val primitiveBool:PackratParser[PrimitiveType] = "boolean" ^^^ PrimitiveBoolean
}
sealed trait PrimitiveType
case object PrimitiveInt extends PrimitiveType
case object PrimitiveChar extends PrimitiveType
case object PrimitiveBoolean extends PrimitiveType
精彩评论