Stave Escura
Stave Escura

Reputation: 2098

Scala Parser Combinator compilation issue: failing to match multiple variables in case

I am learning how to use the Scala Parser Combinators, which by the way are lovely to work with.

Unfortunately I am getting a compilation error. I have read, and recreated the worked examples from: http://www.artima.com/pins1ed/combinator-parsing.html <-- from Chapter 31 of Programming in Scala, First Edition, and a few other blogs.

I've reduced my code to a much simpler version to demonstrate my problem. I am working on parser that would parse the following samples

if a then x else y
if a if b then x else y else z

with a little extra that the conditions can have an optional "/1,2,3" syntax

if a/1 then x else y
if a/2,3 if b/3,4 then x else y else z

So I have ended with the following code

 def ifThenElse: Parser[Any] = 
    "if" ~> condition ~ inputList ~ yes ~> "else" ~ no 
 def condition: Parser[Any] = ident
 def inputList: Parser[Any] = opt("/" ~> repsep(input, ","))
 def input: Parser[Any] = ident
 def yes: Parser[Any] = "then" ~> result | ifThenElse
 def no: Parser[Any] = result | ifThenElse
 def result: Parser[Any] = ident

Now I want to add some transformations. I now get a compilation error on the second ~ in the case:

  def ifThenElse: Parser[Any] =
    "if" ~> condition ~ inputList ~ yes ~> "else" ~ no ^^ {
      case c ~ i ~ y ~ n => null
                 ^ constructor cannot be instantiated to expected type; found : SmallestFailure.this.~[a,b] required: String

When I change the code to

   "if" ~> condition ~ inputList ~ yes ~> "else" ~ no ^^ {
      case c ~ i => println("c: " + c + ", i: " + i)                 

I expected it not to compile, but it did. I thought I would need a variable for each clause. When executed (using parseAll) parsing "if a then b else c" produces "c: else, i: c". So it seems like c and i are the tail of the string.

I don't know if it is significant, but none of the example tutorials seem to have an example with more than two variables being matched, and this is matching four

Upvotes: 2

Views: 438

Answers (1)

gzm0
gzm0

Reputation: 14842

You do not have to match the "else":

def ifThenElse: Parser[Any] =
    "if" ~> condition ~ inputList ~ (yes <~ "else") ~ no ^^ {
      case c ~ i ~ y ~ n => null
    }

Works as expected.

Upvotes: 0

Related Questions