Skip to content

Instantly share code, notes, and snippets.

@huynhjl
Created March 20, 2012 06:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save huynhjl/2132030 to your computer and use it in GitHub Desktop.
Save huynhjl/2132030 to your computer and use it in GitHub Desktop.
Question about parser combinator
// 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