Skip to content

Commit

Permalink
updated to newer Scala 3 syntax with fewer braces
Browse files Browse the repository at this point in the history
Signed-off-by: Konstantin Läufer <[email protected]>
  • Loading branch information
klaeufer committed Sep 30, 2023
1 parent 8756131 commit fc2cdfb
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 48 deletions.
48 changes: 17 additions & 31 deletions src/main/scala/evaluate.scala
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,11 @@ object evaluate:

/** Looks up a variable in memory. */
def lookup(store: Store)(name: String): Result =
store.get(name).fold {
store.get(name).fold(
Failure(new NoSuchFieldException(name)): Result
} {
) (
Success(_)
}
)

/** Evaluates the two operands and applies the operator. */
def binOp(left: Thunk, right: Thunk, op: (Int, Int) => Int): Result =
Expand All @@ -73,45 +73,34 @@ object evaluate:
* tree is achieved by plugging this F-algebra into the
* universal catamorphism (generalized fold).
*/
def evalAlgebra(store: Store): Algebra[ExprF, Thunk] = Algebra {
case Constant(value) => thunk {
def evalAlgebra(store: Store): Algebra[ExprF, Thunk] = Algebra:
case Constant(value) => thunk:
Success(Cell(Num(value)))
}
case Plus(left, right) => thunk {
case Plus(left, right) => thunk:
binOp(left, right, _ + _)
}
case Minus(left, right) => thunk {
case Minus(left, right) => thunk:
binOp(left, right, _ - _)
}
case Times(left, right) => thunk {
case Times(left, right) => thunk:
binOp(left, right, _ * _)
}
case Div(left, right) => thunk {
case Div(left, right) => thunk:
binOp(left, right, _ / _)
}
case Mod(left, right) => thunk {
case Mod(left, right) => thunk:
binOp(left, right, _ % _)
}
case UMinus(expr) => thunk {
case UMinus(expr) => thunk:
for Cell(Num(e)) <- expr.eval yield Cell(Num(-e))
}
case Variable(name) => thunk {
case Variable(name) => thunk:
lookup(store)(name)
}
case Assign(left, right) => thunk {
case Assign(left, right) => thunk:
for
lvalue <- lookup(store)(left)
Cell(rvalue) <- right.eval
_ <- Success(lvalue.set(rvalue))
yield Cell.NULL
}
case Cond(guard, thenBranch, elseBranch) => thunk {
guard.eval match {
case Cond(guard, thenBranch, elseBranch) => thunk:
guard.eval match
case Success(Cell.NULL) => elseBranch.eval
case Success(_) => thenBranch.eval
case f@Failure(_) => f
}
}
case Block(expressions) =>
// TODO http://stackoverflow.com/questions/12892701/abort-early-in-a-fold
// TODO https://stackoverflow.com/questions/57516234/listtryt-to-trylistt-in-scala
Expand All @@ -124,9 +113,8 @@ object evaluate:
case f@Failure(_) => return f
Success(result)

thunk {
thunk:
doSequence
}
case Loop(guard, body) =>
def doLoop: Result =
while true do
Expand All @@ -136,10 +124,8 @@ object evaluate:
case f@Failure(_) => return f
Success(Cell.NULL)

thunk {
thunk:
doLoop
}
}

/** Evaluates the program by recursively applying the algebra to the tree. */
def evaluate(store: Store)(expr: Expr): Result =
Expand Down
23 changes: 8 additions & 15 deletions src/test/scala/imperativeTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,63 +17,56 @@ object imperativeTests extends Properties("imperativeTests"):

/** Enable typesafe equality for `Result`. */
given CanEqual[Result, Success[Cell]] = CanEqual.derived

property("don't do anything unless triggered") = Prop {
property("don't do anything unless triggered") = Prop:
val s = store()
val s0 = store()
val ev = scheme.cata(evalAlgebra(s))
ev(e2)
s == s0
}

property("correctly evaluate a side-effect free expression") = Prop {
property("correctly evaluate a side-effect free expression") = Prop:
val s = store()
val s0 = store()
evaluate(s)(e1) == Success(Cell(Num(7))) &&
s == s0
}

property("correctly evaluate a simple assignment") = Prop {
property("correctly evaluate a simple assignment") = Prop:
val s = store()
val s0 = store()
evaluate(s)(e2)
s - "x" == s0 - "x" &&
s0("x") == Cell(Num(2)) &&
s("x") == Cell(Num(4))
}

property("correctly evaluate a statement block") = Prop {
property("correctly evaluate a statement block") = Prop:
val s = store()
val s0 = store()
evaluate(s)(e3)
s - "r" - "y" == s0 - "r" - "y" &&
s("r") == Cell(Num(2)) &&
s("y") == Cell(Num(2))
}

property("correctly evaluate a conditional") = Prop {
property("correctly evaluate a conditional") = Prop:
val s = store()
val s0 = store()
evaluate(s)(e4a)
s - "r" == s0 - "r" &&
s("r") == Cell(Num(2))
}

property("correctly evaluate another conditional") = Prop {
property("correctly evaluate another conditional") = Prop:
val s = store()
val s0 = store()
evaluate(s)(e4b)
s - "y" == s0 - "y" &&
s("y") == Cell(Num(2))
}

property("correctly evaluate a loop") = Prop {
property("correctly evaluate a loop") = Prop:
val s = store()
val s0 = store()
evaluate(s)(e5)
s - "y" - "r" == s0 - "y" - "r" &&
s("r") == Cell(Num(6)) &&
s("y") == Cell(Num(0))
}

end imperativeTests
3 changes: 1 addition & 2 deletions src/test/scala/lawTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,13 @@ object lawTests extends Properties("lawTests"):
def genLoop[A](g: Gen[A]) = (g, g).mapN(Loop(_, _))
def genAssign[A](f: Gen[String], g: Gen[A]) = (f, g).mapN(Assign(_, _))

given [A](using Arbitrary[A]): Arbitrary[ExprF[A]] = Arbitrary {
given [A](using Arbitrary[A]): Arbitrary[ExprF[A]] = Arbitrary:
val i = Arbitrary.arbInt.arbitrary
val s = Arbitrary.arbString.arbitrary
val g = Arbitrary.arbitrary[A]
Gen.oneOf(genConstant(i), genVariable(s),
genUMinus(g), genPlus(g), genMinus(g), genTimes(g), genDiv(g), genMod(g),
genBlock(g), genCond(g), genLoop(g), genAssign(s, g))
}

include(cats.laws.discipline.FunctorTests[ExprF].functor[Int, Int, Int].all)
// TODO reinclude after fixing Traverse
Expand Down

0 comments on commit fc2cdfb

Please sign in to comment.