aboutsummaryrefslogtreecommitdiff
path: root/lab4/src/test
diff options
context:
space:
mode:
Diffstat (limited to 'lab4/src/test')
-rw-r--r--lab4/src/test/resources/lab4/test4001_id.ans4
-rw-r--r--lab4/src/test/resources/lab4/test4001_id.jsy1
-rw-r--r--lab4/src/test/resources/lab4/test4002_multiparamfun.ans6
-rw-r--r--lab4/src/test/resources/lab4/test4002_multiparamfun.jsy1
-rw-r--r--lab4/src/test/resources/lab4/test4007_objliteral.ans4
-rw-r--r--lab4/src/test/resources/lab4/test4007_objliteral.jsy1
-rw-r--r--lab4/src/test/resources/lab4/test4010_deref.ans4
-rw-r--r--lab4/src/test/resources/lab4/test4010_deref.jsy1
-rw-r--r--lab4/src/test/resources/lab4/test4029_simplerec.ans11
-rw-r--r--lab4/src/test/resources/lab4/test4029_simplerec.jsy2
-rw-r--r--lab4/src/test/scala/jsy/lab4/Lab4Spec.scala217
-rw-r--r--lab4/src/test/scala/jsy/tester/JavascriptyTester.scala23
12 files changed, 275 insertions, 0 deletions
diff --git a/lab4/src/test/resources/lab4/test4001_id.ans b/lab4/src/test/resources/lab4/test4001_id.ans
new file mode 100644
index 0000000..b0ea4bc
--- /dev/null
+++ b/lab4/src/test/resources/lab4/test4001_id.ans
@@ -0,0 +1,4 @@
+## Call(Fun(None,List((x,TNumber)),None,Var(x)),List(N(4.0))) : number
+## step 0: Call(Fun(None,List((x,TNumber)),None,Var(x)),List(N(4.0)))
+## value: N(4.0)
+4.0
diff --git a/lab4/src/test/resources/lab4/test4001_id.jsy b/lab4/src/test/resources/lab4/test4001_id.jsy
new file mode 100644
index 0000000..3402469
--- /dev/null
+++ b/lab4/src/test/resources/lab4/test4001_id.jsy
@@ -0,0 +1 @@
+function(x: number) {return x } (4)
diff --git a/lab4/src/test/resources/lab4/test4002_multiparamfun.ans b/lab4/src/test/resources/lab4/test4002_multiparamfun.ans
new file mode 100644
index 0000000..302ccae
--- /dev/null
+++ b/lab4/src/test/resources/lab4/test4002_multiparamfun.ans
@@ -0,0 +1,6 @@
+## Call(Fun(None,List((x,TNumber), (y,TBool)),None,If(Var(y),Binary(Plus,Var(x),N(1.0)),Binary(Minus,Var(x),N(1.0)))),List(N(4.0), B(true))) : number
+## step 0: Call(Fun(None,List((x,TNumber), (y,TBool)),None,If(Var(y),Binary(Plus,Var(x),N(1.0)),Binary(Minus,Var(x),N(1.0)))),List(N(4.0), B(true)))
+## step 1: If(B(true),Binary(Plus,N(4.0),N(1.0)),Binary(Minus,N(4.0),N(1.0)))
+## step 2: Binary(Plus,N(4.0),N(1.0))
+## value: N(5.0)
+5.0
diff --git a/lab4/src/test/resources/lab4/test4002_multiparamfun.jsy b/lab4/src/test/resources/lab4/test4002_multiparamfun.jsy
new file mode 100644
index 0000000..9c38c07
--- /dev/null
+++ b/lab4/src/test/resources/lab4/test4002_multiparamfun.jsy
@@ -0,0 +1 @@
+function (x: number, y: bool) { return y ? x + 1 : x - 1 } (4, true)
diff --git a/lab4/src/test/resources/lab4/test4007_objliteral.ans b/lab4/src/test/resources/lab4/test4007_objliteral.ans
new file mode 100644
index 0000000..4b4cc1b
--- /dev/null
+++ b/lab4/src/test/resources/lab4/test4007_objliteral.ans
@@ -0,0 +1,4 @@
+## Obj(TreeMap(a -> N(5.0), b -> N(2.0))) : { a: number; b: number }
+## value: Obj(TreeMap(a -> N(5.0), b -> N(2.0)))
+{ a: 5.0,
+ b: 2.0 }
diff --git a/lab4/src/test/resources/lab4/test4007_objliteral.jsy b/lab4/src/test/resources/lab4/test4007_objliteral.jsy
new file mode 100644
index 0000000..b98f88d
--- /dev/null
+++ b/lab4/src/test/resources/lab4/test4007_objliteral.jsy
@@ -0,0 +1 @@
+{a: 5, b: 2} \ No newline at end of file
diff --git a/lab4/src/test/resources/lab4/test4010_deref.ans b/lab4/src/test/resources/lab4/test4010_deref.ans
new file mode 100644
index 0000000..69a991f
--- /dev/null
+++ b/lab4/src/test/resources/lab4/test4010_deref.ans
@@ -0,0 +1,4 @@
+## GetField(Obj(TreeMap(f -> N(3.0))),f) : number
+## step 0: GetField(Obj(TreeMap(f -> N(3.0))),f)
+## value: N(3.0)
+3.0
diff --git a/lab4/src/test/resources/lab4/test4010_deref.jsy b/lab4/src/test/resources/lab4/test4010_deref.jsy
new file mode 100644
index 0000000..83418ef
--- /dev/null
+++ b/lab4/src/test/resources/lab4/test4010_deref.jsy
@@ -0,0 +1 @@
+{ f: 3 }.f
diff --git a/lab4/src/test/resources/lab4/test4029_simplerec.ans b/lab4/src/test/resources/lab4/test4029_simplerec.ans
new file mode 100644
index 0000000..b773df9
--- /dev/null
+++ b/lab4/src/test/resources/lab4/test4029_simplerec.ans
@@ -0,0 +1,11 @@
+## ConstDecl(n,N(1.0),Call(Fun(Some(f),List((n,TNumber)),Some(TNumber),If(Binary(Eq,Var(n),N(0.0)),N(0.0),Call(Var(f),List(Binary(Minus,Var(n),N(1.0)))))),List(N(1.0)))) : number
+## step 0: ConstDecl(n,N(1.0),Call(Fun(Some(f),List((n,TNumber)),Some(TNumber),If(Binary(Eq,Var(n),N(0.0)),N(0.0),Call(Var(f),List(Binary(Minus,Var(n),N(1.0)))))),List(N(1.0))))
+## step 1: Call(Fun(Some(f),List((n,TNumber)),Some(TNumber),If(Binary(Eq,Var(n),N(0.0)),N(0.0),Call(Var(f),List(Binary(Minus,Var(n),N(1.0)))))),List(N(1.0)))
+## step 2: If(Binary(Eq,N(1.0),N(0.0)),N(0.0),Call(Fun(Some(f),List((n,TNumber)),Some(TNumber),If(Binary(Eq,Var(n),N(0.0)),N(0.0),Call(Var(f),List(Binary(Minus,Var(n),N(1.0)))))),List(Binary(Minus,N(1.0),N(1.0)))))
+## step 3: If(B(false),N(0.0),Call(Fun(Some(f),List((n,TNumber)),Some(TNumber),If(Binary(Eq,Var(n),N(0.0)),N(0.0),Call(Var(f),List(Binary(Minus,Var(n),N(1.0)))))),List(Binary(Minus,N(1.0),N(1.0)))))
+## step 4: Call(Fun(Some(f),List((n,TNumber)),Some(TNumber),If(Binary(Eq,Var(n),N(0.0)),N(0.0),Call(Var(f),List(Binary(Minus,Var(n),N(1.0)))))),List(Binary(Minus,N(1.0),N(1.0))))
+## step 5: Call(Fun(Some(f),List((n,TNumber)),Some(TNumber),If(Binary(Eq,Var(n),N(0.0)),N(0.0),Call(Var(f),List(Binary(Minus,Var(n),N(1.0)))))),List(N(0.0)))
+## step 6: If(Binary(Eq,N(0.0),N(0.0)),N(0.0),Call(Fun(Some(f),List((n,TNumber)),Some(TNumber),If(Binary(Eq,Var(n),N(0.0)),N(0.0),Call(Var(f),List(Binary(Minus,Var(n),N(1.0)))))),List(Binary(Minus,N(0.0),N(1.0)))))
+## step 7: If(B(true),N(0.0),Call(Fun(Some(f),List((n,TNumber)),Some(TNumber),If(Binary(Eq,Var(n),N(0.0)),N(0.0),Call(Var(f),List(Binary(Minus,Var(n),N(1.0)))))),List(Binary(Minus,N(0.0),N(1.0)))))
+## value: N(0.0)
+0.0
diff --git a/lab4/src/test/resources/lab4/test4029_simplerec.jsy b/lab4/src/test/resources/lab4/test4029_simplerec.jsy
new file mode 100644
index 0000000..61b2787
--- /dev/null
+++ b/lab4/src/test/resources/lab4/test4029_simplerec.jsy
@@ -0,0 +1,2 @@
+const n = 1;
+(function f(n: number): number { return n === 0 ? 0 : f(n - 1) })(1) \ No newline at end of file
diff --git a/lab4/src/test/scala/jsy/lab4/Lab4Spec.scala b/lab4/src/test/scala/jsy/lab4/Lab4Spec.scala
new file mode 100644
index 0000000..0c05aab
--- /dev/null
+++ b/lab4/src/test/scala/jsy/lab4/Lab4Spec.scala
@@ -0,0 +1,217 @@
+package jsy.lab4
+
+import org.scalatest.flatspec.AnyFlatSpec
+import Parser.parse
+import ast._
+import Lab4._
+
+class Lab4StudentSpec extends AnyFlatSpec {
+}
+
+class Lab4Spec extends AnyFlatSpec {
+
+ /***** hastype Tests *****/
+ {
+ val xtype = TNumber
+ val tenvx = extend(Map.empty, "x", xtype)
+
+ "TypeVar" should "perform TypeVar" in {
+ assertResult(xtype) {
+ hastype(tenvx, Var("x"))
+ }
+ }
+
+ "hastype/call-non-fun" should "yield a static type error" in {
+ for (e <- List(
+ ("3(4)"),
+ ("3(true)"),
+ ("(10 + 4 + 7 - true * 3)(true)"),
+ ("((function (x: number) { return 0 })(10))(true)")
+ )) {
+ intercept[StaticTypeError] {
+ inferType(e)
+ }
+ }
+ }
+
+ "hastype/arithmetic" should "type check JavaScripty arithmetic expressions according to the lab spec" in {
+ for ((e,t) <- List(
+ ("3 <= 4", TBool),
+ ("'3' < '4'", TBool),
+ ("3 + 4", TNumber),
+ ("'3' + '4'", TString),
+ ("3 - 4", TNumber),
+ ("3 * 4 + 1 - 4 / 12", TNumber),
+ ("undefined", TUndefined)
+ )) {
+ assertResult(t){ inferType(e) }
+ }
+ }
+
+ "hastype/functions-objects" should "type check JavaScripty function-object expressions according to the lab spec" in {
+ val f1 = parse("function (x: number) { return x }")
+ val o1 = parse("{f: 3, g: true, h: undefined}")
+ for ((e,t) <- List(
+ (f1, TFun(List(("x", TNumber)), TNumber)),
+ (o1, TObj(Map("f" -> TNumber, "g" -> TBool, "h" -> TUndefined))),
+ (Call(f1, List(N(3))), TNumber),
+ (GetField(o1, "g"), TBool)
+ )) {
+ assertResult(t){ inferType(e) }
+ }
+ }
+
+ "hastype/simple-programs" should "type check JavaScripty programs according to the lab spec" in {
+ assertResult(TNumber) { inferType(
+ """
+ const w = function w(y: number): number { return y === 0 ? 0.1 : y + w(y - 1) };
+ w(3)
+ """
+ )}
+ assertResult(TNumber) { inferType(
+ """
+ const x = 1;
+ const g = function(y: number) { return x; };
+ const h = function(x: number) { return g(2); };
+ h(3)
+ """
+ )}
+ }
+
+ "hastype/recursive-programs" should "type check recursive JavaScripty programs according to the lab spec" in {
+ assertResult(TNumber) { inferType(
+ """
+ const factorial = function f(n: number): number {
+ return n === 0 ? 1 : n * f(n - 1)
+ }
+ factorial(4)
+ """
+ )}
+ }
+ }
+
+
+ /***** substitute Tests *****/
+ {
+ "substitute" should "substitute a value for uses of a variable" in {
+ for ((r,e,v,x) <- List(
+ ("const x = 3; x", "const x = x; x", "3", "x"),
+ ("function (x: number) { return x + y }", "function (x: number) { return x + y }", "3", "x"),
+ ("function x(y: number) { return x + y }", "function x(y: number) { return x + y }", "3", "x")
+ )) {
+ assertResult(parse(r)){ substitute(parse(v), x, parse(e)) }
+ }
+ }
+ }
+
+
+ /***** step Tests *****/
+ {
+ "step" should "perform one step of evaluation according to the lab spec" in {
+ for ((r, s) <- List (
+ ("1", "4 - 3"),
+ ("3 + 4", "1, 3 + 4"),
+ ("(3) + 3", "(1 + 2) + 3"),
+ ("(2) + (3 / 4)", "(1 * 2) + (3 / 4)"),
+ ("(2 + 4)", "true ? (2 + 4) : (1 + 1)"),
+ ("const x = 2; x", "const x = 1 + 1; x"),
+ ("2", "const x = 2; x"),
+ ("3 + 3 + 4 + 5", "1 + 2 + 3 + 4 + 5"),
+ ("3", "(function (x: number) { return x })(3)"),
+// ("3 + 1", "(function (x: number) { return x })(3 + 1)")
+ )) {
+ assertResult(parse(r)){oneStep(s)}
+ }
+ }
+
+ "step/call-non-fun" should "yield a stuck error" in {
+ for (e <- List(
+ ("3(4)"),
+ ("3(true)"),
+ ("((function (x: number) { return 0 })(10))(true)")
+ )) {
+ intercept[StuckError] { iterateStep(e) }
+ }
+ }
+
+ "step/simple-programs" should "evaluate JavaScripty programs according to the lab spec" in {
+ assertResult(N(6.1)) { iterateStep(
+ """
+ const w = function w(y: number) { return y === 0 ? 0.1 : y + w(y - 1) }
+ w(3)
+ """
+ )}
+ assertResult(N(1)) { iterateStep(
+ """
+ const x = 1;
+ const g = function(y: number) { return x; };
+ const h = function(x: number) { return g(2); };
+ h(3)
+ """
+ )}
+ assertResult(N(1.1)) { iterateStep(
+ """
+ const g = function(x: number) { return function(y: number) { return x - y } };
+ g(1)(0) + 0.1
+ """
+ )}
+ assertResult(N(6)) { iterateStep(
+ """
+ const plus = function(x: number, y: number) { return x + y };
+ plus(1 + 2, 3)
+ """
+ )}
+ assertResult(N(6)) { iterateStep(
+ """
+ const plus = function(x: number) { return function(y: number) { return x + y } };
+ plus(1 + 2)(3)
+ """
+ )}
+ }
+
+ "step/recursive-programs" should "evaluate recursive JavaScripty programs according to the lab spec" in {
+ assertResult(N(6)) { iterateStep(
+ """
+ const factorial = function f(n: number) {
+ return n === 0 ? 1 : n * f(n - 1)
+ }
+ factorial(3)
+ """
+ )}
+ assertResult(S("aaa")) { iterateStep(
+ """
+ const repeat = function(s: string) {
+ return function loop(n: number) {
+ return n === 0 ? "" : s + loop(n - 1)
+ }
+ }
+ repeat("a")(3)
+ """
+ )}
+ }
+
+ "step/objects" should "evaluate JavaScripty objects according to the lab spec" in {
+ assertResult(N(7.0)) { iterateStep(
+ """
+ const pair = function(x: number, y: number) {
+ return {x: x, y: y}
+ };
+ const p = pair(3, 4);
+ p.x + p.y
+ """
+ )}
+ assertResult(N(5.0)) { iterateStep(
+ """
+ const suspension = function(f: (a: number) => number, n: number) {
+ return {f: f, n: n}
+ };
+ const s = suspension((a: number) => a + 1, 4);
+ s.f(s.n)
+ """
+ )}
+ }
+ }
+
+}
+
+class Lab4JsyTests extends jsy.tester.JavascriptyTester(None, "lab4", Lab4)
diff --git a/lab4/src/test/scala/jsy/tester/JavascriptyTester.scala b/lab4/src/test/scala/jsy/tester/JavascriptyTester.scala
new file mode 100644
index 0000000..48e789c
--- /dev/null
+++ b/lab4/src/test/scala/jsy/tester/JavascriptyTester.scala
@@ -0,0 +1,23 @@
+package jsy.tester
+import java.io.File
+import jsy.util.JsyApplication
+import org.scalatest._
+import flatspec._
+
+/*
+ * A ScalaTest interface for running system tests.
+ */
+class JavascriptyTester(rootPrefix: Option[String], testDirectory: String, jsy: JsyApplication) extends AnyFlatSpec {
+ val testResources = s"src${File.separator}test${File.separator}resources"
+ val testPrefix = rootPrefix match {
+ case None => testResources
+ case Some(p) => s"${p}${File.separator}${testResources}"
+ }
+ val testPath = s"${testPrefix}${File.separator}${testDirectory}"
+ jsy.test(new File(testPath)) { case (in,ans,assertion) =>
+ s"eval on ${in}" should s"match ${ans}" in {
+ val (b: Boolean, msg: String) = assertion
+ assert(b, msg)
+ }
+ }
+}