Skip to content

Commit 73880a3

Browse files
committed
Check type of all evaluated interpretation+fixed bug in 'Eval' type checking
1 parent 9fd4b27 commit 73880a3

3 files changed

Lines changed: 46 additions & 29 deletions

File tree

src/main/scala/org/miniML/TypeChecker.scala

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ object TypeChecker {
1111

1212
def apply(e: Expression, env: Environment, equations: Equations): Either[String, (EType, Equations)] = {
1313

14-
def newVariable(eq: Equations, env: Environment): EType = {
14+
def nextIndex(eq: Equations, env: Environment): Int = {
1515
def maxIndex(t: EType): Int = t match {
1616
case Nat() => 0
1717
case F(t1, t2) => Math.max(maxIndex(t1), maxIndex(t2))
@@ -21,10 +21,11 @@ object TypeChecker {
2121

2222
val nEquations = eq.foldLeft(0)((a, eq) => Math.max(a, Math.max(maxIndex(eq._1), maxIndex(eq._2))))
2323
val nEnvironment = env.foldLeft(0)((n, typedExp) => Math.max(n, maxIndex(typedExp._2)))
24-
val n = Math.max(nEquations, nEnvironment)
25-
V(n + 1)
24+
Math.max(nEquations, nEnvironment)
2625
}
2726

27+
def newVariable(eq: Equations, env: Environment): EType = V(nextIndex(eq, env) + 1)
28+
2829
def addNatEquation(eq: Equations, e: Expression, t: EType) = addEquation2(eq, e, t, Integer(0), Nat()) match {
2930
case Right(eq2) => Right(eq2)
3031
case _ => Left(e + " type should be integer. ")
@@ -121,7 +122,7 @@ object TypeChecker {
121122
rEquations <- addEquation2(equations, funExp, t1, exp, eType)
122123
} yield (replaceVariable(t2,rEquations), rEquations)
123124
case V(i) =>
124-
val newVar = newVariable(equations, env)
125+
val newVar = V(Math.max(nextIndex(equations, env), i) + 1)
125126
for {
126127
rEquations <- addEquation(equations, e, V(i) -> F(eType, newVar))
127128
} yield (newVar, rEquations)

src/test/scala/org/miniML/EvalInterpretSuite.scala

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
package org.miniML
44

55
import org.junit.runner.RunWith
6+
import org.miniML.TypeChecker.{EType, F, Nat, V}
67
import org.scalatest.FunSuite
78
import org.scalatest.junit.JUnitRunner
89
import org.miniML.parser._
@@ -12,9 +13,16 @@ import org.miniML.parser.Identifier._
1213
@RunWith(classOf[JUnitRunner])
1314
class EvalInterpretSuite extends FunSuite {
1415

15-
def check(e: String, i: Int): Unit = check(e, i, None)
16+
val ep = new ExpressionParser()
17+
18+
def check(e: String, exp: Expression, mode: Option[Eval.Mode] = None, eType: Option[EType] = Some(Nat())) {
19+
20+
val t = TypeChecker(ep.parse(e).get)
21+
eType match {
22+
case Some(et) => assert(t.isRight && t.right.get._1 == et)
23+
case None => assert(t.isLeft)
24+
}
1625

17-
def check(e: String, exp: Expression, mode:Option[Eval.Mode] = None) {
1826
if (mode.isEmpty || mode.contains(Eval.ByName)) {
1927
val r1 = Eval(e, Eval.ByName)
2028
eAssert(r1, exp)
@@ -86,7 +94,8 @@ class EvalInterpretSuite extends FunSuite {
8694
}
8795

8896
test("simple let test (call by name)") {
89-
check("let f = fun x-> (x x) in let v = f f in 1", 1, Some(Eval.ByName))
97+
// (x x) is not typable
98+
check("let f = fun x-> (x x) in let v = f f in 1", 1, Some(Eval.ByName), None)
9099
}
91100

92101
test("simple nested let test") {
@@ -98,7 +107,7 @@ class EvalInterpretSuite extends FunSuite {
98107
}
99108

100109
test("simple ifz test") {
101-
check("ifz 1 then (let f = fun x-> (x x) in (f f)) else 0", 0)
110+
check("ifz 1 then (let f = fun x-> (x x) in (f f)) else 0", 0, eType = None)
102111
}
103112

104113
test("ifz test with expressions") {
@@ -110,11 +119,11 @@ class EvalInterpretSuite extends FunSuite {
110119
}
111120

112121
test("simple function test") {
113-
check("fun a -> a + 1", Fun("a", Sum("a", 1)))
122+
check("fun a -> a + 1", Fun("a", Sum("a", 1)), eType = Some(F(Nat(), Nat())))
114123
}
115124

116125
test("double function test") {
117-
check("fun a -> fun b -> b + a", Fun("a", Fun("b", Sum("b", "a"))))
126+
check("fun a -> fun b -> b + a", Fun("a", Fun("b", Sum("b", "a"))), eType=Some(F(Nat(), F(Nat(), Nat()))))
118127
}
119128

120129
test("function application 1") {
@@ -167,7 +176,7 @@ class EvalInterpretSuite extends FunSuite {
167176

168177
// This would not finish when evaluated by value
169178
test("function for call by name") {
170-
check("let f1 = fun a -> 1 in let f2 = fun x-> (x x) in 2 + (f1 (f2 f2))", 3, Some(Eval.ByName))
179+
check("let f1 = fun a -> 1 in let f2 = fun x-> (x x) in 2 + (f1 (f2 f2))", 3, Some(Eval.ByName), None)
171180
}
172181

173182
test("combining simple functions 1") {
@@ -179,7 +188,9 @@ class EvalInterpretSuite extends FunSuite {
179188
}
180189

181190
test("combine functions") {
182-
check("let f = fun x -> x * 2 in let g = fun x -> x + 1 in let combine = fun f1 -> fun f2 -> fun x -> (f1 (f2 x)) in combine g f 1",3)
191+
// TODO: Type should be 'Nat()'
192+
check("let f = fun x -> x * 2 in let g = fun x -> x + 1 in let combine = fun f1 -> fun f2 -> fun x -> (f1 (f2 x)) in combine g f 1",
193+
3, eType = Some(V(6)))
183194
}
184195

185196
test("iFactorial test") {
@@ -199,16 +210,16 @@ class EvalInterpretSuite extends FunSuite {
199210
"let iFactorial = fun f2 -> fun n -> ifz n then 1 else (n * (f2 (n-1))) in " +
200211
"let fact = yCombinator iFactorial in fact "
201212

202-
check(fact2 + "0", 1)
203-
check(fact2 + "1", 1)
204-
check(fact2 + "5", 1*2*3*4*5)
213+
check(fact2 + "0", 1, eType = None)
214+
check(fact2 + "1", 1, eType = None)
215+
check(fact2 + "5", 1*2*3*4*5, eType = None)
205216
}
206217

207218
test("power function (With Y combinator)") {
208219
check("let yCombinator = fun f -> (fun x -> f (x x)) fun x -> f (x x) in "
209220
+ "let iPower = fun n -> fun f2 -> fun p -> ifz p then 1 else n * (f2 p - 1) in "
210221
+ "let power = fun n -> fun p -> (yCombinator (iPower n) p) in "
211-
+ "power 2 3", Integer(2*2*2))
222+
+ "power 2 3", Integer(2*2*2), eType = None)
212223
}
213224

214225
test("factorial (with fix function)") {
@@ -287,15 +298,15 @@ class EvalInterpretSuite extends FunSuite {
287298
"let and = fun a -> fun b -> a b false in " +
288299
"let or = fun a -> fun b -> a true b in "
289300

290-
check(e + " not true", eFalse)
291-
check(e + " not false",eTrue)
292-
check(e + " and true true", eTrue)
293-
check(e + " and true false", eFalse)
294-
check(e + " and false true", eFalse)
295-
check(e + " and false false", eFalse)
296-
check(e + " or true true", eTrue)
297-
check(e + " or true false", eTrue)
298-
check(e + " or false true", eTrue)
299-
check(e + " or false false", eFalse)
301+
check(e + " not true", eFalse, eType = Some(V(7)))
302+
check(e + " not false",eTrue, eType = Some(V(7)))
303+
check(e + " and true true", eTrue, eType = Some(V(11)))
304+
check(e + " and true false", eFalse, eType = Some(V(11)))
305+
check(e + " and false true", eFalse, eType = Some(V(11)))
306+
check(e + " and false false", eFalse, eType = Some(V(11)))
307+
check(e + " or true true", eTrue, eType = Some(V(15)))
308+
check(e + " or true false", eTrue, eType = Some(V(15)))
309+
check(e + " or false true", eTrue, eType = Some(V(15)))
310+
check(e + " or false false", eFalse, eType = Some(V(15)))
300311
}
301312
}

src/test/scala/org/miniML/TypeCheckerSuite.scala

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package org.miniML
22

33
import org.junit.runner.RunWith
4-
import org.miniML.TypeChecker.{EType, F, Nat, V}
4+
import org.miniML.TypeChecker._
55
import org.scalatest.FunSuite
66
import org.scalatest.junit.JUnitRunner
77
import org.miniML.parser.{ExpressionParser, Integer}
@@ -18,7 +18,7 @@ class TypeCheckerSuite extends FunSuite {
1818
val ep = new ExpressionParser()
1919

2020
def check(s: String, et: EType): Unit = {
21-
val t = TypeChecker(ep.parse(s).get)
21+
val t: Either[String, (EType, Equations)] = TypeChecker(ep.parse(s).get)
2222
println(s)
2323
if (t.isLeft) {
2424
println(t.left.get)
@@ -99,7 +99,12 @@ class TypeCheckerSuite extends FunSuite {
9999
}
100100

101101
test("fix test") {
102-
check("(fix f fun n -> (ifz n then 1 else (n * (f (n -1)))))", F(Nat(),Nat()));
102+
check("(fix f fun n -> (ifz n then 1 else (n * (f (n -1)))))", F(Nat(),Nat()))
103+
}
104+
105+
test("fix test 2") {
106+
val sumSquares = "(fun n -> (fix f fun i -> fun j -> ifz i then j else f (i-1) j+i) n 0) "
107+
check(sumSquares + "2", Nat())
103108
}
104109

105110
}

0 commit comments

Comments
 (0)