I wrote a parser to act as a lexer. This lexer parses a file and returns a list of tokens, each of which is a case class or object that extends a common trait.
I am now trying to write a parser for the output of the lexer, but I have hit a very confusing snag. The parser is happy to implicitly cast my case objects, but throws a fit if I even try to call apply(classHere) manually.
The following is a simplified version of my code:
// CODE
trait Token
case class StringWrapperIgnoresCase(val string: String) {
private case class InnerWrapper(s: String)
lazy val lower = string.toLowerCase
override lazy val hashCode = InnerWrapper(lower).hashCode
override def equals(that: Any) =
that.isInstanceOf[StringWrapperIgnoresCase] &&
lower == that.asInstanceOf[StringWrapperIgnoresCase].lower
}
case class ID(val text: String)
extends StringWrapperIgnoresCase(text)
with Token {
override def toString = "ID(" + text + ")"
}
case object PERIOD extends Token
object Parser extends Parsers {
type Elem = Token
def doesWork: Parser[Token] = PERIOD
def doesNotWork: Parser[Token] = ID
}
The compiler reports the following message about doesNotWork:
// ERROR MESSAGE
type mismatch; found : alan.parser.ID.type (with underlying type object alan.parser.ID) required: alan.parser.Parser.Parser[alan.parser.Token]
How can I fix this?
Update: It wasn’t clear to me from your question exactly what you were asking, but now that you’ve specified that you want a parser that matches any
IDin your answer, here’s a more idiomatic solution:Here you’ve provided a description of what the parser wants (for error messages) and a partial function with
IDs as its domain. You could also use theacceptIfversion that xiefei provides in a comment on your answer.When you refer to a case class (as opposed to a case object) without a parameter list, you get the automatically generated companion object, which is not an instance of the class itself. Consider the following:
Now
Baz: Foois just fine, butBar: Foowill give an error very similar to what you’re seeing.Note also that what’s happening here isn’t strictly casting. The
Parserstrait has a method with the following signature:When you write this:
You’re trying to type an
Elemas aParser[Elem], and the implicit conversion kicks in (see section 7.3 of the spec for more information about implicit conversions). When you write this, on the other hand:You’re trying to type the
IDcompanion object (which has typeID.type, notIDorToken, and therefore notElem) as aParser[Elem], and there’s no implicit conversion that makes this possible.You’re probably better off writing out
accept(PERIOD)andaccept(ID("whatever")), for now, at least, and obeying the deprecation warning that says the following when you try to compile your code: