1
votes

I am creating a parser to parse a query string like this

e = "500.3" AND dt = "20190710" AND s in ("ERROR", "WARN") OR cat = "Conditional"

For the previous string I get the following: Exception in thread "main" scala.MatchError: (Identifier(e),(=,StringLiteral(500.3))) (of class scala.Tuple2)

I am assuming that my grammar is fine (maybe not). Maybe someone can help find out why I am getting this error. Here is my parser.

class SearchQueryParser extends StandardTokenParsers {
  lexical.reserved += ("OR", "AND")
  lexical.delimiters += ( "<", "=", "<>", "!=", "<=", ">=", ">",  "(", ")")

  def expr: Parser[QueryExp] = orExp
  def orExp: Parser[QueryExp] = andExp *("OR" ^^^ {(a: QueryExp, b: QueryExp) => BoolExp("OR", (a, b))})
  def andExp: Parser[QueryExp] = compareExp *("AND" ^^^ {(a: QueryExp, b: QueryExp) => BoolExp("AND", (a, b))})

  def compareExp: Parser[QueryExp] = {
    identifier ~ rep(("=" | "<>" | "!=" | "<" | "<=" | ">" | ">=") ~ literal ^^ {
      case op ~ rhs => (op, rhs)
    }) ^^ {
      case lhs ~ elems =>
        elems.foldLeft(lhs) {
          case (id, ("=", rhs: String)) => Binomial("=", id.str, rhs)
          case (id, ("<>", rhs: String)) => Binomial("!=", id.str, rhs)
          case (id, ("!=", rhs: String)) => Binomial("!=", id.str, rhs)
          case (id, ("<", rhs: String)) => Binomial("<", id.str, rhs)
          case (id, ("<=", rhs: String)) => Binomial("<=", id.str, rhs)
          case (id, (">", rhs: String)) => Binomial(">", id.str, rhs)
          case (id, (">=", rhs: String)) => Binomial(">=", id.str, rhs)
        }
      }
  }

  def literal: Parser[QueryExp] = stringLit ^^ (s => StringLiteral(s))
  def identifier: Parser[QueryExp] = ident ^^ (s => Identifier(s))

  def parse(queryStr: String): Option[QueryExp] = {
    phrase(expr)(new lexical.Scanner(queryStr)) match {
      case Success(r, _) => Option(r)
      case x => println(x); None
    }
  } 
}
1

1 Answers

1
votes

I was able to find the issue. It seems like the error was produced because the partial function in the foldLeft(lhs) statement wasn't matching the tuple (=,StringLiteral(500.3))

As you can see, in every case statement of the partial function, I am trying to match a rhs of type String

...
 case (id, ("=", rhs: String)) => Binomial("=", id.str, rhs)
 case (id, ("<>", rhs: String)) => Binomial("!=", id.str, rhs)
 case (id, ("!=", rhs: String)) => Binomial("!=", id.str, rhs)
...

However, as you can see in the error Exception in thread "main" scala.MatchError: (Identifier(e),(=,StringLiteral(500.3))) (of class scala.Tuple2) the input was parsed as a tuple of "=" and StringLiteral.

The solution was to change the type of the rhs parameter:

...
 case (id, ("=", rhs: StringLiteral)) => Binomial("=", id.str, rhs.toString)
 case (id, ("<>", rhs: StringLiteral)) => Binomial("!=", id.str, rhs.toString)
 case (id, ("!=", rhs: StringLiteral)) => Binomial("!=", id.str, rhs.toString)
...