views:

90

answers:

2

I have the following code being compiled against scala 2.8.0:

import scala.util.parsing.combinator.{syntactical,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"?

+4  A: 

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.

Stefan Endrullis
Ah, good answer. I'm retracting mine.
pelotom
Thanks, of course that solved my problem. However, I'm still missing why is U >: T required in |.
kmels
@kmels `U` must be a supertype of `T` because `|` constructs a compound parser which will produce either `T` or `U`. In practice, given `T | S`, the compiler will search for a *least upper bound* of `T` and `S` in the type hierarchy, and call that `U`.
pelotom
+2  A: 

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
Ben Lings