diff --git a/.scalafmt.conf b/.scalafmt.conf index 5ff1aed..78e040d 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,4 +1,4 @@ -maxColumn = 80 +maxColumn = 160 version = 3.7.14 runner.dialect = scala3 preset = IntelliJ diff --git a/catculator-core/src/main/scala/pl/writeonly/catculator/core/Extras.scala b/catculator-core/src/main/scala/pl/writeonly/catculator/core/Extras.scala index 63f91fd..8eedffd 100644 --- a/catculator-core/src/main/scala/pl/writeonly/catculator/core/Extras.scala +++ b/catculator-core/src/main/scala/pl/writeonly/catculator/core/Extras.scala @@ -4,9 +4,7 @@ import cats.data.NonEmptyList object Extras { - def foldNonEmpty[A](l: NonEmptyList[A])(f: (A, A) => A): A = l - .tail - .fold(l.head)(f) + def foldNonEmpty[A](l: NonEmptyList[A])(f: (A, A) => A): A = l.tail.fold(l.head)(f) def fix[T, R](f: (T => R) => (T => R)): (T => R) = new Function1[T, R] { def apply(t: T): R = f(this)(t) diff --git a/catculator-core/src/main/scala/pl/writeonly/catculator/core/LambdaConfig.scala b/catculator-core/src/main/scala/pl/writeonly/catculator/core/LambdaConfig.scala index a70dccc..522860a 100644 --- a/catculator-core/src/main/scala/pl/writeonly/catculator/core/LambdaConfig.scala +++ b/catculator-core/src/main/scala/pl/writeonly/catculator/core/LambdaConfig.scala @@ -6,24 +6,11 @@ import pl.writeonly.catculator.core.adt.calculus.Lambda import pl.writeonly.catculator.core.adt.calculus.Lambda._ object LambdaConfig { - val haskellConfig: LambdaConfig = LambdaConfig( - apply = "apply", - pair = "pair", - nil = "nil", - succ = "succ", - zero = "zero", - ) - val lambdaConfig: LambdaConfig = - LambdaConfig(apply = ";", pair = ",", nil = ".", succ = ":", zero = "0") + val haskellConfig: LambdaConfig = LambdaConfig(apply = "apply", pair = "pair", nil = "nil", succ = "succ", zero = "zero") + val lambdaConfig: LambdaConfig = LambdaConfig(apply = ";", pair = ",", nil = ".", succ = ":", zero = "0") } -case class LambdaConfig( - apply: String, - pair: String, - nil: String, - succ: String, - zero: String, -) { +case class LambdaConfig(apply: String, pair: String, nil: String, succ: String, zero: String) { val thrushVariable: Var = Var(apply) val vireoVariable: Lambda = Var(pair) @@ -40,17 +27,13 @@ case class LambdaConfig( l |> appAppAbs(applyBody, applyBody, apply) } - def appAppAbs(l1: Lambda, l2: Lambda, name: String)(l3: Lambda): Lambda = - App(l1, App(l2, Abs(name, l3))) + def appAppAbs(l1: Lambda, l2: Lambda, name: String)(l3: Lambda): Lambda = App(l1, App(l2, Abs(name, l3))) - def wrapAppThrush(l1: Lambda, name: String)(l2: Lambda): Lambda = - appAppAbs(thrushVariable, l1, name)(l2) + def wrapAppThrush(l1: Lambda, name: String)(l2: Lambda): Lambda = appAppAbs(thrushVariable, l1, name)(l2) - def reThrush(oldName: String, newName: String)(l: Lambda): Lambda = - wrapAppThrush(Var(oldName), newName)(l) + def reThrush(oldName: String, newName: String)(l: Lambda): Lambda = wrapAppThrush(Var(oldName), newName)(l) - def wrapAppVireoApp(l1: Lambda, l2: Lambda): Lambda = - App(App(vireoVariable, l1), l2) + def wrapAppVireoApp(l1: Lambda, l2: Lambda): Lambda = App(App(vireoVariable, l1), l2) def appSuccVariable(l: Lambda): Lambda = App(succVariable, l) } diff --git a/catculator-core/src/main/scala/pl/writeonly/catculator/core/adt/calculus/Constants.scala b/catculator-core/src/main/scala/pl/writeonly/catculator/core/adt/calculus/Constants.scala index b3a060b..1e57f89 100644 --- a/catculator-core/src/main/scala/pl/writeonly/catculator/core/adt/calculus/Constants.scala +++ b/catculator-core/src/main/scala/pl/writeonly/catculator/core/adt/calculus/Constants.scala @@ -18,15 +18,9 @@ object Constants { def appK(a: CombinatorBT): Node[Combinator] = Node(kCom, a) - def app4( - c1: CombinatorBT, - c2: CombinatorBT, - c3: CombinatorBT, - c4: CombinatorBT, - ): CombinatorBT = Node(c1, app3(c2, c3, c4)) - - def app3(c1: CombinatorBT, c2: CombinatorBT, c3: CombinatorBT): CombinatorBT = - Node(c1, Node(c2, c3)) + def app4(c1: CombinatorBT, c2: CombinatorBT, c3: CombinatorBT, c4: CombinatorBT): CombinatorBT = Node(c1, app3(c2, c3, c4)) + + def app3(c1: CombinatorBT, c2: CombinatorBT, c3: CombinatorBT): CombinatorBT = Node(c1, Node(c2, c3)) def com(c: Combinator): CombinatorBT = Leaf(c) diff --git a/catculator-core/src/main/scala/pl/writeonly/catculator/core/adt/calculus/InputEncoder.scala b/catculator-core/src/main/scala/pl/writeonly/catculator/core/adt/calculus/InputEncoder.scala index 52174cc..8de318e 100644 --- a/catculator-core/src/main/scala/pl/writeonly/catculator/core/adt/calculus/InputEncoder.scala +++ b/catculator-core/src/main/scala/pl/writeonly/catculator/core/adt/calculus/InputEncoder.scala @@ -15,13 +15,11 @@ object InputEncoder { }, ) - def encodeInput(input: List[Natural]): CombinatorBT = input - .foldRight(falseCom) { case (n, l) => - cons(church(n), l) - } + def encodeInput(input: List[Natural]): CombinatorBT = input.foldRight(falseCom) { case (n, l) => + cons(church(n), l) + } - def cons(a: CombinatorBT, b: CombinatorBT): CombinatorBT = - app3(sCom, Constants.app3SI(appK(a)), appK(b)) + def cons(a: CombinatorBT, b: CombinatorBT): CombinatorBT = app3(sCom, Constants.app3SI(appK(a)), appK(b)) def church(n: Natural): CombinatorBT = n.toBigInt match { case n if n === BigInt(0) => falseCom diff --git a/catculator-core/src/main/scala/pl/writeonly/catculator/core/adt/calculus/Lambda.scala b/catculator-core/src/main/scala/pl/writeonly/catculator/core/adt/calculus/Lambda.scala index 0b04dee..d54e0a7 100644 --- a/catculator-core/src/main/scala/pl/writeonly/catculator/core/adt/calculus/Lambda.scala +++ b/catculator-core/src/main/scala/pl/writeonly/catculator/core/adt/calculus/Lambda.scala @@ -28,25 +28,21 @@ object Lambda { .mkString // I know it is crazy, but I wanted to check it is possible - private val isOnlyCombinatorStep: (Lambda => Boolean) => Lambda => Boolean = - rec => { - case Com(_) => true - case App(f, g) => rec(f) && rec(g) - case _ => false - } + private val isOnlyCombinatorStep: (Lambda => Boolean) => Lambda => Boolean = rec => { + case Com(_) => true + case App(f, g) => rec(f) && rec(g) + case _ => false + } // I know it is crazy, but I wanted to check it is possible val isOnlyCombinator: Lambda => Boolean = fix(isOnlyCombinatorStep) def let1(t: (String, Lambda), body: Lambda): Lambda = Let(t._1, t._2, body) - def multi(params: List[String], body: NonEmptyList[Lambda]): Lambda = - MultiAbs(params, MultiApp(body)) + def multi(params: List[String], body: NonEmptyList[Lambda]): Lambda = MultiAbs(params, MultiApp(body)) - def multi1(head: Lambda, tail: List[Lambda]): Lambda = - MultiApp(NonEmptyList(head, tail)) - def local1(head: Lambda, tail: List[Lambda]): Lambda = - LocalScope(NonEmptyList(head, tail)) + def multi1(head: Lambda, tail: List[Lambda]): Lambda = MultiApp(NonEmptyList(head, tail)) + def local1(head: Lambda, tail: List[Lambda]): Lambda = LocalScope(NonEmptyList(head, tail)) def natNumFromString(s: String): Lambda = NatNum(Natural(s)) diff --git a/catculator-core/src/main/scala/pl/writeonly/catculator/core/adt/tree/Tree.scala b/catculator-core/src/main/scala/pl/writeonly/catculator/core/adt/tree/Tree.scala index 418c5a3..9744c1e 100644 --- a/catculator-core/src/main/scala/pl/writeonly/catculator/core/adt/tree/Tree.scala +++ b/catculator-core/src/main/scala/pl/writeonly/catculator/core/adt/tree/Tree.scala @@ -7,6 +7,5 @@ enum Tree[A]: case Node(children: NonEmptyList[Tree[A]]) object Tree { - def node[A](head: Tree[A], tail: Tree[A]*): Tree[A] = - Node(NonEmptyList(head, tail.toList)) + def node[A](head: Tree[A], tail: Tree[A]*): Tree[A] = Node(NonEmptyList(head, tail.toList)) } diff --git a/catculator-core/src/main/scala/pl/writeonly/catculator/core/calculators/lazyk/ADT.scala b/catculator-core/src/main/scala/pl/writeonly/catculator/core/calculators/lazyk/ADT.scala index 841e0e5..4671dcb 100644 --- a/catculator-core/src/main/scala/pl/writeonly/catculator/core/calculators/lazyk/ADT.scala +++ b/catculator-core/src/main/scala/pl/writeonly/catculator/core/calculators/lazyk/ADT.scala @@ -2,11 +2,9 @@ package pl.writeonly.catculator.core.calculators.lazyk import pl.writeonly.catculator.core.adt.calculus.Combinator import pl.writeonly.catculator.core.adt.calculus.Combinator.CombinatorBT +import pl.writeonly.catculator.core.adt.calculus.Constants import pl.writeonly.catculator.core.adt.tree.BinaryTree import pl.writeonly.catculator.core.adt.tree.BinaryTree._ - -import pl.writeonly.catculator.core.adt.calculus.Constants - import spire.math.Natural enum ADT: @@ -17,16 +15,18 @@ enum ADT: object ADT { type ADTBT = BinaryTree[ADT] + type ADTBTSafe = Either[String, ADTBT] - val number0: ADTBT = Leaf(ADT.Num(Natural(0))) + val number0: ADTBT = Leaf(ADT.Num(Natural.zero)) + val number1: ADTBT = Leaf(ADT.Num(Natural.one)) val trueVar: ADTBT = fromCombinatorBT(Constants.trueCom) val falseVar: ADTBT = fromCombinatorBT(Constants.falseCom) def fromCombinatorBT(c: CombinatorBT): ADTBT = c match { case Node(a, b) => Node(fromCombinatorBT(a), fromCombinatorBT(b)) - case Leaf(a) => Leaf(fromCombinator(a)) + case Leaf(a) => Leaf(fromCombinator(a)) } private def fromCombinator(c: Combinator): ADT = ADT.Com(c) -} \ No newline at end of file +} diff --git a/catculator-core/src/main/scala/pl/writeonly/catculator/core/calculators/lazyk/Reducer.scala b/catculator-core/src/main/scala/pl/writeonly/catculator/core/calculators/lazyk/Reducer.scala new file mode 100644 index 0000000..16b6c6f --- /dev/null +++ b/catculator-core/src/main/scala/pl/writeonly/catculator/core/calculators/lazyk/Reducer.scala @@ -0,0 +1,40 @@ +package pl.writeonly.catculator.core.calculators.lazyk + +import pl.writeonly.catculator.core.adt.calculus.Combinator +import pl.writeonly.catculator.core.adt.calculus.Combinator._ +import pl.writeonly.catculator.core.adt.tree.BinaryTree +import pl.writeonly.catculator.core.adt.tree.BinaryTree._ +import pl.writeonly.catculator.core.calculators.lazyk.ADT._ +import spire.math.Natural + +import scala.util.Right + +object Reducer { + def reduce(f: ADTBT): ADTBTSafe = f match { + case Node(x, y) => applyM(reduce(x), reduce(y)) + case x => Right(x) + } + + def applyM(fM: ADTBTSafe, xM: ADTBTSafe): ADTBTSafe = + for + f <- fM + x <- xM + r <- apply(f, x) + yield r + + def flippedApply(x: ADTBT, y: ADTBT): ADTBTSafe = apply(y, x) + + def apply(f: ADTBT, x: ADTBT): ADTBTSafe = f match { + case Leaf(ADT.Succ()) => succ(x) + case Node(Node(Leaf(ADT.Com(S)), z), y) => applyM(apply(z, x), apply(y, x)) + case Node(Leaf(ADT.Com(K)), y) => Right(y) + case Leaf(ADT.Com(I)) => Right(x) + case _ => Right(Node(f, x)) + } + + private def succ(x: ADTBT) = x match { + case Leaf(ADT.Num(x)) => Right(Leaf(ADT.Num(x + Natural.one))) + case _ => Left(s"attempted to apply inc to a non-number $x") + } + +} diff --git a/catculator-core/src/main/scala/pl/writeonly/catculator/core/parsers/HaskellParser.scala b/catculator-core/src/main/scala/pl/writeonly/catculator/core/parsers/HaskellParser.scala index ab0adad..4b2cf91 100644 --- a/catculator-core/src/main/scala/pl/writeonly/catculator/core/parsers/HaskellParser.scala +++ b/catculator-core/src/main/scala/pl/writeonly/catculator/core/parsers/HaskellParser.scala @@ -19,8 +19,7 @@ object HaskellParser { c.isLetterOrDigit || c === '_' } - private val identifier: P[String] = - horizontalSymbol((identifierStart ~ identifierContinue.rep0).string) + private val identifier: P[String] = horizontalSymbol((identifierStart ~ identifierContinue.rep0).string) // format: off private val lambda: P[Lambda] = P.defer( @@ -38,35 +37,25 @@ object HaskellParser { private val application0: P[Lambda] = lambda.rep.map(MultiApp.apply) - private val application: P[Lambda] = charSymbol('(') *> application0 <* - charHorizontalSymbol(')') + private val application: P[Lambda] = charSymbol('(') *> application0 <* charHorizontalSymbol(')') - private val let: P[Lambda] = - ( - stringSymbol("let") *> - ((identifier <* stringSymbol("=")) ~ lambda) ~ - (stringSymbol("in") *> lambda) - ).map(let1) + private val let: P[Lambda] = (stringSymbol("let") *> ((identifier <* stringSymbol("=")) ~ lambda) ~ (stringSymbol("in") *> lambda)).map(let1) - private val abstraction0 = charSymbol('\\') *> identifier.rep0 <* - stringSymbol("->") + private val abstraction0 = charSymbol('\\') *> identifier.rep0 <* stringSymbol("->") - private val abstraction: P[Lambda] = (abstraction0 ~ application0) - .map(MultiAbs.apply) + private val abstraction: P[Lambda] = (abstraction0 ~ application0).map(MultiAbs.apply) val charStr: P[Lambda] = horizontalSymbol(jsonString.map(CharStr.apply)) private val apostrophe = P.char('\'') - val char: P[Lambda] = horizontalSymbol(apostrophe *> P.anyChar <* apostrophe) - .map { c => - natNumFromLong(c.toLong) - } + val char: P[Lambda] = horizontalSymbol(apostrophe *> P.anyChar <* apostrophe).map { c => + natNumFromLong(c.toLong) + } val natNum: P[Lambda] = horizontalSymbol(digits.map(natNumFromString)) - private val function: P[Func] = - ((identifier <* charSymbol('=')) ~ symbol(lambda)).map(Func.apply) + private val function: P[Func] = ((identifier <* charSymbol('=')) ~ symbol(lambda)).map(Func.apply) private val functionParser: P[Func] = function <* P.end @@ -74,8 +63,7 @@ object HaskellParser { val parseFunction: String => Either[P.Error, Func] = functionParser.parseAll - val parseFunctions: String => Either[P.Error, NonEmptyList[Func]] = - functionsParser.parseAll + val parseFunctions: String => Either[P.Error, NonEmptyList[Func]] = functionsParser.parseAll val parse3: String => Either[P.Error, NonEmptyList[Func]] = (s) => parseFunctions(s) match { diff --git a/catculator-core/src/main/scala/pl/writeonly/catculator/core/parsers/LambdaParser.scala b/catculator-core/src/main/scala/pl/writeonly/catculator/core/parsers/LambdaParser.scala index 127ac40..f035dcc 100644 --- a/catculator-core/src/main/scala/pl/writeonly/catculator/core/parsers/LambdaParser.scala +++ b/catculator-core/src/main/scala/pl/writeonly/catculator/core/parsers/LambdaParser.scala @@ -19,8 +19,7 @@ object LambdaParser { c.isLetterOrDigit || c === '_' } - val identifier: P[String] = - symbol((identifierStart ~ identifierContinue.rep0).string) + val identifier: P[String] = symbol((identifierStart ~ identifierContinue.rep0).string) // format: off val lambda: P[Lambda] = P.defer( @@ -38,26 +37,19 @@ object LambdaParser { val variable: P[Lambda] = identifier.map(Var.apply) - val abstraction: P[Lambda] = (charSymbol('\\') *> identifier ~ lambda) - .map(Abs.apply) + val abstraction: P[Lambda] = (charSymbol('\\') *> identifier ~ lambda).map(Abs.apply) - val application: P[Lambda] = (charSymbol('`') *> lambda ~ lambda) - .map(App.apply) + val application: P[Lambda] = (charSymbol('`') *> lambda ~ lambda).map(App.apply) - val mautiApplicationChildren: P[Lambda] = (lambda ~ lambda.rep0) - .map((multi1 _).tupled) + val mautiApplicationChildren: P[Lambda] = (lambda ~ lambda.rep0).map((multi1 _).tupled) - val multiApplication: P[Lambda] = - charSymbol('(') *> mautiApplicationChildren <* charSymbol(')') + val multiApplication: P[Lambda] = charSymbol('(') *> mautiApplicationChildren <* charSymbol(')') - val localScopeChildren: P[Lambda] = (lambda ~ lambda.rep0) - .map((local1 _).tupled) + val localScopeChildren: P[Lambda] = (lambda ~ lambda.rep0).map((local1 _).tupled) - val localScope: P[Lambda] = charSymbol('{') *> localScopeChildren <* - charSymbol('}') + val localScope: P[Lambda] = charSymbol('{') *> localScopeChildren <* charSymbol('}') - val nilList: P[Lambda] = charSymbol('[') *> lambda.rep0.map(NilList.apply) <* - charSymbol(']') + val nilList: P[Lambda] = charSymbol('[') *> lambda.rep0.map(NilList.apply) <* charSymbol(']') val charStr: P[Lambda] = jsonString.map(CharStr.apply) diff --git a/catculator-core/src/main/scala/pl/writeonly/catculator/core/reducers/AbstractionReducer.scala b/catculator-core/src/main/scala/pl/writeonly/catculator/core/reducers/AbstractionReducer.scala index 4ecdf50..e8680c2 100644 --- a/catculator-core/src/main/scala/pl/writeonly/catculator/core/reducers/AbstractionReducer.scala +++ b/catculator-core/src/main/scala/pl/writeonly/catculator/core/reducers/AbstractionReducer.scala @@ -18,22 +18,17 @@ object AbstractionReducer { case l if isOnlyCombinator(l) => wrapAppK(l) case Var(n1) => reduceVar(p0, n1) case Abs(p1, b1) => reduceAbs(p0, p1, b1) - case App(f, g) => - wrapAppAppS(reduceAbstraction1(p0, f), reduceAbstraction1(p0, g)) - case lambda => lambda + case App(f, g) => wrapAppAppS(reduceAbstraction1(p0, f), reduceAbstraction1(p0, g)) + case lambda => lambda } - private def reduceVar(n0: String, n1: String): Lambda = - ifElse(n0 === n1)(Com(I))(wrapAppK(Var(n1))) + private def reduceVar(n0: String, n1: String): Lambda = ifElse(n0 === n1)(Com(I))(wrapAppK(Var(n1))) - private def reduceAbs(p0: String, p1: String, b1: Lambda): Lambda = - reduceAbs1(p0, p1, reduceAbstraction1(p1, b1)) + private def reduceAbs(p0: String, p1: String, b1: Lambda): Lambda = reduceAbs1(p0, p1, reduceAbstraction1(p1, b1)) - private def reduceAbs1(p0: String, p1: String, c: Lambda): Lambda = - ifElse(p0 === p1)(wrapAppK(c))(reduceAbstraction1(p0, c)) + private def reduceAbs1(p0: String, p1: String, c: Lambda): Lambda = ifElse(p0 === p1)(wrapAppK(c))(reduceAbstraction1(p0, c)) private def wrapAppK(c: Lambda): Lambda = App(Com(K), c) - private def wrapAppAppS(c1: Lambda, c2: Lambda): Lambda = - App(App(Com(S), c1), c2) + private def wrapAppAppS(c1: Lambda, c2: Lambda): Lambda = App(App(Com(S), c1), c2) } diff --git a/catculator-core/src/main/scala/pl/writeonly/catculator/core/reducers/SugarReducer.scala b/catculator-core/src/main/scala/pl/writeonly/catculator/core/reducers/SugarReducer.scala index 16bfbf4..c3baf44 100644 --- a/catculator-core/src/main/scala/pl/writeonly/catculator/core/reducers/SugarReducer.scala +++ b/catculator-core/src/main/scala/pl/writeonly/catculator/core/reducers/SugarReducer.scala @@ -35,22 +35,15 @@ class SugarReducer(config: LambdaConfig) { case IntNum(s, n) => reduceIntNum(s, n) } - private def reduceAbss(params: List[String], body: Lambda): Lambda = params - .foldRight(body)(Abs.apply) + private def reduceAbss(params: List[String], body: Lambda): Lambda = params.foldRight(body)(Abs.apply) - private def reduceApps(l: NonEmptyList[Lambda]): Lambda = - foldNonEmpty(l)(App.apply) + private def reduceApps(l: NonEmptyList[Lambda]): Lambda = foldNonEmpty(l)(App.apply) - def reduceLets(ps: NonEmptyList[(String, Lambda)], body: Lambda): Lambda = - MultiApp( - NonEmptyList(MultiAbs(ps.map(_._1).toList, body), ps.map(_._2).toList), - ) + def reduceLets(ps: NonEmptyList[(String, Lambda)], body: Lambda): Lambda = MultiApp(NonEmptyList(MultiAbs(ps.map(_._1).toList, body), ps.map(_._2).toList)) - private def reduceNilList(xs: List[Lambda]): Lambda = xs - .foldRight(config.nilVariable)(config.wrapAppVireoApp) + private def reduceNilList(xs: List[Lambda]): Lambda = xs.foldRight(config.nilVariable)(config.wrapAppVireoApp) - private def reduceCharStr(s: String): Lambda = - reduceNilList(nilListFromCharStr(s)) + private def reduceCharStr(s: String): Lambda = reduceNilList(nilListFromCharStr(s)) private def nilListFromCharStr(s: String): List[Lambda] = s .toList @@ -61,12 +54,9 @@ class SugarReducer(config: LambdaConfig) { List(config.vireoVariable, l) } - private def reduceNatNum(n: Natural): Lambda = ifElse(n.isZero)( - config.zeroVariable, - )(config.appSuccVariable(reduceNatNum(n - UInt(1)))) + private def reduceNatNum(n: Natural): Lambda = ifElse(n.isZero)(config.zeroVariable)(config.appSuccVariable(reduceNatNum(n - UInt(1)))) - private def reduceIntNum(s: Sign, n: Natural): Lambda = config - .wrapAppVireoApp(reduceSign(s), reduceNatNum(n)) + private def reduceIntNum(s: Sign, n: Natural): Lambda = config.wrapAppVireoApp(reduceSign(s), reduceNatNum(n)) private def reduceSign(s: Sign): Lambda = s match { case Plus => config.falseVariable diff --git a/catculator-core/src/test/scala/pl/writeonly/catculator/core/TableDrivenPropertySpec.scala b/catculator-core/src/test/scala/pl/writeonly/catculator/core/TableDrivenPropertySpec.scala index c3ea51e..9065b1a 100644 --- a/catculator-core/src/test/scala/pl/writeonly/catculator/core/TableDrivenPropertySpec.scala +++ b/catculator-core/src/test/scala/pl/writeonly/catculator/core/TableDrivenPropertySpec.scala @@ -3,7 +3,4 @@ package pl.writeonly.catculator.core import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.prop.TableDrivenPropertyChecks -class TableDrivenPropertySpec - extends AnyFlatSpec - with TableDrivenPropertyChecks - with BaseSpec +class TableDrivenPropertySpec extends AnyFlatSpec with TableDrivenPropertyChecks with BaseSpec diff --git a/catculator-core/src/test/scala/pl/writeonly/catculator/core/adt/calculus/InputEncoderSpec.scala b/catculator-core/src/test/scala/pl/writeonly/catculator/core/adt/calculus/InputEncoderSpec.scala index 4620708..6466b37 100644 --- a/catculator-core/src/test/scala/pl/writeonly/catculator/core/adt/calculus/InputEncoderSpec.scala +++ b/catculator-core/src/test/scala/pl/writeonly/catculator/core/adt/calculus/InputEncoderSpec.scala @@ -1,45 +1,33 @@ package pl.writeonly.catculator.core.adt.calculus +import pl.writeonly.catculator.core.TableDrivenPropertySpec import pl.writeonly.catculator.core.adt.calculus.Combinator._ import pl.writeonly.catculator.core.adt.calculus.Constants._ import pl.writeonly.catculator.core.adt.tree.BinaryTree._ - -import pl.writeonly.catculator.core.TableDrivenPropertySpec - import spire.math.Natural class InputEncoderSpec extends TableDrivenPropertySpec { private val oneCom = Node(Leaf(S), Node(Node(Leaf(S), Node(Node(Leaf(K), Leaf(S)), Leaf(K))), Node(Leaf(K), Leaf(I)))) - private var zeroListCom = Node(Leaf(S), Node(Node(Leaf(S), Node(Leaf(I), Node(Leaf(K), Node(Leaf(K), Leaf(I))))), Node(Leaf(K), Node(Leaf(K), Leaf(I))))) + private val zeroListCom = Node(Leaf(S), Node(Node(Leaf(S), Node(Leaf(I), Node(Leaf(K), Node(Leaf(K), Leaf(I))))), Node(Leaf(K), Node(Leaf(K), Leaf(I))))) it should "church number" in { - val combinators = Table( - ("input", "ast"), - (Natural.zero, falseCom), - (Natural.one, oneCom), - ) + val combinators = Table(("input", "ast"), (Natural.zero, falseCom), (Natural.one, oneCom)) forAll(combinators) { (input, code) => InputEncoder.church(input) shouldBe code } } it should "encode input List" in { - val combinators = Table( - ("input", "ast"), - (List(Natural.zero), zeroListCom), - ) + val combinators = Table(("input", "ast"), (List(Natural.zero), zeroListCom)) forAll(combinators) { (input, code) => InputEncoder.encodeInput(input) shouldBe code } } it should "encode input String" in { - val combinators = Table( - ("input", "ast"), - ("", falseCom), - ) + val combinators = Table(("input", "ast"), ("", falseCom)) forAll(combinators) { (input, code) => InputEncoder.readInput(input) shouldBe code } diff --git a/catculator-core/src/test/scala/pl/writeonly/catculator/core/calculators/lazyk/ReducerSpec.scala b/catculator-core/src/test/scala/pl/writeonly/catculator/core/calculators/lazyk/ReducerSpec.scala new file mode 100644 index 0000000..8545f16 --- /dev/null +++ b/catculator-core/src/test/scala/pl/writeonly/catculator/core/calculators/lazyk/ReducerSpec.scala @@ -0,0 +1,34 @@ +package pl.writeonly.catculator.core.calculators.lazyk + +import pl.writeonly.catculator.core.UnitSpec +import pl.writeonly.catculator.core.adt.calculus.Combinator.* +import pl.writeonly.catculator.core.adt.tree.BinaryTree.* +import pl.writeonly.catculator.core.calculators.lazyk.ADT.* +import pl.writeonly.catculator.core.calculators.lazyk.Reducer.* + +class ReducerSpec extends UnitSpec { + "A Reducer" should { + val idVar = Leaf(Com(I)) + val succ = Leaf(Succ()) + + "return 1 for succ zero" in { + reduce(Node(succ, number0)).value shouldBe number1 + } + + "return 0 for I 0" in { + reduce(Node(idVar, number0)).value shouldBe number0 + } + + "return 0 for K 0 1" in { + reduce(Node(Node(trueVar, number0), number1)).value shouldBe number0 + } + + "return 1 for F 0 1" in { + reduce(Node(Node(falseVar, number0), number1)).value shouldBe number1 + } + + "return 0 for S K 0 1" in { + reduce(Node(Node(Node(Leaf(Com(S)), trueVar), succ), number0)).value shouldBe number0 + } + } +} diff --git a/catculator-core/src/test/scala/pl/writeonly/catculator/core/generators/CombinatorSpec.scala b/catculator-core/src/test/scala/pl/writeonly/catculator/core/generators/CombinatorSpec.scala index 4ec6ad3..0ccb222 100644 --- a/catculator-core/src/test/scala/pl/writeonly/catculator/core/generators/CombinatorSpec.scala +++ b/catculator-core/src/test/scala/pl/writeonly/catculator/core/generators/CombinatorSpec.scala @@ -6,11 +6,7 @@ import pl.writeonly.catculator.core.adt.calculus.Combinator._ class CombinatorSpec extends TableDrivenPropertySpec { it should "generate code for BinaryTree of Combinators" in { import pl.writeonly.catculator.core.adt.tree.BinaryTree._ - val combinators = Table( - ("ast", "code"), - (Leaf(I), "I"), - (Node(Leaf(S), Node(Leaf(K), Leaf(K))), "`S `K K"), - ) + val combinators = Table(("ast", "code"), (Leaf(I), "I"), (Node(Leaf(S), Node(Leaf(K), Leaf(K))), "`S `K K")) forAll(combinators) { (ast, code) => generateBT(ast) shouldBe code } @@ -18,11 +14,7 @@ class CombinatorSpec extends TableDrivenPropertySpec { it should "generate code for Tree of Combinators" in { import pl.writeonly.catculator.core.adt.tree.Tree._ - val combinators = Table( - ("ast", "code"), - (Leaf(I), "I"), - (node(Leaf(S), node(Leaf(K), Leaf(K))), "(S (K K))"), - ) + val combinators = Table(("ast", "code"), (Leaf(I), "I"), (node(Leaf(S), node(Leaf(K), Leaf(K))), "(S (K K))")) forAll(combinators) { (ast, code) => generateT(ast) shouldBe code } diff --git a/catculator-core/src/test/scala/pl/writeonly/catculator/core/parsers/HaskellSpec.scala b/catculator-core/src/test/scala/pl/writeonly/catculator/core/parsers/HaskellSpec.scala index 1ef693b..2dc647e 100644 --- a/catculator-core/src/test/scala/pl/writeonly/catculator/core/parsers/HaskellSpec.scala +++ b/catculator-core/src/test/scala/pl/writeonly/catculator/core/parsers/HaskellSpec.scala @@ -136,26 +136,14 @@ class HaskellSpec extends TableDrivenPropertySpec { (HelloWorld2, "`apply `0 \\const `apply `1 \\main main"), (HelloWorld3, "`apply `\\a \\b (a) \\const `apply `0 \\main main"), (HelloWorld4, "`apply `\\a \\b (a) \\const `apply `const \\main main"), - ( - HelloWorld5, - "`apply `\\a \\b (a) \\const `apply `(const const) \\main main", - ), + (HelloWorld5, "`apply `\\a \\b (a) \\const `apply `(const const) \\main main"), ) - val programs: TableFor3[String, String, String] = Table( - ("function", "input", "output"), - (Empty, "", ""), - (HelloWorld, "", ""), - (Factorial, "", ""), - ) + val programs: TableFor3[String, String, String] = Table(("function", "input", "output"), (Empty, "", ""), (HelloWorld, "", ""), (Factorial, "", "")) it should "parse sinpleFunctions and save lambda" in { forAll(simpleFunctions) { (function, lambda) => - HaskellParser - .parseFunction(function) - .map(_.lambda) - .map(HaskellGenerator.generate) - .value shouldBe lambda + HaskellParser.parseFunction(function).map(_.lambda).map(HaskellGenerator.generate).value shouldBe lambda } } diff --git a/catculator-core/src/test/scala/pl/writeonly/catculator/core/parsers/LambdaSpec.scala b/catculator-core/src/test/scala/pl/writeonly/catculator/core/parsers/LambdaSpec.scala index 5da6e6d..7ec1e6e 100644 --- a/catculator-core/src/test/scala/pl/writeonly/catculator/core/parsers/LambdaSpec.scala +++ b/catculator-core/src/test/scala/pl/writeonly/catculator/core/parsers/LambdaSpec.scala @@ -18,16 +18,8 @@ class LambdaSpec extends TableDrivenPropertySpec { ("`a a", App(Var("a"), Var("a")), "`a a"), ("\\a `a a", Abs("a", App(Var("a"), Var("a"))), "``S I I"), ("\\a \\a a", Abs("a", Abs("a", Var("a"))), "`K I"), - ( - "\\a \\b `a b", - Abs("a", Abs("b", App(Var("a"), Var("b")))), - "``S ``S `K S ``S `K K I `K I", - ), - ( - "\\a \\b `b a", - Abs("a", Abs("b", App(Var("b"), Var("a")))), - "``S `K `S I ``S `K K I", - ), + ("\\a \\b `a b", Abs("a", Abs("b", App(Var("a"), Var("b")))), "``S ``S `K S ``S `K K I `K I"), + ("\\a \\b `b a", Abs("a", Abs("b", App(Var("b"), Var("a")))), "``S `K `S I ``S `K K I"), ) val advancedLambda: TableFor3[String, String, String] = Table( @@ -64,40 +56,25 @@ class LambdaSpec extends TableDrivenPropertySpec { it should "compile basic Lambda" in { forAll(basicLambda) { (lambda, _, combinators) => - LambdaParser - .parse(lambda) - .map(lambdaSugarReducer.reduceSugar) - .map(reduceAbstraction) - .map(LambdaGenerator.generate) - .value shouldBe combinators + LambdaParser.parse(lambda).map(lambdaSugarReducer.reduceSugar).map(reduceAbstraction).map(LambdaGenerator.generate).value shouldBe combinators } } it should "parse advanced Lambda" in { forAll(advancedLambda) { (lambda, _, _) => - LambdaParser.parse(lambda).map(LambdaGenerator.generate).value shouldBe - lambda + LambdaParser.parse(lambda).map(LambdaGenerator.generate).value shouldBe lambda } } it should "desugar advanced Lambda" in { forAll(advancedLambda) { (lambda, desugared, _) => - LambdaParser - .parse(lambda) - .map(lambdaSugarReducer.reduceSugar) - .map(LambdaGenerator.generate) - .value shouldBe desugared + LambdaParser.parse(lambda).map(lambdaSugarReducer.reduceSugar).map(LambdaGenerator.generate).value shouldBe desugared } } it should "compile advanced Lambda" in { forAll(advancedLambda) { (sugar, _, combinators) => - LambdaParser - .parse(sugar) - .map(lambdaSugarReducer.reduceSugar) - .map(reduceAbstraction) - .map(LambdaGenerator.generate) - .value shouldBe combinators + LambdaParser.parse(sugar).map(lambdaSugarReducer.reduceSugar).map(reduceAbstraction).map(LambdaGenerator.generate).value shouldBe combinators } } }