I'm writing a parser, something like,
object MyParser:
def int[$: P]: P[Int] = digit.rep(1).!.map(s => s.toInt)
def digit[$: P]: P[Unit] = CharIn("0-9")
Now I'd like to test this in a test class. But I'd like to be able to test each parser separately, so even though in the context of the big parser, the parsers don't have to match the whole string, I'd like to write tests that try to, so partial matches will come out as failures.
class MyParserTest extends AnyFunSuite with Matchers:
def parseAll[$: P, T](p: => P[T]): P[T] = Start ~ p ~ End
test("int parses correctly") {
fastparse.parse("1234", parseAll(MyParser.int)) shouldBe Success(1234, 4)
}
(see the code in Scastie)
This gives the error
No given instance of type fastparse.ParsingRun[$] was found for an implicit parameter
of method int in object MyParser
where: $ is a type variable
which goes away if I just try
fastparse.parse("1234", MyParser.int)
I've tried importing MyParser.given
in the test, defining parseAll
in MyParser
rather than MyParserTest
, and general keyboard flailing to no avail.
Is there a way to wrap the parsers in Start
and End
when I'm testing them, or is there an implicit somewhere that I just can't get access to?
Try using Scala 2 syntax (still working in Scala 3 so far)
fastparse.parse("1234", implicit p => parseAll(MyParser.int(/*using*/ p)))
https://scastie.scala-lang.org/DmytroMitin/MrFZ0EhiSPeFDHd1IyBhrA
fastparse.parse("1234", implicit p => parseAll(MyParser.int))
https://scastie.scala-lang.org/DmytroMitin/MrFZ0EhiSPeFDHd1IyBhrA/28
Possible Scala 3 syntaxes are a little awkward:
fastparse.parse("1234", p => {given P[_] = p; parseAll(MyParser.int(/*using*/ p))})
https://scastie.scala-lang.org/DmytroMitin/MrFZ0EhiSPeFDHd1IyBhrA/11
fastparse.parse("1234", p => {given P[_] = p; parseAll(MyParser.int)})
https://scastie.scala-lang.org/DmytroMitin/MrFZ0EhiSPeFDHd1IyBhrA/21
fastparse.parse("1234", { case p @ given P[_] => parseAll(MyParser.int(/*using*/ p))})
https://scastie.scala-lang.org/DmytroMitin/MrFZ0EhiSPeFDHd1IyBhrA/13
fastparse.parse("1234", { case given P[_] => parseAll(MyParser.int)})
https://scastie.scala-lang.org/DmytroMitin/MrFZ0EhiSPeFDHd1IyBhrA/20
fastparse.parse("1234", p => parseAll(MyParser.int(/*using*/ p))(/*using*/ p))
https://scastie.scala-lang.org/DmytroMitin/MrFZ0EhiSPeFDHd1IyBhrA/16
It would be nice if fastparse.parse("1234", p ?=> parseAll(MyParser.int(p)))
worked, but this would require support on fastparse side.
correct Scala 3 syntax for providing a given from a higher order function argument