Created
March 20, 2012 06:33
-
-
Save huynhjl/2132030 to your computer and use it in GitHub Desktop.
Question about parser combinator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// http://stackoverflow.com/questions/9780196/scala-creating-a-basic-dynamic-function-parser | |
import scala.util.parsing.combinator._ | |
object Expr { type VARS = Map[String, Any] } | |
import Expr._ | |
sealed trait Expr { def eval(v: VARS) : Any } | |
case class If(cond: Cond, ifTrue: Expr, ifFalse: Expr) extends Expr { | |
def eval(v: VARS) = | |
if (cond.eval(v)) ifTrue.eval(v) else ifFalse.eval(v) | |
} | |
case class Cond(left: Expr, right: Expr) extends Expr { | |
def eval(v: VARS) = left.eval(v) == right.eval(v) | |
} | |
case class Len(ident: String) extends Expr { | |
def eval(v: VARS) = v(ident).toString.size | |
} | |
case class Mid(ident: String, start: Expr, count: Expr) extends Expr { | |
def eval(v: VARS) = { | |
val s = start.eval(v).asInstanceOf[Int] | |
val e = s + count.eval(v).asInstanceOf[Int] | |
v(ident).asInstanceOf[String].substring(s, e) | |
} | |
} | |
case class Ident(ident: String) extends Expr { def eval(v: VARS) = v(ident) } | |
case class StringLit(value: String) extends Expr { def eval(v: VARS) = value } | |
case class Number(value: String) extends Expr { def eval(v: VARS) = value.toInt } | |
class Equation extends JavaTokenParsers { | |
def IF: Parser[If] = "IF" ~ "(" ~ booleanExpr ~ "," ~ expr ~ "," ~ expr ~ ")" ^^ { | |
case "IF" ~ "(" ~ booleanExpr ~ "," ~ ifTrue ~ "," ~ ifFalse ~ ")" => | |
If(booleanExpr, ifTrue, ifFalse) | |
} | |
def LEN: Parser[Len] = "LEN" ~> "(" ~> ident <~ ")" ^^ (Len(_)) | |
def MID: Parser[Mid] = "MID" ~ "(" ~ ident ~ "," ~ expr ~ "," ~ expr ~ ")" ^^ { | |
case "MID" ~ "(" ~ ident ~ "," ~ expr1 ~ "," ~ expr2 ~ ")" => Mid(ident, expr1, expr2) | |
} | |
def expr: Parser[Expr] = ( | |
stringLiteral ^^ (StringLit(_)) | |
| wholeNumber ^^ (Number(_)) | |
| LEN | |
| MID | |
| IF | |
| ident ^^ (Ident(_)) | |
) | |
def booleanExpr: Parser[Cond] = expr ~ "=" ~ expr ^^ { | |
case expr1 ~ "=" ~ expr2 => Cond(expr1, expr2) | |
} | |
} | |
object A extends App { | |
val equation = new Equation | |
val parsed = equation.parseAll(equation.expr, | |
"""IF(LEN(param1)=4,MID(param1,2,1), MID(param1,0,LEN(param1)))""") | |
parsed match { | |
case equation.Success(expr, _) => | |
println(expr) | |
println(expr.eval(Map("param1" -> "scala"))) | |
println(expr.eval(Map("param1" -> "scat"))) | |
case _ => | |
println("cannot parse") | |
} | |
} | |
// vim:set ts=2 sw=2 et: |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment