From 25351c317c19c734bb3ce875c3bb8d9612cc9ccb Mon Sep 17 00:00:00 2001 From: octalsrc Date: Tue, 4 Apr 2017 03:00:28 -0600 Subject: [PATCH 1/6] Reorganize into general interpreter (WIP) --- .../cuanto/scoot/arithmetic/Interpreter.scala | 77 ------------------- .../scoot/interpreter/control/package.scala | 14 ++++ .../interpreter/expression/Arithmetic.scala | 63 +++++++++++++++ .../expression}/Builder.scala | 0 .../interpreter/expression/package.scala | 18 +++++ .../scoot/interpreter/mutation/package.scala | 28 +++++++ 6 files changed, 123 insertions(+), 77 deletions(-) delete mode 100644 src/main/scala/edu/colorado/plv/cuanto/scoot/arithmetic/Interpreter.scala create mode 100644 src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/control/package.scala create mode 100644 src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/Arithmetic.scala rename src/main/scala/edu/colorado/plv/cuanto/scoot/{arithmetic => interpreter/expression}/Builder.scala (100%) create mode 100644 src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/package.scala create mode 100644 src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/mutation/package.scala diff --git a/src/main/scala/edu/colorado/plv/cuanto/scoot/arithmetic/Interpreter.scala b/src/main/scala/edu/colorado/plv/cuanto/scoot/arithmetic/Interpreter.scala deleted file mode 100644 index 2c6c882..0000000 --- a/src/main/scala/edu/colorado/plv/cuanto/scoot/arithmetic/Interpreter.scala +++ /dev/null @@ -1,77 +0,0 @@ -package edu.colorado.plv.cuanto.scoot -package arithmetic - -import soot._ -import soot.jimple._ - -import scala.collection.immutable.HashMap - -/** Implement an interpreter for sequences of Jimple assignment - * statements that represent integer arithmetic programs - */ -object Interpreter { - - /** An "execution environment" or state, mapping variables (of type - * `Local`) to integer values */ - type Env = Map[Local,Int] - - /** An environment with no assigned variables */ - val emptyEnv: Env = new HashMap[Local,Int]() - - private def some[A](a: A): Option[A] = Some(a) - - /** Step an environment forward over a single statement */ - def step(stmt: AssignStmt)(env: Env): Option[Env] = { - val varNameO: Option[Local] = stmt.getLeftOp() match { - case l: Local => Some(l) - case _ => None - } - val newValueO: Option[Int] = denote(stmt.getRightOp(), env) - for { - varName <- varNameO - newValue <- newValueO - } yield env + (varName -> newValue) - } - - - /** Interpret the integer value of a variable mutated over a sequence - * of assignment statements */ - def denote(ss: Traversable[AssignStmt], v: Local): Option[Int] = - denote(ss).flatMap(_ get v) - - def denote(ss: Traversable[AssignStmt]): Option[Env] = - ss.foldLeft(some(emptyEnv))((env,stmt) => env.flatMap(step(stmt))) - - /** Interpret arithmetic expressions encoded as a single `Value` */ - def denote(v: Value, env: Env = emptyEnv): Option[Int] = v match { - case v: Local => env get v - case v: IntConstant => Some(v.value) - case v: BinopExpr => for { - op <- bop(v) - arg1 <- denote(v.getOp1(), env) - arg2 <- denote(v.getOp2(), env) - } yield op(arg1, arg2) - case v: UnopExpr => for { - op <- uop(v) - arg <- denote(v.getOp(), env) - } yield op(arg) - } - - /** Interpret an arithmetic unary operator node, getting back a - * function that performs the operation */ - def uop(op: UnopExpr): Option[Int => Int] = op match { - case _: NegExpr => Some(_ * -1) - case _ => None - } - - /** Interpret an arithemetic binary operator node, getting back a - * function that performs the operation */ - def bop(op: BinopExpr): Option[(Int, Int) => Int] = op match { - case _: AddExpr => Some(_ + _) - case _: SubExpr => Some(_ - _) - case _: DivExpr => Some(_ / _) - case _: MulExpr => Some(_ * _) - case _ => None - } - -} diff --git a/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/control/package.scala b/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/control/package.scala new file mode 100644 index 0000000..e306dba --- /dev/null +++ b/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/control/package.scala @@ -0,0 +1,14 @@ +package edu.colorado.plv.cuanto.scoot.interpreter +package control + +import soot.{Unit => SootUnit} +import soot.toolkits.graph.UnitGraph + +import expression.Env + +package object control { + + def succ(graph: UnitGraph)(env: Env, unit: SootUnit): + Option[SootUnit] = ??? + +} diff --git a/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/Arithmetic.scala b/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/Arithmetic.scala new file mode 100644 index 0000000..251e910 --- /dev/null +++ b/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/Arithmetic.scala @@ -0,0 +1,63 @@ +package edu.colorado.plv.cuanto.scoot.interpreter +package expression + +import soot._ +import soot.jimple._ + +//////////////////////////////////////////////////////////////////////// + +object Arithmetic { + + def omerge[A,B](t: (Option[A],Option[B])): Option[(A,B)] = + for (a <- t._1; b <- t._2) yield (a,b) + + + def interpNode(v: Value)(r: Value => Option[RFun]): + Option[RFun] = v match { + // case v: Local => env get v + case v: IntConstant => Some(_ => Some(IntR(v.value))) + case v: BinopExpr => for { + op <- bop(v) + arg1 <- r(v.getOp1()) + arg2 <- r(v.getOp2()) + } yield { e: Env => op(arg1(e), arg2(e)) } + case v: UnopExpr => for { + op <- uop(v) + arg <- r(v.getOp()) + } yield { e: Env => op(arg(e)) } + } + + /** Interpret an arithmetic unary operator node, getting back a + * function that performs the operation */ + private def uop(op: UnopExpr): + Option[Option[Result] => Option[Result]] = { + def tryOp(f: Int => Int)(a: Option[Result]): Option[Result] = a match { + case Some(IntR(a)) => Some(IntR(f(a))) + case _ => None + } + op match { + case _: NegExpr => Some(tryOp(_ * -1)) + case _ => None + } + } + + /** Interpret an arithemetic binary operator node, getting back a + * function that performs the operation */ + private def bop(op: BinopExpr): + Option[(Option[Result], Option[Result]) => Option[Result]] = { + def tryOp(f: (Int,Int) => Int)(a: Option[Result], b: Option[Result]): + Option[Result] = + (a,b) match { + case (Some(IntR(a)),(Some(IntR(b)))) => Some(IntR(f(a,b))) + case _ => None + } + op match { + case _: AddExpr => Some(tryOp(_ + _)) + case _: SubExpr => Some(tryOp(_ - _)) + case _: DivExpr => Some(tryOp(_ / _)) + case _: MulExpr => Some(tryOp(_ * _)) + case _ => None + } + } + +} diff --git a/src/main/scala/edu/colorado/plv/cuanto/scoot/arithmetic/Builder.scala b/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/Builder.scala similarity index 100% rename from src/main/scala/edu/colorado/plv/cuanto/scoot/arithmetic/Builder.scala rename to src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/Builder.scala diff --git a/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/package.scala b/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/package.scala new file mode 100644 index 0000000..465b4eb --- /dev/null +++ b/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/package.scala @@ -0,0 +1,18 @@ +package edu.colorado.plv.cuanto.scoot.interpreter + +import scala.collection.immutable.{Map, HashMap} +import soot._ + +package expression { + trait Result + case class IntR(i: Int) extends Result +} + +package object expression { + type Env = Map[String,Result] + type RFun = Env => Option[Result] + + val emptyEnv: Env = new HashMap[String,Result]() + + def interpret(v: Value, env: Env = emptyEnv): Option[Result] = ??? +} diff --git a/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/mutation/package.scala b/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/mutation/package.scala new file mode 100644 index 0000000..9428391 --- /dev/null +++ b/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/mutation/package.scala @@ -0,0 +1,28 @@ +package edu.colorado.plv.cuanto.scoot.interpreter +package mutation + +package object mutation { + + // private def some[A](a: A): Option[A] = Some(a) + + // /** Step an environment forward over a single statement */ + // def step(stmt: AssignStmt)(env: Env): Option[Env] = { + // val varNameO: Option[Local] = stmt.getLeftOp() match { + // case l: Local => Some(l) + // case _ => None + // } + // val newValueO: Option[Result] = denote(stmt.getRightOp(), env) + // for { + // varName <- varNameO + // newValue <- newValueO + // } yield env + (varName.getName() -> newValue) + // } + + // /** Interpret the integer value of a variable mutated over a sequence + // * of assignment statements */ + // def denote(ss: Traversable[AssignStmt], v: Local): Option[Result] = + // denote(ss).flatMap(_ get v.getName()) + + // def denote(ss: Traversable[AssignStmt]): Option[Env] = + // ss.foldLeft(some(emptyEnv))((env,stmt) => env.flatMap(step(stmt))) +} From 66a5027d364149ed73ba523d315d6622a21e482d Mon Sep 17 00:00:00 2001 From: octalsrc Date: Tue, 4 Apr 2017 12:36:05 -0600 Subject: [PATCH 2/6] Test generalized expression interpreter --- .../interpreter/expression/Arithmetic.scala | 1 + .../interpreter/expression/Builder.scala | 4 +- .../interpreter/expression/package.scala | 18 ++++- .../ArithmeticInterpreterSpec.scala | 78 ------------------- .../control/ControlInterpreterSpec.scala | 12 +++ .../ExpressionInterpreterSpec.scala | 51 ++++++++++++ .../mutation/MutationInterpreterSpec.scala | 42 ++++++++++ 7 files changed, 125 insertions(+), 81 deletions(-) delete mode 100644 src/test/scala/edu/colorado/plv/cuanto/scoot/arithmetic/ArithmeticInterpreterSpec.scala create mode 100644 src/test/scala/edu/colorado/plv/cuanto/scoot/interpreter/control/ControlInterpreterSpec.scala create mode 100644 src/test/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/ExpressionInterpreterSpec.scala create mode 100644 src/test/scala/edu/colorado/plv/cuanto/scoot/interpreter/mutation/MutationInterpreterSpec.scala diff --git a/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/Arithmetic.scala b/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/Arithmetic.scala index 251e910..b40553b 100644 --- a/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/Arithmetic.scala +++ b/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/Arithmetic.scala @@ -25,6 +25,7 @@ object Arithmetic { op <- uop(v) arg <- r(v.getOp()) } yield { e: Env => op(arg(e)) } + case _ => None } /** Interpret an arithmetic unary operator node, getting back a diff --git a/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/Builder.scala b/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/Builder.scala index 1245c72..e6320e1 100644 --- a/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/Builder.scala +++ b/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/Builder.scala @@ -1,5 +1,5 @@ -package edu.colorado.plv.cuanto.scoot -package arithmetic +package edu.colorado.plv.cuanto.scoot.interpreter +package expression import soot.{Value, IntType, Local, Immediate} import soot.jimple.{Jimple, AssignStmt, IntConstant, AddExpr, SubExpr, diff --git a/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/package.scala b/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/package.scala index 465b4eb..9966421 100644 --- a/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/package.scala +++ b/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/package.scala @@ -14,5 +14,21 @@ package object expression { val emptyEnv: Env = new HashMap[String,Result]() - def interpret(v: Value, env: Env = emptyEnv): Option[Result] = ??? + def interpret(v: Value, env: Env = emptyEnv): Option[Result] = (for { + rfun <- interpR(v) + } yield rfun(env)).flatten + + def interpR(v: Value): Option[RFun] = + anyOf(Seq(Arithmetic.interpNode(v)(interpR), Locals.interpNode(v)(interpR))) + + def anyOf(is: Traversable[Option[RFun]]): Option[RFun] = + is.flatten.headOption + + object Locals { + def interpNode(v: Value)(r: Value => Option[RFun]): + Option[RFun] = v match { + case v: Local => Some(_ get v.getName()) + case _ => None + } + } } diff --git a/src/test/scala/edu/colorado/plv/cuanto/scoot/arithmetic/ArithmeticInterpreterSpec.scala b/src/test/scala/edu/colorado/plv/cuanto/scoot/arithmetic/ArithmeticInterpreterSpec.scala deleted file mode 100644 index e93d96d..0000000 --- a/src/test/scala/edu/colorado/plv/cuanto/scoot/arithmetic/ArithmeticInterpreterSpec.scala +++ /dev/null @@ -1,78 +0,0 @@ -package edu.colorado.plv.cuanto.scoot -package arithmetic - -import org.scalatest.{FlatSpec, Matchers} -import org.scalatest.prop.PropertyChecks - -class ArithmeticInterpreterSpec extends FlatSpec with Matchers with PropertyChecks { - import Builder._ - import Interpreter._ - - val va = local("va") - val vb = local("vb") - - val testEnv = Map((va,3),(vb,15)) - - val exprTests = Table( - "expression" -> "denotation", - int(1) -> 1, - neg(int(1)) -> -1, - add(int(1))(int(1)) -> 2, - sub(int(3))(int(1)) -> 2, - mul(int(3))(int(2)) -> 6, - div(int(8))(int(4)) -> 2 - ) - - val exprLocalTests = Table( - "expression" -> "denotation", - add(va)(int(1)) -> 4, - div(vb)(va) -> 5 - ) - - "The Scoot interpreter" should "interpret stateless Values" in { - forAll (exprTests) { (e, n) => - denote(e,testEnv) should equal (Some(n)) - } - } - - it should "interpret Values containing in-scope Locals" in { - forAll (exprLocalTests) { (e, n) => - denote(e,testEnv) should equal (Some(n)) - } - } - - it should "give None when asked to interpret undefined Locals" in { - forAll (exprLocalTests) { (e, n) => denote(e) should equal (None) } - } - - val other = local("other") - - val stmtTests = Table( - "program" -> "denotation", - Seq(assign(add(int(1))(int(1)))) -> 2, - Seq(assign(int(0)), assign(int(5))) -> 5, - Seq(assign(int(4)), subs(int(8)), muls(int(2))) -> -8, - Seq(assign(int(1)), negs()) -> -1, - Seq(assign(int(1), other), - assign(add(int(1))(other))) -> 2 - ) - - val stmtFailTests = Table( - "bad program", - Seq(adds(int(1)), assign(int(2))), - Seq(assign(int(2),other)), - Seq() - ) - - it should "interpret a variable mutated through a sequence of AssignStmts" in { - forAll (stmtTests) { (e, n) => denote(e,acc) should equal (Some(n)) } - } - - /** Here, "bad program" means that either the variable being tracked - * is never assigned, or one or more expressions in the program - * could not be interpreted */ - it should "give None when asked to interpret a bad program" in { - forAll (stmtFailTests) { e => denote(e,acc) should equal (None) } - } - -} diff --git a/src/test/scala/edu/colorado/plv/cuanto/scoot/interpreter/control/ControlInterpreterSpec.scala b/src/test/scala/edu/colorado/plv/cuanto/scoot/interpreter/control/ControlInterpreterSpec.scala new file mode 100644 index 0000000..b686884 --- /dev/null +++ b/src/test/scala/edu/colorado/plv/cuanto/scoot/interpreter/control/ControlInterpreterSpec.scala @@ -0,0 +1,12 @@ +package edu.colorado.plv.cuanto.scoot.interpreter +package control + +import org.scalatest.{FlatSpec, Matchers} +import org.scalatest.prop.PropertyChecks + +//////////////////////////////////////////////////////////////////////// + +class ControlInterpreterSpec extends FlatSpec with Matchers + with PropertyChecks { + // import Builder._ +} diff --git a/src/test/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/ExpressionInterpreterSpec.scala b/src/test/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/ExpressionInterpreterSpec.scala new file mode 100644 index 0000000..92cf2f1 --- /dev/null +++ b/src/test/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/ExpressionInterpreterSpec.scala @@ -0,0 +1,51 @@ +package edu.colorado.plv.cuanto.scoot.interpreter +package expression + +import org.scalatest.{FlatSpec, Matchers} +import org.scalatest.prop.PropertyChecks + +//////////////////////////////////////////////////////////////////////// + +class ExpressionInterpreterSpec extends FlatSpec with Matchers + with PropertyChecks { + import Builder._ + + val va = local("va") + val vb = local("vb") + + val testEnv = Map(("va",IntR(3)),("vb",IntR(15))) + + val exprTests = Table( + "expression" -> "denotation", + int(1) -> 1, + neg(int(1)) -> -1, + add(int(1))(int(1)) -> 2, + sub(int(3))(int(1)) -> 2, + mul(int(3))(int(2)) -> 6, + div(int(8))(int(4)) -> 2 + ) + + val exprLocalTests = Table( + "expression" -> "denotation", + add(va)(int(1)) -> 4, + div(vb)(va) -> 5 + ) + + "The Scoot interpreter" should "interpret stateless Values" in { + forAll (exprTests) { (e, n) => + interpret(e,testEnv) should equal (Some(IntR(n))) + } + } + + it should "interpret Values containing in-scope Locals" in { + forAll (exprLocalTests) { (e, n) => + interpret(e,testEnv) should equal (Some(IntR(n))) + } + } + + it should "give None when asked to interpret undefined Locals" in { + forAll (exprLocalTests) { (e, n) => interpret(e) should equal (None) } + } + + +} diff --git a/src/test/scala/edu/colorado/plv/cuanto/scoot/interpreter/mutation/MutationInterpreterSpec.scala b/src/test/scala/edu/colorado/plv/cuanto/scoot/interpreter/mutation/MutationInterpreterSpec.scala new file mode 100644 index 0000000..7fb3867 --- /dev/null +++ b/src/test/scala/edu/colorado/plv/cuanto/scoot/interpreter/mutation/MutationInterpreterSpec.scala @@ -0,0 +1,42 @@ +package edu.colorado.plv.cuanto.scoot.interpreter +package mutation + +import org.scalatest.{FlatSpec, Matchers} +import org.scalatest.prop.PropertyChecks + +//////////////////////////////////////////////////////////////////////// + +class MutationInterpreterSpec extends FlatSpec with Matchers + with PropertyChecks { + // import Builder._ + + // val other = local("other") + + // val stmtTests = Table( + // "program" -> "denotation", + // Seq(assign(add(int(1))(int(1)))) -> 2, + // Seq(assign(int(0)), assign(int(5))) -> 5, + // Seq(assign(int(4)), subs(int(8)), muls(int(2))) -> -8, + // Seq(assign(int(1)), negs()) -> -1, + // Seq(assign(int(1), other), + // assign(add(int(1))(other))) -> 2 + // ) + + // val stmtFailTests = Table( + // "bad program", + // Seq(adds(int(1)), assign(int(2))), + // Seq(assign(int(2),other)), + // Seq() + // ) + + // it should "interpret a variable mutated through a sequence of AssignStmts" in { + // forAll (stmtTests) { (e, n) => denote(e,acc) should equal (Some(n)) } + // } + + // /** Here, "bad program" means that either the variable being tracked + // * is never assigned, or one or more expressions in the program + // * could not be interpreted */ + // it should "give None when asked to interpret a bad program" in { + // forAll (stmtFailTests) { e => denote(e,acc) should equal (None) } + // } +} From 8218787d0cc4385e5845031ce3d1770b1548e576 Mon Sep 17 00:00:00 2001 From: octalsrc Date: Tue, 4 Apr 2017 12:56:47 -0600 Subject: [PATCH 3/6] Test mutation interpreter --- .../scoot/interpreter/mutation/package.scala | 43 ++++++------ .../mutation/MutationInterpreterSpec.scala | 65 ++++++++++--------- 2 files changed, 58 insertions(+), 50 deletions(-) diff --git a/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/mutation/package.scala b/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/mutation/package.scala index 9428391..470c370 100644 --- a/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/mutation/package.scala +++ b/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/mutation/package.scala @@ -1,28 +1,33 @@ package edu.colorado.plv.cuanto.scoot.interpreter package mutation +import soot._ +import soot.jimple._ + +import expression._ + package object mutation { - // private def some[A](a: A): Option[A] = Some(a) + private def some[A](a: A): Option[A] = Some(a) - // /** Step an environment forward over a single statement */ - // def step(stmt: AssignStmt)(env: Env): Option[Env] = { - // val varNameO: Option[Local] = stmt.getLeftOp() match { - // case l: Local => Some(l) - // case _ => None - // } - // val newValueO: Option[Result] = denote(stmt.getRightOp(), env) - // for { - // varName <- varNameO - // newValue <- newValueO - // } yield env + (varName.getName() -> newValue) - // } + /** Step an environment forward over a single statement */ + def step(stmt: AssignStmt)(env: Env): Option[Env] = { + val varNameO: Option[Local] = stmt.getLeftOp() match { + case l: Local => Some(l) + case _ => None + } + val newValueO: Option[Result] = expression.interpret(stmt.getRightOp(), env) + for { + varName <- varNameO + newValue <- newValueO + } yield env + (varName.getName() -> newValue) + } - // /** Interpret the integer value of a variable mutated over a sequence - // * of assignment statements */ - // def denote(ss: Traversable[AssignStmt], v: Local): Option[Result] = - // denote(ss).flatMap(_ get v.getName()) + /** Interpret the integer value of a variable mutated over a sequence + * of assignment statements */ + def interpret(ss: Traversable[AssignStmt], v: String): Option[Result] = + interpret(ss).flatMap(_ get v) - // def denote(ss: Traversable[AssignStmt]): Option[Env] = - // ss.foldLeft(some(emptyEnv))((env,stmt) => env.flatMap(step(stmt))) + def interpret(ss: Traversable[AssignStmt]): Option[Env] = + ss.foldLeft(some(emptyEnv))((env,stmt) => env.flatMap(step(stmt))) } diff --git a/src/test/scala/edu/colorado/plv/cuanto/scoot/interpreter/mutation/MutationInterpreterSpec.scala b/src/test/scala/edu/colorado/plv/cuanto/scoot/interpreter/mutation/MutationInterpreterSpec.scala index 7fb3867..fbe8fba 100644 --- a/src/test/scala/edu/colorado/plv/cuanto/scoot/interpreter/mutation/MutationInterpreterSpec.scala +++ b/src/test/scala/edu/colorado/plv/cuanto/scoot/interpreter/mutation/MutationInterpreterSpec.scala @@ -4,39 +4,42 @@ package mutation import org.scalatest.{FlatSpec, Matchers} import org.scalatest.prop.PropertyChecks +import expression._ + //////////////////////////////////////////////////////////////////////// class MutationInterpreterSpec extends FlatSpec with Matchers with PropertyChecks { - // import Builder._ - - // val other = local("other") - - // val stmtTests = Table( - // "program" -> "denotation", - // Seq(assign(add(int(1))(int(1)))) -> 2, - // Seq(assign(int(0)), assign(int(5))) -> 5, - // Seq(assign(int(4)), subs(int(8)), muls(int(2))) -> -8, - // Seq(assign(int(1)), negs()) -> -1, - // Seq(assign(int(1), other), - // assign(add(int(1))(other))) -> 2 - // ) - - // val stmtFailTests = Table( - // "bad program", - // Seq(adds(int(1)), assign(int(2))), - // Seq(assign(int(2),other)), - // Seq() - // ) - - // it should "interpret a variable mutated through a sequence of AssignStmts" in { - // forAll (stmtTests) { (e, n) => denote(e,acc) should equal (Some(n)) } - // } - - // /** Here, "bad program" means that either the variable being tracked - // * is never assigned, or one or more expressions in the program - // * could not be interpreted */ - // it should "give None when asked to interpret a bad program" in { - // forAll (stmtFailTests) { e => denote(e,acc) should equal (None) } - // } + import expression.Builder._ + + val other = local("other") + + val stmtTests = Table( + "program" -> "denotation", + Seq(assign(add(int(1))(int(1)))) -> 2, + Seq(assign(int(0)), assign(int(5))) -> 5, + Seq(assign(int(4)), subs(int(8)), muls(int(2))) -> -8, + Seq(assign(int(1)), negs()) -> -1, + Seq(assign(int(1), other), + assign(add(int(1))(other))) -> 2 + ) + + val stmtFailTests = Table( + "bad program", + Seq(adds(int(1)), assign(int(2))), + Seq(assign(int(2),other)), + Seq() + ) + + it should "interpret a variable mutated through a sequence of AssignStmts" in { + forAll (stmtTests) { (e, n) => + mutation.interpret(e,acc.getName()) should equal (Some(IntR(n))) } + } + + /** Here, "bad program" means that either the variable being tracked + * is never assigned, or one or more expressions in the program + * could not be interpreted */ + it should "give None when asked to interpret a bad program" in { + forAll (stmtFailTests) { e => mutation.interpret(e,acc.getName()) should equal (None) } + } } From 92fa31a5be4e891997ffa48bfc3bed32dfba39cc Mon Sep 17 00:00:00 2001 From: octalsrc Date: Tue, 18 Apr 2017 09:56:34 -0600 Subject: [PATCH 4/6] Add scoot interpretation domains --- .../plv/cuanto/scoot/domains/ArithDom.scala | 15 ++++++++ .../plv/cuanto/scoot/domains/concrete.scala | 36 +++++++++++++++++++ .../plv/cuanto/scoot/domains/package.scala | 9 +++++ 3 files changed, 60 insertions(+) create mode 100644 src/main/scala/edu/colorado/plv/cuanto/scoot/domains/ArithDom.scala create mode 100644 src/main/scala/edu/colorado/plv/cuanto/scoot/domains/concrete.scala create mode 100644 src/main/scala/edu/colorado/plv/cuanto/scoot/domains/package.scala diff --git a/src/main/scala/edu/colorado/plv/cuanto/scoot/domains/ArithDom.scala b/src/main/scala/edu/colorado/plv/cuanto/scoot/domains/ArithDom.scala new file mode 100644 index 0000000..25f7d9c --- /dev/null +++ b/src/main/scala/edu/colorado/plv/cuanto/scoot/domains/ArithDom.scala @@ -0,0 +1,15 @@ +package edu.colorado.plv.cuanto +package scoot.domains + +/** Generic abstraction of numeric types. + */ +trait ArithDom { + type D + + def neg(e: D): D + + def add(e1: D)(e2: D): D + def sub(e1: D)(e2: D): D + def mul(e1: D)(e2: D): D + def div(e1: D)(e2: D): D +} diff --git a/src/main/scala/edu/colorado/plv/cuanto/scoot/domains/concrete.scala b/src/main/scala/edu/colorado/plv/cuanto/scoot/domains/concrete.scala new file mode 100644 index 0000000..8052dfe --- /dev/null +++ b/src/main/scala/edu/colorado/plv/cuanto/scoot/domains/concrete.scala @@ -0,0 +1,36 @@ +package edu.colorado.plv.cuanto +package scoot.domains + +import abstracting._ + +object concrete { + /** Concrete domain of integer values. + */ + case class IntDom(i: Int) extends ArithDom + with Abstractable[Int,IntDom] { + override type D = IntDom + + override def represent(i: Int): IntDom = IntDom(i) + + override def neg(e: IntDom): IntDom = e match { + case IntDom(i) => i * -1 + } + + override def add(e1: IntDom)(e2: IntDom): IntDom = + (e1,e2) match { + case (IntDom(i1),IntDom(i2)) => i1 + i2 + } + override def sub(e1: IntDom)(e2: IntDom): IntDom = + (e1,e2) match { + case (IntDom(i1),IntDom(i2)) => i1 - i2 + } + override def mul(e1: IntDom)(e2: IntDom): IntDom = + (e1,e2) match { + case (IntDom(i1),IntDom(i2)) => i1 * i2 + } + override def div(e1: IntDom)(e2: IntDom): IntDom = + (e1,e2) match { + case (IntDom(i1),IntDom(i2)) => i1 / i2 + } + } +} diff --git a/src/main/scala/edu/colorado/plv/cuanto/scoot/domains/package.scala b/src/main/scala/edu/colorado/plv/cuanto/scoot/domains/package.scala new file mode 100644 index 0000000..791a251 --- /dev/null +++ b/src/main/scala/edu/colorado/plv/cuanto/scoot/domains/package.scala @@ -0,0 +1,9 @@ +package edu.colorado.plv.cuanto +package scoot.domains + +import abstracting.{Abstractable, Abstraction} + +package object domains { + sealed trait Result + case class Arith[A <: ArithDom](a: A) extends Result +} From 0c93d7c43470c42c86f32714a7e9f24c90dc90de Mon Sep 17 00:00:00 2001 From: octalsrc Date: Tue, 18 Apr 2017 10:51:05 -0600 Subject: [PATCH 5/6] Modify scoot interpreter to use domains --- .../plv/cuanto/scoot/domains/IntDom.scala | 34 ++++++++++++++++++ .../plv/cuanto/scoot/domains/concrete.scala | 36 ------------------- .../plv/cuanto/scoot/domains/package.scala | 11 +++--- .../scoot/interpreter/control/package.scala | 2 ++ .../interpreter/expression/Arithmetic.scala | 33 ++++++++--------- .../interpreter/expression/package.scala | 17 +++++---- .../scoot/interpreter/mutation/package.scala | 4 +-- .../ExpressionInterpreterSpec.scala | 12 ++++--- .../mutation/MutationInterpreterSpec.scala | 10 +++--- 9 files changed, 79 insertions(+), 80 deletions(-) create mode 100644 src/main/scala/edu/colorado/plv/cuanto/scoot/domains/IntDom.scala delete mode 100644 src/main/scala/edu/colorado/plv/cuanto/scoot/domains/concrete.scala diff --git a/src/main/scala/edu/colorado/plv/cuanto/scoot/domains/IntDom.scala b/src/main/scala/edu/colorado/plv/cuanto/scoot/domains/IntDom.scala new file mode 100644 index 0000000..5dea1bd --- /dev/null +++ b/src/main/scala/edu/colorado/plv/cuanto/scoot/domains/IntDom.scala @@ -0,0 +1,34 @@ +package edu.colorado.plv.cuanto +package scoot.domains + +import abstracting._ + +/** Concrete domain of integer values. + */ +case class IntDom(i: Int) extends ArithDom + with Abstractable[Int,IntDom] { + override type D = IntDom + + override def represent(i: Int): IntDom = IntDom(i) + + override def neg(e: IntDom): IntDom = e match { + case IntDom(i) => i * -1 + } + + override def add(e1: IntDom)(e2: IntDom): IntDom = + (e1,e2) match { + case (IntDom(i1),IntDom(i2)) => i1 + i2 + } + override def sub(e1: IntDom)(e2: IntDom): IntDom = + (e1,e2) match { + case (IntDom(i1),IntDom(i2)) => i1 - i2 + } + override def mul(e1: IntDom)(e2: IntDom): IntDom = + (e1,e2) match { + case (IntDom(i1),IntDom(i2)) => i1 * i2 + } + override def div(e1: IntDom)(e2: IntDom): IntDom = + (e1,e2) match { + case (IntDom(i1),IntDom(i2)) => i1 / i2 + } +} diff --git a/src/main/scala/edu/colorado/plv/cuanto/scoot/domains/concrete.scala b/src/main/scala/edu/colorado/plv/cuanto/scoot/domains/concrete.scala deleted file mode 100644 index 8052dfe..0000000 --- a/src/main/scala/edu/colorado/plv/cuanto/scoot/domains/concrete.scala +++ /dev/null @@ -1,36 +0,0 @@ -package edu.colorado.plv.cuanto -package scoot.domains - -import abstracting._ - -object concrete { - /** Concrete domain of integer values. - */ - case class IntDom(i: Int) extends ArithDom - with Abstractable[Int,IntDom] { - override type D = IntDom - - override def represent(i: Int): IntDom = IntDom(i) - - override def neg(e: IntDom): IntDom = e match { - case IntDom(i) => i * -1 - } - - override def add(e1: IntDom)(e2: IntDom): IntDom = - (e1,e2) match { - case (IntDom(i1),IntDom(i2)) => i1 + i2 - } - override def sub(e1: IntDom)(e2: IntDom): IntDom = - (e1,e2) match { - case (IntDom(i1),IntDom(i2)) => i1 - i2 - } - override def mul(e1: IntDom)(e2: IntDom): IntDom = - (e1,e2) match { - case (IntDom(i1),IntDom(i2)) => i1 * i2 - } - override def div(e1: IntDom)(e2: IntDom): IntDom = - (e1,e2) match { - case (IntDom(i1),IntDom(i2)) => i1 / i2 - } - } -} diff --git a/src/main/scala/edu/colorado/plv/cuanto/scoot/domains/package.scala b/src/main/scala/edu/colorado/plv/cuanto/scoot/domains/package.scala index 791a251..9597f98 100644 --- a/src/main/scala/edu/colorado/plv/cuanto/scoot/domains/package.scala +++ b/src/main/scala/edu/colorado/plv/cuanto/scoot/domains/package.scala @@ -1,9 +1,6 @@ -package edu.colorado.plv.cuanto -package scoot.domains +package edu.colorado.plv.cuanto.scoot -import abstracting.{Abstractable, Abstraction} - -package object domains { - sealed trait Result - case class Arith[A <: ArithDom](a: A) extends Result +package domains { + trait Result[A <: ArithDom] + case class Arith[A <: ArithDom](a: A) extends Result[A] } diff --git a/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/control/package.scala b/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/control/package.scala index e306dba..92eb62f 100644 --- a/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/control/package.scala +++ b/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/control/package.scala @@ -11,4 +11,6 @@ package object control { def succ(graph: UnitGraph)(env: Env, unit: SootUnit): Option[SootUnit] = ??? + def next[D](graph: UnitGraph, unit: SootUnit): Traversable[(Unit,D)] = ??? + } diff --git a/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/Arithmetic.scala b/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/Arithmetic.scala index b40553b..9bb19c8 100644 --- a/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/Arithmetic.scala +++ b/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/Arithmetic.scala @@ -1,10 +1,11 @@ -package edu.colorado.plv.cuanto.scoot.interpreter -package expression +package edu.colorado.plv.cuanto.scoot +package interpreter.expression import soot._ import soot.jimple._ -//////////////////////////////////////////////////////////////////////// +import domains._ +import domains.IntDom object Arithmetic { @@ -15,7 +16,7 @@ object Arithmetic { def interpNode(v: Value)(r: Value => Option[RFun]): Option[RFun] = v match { // case v: Local => env get v - case v: IntConstant => Some(_ => Some(IntR(v.value))) + case v: IntConstant => Some(_ => Some(Arith(IntDom(v.value)))) case v: BinopExpr => for { op <- bop(v) arg1 <- r(v.getOp1()) @@ -31,13 +32,13 @@ object Arithmetic { /** Interpret an arithmetic unary operator node, getting back a * function that performs the operation */ private def uop(op: UnopExpr): - Option[Option[Result] => Option[Result]] = { - def tryOp(f: Int => Int)(a: Option[Result]): Option[Result] = a match { - case Some(IntR(a)) => Some(IntR(f(a))) + Option[Option[R] => Option[R]] = { + def tryOp(f: IntDom => IntDom)(a: Option[R]): Option[R] = a match { + case Some(Arith(a)) => Some(Arith(f(a))) case _ => None } op match { - case _: NegExpr => Some(tryOp(_ * -1)) + case _: NegExpr => Some(tryOp((i: IntDom) => i.neg(i))) case _ => None } } @@ -45,18 +46,18 @@ object Arithmetic { /** Interpret an arithemetic binary operator node, getting back a * function that performs the operation */ private def bop(op: BinopExpr): - Option[(Option[Result], Option[Result]) => Option[Result]] = { - def tryOp(f: (Int,Int) => Int)(a: Option[Result], b: Option[Result]): - Option[Result] = + Option[(Option[R], Option[R]) => Option[R]] = { + def tryOp(f: (IntDom,IntDom) => IntDom)(a: Option[R], b: Option[R]): + Option[R] = (a,b) match { - case (Some(IntR(a)),(Some(IntR(b)))) => Some(IntR(f(a,b))) + case (Some(Arith(a)),(Some(Arith(b)))) => Some(Arith(f(a,b))) case _ => None } op match { - case _: AddExpr => Some(tryOp(_ + _)) - case _: SubExpr => Some(tryOp(_ - _)) - case _: DivExpr => Some(tryOp(_ / _)) - case _: MulExpr => Some(tryOp(_ * _)) + case _: AddExpr => Some(tryOp((i1: IntDom,i2: IntDom) => i1.add(i1)(i2))) + case _: SubExpr => Some(tryOp((i1: IntDom,i2: IntDom) => i1.sub(i1)(i2))) + case _: DivExpr => Some(tryOp((i1: IntDom,i2: IntDom) => i1.div(i1)(i2))) + case _: MulExpr => Some(tryOp((i1: IntDom,i2: IntDom) => i1.mul(i1)(i2))) case _ => None } } diff --git a/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/package.scala b/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/package.scala index 9966421..7851270 100644 --- a/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/package.scala +++ b/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/package.scala @@ -1,20 +1,19 @@ -package edu.colorado.plv.cuanto.scoot.interpreter +package edu.colorado.plv.cuanto +package scoot.interpreter import scala.collection.immutable.{Map, HashMap} import soot._ -package expression { - trait Result - case class IntR(i: Int) extends Result -} +import scoot.domains._ package object expression { - type Env = Map[String,Result] - type RFun = Env => Option[Result] + type R = Result[IntDom] + type Env = Map[String,R] + type RFun = Env => Option[R] - val emptyEnv: Env = new HashMap[String,Result]() + val emptyEnv: Env = new HashMap[String,R]() - def interpret(v: Value, env: Env = emptyEnv): Option[Result] = (for { + def interpret(v: Value, env: Env = emptyEnv): Option[R] = (for { rfun <- interpR(v) } yield rfun(env)).flatten diff --git a/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/mutation/package.scala b/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/mutation/package.scala index 470c370..036ad00 100644 --- a/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/mutation/package.scala +++ b/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/mutation/package.scala @@ -16,7 +16,7 @@ package object mutation { case l: Local => Some(l) case _ => None } - val newValueO: Option[Result] = expression.interpret(stmt.getRightOp(), env) + val newValueO: Option[R] = expression.interpret(stmt.getRightOp(), env) for { varName <- varNameO newValue <- newValueO @@ -25,7 +25,7 @@ package object mutation { /** Interpret the integer value of a variable mutated over a sequence * of assignment statements */ - def interpret(ss: Traversable[AssignStmt], v: String): Option[Result] = + def interpret(ss: Traversable[AssignStmt], v: String): Option[R] = interpret(ss).flatMap(_ get v) def interpret(ss: Traversable[AssignStmt]): Option[Env] = diff --git a/src/test/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/ExpressionInterpreterSpec.scala b/src/test/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/ExpressionInterpreterSpec.scala index 92cf2f1..31adf19 100644 --- a/src/test/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/ExpressionInterpreterSpec.scala +++ b/src/test/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/ExpressionInterpreterSpec.scala @@ -1,9 +1,11 @@ -package edu.colorado.plv.cuanto.scoot.interpreter -package expression +package edu.colorado.plv.cuanto.scoot +package interpreter.expression import org.scalatest.{FlatSpec, Matchers} import org.scalatest.prop.PropertyChecks +import domains._ + //////////////////////////////////////////////////////////////////////// class ExpressionInterpreterSpec extends FlatSpec with Matchers @@ -13,7 +15,7 @@ class ExpressionInterpreterSpec extends FlatSpec with Matchers val va = local("va") val vb = local("vb") - val testEnv = Map(("va",IntR(3)),("vb",IntR(15))) + val testEnv = Map(("va",Arith[IntDom](IntDom(3))),("vb",Arith[IntDom](IntDom(15)))) val exprTests = Table( "expression" -> "denotation", @@ -33,13 +35,13 @@ class ExpressionInterpreterSpec extends FlatSpec with Matchers "The Scoot interpreter" should "interpret stateless Values" in { forAll (exprTests) { (e, n) => - interpret(e,testEnv) should equal (Some(IntR(n))) + interpret(e,testEnv) should equal (Some(Arith[IntDom](IntDom(n)))) } } it should "interpret Values containing in-scope Locals" in { forAll (exprLocalTests) { (e, n) => - interpret(e,testEnv) should equal (Some(IntR(n))) + interpret(e,testEnv) should equal (Some(Arith[IntDom](IntDom(n)))) } } diff --git a/src/test/scala/edu/colorado/plv/cuanto/scoot/interpreter/mutation/MutationInterpreterSpec.scala b/src/test/scala/edu/colorado/plv/cuanto/scoot/interpreter/mutation/MutationInterpreterSpec.scala index fbe8fba..94c8423 100644 --- a/src/test/scala/edu/colorado/plv/cuanto/scoot/interpreter/mutation/MutationInterpreterSpec.scala +++ b/src/test/scala/edu/colorado/plv/cuanto/scoot/interpreter/mutation/MutationInterpreterSpec.scala @@ -1,16 +1,16 @@ -package edu.colorado.plv.cuanto.scoot.interpreter -package mutation +package edu.colorado.plv.cuanto.scoot +package interpreter.mutation import org.scalatest.{FlatSpec, Matchers} import org.scalatest.prop.PropertyChecks -import expression._ +import domains._ //////////////////////////////////////////////////////////////////////// class MutationInterpreterSpec extends FlatSpec with Matchers with PropertyChecks { - import expression.Builder._ + import interpreter.expression.Builder._ val other = local("other") @@ -33,7 +33,7 @@ class MutationInterpreterSpec extends FlatSpec with Matchers it should "interpret a variable mutated through a sequence of AssignStmts" in { forAll (stmtTests) { (e, n) => - mutation.interpret(e,acc.getName()) should equal (Some(IntR(n))) } + mutation.interpret(e,acc.getName()) should equal (Some(Arith[IntDom](IntDom(n)))) } } /** Here, "bad program" means that either the variable being tracked From 6bf6c9501c815adffd397285d32a85733c52ac89 Mon Sep 17 00:00:00 2001 From: octalsrc Date: Tue, 18 Apr 2017 11:41:48 -0600 Subject: [PATCH 6/6] Document interpreter structure --- .../scoot/interpreter/control/package.scala | 2 ++ .../scoot/interpreter/expression/Arithmetic.scala | 4 +++- .../scoot/interpreter/expression/package.scala | 15 +++++++++++++-- .../scoot/interpreter/mutation/package.scala | 2 ++ 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/control/package.scala b/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/control/package.scala index e306dba..65c138b 100644 --- a/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/control/package.scala +++ b/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/control/package.scala @@ -6,8 +6,10 @@ import soot.toolkits.graph.UnitGraph import expression.Env +/** Interpret soot Units that affect control-flow */ package object control { + /** Find the next Unit, given an environment */ def succ(graph: UnitGraph)(env: Env, unit: SootUnit): Option[SootUnit] = ??? diff --git a/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/Arithmetic.scala b/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/Arithmetic.scala index b40553b..1a35411 100644 --- a/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/Arithmetic.scala +++ b/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/Arithmetic.scala @@ -6,12 +6,14 @@ import soot.jimple._ //////////////////////////////////////////////////////////////////////// +/** Sub-interpreter for arithmetic nodes */ object Arithmetic { - def omerge[A,B](t: (Option[A],Option[B])): Option[(A,B)] = + private def omerge[A,B](t: (Option[A],Option[B])): Option[(A,B)] = for (a <- t._1; b <- t._2) yield (a,b) + /** Interpret an arithmetic operator node */ def interpNode(v: Value)(r: Value => Option[RFun]): Option[RFun] = v match { // case v: Local => env get v diff --git a/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/package.scala b/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/package.scala index 9966421..6cd747b 100644 --- a/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/package.scala +++ b/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/expression/package.scala @@ -3,28 +3,39 @@ package edu.colorado.plv.cuanto.scoot.interpreter import scala.collection.immutable.{Map, HashMap} import soot._ +/** Interpreter for expressions (soot Values). This depends on + * expression evaluation not having side-effects. + */ package expression { + + /** A sum type of possible types that an expression can evaluate to */ trait Result case class IntR(i: Int) extends Result } package object expression { + + /** Evaluation environment */ type Env = Map[String,Result] type RFun = Env => Option[Result] + /** The empty environment */ val emptyEnv: Env = new HashMap[String,Result]() + /** Interpret a value under a particular environment */ def interpret(v: Value, env: Env = emptyEnv): Option[Result] = (for { rfun <- interpR(v) } yield rfun(env)).flatten - def interpR(v: Value): Option[RFun] = + private def interpR(v: Value): Option[RFun] = anyOf(Seq(Arithmetic.interpNode(v)(interpR), Locals.interpNode(v)(interpR))) - def anyOf(is: Traversable[Option[RFun]]): Option[RFun] = + private def anyOf(is: Traversable[Option[RFun]]): Option[RFun] = is.flatten.headOption + /** Sub-interpreter for looking up Local values in the environment */ object Locals { + /** Interpret a Local node */ def interpNode(v: Value)(r: Value => Option[RFun]): Option[RFun] = v match { case v: Local => Some(_ get v.getName()) diff --git a/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/mutation/package.scala b/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/mutation/package.scala index 470c370..307f792 100644 --- a/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/mutation/package.scala +++ b/src/main/scala/edu/colorado/plv/cuanto/scoot/interpreter/mutation/package.scala @@ -6,6 +6,8 @@ import soot.jimple._ import expression._ +/** Interpreter for soot Units that modify the evaluation + * environment */ package object mutation { private def some[A](a: A): Option[A] = Some(a)