Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Errors and failures in Scala Parser Combinators

I would like to implement a parser for some defined language using Scala Parser Combinators. However, the software that will compile the language does not implements all the language's feature, so I would like to fail if these features are used. I tried to forge a small example below :

object TestFail extends JavaTokenParsers {
  def test: Parser[String] =
    "hello" ~ "world" ^^ { case _ => ??? } |
    "hello" ~ ident ^^ { case "hello" ~ id => s"hi, $id" }
}

I.e., the parser succeeds on "hello" + some identifier, but fails if the identifier is "world". I see that there exist fail() and err() parsers in the Parsers class, but I cannot figure out how to use them, as they return Parser[Nothing] instead of a String. The documentation does not seem to cover this use case…

like image 998
scand1sk Avatar asked Jul 03 '13 12:07

scand1sk


2 Answers

In this case you want err, not failure, since if the first parser in a disjunction fails you'll just move on to the second, which isn't what you want.

The other issue is that ^^ is the equivalent of map, but you want flatMap, since err("whatever") is a Parser[Nothing], not a Nothing. You could use the flatMap method on Parser, but in this context it's more idiomatic to use the (completely equivalent) >> operator:

object TestFail extends JavaTokenParsers {
  def test: Parser[String] =
    "hello" ~> "world" >> (x => err(s"Can't say hello to the $x!")) |
    "hello" ~ ident ^^ { case "hello" ~ id => s"hi, $id" }
}

Or, a little more simply:

object TestFail extends JavaTokenParsers {
  def test: Parser[String] =
    "hello" ~ "world" ~> err(s"Can't say hello to the world!") |
    "hello" ~ ident ^^ { case "hello" ~ id => s"hi, $id" }
}

Either approach should do what you want.

like image 129
Travis Brown Avatar answered Sep 22 '22 03:09

Travis Brown


You could use ^? method:

object TestFail extends JavaTokenParsers {
  def test: Parser[String] =
    "hello" ~> ident ^? (
      { case id if id != "world" => s"hi, $id" },
      s => s"Should not use '$s' here."
  )
}
like image 34
senia Avatar answered Sep 20 '22 03:09

senia