Search code examples
scalafastparse

scala fastparse typechecking


I am puzzled by why the following code using scala fastparse 0.4.3 fails typechecking.

val White = WhitespaceApi.Wrapper{
  import fastparse.all._
  NoTrace(CharIn(" \t\n").rep)
}
import fastparse.noApi._
import White._

case class Term(tokens: Seq[String])
case class Terms(terms: Seq[Term])

val token = P[String] ( CharIn('a' to 'z', 'A' to 'Z', '0' to '9').rep(min=1).!)
val term: P[Term] = P("[" ~ token.!.rep(sep=" ", min=1) ~ "]").map(x => Term(x))
val terms = P("(" ~ term.!.rep(sep=" ", min=1) ~ ")").map{x => Terms(x)}
val parse = terms.parse("([ab bd ef] [xy wa dd] [jk mn op])")

The error messages:

[error] .../MyParser.scala: type mismatch;
[error]  found   : Seq[String]
[error]  required: Seq[Term]
[error]     val terms = P("(" ~ term.!.rep(sep=" ", min=1) ~")").map{x => Terms(x)}
[error]                                                                         ^

I would imagine that since term is of type Term and since the terms pattern uses term.!.rep(..., it should get a Seq[Term].


Solution

  • I figured it out. My mistake was capturing (with !) redundantly in terms. That line should instead be written:

    val terms = P("(" ~ term.rep(sep=" ", min=1) ~ ")").map{x => Terms(x)}
    

    Notice that term.!.rep( has been rewritten to term.rep(. Apparently capturing in any rule will return the text that the captured subrule matches overriding what the subrule actually returns. I guess this is a feature when used correctly. :)