0

I tried this

import scala.util.parsing.combinator._  
def name = ident ^^ {case ident => if (ident.contains("a")) ident.toUpperCase else ident 

println(parseAll(name, "aa")) // parsed: AA
println(parseAll(name, "bb")) 

with output

[1.3] parsed: AA
[1.3] parsed: bb
[1.1] failure: `(' expected but `a' found

aa
^
[1.3] failure: end of input expected

f1(aa)
  ^

As you see, second parsing fails. It seems that failure in the first production stops from trying the second alternative. I actually want depending on the value of first indentifier to choose this or that parser to continue.

1 Answers1

0

It can be done returning Failure, which will pass the ball to the subsequent alternative (do not confuse Failure with failure. The second will stop the parsing)

def name = new Parser[String] {
  def apply(s: Input) = ident(s) match {
    case Success(ident, rem) => if (ident.contains("a")) Success(ident.toUpperCase, rem) else Failure("identifier with 'a' expected", s)
    case a => a
  }
} | ident 

This enables the real semantic dispatching of the productions

def pkg(prefix: String): Parser[_] = "." ~> name ^^ {case arg => s"P:$prefix.$arg"}
def function(fID: String): Parser[_] = "(" ~> name <~ ")" ^^ {case arg => s"F:$fID($arg)"}
val env = Map("p1" -> pkg _, "p2" -> pkg _, "f1" -> function _)

def name = new Parser[Any] {
  def apply(s: Input) = ident(s) match {
    case Success(ident, rem) => env.get(ident) match {
        case Some(parser) => parser(ident)(rem)
        case _ => Failure(s"object $ident not found", s)
    } ; case a => a // how can we monade this identity?
  }
} | ident

// test inputs
List("aaa","f1(bb)","p1.p2.c","f1(f1(c))","f1(f1(p1.f1(bbb)))","aaa(bb(.cc(bbb)))") foreach {
    input => println(s"$input => " + parseAll(name, input))
}

Here names are parsed. Parser first tries an identifier. It semantically checks if the identifier is known in the context as function or package. If it does not, it falls back to simple identifier parser. This is stupid but this is what I asked for. The demo parsing is

aaa => [1.4] parsed: aaa
f1(bb) => [1.7] parsed: F:f1(bb)
p1.p2.c => [1.8] parsed: P:p1.P:p2.c
f1(f1(c)) => [1.10] parsed: F:f1(F:f1(c))
f1(f1(p1.f1(bbb))) => [1.19] parsed: F:f1(F:f1(P:p1.F:f1(bbb)))
aa(b) => [1.3] failure: end of input expected

aa(b)
  ^
f1(cc.dd) => [1.6] failure: `)' expected but `.' found

f1(cc.dd)
     ^

The errors are expected: f1 is the only defined function and aa is not one of them. Therefore, it is consumed as identifier, leaving (b) unconsumed. Similarly, cc is consumed as simple identifier because it is not a defined package.