Search code examples
regexscalaparsingparser-combinators

Scala Parser Combinators :Extract List of a type


I am writing parser and grammer using scala.util.parsing.combinator . My input is ":za >= 1 alok && :ft == 9"

case class Expression(op1:Operand,operator:Operator,op2:Operand)

def word: Parser[String] = """[a-z\\\s]+""".r ^^ { _.toString }

def colonWord:Parser[Operand]=":"~> word ^^{case variable => Operand(variable)}

def constant:Parser[Operand]="""^[a-zA-Z0-9\\\s-]*""".r ^^ {case constant => Operand(constant)}

def expression:Parser[Expression] = colonWord ~ operator ~ constant  ^^{ case op1~operator~op2 => Expression(op1, operator, op2)}

def expressions = expression ~ opt(" && " ~> expression)* 

but when I parse sample String , the result is not expected. The second expression after && is not parsed. Please note there can be multiple expression joined using &&.

When i execute:

val expr= ":za >= 1 alok && :ft == 9"
    parse(expressions, expr) match {
      case Success(matched, _) => println(matched)
      case ..}

Output is :

List((Expression(za ,>= ,1 alok )~None))

I dont see the second expression being parsed. Can anyone help what have i missed here?

EDIT -----------------------------------

The requirement is to get List[Expression]. when I say, incorporting the changes mentioned in Ans :

def expressions = expression ~ ("&&" ~> expression)* 

The return type of expressions is not List[Expression]. For eg: If I write another def :

case class Condition(exprs: List[Expression], st:Statement)
def condition = expressions ~","~statement ^^{
    case exprs~commaa~statement => Condition(exprs,statement) //This is giving error.

the error is: type mismatch; found : ~[Expression,Expression]] required: Expressions.

So how do i convert [Expression, Expression] to List[Expressions]?

Thanks


Solution

  • The correction needed was:

    expression ~ opt("&&" ~> expression)*
    

    Remove space across && and it should work. This is because you are already covering space in your constant parser.

    Edit: Based on edited question, is this what you want:

     def expressions = expression ~ (("&&" ~> expression)*) ^^{
        case x ~ y => x :: y
      }
    

    Now the return type of expressions is List[Expression]. Your condition will now compile