diff --git a/Lab5/CS2030STest.java b/Lab5/CS2030STest.java new file mode 100644 index 0000000..76d14a5 --- /dev/null +++ b/Lab5/CS2030STest.java @@ -0,0 +1,76 @@ +import java.net.URI; +import java.util.List; +import java.util.ArrayList; +import javax.tools.DiagnosticCollector; +import javax.tools.SimpleJavaFileObject; +import javax.tools.ToolProvider; +import java.io.PrintStream; +import java.io.ByteArrayOutputStream; + +public class CS2030STest { + + private static final String ANSI_RESET = "\u001B[0m"; + private static final String ANSI_RED = "\u001B[31m"; + private static final String ANSI_GREEN = "\u001B[32m"; + + public void expect(String test, Object output, Object expect) { + System.out.print(test); + if ((expect == null && output == null) || output.equals(expect)) { + System.out.println(".. " + ANSI_GREEN + "ok" + ANSI_RESET); + } else { + System.out.println(".. " + ANSI_RED + "failed" + ANSI_RESET); + System.out.println(" expected: " + expect); + System.out.println(" got this: " + output); + } + } + + public static String clean(String txt) { + String res = ""; + for (int i=0; i(), null, null, + List.of(new JavaSourceFromString(statement))) + .call(); + + if (noError != success) { + System.out.println(".. " + ANSI_RED + "failed" + ANSI_RESET); + if (!success) { + System.out.println(" expected compilation error but it compiles fine."); + } else { + System.out.println(" expected the statement to compile without errors but it does not."); + } + } else { + System.out.println(".. " + ANSI_GREEN + "ok" + ANSI_RESET); + } + } +} diff --git a/Lab5/Lab5.java b/Lab5/Lab5.java new file mode 100644 index 0000000..8a06e2e --- /dev/null +++ b/Lab5/Lab5.java @@ -0,0 +1,216 @@ +import cs2030s.fp.Actually; +import cs2030s.fp.Immutator; +import cs2030s.fp.Constant; +import cs2030s.fp.Action; +import cs2030s.fp.Transformer; +import java.util.Map; +import java.util.HashMap; +import java.util.Scanner; + +class Lab5 { + public static String getGrade(String module, String student, String assessment, + Map>> db) { + try { + return db.get(module).get(student).get(assessment).toString(); + } catch(Exception e) { + return "No such entry"; + } + } + public static void main(String[] args) { + // Create a scanner to read from standard input. + Scanner sc = new Scanner(System.in); + + // Read a single integer from the test file + // and then run the appropriate test case + switch (sc.nextInt()) { + case 1: + test1(); + break; + case 2: + test2(); + break; + case 3: + test3(); + break; + case 4: + test4(); + break; + case 5: + test5(); + break; + case 6: + test6(); + break; + } + } + + public static void test1() { + String none = null; + + System.out.println(Actually.err(new ArithmeticException("Err")).equals(Actually.err(new Exception("Err")))); + System.out.println(Actually.err(new ArithmeticException("Err")).equals(Actually.err(new Exception("Error")))); + System.out.println(Actually.err(new ArithmeticException("Err")).equals(Actually.err(new Exception(none)))); + System.out.println(Actually.err(new ArithmeticException(none)).equals(Actually.err(new Exception(none)))); + System.out.println(Actually.err(new ArithmeticException("Err")).equals(Actually.ok("Err"))); + System.out.println(Actually.ok("Err").equals(Actually.ok("Err"))); + System.out.println(Actually.ok("Err").equals(Actually.err(new Exception("Error")))); + System.out.println(Actually.ok("Err").equals("Err")); + System.out.println(Actually.ok(null).equals(Actually.ok("Err"))); + System.out.println(Actually.ok(null).equals(Actually.ok(null))); + System.out.println(Actually.ok(null).equals("Err")); + System.out.println(Actually.ok(null).equals(null)); + } + + public static void test2() { + Constant zero = new Constant<>() { + public Integer init() { + return 0; + } + }; + Action print = new Action<>() { + public void call(Integer i) { + System.out.println(i); + } + }; + + try { + Actually.ok(0).unwrap().toString(); + } catch(Exception e) { + System.out.println(e.getMessage()); + } + + Actually.ok(9).finish(print); + Actually.err(new Exception("Err")).finish(print); + System.out.println(Actually.ok(9).except(zero).toString()); + System.out.println(Actually.err(new ArithmeticException("div by 0")).except(zero).toString()); + System.out.println(Actually.err(new ArithmeticException("div by 0")).unless(4).toString()); + System.out.println(Actually.ok(0).unless(4).toString()); + } + + public static void test3() { + Immutator inc = new Immutator<>() { + public Integer invoke(Integer p) { + return p+1; + } + }; + Immutator inv = new Immutator<>() { + public Integer invoke(Integer p) { + return 1/p; + } + }; + Immutator incNum = new Immutator<>() { + public Number invoke(Integer p) { + return p+1; + } + }; + Immutator invNum = new Immutator<>() { + public Number invoke(Integer p) { + return 1/p; + } + }; + + System.out.println(Actually.ok(0).transform(inc).toString()); + System.out.println(Actually.ok(0).transform(inv).toString()); + System.out.println(Actually.ok(0).transform(inc).toString()); + System.out.println(Actually.ok(0).transform(inv).toString()); + System.out.println(Actually.ok(0).transform(incNum).toString()); + System.out.println(Actually.ok(0).transform(invNum).toString()); + System.out.println(Actually.ok(0).transform(incNum).toString()); + System.out.println(Actually.ok(0).transform(invNum).toString()); + } + + public static void test4() { + Transformer inc = new Transformer<>() { + public Integer invoke(Integer p) { + return p+1; + } + }; + Transformer sqr = new Transformer<>() { + public Integer invoke(Integer p) { + return p*p; + } + }; + + Transformer sqrPlusOneA = sqr.before(inc); + Transformer sqrPlusOneB = inc.after(sqr); + Transformer plusOneSqrA = sqr.after(inc); + Transformer plusOneSqrB = inc.before(sqr); + + System.out.println(sqrPlusOneA.invoke(2).toString()); + System.out.println(sqrPlusOneA.invoke(2).toString()); + System.out.println(plusOneSqrA.invoke(2).toString()); + System.out.println(plusOneSqrB.invoke(2).toString()); + } + + public static void test5() { + Immutator,Integer> half = new Immutator<>() { + public Actually invoke(Integer p) { + if (p%2 == 0) { + return Actually.ok(p/2); + } else { + return Actually.err(new Exception("odd number")); + } + } + }; + Immutator,Integer> inc = new Immutator<>() { + public Actually invoke(Integer p) { + return Actually.ok(p+1); + } + }; + Immutator,Integer> make = new Immutator<>() { + public Actually invoke(Integer p) { + return Actually.ok(p); + } + }; + Constant zero = new Constant<>() { + public Integer init() { + return 0; + } + }; + + System.out.println(make.invoke(0).next(inc).next(inc).next(half).toString()); + System.out.println(make.invoke(0).next(inc).next(half).next(inc).toString()); + System.out.println(make.invoke(0).next(inc).next(inc).next(half).except(zero).toString()); + System.out.println(make.invoke(0).next(inc).next(half).next(inc).except(zero).toString()); + } + + public static void test6() { + Map>> nus = + Map.of( + "CS2030S", Map.of( + "Steve", Map.of( + "lab1", "A", + "lab2", "A-", + "lab3", "A+", + "lab4", "B", + "pe1", "C" + ), + "Tony", Map.of( + "lab1", "C", + "lab2", "C", + "lab3", "B-", + "lab4", "B+", + "pe1", "A" + ) + ), + "CS2040S", Map.of( + "Steve", Map.of( + "lab1", "A", + "lab2", "A+", + "lab3", "A+", + "lab4", "A", + "midterm", "A+" + ) + ) + ); + + System.out.println(getGrade("CS2030S", "Steve", "lab1", nus)); + System.out.println(getGrade("CS2030S", "Steve", "lab2", nus)); + System.out.println(getGrade("CS2040S", "Steve", "lab3", nus)); + System.out.println(getGrade("CS2040S", "Steve", "lab4", nus)); + System.out.println(getGrade("CS2030S", "Tony", "lab1", nus)); + System.out.println(getGrade("CS2030S", "Tony", "midterm", nus)); + System.out.println(getGrade("CS2040S", "Tony", "lab4", nus)); + System.out.println(getGrade("CS2040S", "Bruce", "lab4", nus)); + } +} diff --git a/Lab5/Lab5.pdf b/Lab5/Lab5.pdf new file mode 100644 index 0000000..79fef47 Binary files /dev/null and b/Lab5/Lab5.pdf differ diff --git a/Lab5/Lab5.sh b/Lab5/Lab5.sh new file mode 100644 index 0000000..780b43a --- /dev/null +++ b/Lab5/Lab5.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +mkdir cs2030s +cd cs2030s +mkdir fp +cd .. + +mv Action.java cs2030s/fp/Action.java +mv Actionable.java cs2030s/fp/Actionable.java +mv Actually.java cs2030s/fp/Actually.java +mv Constant.java cs2030s/fp/Constant.java +mv Immutator.java cs2030s/fp/Immutator.java +mv Immutatorable.java cs2030s/fp/Immutatorable.java +mv Transformer.java cs2030s/fp/Transformer.java + +javac cs2030s/fp/*.java +javac *.java \ No newline at end of file diff --git a/Lab5/Test0.java b/Lab5/Test0.java new file mode 100644 index 0000000..f236436 --- /dev/null +++ b/Lab5/Test0.java @@ -0,0 +1,24 @@ +import java.io.PrintStream; +import java.io.ByteArrayOutputStream; + +public class Test0 { + public static void main(String[] args) { + CS2030STest we = new CS2030STest(); + + we.expectCompile("Actually a = new Actually<>() should not compile", + "cs2030s.fp.Actually a = new cs2030s.fp.Actually<>();", false); + we.expectCompile("Actually.Success s should not compile", + "cs2030s.fp.Actually.Success s;", false); + we.expectCompile("Actually.Failure f should not compile", + "cs2030s.fp.Actually.Failure f;", false); + + we.expectCompile("Actually success = Actually.ok(\"success\") should compile", + "cs2030s.fp.Actually success = cs2030s.fp.Actually.ok(\"success\");", true); + we.expectCompile("Actually none = Actually.ok(null) should compile", + "cs2030s.fp.Actually none = cs2030s.fp.Actually.ok(null);", true); + we.expectCompile("Actually four = Actually.ok(4) should compile", + "cs2030s.fp.Actually four = cs2030s.fp.Actually.ok(4);", true); + we.expectCompile("Actually div0 = Actually.err(new ArithmeticException(\"Divide by 0\")) should compile", + "cs2030s.fp.Actually div0 = cs2030s.fp.Actually.err(new ArithmeticException(\"Divide by 0\"));", true); + } +} \ No newline at end of file diff --git a/Lab5/Test1.java b/Lab5/Test1.java new file mode 100644 index 0000000..460da0b --- /dev/null +++ b/Lab5/Test1.java @@ -0,0 +1,73 @@ +import java.io.PrintStream; +import java.io.ByteArrayOutputStream; + +public class Test1 { + public static void main(String[] args) { + CS2030STest we = new CS2030STest(); + + String none = null; + + we.expect( + "Actually.err(new ArithmeticException(\"Err\")).equals(Actually.err(new Exception(\"Err\")))", + cs2030s.fp.Actually.err(new ArithmeticException("Err")).equals(cs2030s.fp.Actually.err(new Exception("Err"))), + true + ); + we.expect( + "Actually.err(new ArithmeticException(\"Err\")).equals(Actually.err(new Exception(\"Error\")))", + cs2030s.fp.Actually.err(new ArithmeticException("Err")).equals(cs2030s.fp.Actually.err(new Exception("Error"))), + false + ); + we.expect( + "Actually.err(new ArithmeticException(\"Err\")).equals(Actually.err(new Exception(null)))", + cs2030s.fp.Actually.err(new ArithmeticException("Err")).equals(cs2030s.fp.Actually.err(new Exception(none))), + false + ); + we.expect( + "Actually.err(new ArithmeticException(null)).equals(Actually.err(new Exception(null)))", + cs2030s.fp.Actually.err(new ArithmeticException(none)).equals(cs2030s.fp.Actually.err(new Exception(none))), + false + ); + we.expect( + "Actually.err(new ArithmeticException(\"Err\")).equals(Actually.ok(\"Err\"))", + cs2030s.fp.Actually.err(new ArithmeticException("Err")).equals(cs2030s.fp.Actually.ok("Err")), + false + ); + + we.expect( + "Actually.ok(\"Err\").equals(Actually.ok(\"Err\"))", + cs2030s.fp.Actually.ok("Err").equals(cs2030s.fp.Actually.ok("Err")), + true + ); + we.expect( + "Actually.ok(\"Err\").equals(Actually.err(new Exception(\"Error\")))", + cs2030s.fp.Actually.ok("Err").equals(cs2030s.fp.Actually.err(new Exception("Error"))), + false + ); + we.expect( + "Actually.ok(\"Err\").equals(\"Err\")", + cs2030s.fp.Actually.ok("Err").equals("Err"), + false + ); + + we.expect( + "Actually.ok(null).equals(Actually.ok(\"Err\"))", + cs2030s.fp.Actually.ok(null).equals(cs2030s.fp.Actually.ok("Err")), + false + ); + we.expect( + "Actually.ok(null).equals(Actually.ok(null))", + cs2030s.fp.Actually.ok(null).equals(cs2030s.fp.Actually.ok(null)), + true + ); + we.expect( + "Actually.ok(null).equals(\"Err\")", + cs2030s.fp.Actually.ok(null).equals("Err"), + false + ); + we.expect( + "Actually.ok(null).equals(null)", + cs2030s.fp.Actually.ok(null).equals(null), + false + ); + } +} \ No newline at end of file diff --git a/Lab5/Test2.java b/Lab5/Test2.java new file mode 100644 index 0000000..7edf703 --- /dev/null +++ b/Lab5/Test2.java @@ -0,0 +1,72 @@ +import java.io.PrintStream; +import java.io.ByteArrayOutputStream; + +public class Test2 { + public static void main(String[] args) { + CS2030STest we = new CS2030STest(); + PrintStream old = System.out; + ByteArrayOutputStream baos; + PrintStream ps; + + cs2030s.fp.Constant zero = new cs2030s.fp.Constant<>() { + public Integer init() { + return 0; + } + }; + cs2030s.fp.Action print = new cs2030s.fp.Action<>() { + public void call(Integer i) { + System.out.println(i); + } + }; + + try { + we.expect( + "Actually.ok(0).unwrap()", + cs2030s.fp.Actually.ok(0).unwrap().toString(), + "0" + ); + } catch(Exception e) { + System.out.println("Unexpected error occurs"); + } + + baos = new ByteArrayOutputStream(); + ps = new PrintStream(baos); + System.setOut(ps); + cs2030s.fp.Actually.ok(9).finish(print); + we.expectPrint("Actually.ok(9).finish(print)", + "9", + baos, + old); + + baos = new ByteArrayOutputStream(); + ps = new PrintStream(baos); + System.setOut(ps); + cs2030s.fp.Actually.err(new Exception("Err")).finish(print); + we.expectPrint("Actually.err(new Exception(\"Err\")).finish(print)", + "", + baos, + old); + + we.expect( + "Actually.ok(9).except(zero)", + cs2030s.fp.Actually.ok(9).except(zero).toString(), + "9" + ); + we.expect( + "Actually.err(new ArithmeticException(\"div by 0\")).except(zero)", + cs2030s.fp.Actually.err(new ArithmeticException("div by 0")).except(zero).toString(), + "0" + ); + + we.expect( + "Actually.err(new ArithmeticException(\"div by 0\")).unless(4)", + cs2030s.fp.Actually.err(new ArithmeticException("div by 0")).unless(4).toString(), + "4" + ); + we.expect( + "Actually.ok(0).unless(4)", + cs2030s.fp.Actually.ok(0).unless(4).toString(), + "0" + ); + } +} \ No newline at end of file diff --git a/Lab5/Test3.java b/Lab5/Test3.java new file mode 100644 index 0000000..04eb766 --- /dev/null +++ b/Lab5/Test3.java @@ -0,0 +1,71 @@ +import java.io.PrintStream; +import java.io.ByteArrayOutputStream; + +public class Test3 { + public static void main(String[] args) { + CS2030STest we = new CS2030STest(); + + cs2030s.fp.Immutator inc = new cs2030s.fp.Immutator<>() { + public Integer invoke(Integer p) { + return p+1; + } + }; + cs2030s.fp.Immutator inv = new cs2030s.fp.Immutator<>() { + public Integer invoke(Integer p) { + return 1/p; + } + }; + cs2030s.fp.Immutator incNum = new cs2030s.fp.Immutator<>() { + public Number invoke(Integer p) { + return p+1; + } + }; + cs2030s.fp.Immutator invNum = new cs2030s.fp.Immutator<>() { + public Number invoke(Integer p) { + return 1/p; + } + }; + + we.expect( + "Actually.ok(0).transform(inc)", + cs2030s.fp.Actually.ok(0).transform(inc).toString(), + "<1>" + ); + we.expect( + "Actually.ok(0).transform(inv)", + cs2030s.fp.Actually.ok(0).transform(inv).toString(), + "[java.lang.ArithmeticException] / by zero" + ); + we.expect( + "Actually.ok(0).transform(inc)", + cs2030s.fp.Actually.ok(0).transform(inc).toString(), + "<1>" + ); + we.expect( + "Actually.ok(0).transform(inv)", + cs2030s.fp.Actually.ok(0).transform(inv).toString(), + "[java.lang.ArithmeticException] / by zero" + ); + + we.expect( + "Actually.ok(0).transform(incNum)", + cs2030s.fp.Actually.ok(0).transform(incNum).toString(), + "<1>" + ); + we.expect( + "Actually.ok(0).transform(invNum)", + cs2030s.fp.Actually.ok(0).transform(invNum).toString(), + "[java.lang.ArithmeticException] / by zero" + ); + we.expect( + "Actually.ok(0).transform(incNum)", + cs2030s.fp.Actually.ok(0).transform(incNum).toString(), + "<1>" + ); + we.expect( + "Actually.ok(0).transform(invNum)", + cs2030s.fp.Actually.ok(0).transform(invNum).toString(), + "[java.lang.ArithmeticException] / by zero" + ); + } +} \ No newline at end of file diff --git a/Lab5/Test4.java b/Lab5/Test4.java new file mode 100644 index 0000000..b0df25a --- /dev/null +++ b/Lab5/Test4.java @@ -0,0 +1,45 @@ +import java.io.PrintStream; +import java.io.ByteArrayOutputStream; + +public class Test4 { + public static void main(String[] args) { + CS2030STest we = new CS2030STest(); + + cs2030s.fp.Transformer inc = new cs2030s.fp.Transformer<>() { + public Integer invoke(Integer p) { + return p+1; + } + }; + cs2030s.fp.Transformer sqr = new cs2030s.fp.Transformer<>() { + public Integer invoke(Integer p) { + return p*p; + } + }; + + cs2030s.fp.Transformer sqrPlusOneA = sqr.before(inc); + cs2030s.fp.Transformer sqrPlusOneB = inc.after(sqr); + cs2030s.fp.Transformer plusOneSqrA = sqr.after(inc); + cs2030s.fp.Transformer plusOneSqrB = inc.before(sqr); + + we.expect( + "sqrPlusOneA.invoke(2)", + sqrPlusOneA.invoke(2).toString(), + "5" + ); + we.expect( + "sqrPlusOneB.invoke(2)", + sqrPlusOneA.invoke(2).toString(), + "5" + ); + we.expect( + "plusOneSqrA.invoke(2)", + plusOneSqrA.invoke(2).toString(), + "9" + ); + we.expect( + "plusOneSqrB.invoke(2)", + plusOneSqrB.invoke(2).toString(), + "9" + ); + } +} \ No newline at end of file diff --git a/Lab5/Test5.java b/Lab5/Test5.java new file mode 100644 index 0000000..b6acaa7 --- /dev/null +++ b/Lab5/Test5.java @@ -0,0 +1,55 @@ +import java.io.PrintStream; +import java.io.ByteArrayOutputStream; + +public class Test5 { + public static void main(String[] args) { + CS2030STest we = new CS2030STest(); + + cs2030s.fp.Immutator,Integer> half = new cs2030s.fp.Immutator<>() { + public cs2030s.fp.Actually invoke(Integer p) { + if (p%2 == 0) { + return cs2030s.fp.Actually.ok(p/2); + } else { + return cs2030s.fp.Actually.err(new Exception("odd number")); + } + } + }; + cs2030s.fp.Immutator,Integer> inc = new cs2030s.fp.Immutator<>() { + public cs2030s.fp.Actually invoke(Integer p) { + return cs2030s.fp.Actually.ok(p+1); + } + }; + cs2030s.fp.Immutator,Integer> make = new cs2030s.fp.Immutator<>() { + public cs2030s.fp.Actually invoke(Integer p) { + return cs2030s.fp.Actually.ok(p); + } + }; + cs2030s.fp.Constant zero = new cs2030s.fp.Constant<>() { + public Integer init() { + return 0; + } + }; + + we.expect( + "make.invoke(0).next(inc).next(inc).next(half)", + make.invoke(0).next(inc).next(inc).next(half).toString(), + "<1>" + ); + we.expect( + "make.invoke(0).next(inc).next(half).next(inc)", + make.invoke(0).next(inc).next(half).next(inc).toString(), + "[java.lang.Exception] odd number" + ); + + we.expect( + "make.invoke(0).next(inc).next(inc).next(half).except(zero)", + make.invoke(0).next(inc).next(inc).next(half).except(zero).toString(), + "1" + ); + we.expect( + "make.invoke(0).next(inc).next(half).next(inc).except(zero)", + make.invoke(0).next(inc).next(half).next(inc).except(zero).toString(), + "0" + ); + } +} \ No newline at end of file diff --git a/Lab5/cs2030s/fp/Actually.java b/Lab5/cs2030s/fp/Actually.java new file mode 100644 index 0000000..e69de29 diff --git a/Lab5/cs2030s/fp/Constant.java b/Lab5/cs2030s/fp/Constant.java new file mode 100644 index 0000000..e69de29 diff --git a/Lab5/cs2030s/fp/Transformer.java b/Lab5/cs2030s/fp/Transformer.java new file mode 100644 index 0000000..e69de29