Skip to content

Instantly share code, notes, and snippets.

@icejoywoo
Last active June 25, 2019 06:14
Show Gist options
  • Save icejoywoo/706edf1a7e9d277f5349c44990b4e81a to your computer and use it in GitHub Desktop.
Save icejoywoo/706edf1a7e9d277f5349c44990b4e81a to your computer and use it in GitHub Desktop.
a simple calculator or expression in scala combinators
import scala.collection.mutable
import scala.util.parsing.combinator._
class Arith extends JavaTokenParsers {
var env: mutable.Map[String, Double] = mutable.Map.empty
def expr: Parser[Double] = term~rep("+"~term | "-"~term) ^^ {
case term~ops =>
ops.foldLeft(term) {
case (a, "+"~b) => a + b
case (a, "-"~b) => a - b
}
}
def term: Parser[Double] = factor~rep("*"~factor | "/"~factor) ^^ {
case factor~ops =>
ops.foldLeft(factor) {
case (a, "*"~b) => a * b
case (a, "/"~b) => a / b
}
}
def factor: Parser[Double] = (
floatingPointNumber ^^ { _.toDouble }
| ("-" | "+")~floatingPointNumber ^? ({
case "-"~v => -v.toDouble
case "+"~v => v.toDouble
}, { i => s"unexpected error [$i]" })
| ident ^? ({ case i if env.contains(i) => env(i) }, { i => s"$i is not found in context"})
| ("-" | "+")~ident ^? ({
case "-"~v if env.contains(v) => -env(v)
case "+"~v if env.contains(v) => env(v)
}, { case _~i => s"$i is not found in context" })
| "(" ~> expr <~ ")"
)
}
object TestArith extends Arith {
def main(args: Array[String]): Unit = {
env += "a" -> 5
env += "b" -> 6
env += "c" -> 7
assert(parseAll(expr, "2 * (3 + 7) * a + (b + c) * c").get == 191.0)
assert(parseAll(expr, "2 * (3 + 7) * (a + (b + c) * c)").get == 1920.0)
assert(parseAll(expr, "a + 4").get == 9.0)
assert(parseAll(expr, "((a) + (4))").get == 9.0)
assert(parseAll(expr, "a / 20 + 10 + a * b + c * 10").get == 110.25)
assert(parseAll(expr, "+5").get == 5.0)
assert(parseAll(expr, "-a").get == -5.0)
parseAll(expr, "2 * (3 + 7)") match {
case Success(matched,_) => println(matched)
case Failure(msg,_) => println("FAILURE: " + msg)
case Error(msg,_) => println("ERROR: " + msg)
}
parseAll(expr, "2 * (3 + 7))") match {
case Success(matched,_) => println(matched)
case Failure(msg,_) => println("FAILURE: " + msg)
case Error(msg,_) => println("ERROR: " + msg)
}
assert(!parseAll(expr, "2 * (3 + 7))").successful)
assert(!parseAll(expr, "(2 * (3 + 7)").successful)
}
}
object TestArith2 {
def main(args: Array[String]): Unit = {
val a = new Arith
a.env ++= Map(
"a" -> 5,
"b" -> 6,
"c" -> 7
)
assert(a.parseAll(a.expr, "2 * (3 + 7) * a + (b + c) * c").get == 191.0)
assert(a.parseAll(a.expr, "2 * (3 + 7) * (a + (b + c) * c)").get == 1920.0)
assert(a.parseAll(a.expr, "a + 4").get == 9.0)
assert(a.parseAll(a.expr, "((a) + (4))").get == 9.0)
assert(a.parseAll(a.expr, "a / 20 + 10 + a * b + c * 10").get == 110.25)
assert(!a.parseAll(a.expr, "2 * (3 + 7))").successful)
assert(!a.parseAll(a.expr, "(2 * (3 + 7)").successful)
}
}
import com.twitter.util.Eval
object EvalDemo {
def main(args: Array[String]): Unit = {
val eval = new Eval
eval.compile(
"""
|object Env {
| val a = 5
|}
""".stripMargin)
println(eval.inPlace[Int]("import Env._; a"))
}
}
@icejoywoo
Copy link
Author

icejoywoo commented Jun 13, 2019

<dependency>
    <groupId>org.scala-lang.modules</groupId>
    <artifactId>scala-parser-combinators_2.12</artifactId>
    <version>1.1.2</version>
</dependency>

<dependency>
    <groupId>com.twitter</groupId>
    <artifactId>util-eval_2.11</artifactId>
    <version>6.43.0</version>
</dependency>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment