Search code examples
scalaparser-combinators

Scala parsing left-associative subscript operator


I've mastered this syntax for building a left-associative tree for infix operators:

term * (
        "+" ^^^ { (a:Expr, b:Expr) => new FunctionCall(plus, a::b::Nil) } |
        "-" ^^^ { (a:Expr, b:Expr) => new FunctionCall(minus, a::b::Nil) } )

Though I have to confess I don't fully understand how it works. What I want to do now is to achieve a similar effect for syntax that might look like

a[b](c)(d)[e]

which should parse as

sub(call(call(sub(a, b), c), d), e)

Can the high-level "^^^" magic be extended to cover a case where it's not a pure infix operator? Or do I have to implement some kind of fold-left logic myself? If so, any hints as to what it might look like?


Solution

  • I have solved the problem as follows. I'm happy with the solution, but if any Scala experts out there can help me improve it, that's very welcome.

      def subscript: Parser[Expr => Expr] = {
        "[" ~> expr <~ "]" ^^ {
          case sub => {
            { (base: Expr) => new FunctionCall(subscriptFn, base :: sub :: Nil)}
          }
        }
      }
    
      def argumentList: Parser[Expr => Expr] = {
        "(" ~> repsep(expr, ",") <~ ")" ^^ {
          case args => {
            { (base: Expr) => new FunctionCall(base :: args)}
          }
        }
      }
    
      def postfixExpr: Parser[Expr] = {
        primary ~ rep ( subscript | argumentList ) ^^ {
          case base ~ suffixes => {
            (base /: suffixes)((b:Expr, f:Expr=>Expr) => f(b))
          }
        }
      }