From 462e5ea15e41be695f33227a9abba1e83e9db073 Mon Sep 17 00:00:00 2001 From: Mike Cifelli Date: Sun, 26 Feb 2017 16:47:06 -0500 Subject: [PATCH] Built-in function names are now defined through annotations --- src/function/FunctionNames.java | 11 ++ src/function/builtin/APPLY.java | 1 + src/function/builtin/EVAL.java | 1 + src/function/builtin/EXIT.java | 1 + src/function/builtin/FUNCALL.java | 1 + src/function/builtin/LOAD.java | 1 + src/function/builtin/PRINT.java | 1 + src/function/builtin/SET.java | 1 + src/function/builtin/SYMBOL_FUNCTION.java | 1 + src/function/builtin/cons/CONS.java | 1 + src/function/builtin/cons/FIRST.java | 1 + src/function/builtin/cons/LENGTH.java | 1 + src/function/builtin/cons/LIST.java | 1 + src/function/builtin/cons/REST.java | 1 + src/function/builtin/math/DIVIDE.java | 1 + src/function/builtin/math/MINUS.java | 1 + src/function/builtin/math/MULTIPLY.java | 1 + src/function/builtin/math/PLUS.java | 1 + src/function/builtin/predicate/ATOM.java | 1 + src/function/builtin/predicate/EQ.java | 1 + src/function/builtin/predicate/EQUAL.java | 1 + src/function/builtin/predicate/EQUALSP.java | 1 + src/function/builtin/predicate/GREATERP.java | 1 + src/function/builtin/predicate/LESSP.java | 1 + src/function/builtin/predicate/LISTP.java | 1 + src/function/builtin/predicate/NULL.java | 1 + src/function/builtin/special/AND.java | 1 + src/function/builtin/special/COND.java | 1 + .../builtin/special/DEFINE_MACRO.java | 1 + src/function/builtin/special/DEFUN.java | 3 +- src/function/builtin/special/IF.java | 1 + src/function/builtin/special/LAMBDA.java | 1 + src/function/builtin/special/LET.java | 1 + src/function/builtin/special/OR.java | 1 + src/function/builtin/special/QUOTE.java | 1 + src/function/builtin/special/SETF.java | 1 + src/table/FunctionTable.java | 164 ++++++++++++------ test/table/FunctionTableTester.java | 80 ++++++++- 38 files changed, 237 insertions(+), 55 deletions(-) create mode 100644 src/function/FunctionNames.java diff --git a/src/function/FunctionNames.java b/src/function/FunctionNames.java new file mode 100644 index 0000000..d4b3004 --- /dev/null +++ b/src/function/FunctionNames.java @@ -0,0 +1,11 @@ +package function; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface FunctionNames { + + String[] value(); + +} diff --git a/src/function/builtin/APPLY.java b/src/function/builtin/APPLY.java index b1836a7..3f77a0c 100644 --- a/src/function/builtin/APPLY.java +++ b/src/function/builtin/APPLY.java @@ -3,6 +3,7 @@ package function.builtin; import function.*; import sexpression.*; +@FunctionNames({ "APPLY" }) public class APPLY extends LispFunction { private ArgumentValidator argumentValidator; diff --git a/src/function/builtin/EVAL.java b/src/function/builtin/EVAL.java index eccbf4b..54b7733 100644 --- a/src/function/builtin/EVAL.java +++ b/src/function/builtin/EVAL.java @@ -9,6 +9,7 @@ import function.builtin.special.LAMBDA; import sexpression.*; import table.*; +@FunctionNames({ "EVAL" }) public class EVAL extends LispFunction { public static LispFunction lookupFunctionOrLambda(SExpression functionExpression) { diff --git a/src/function/builtin/EXIT.java b/src/function/builtin/EXIT.java index 8b225ab..ba2f176 100644 --- a/src/function/builtin/EXIT.java +++ b/src/function/builtin/EXIT.java @@ -4,6 +4,7 @@ import environment.RuntimeEnvironment; import function.*; import sexpression.*; +@FunctionNames({ "EXIT" }) public class EXIT extends LispFunction { private ArgumentValidator argumentValidator; diff --git a/src/function/builtin/FUNCALL.java b/src/function/builtin/FUNCALL.java index a8f8291..6cb64c6 100644 --- a/src/function/builtin/FUNCALL.java +++ b/src/function/builtin/FUNCALL.java @@ -6,6 +6,7 @@ import static function.builtin.cons.LIST.makeList; import function.*; import sexpression.*; +@FunctionNames({ "FUNCALL" }) public class FUNCALL extends LispFunction { private ArgumentValidator argumentValidator; diff --git a/src/function/builtin/LOAD.java b/src/function/builtin/LOAD.java index 1e6586e..153d881 100644 --- a/src/function/builtin/LOAD.java +++ b/src/function/builtin/LOAD.java @@ -11,6 +11,7 @@ import function.*; import parser.LispParser; import sexpression.*; +@FunctionNames({ "LOAD" }) public class LOAD extends LispFunction { private ArgumentValidator argumentValidator; diff --git a/src/function/builtin/PRINT.java b/src/function/builtin/PRINT.java index 168d001..63dd5a3 100644 --- a/src/function/builtin/PRINT.java +++ b/src/function/builtin/PRINT.java @@ -4,6 +4,7 @@ import environment.RuntimeEnvironment; import function.*; import sexpression.*; +@FunctionNames({ "PRINT" }) public class PRINT extends LispFunction { private ArgumentValidator argumentValidator; diff --git a/src/function/builtin/SET.java b/src/function/builtin/SET.java index 1041f47..8af2b83 100644 --- a/src/function/builtin/SET.java +++ b/src/function/builtin/SET.java @@ -4,6 +4,7 @@ import function.*; import sexpression.*; import table.*; +@FunctionNames({ "SET" }) public class SET extends LispFunction { private ArgumentValidator argumentValidator; diff --git a/src/function/builtin/SYMBOL_FUNCTION.java b/src/function/builtin/SYMBOL_FUNCTION.java index b5dced5..8010e9e 100644 --- a/src/function/builtin/SYMBOL_FUNCTION.java +++ b/src/function/builtin/SYMBOL_FUNCTION.java @@ -7,6 +7,7 @@ import function.*; import sexpression.*; import table.FunctionTable; +@FunctionNames({ "SYMBOL-FUNCTION" }) public class SYMBOL_FUNCTION extends LispFunction { private ArgumentValidator argumentValidator; diff --git a/src/function/builtin/cons/CONS.java b/src/function/builtin/cons/CONS.java index 013fed6..fdfc7f9 100644 --- a/src/function/builtin/cons/CONS.java +++ b/src/function/builtin/cons/CONS.java @@ -3,6 +3,7 @@ package function.builtin.cons; import function.*; import sexpression.*; +@FunctionNames({ "CONS" }) public class CONS extends LispFunction { private ArgumentValidator argumentValidator; diff --git a/src/function/builtin/cons/FIRST.java b/src/function/builtin/cons/FIRST.java index 7a9a206..f956022 100644 --- a/src/function/builtin/cons/FIRST.java +++ b/src/function/builtin/cons/FIRST.java @@ -3,6 +3,7 @@ package function.builtin.cons; import function.*; import sexpression.*; +@FunctionNames({ "FIRST", "CAR" }) public class FIRST extends LispFunction { private ArgumentValidator argumentValidator; diff --git a/src/function/builtin/cons/LENGTH.java b/src/function/builtin/cons/LENGTH.java index 5b242d7..aae5b67 100644 --- a/src/function/builtin/cons/LENGTH.java +++ b/src/function/builtin/cons/LENGTH.java @@ -5,6 +5,7 @@ import java.math.BigInteger; import function.*; import sexpression.*; +@FunctionNames({ "LENGTH" }) public class LENGTH extends LispFunction { public static BigInteger getLength(Cons list) { diff --git a/src/function/builtin/cons/LIST.java b/src/function/builtin/cons/LIST.java index 839e462..612b2fa 100644 --- a/src/function/builtin/cons/LIST.java +++ b/src/function/builtin/cons/LIST.java @@ -3,6 +3,7 @@ package function.builtin.cons; import function.*; import sexpression.*; +@FunctionNames({ "LIST" }) public class LIST extends LispFunction { private ArgumentValidator argumentValidator; diff --git a/src/function/builtin/cons/REST.java b/src/function/builtin/cons/REST.java index 34fceb1..f7e8265 100644 --- a/src/function/builtin/cons/REST.java +++ b/src/function/builtin/cons/REST.java @@ -3,6 +3,7 @@ package function.builtin.cons; import function.*; import sexpression.*; +@FunctionNames({ "REST", "CDR" }) public class REST extends LispFunction { private ArgumentValidator argumentValidator; diff --git a/src/function/builtin/math/DIVIDE.java b/src/function/builtin/math/DIVIDE.java index 4ec3bcd..bf1020b 100644 --- a/src/function/builtin/math/DIVIDE.java +++ b/src/function/builtin/math/DIVIDE.java @@ -5,6 +5,7 @@ import java.math.BigInteger; import function.*; import sexpression.*; +@FunctionNames({ "/" }) public class DIVIDE extends LispFunction { private ArgumentValidator argumentValidator; diff --git a/src/function/builtin/math/MINUS.java b/src/function/builtin/math/MINUS.java index a84f101..7a2c39e 100644 --- a/src/function/builtin/math/MINUS.java +++ b/src/function/builtin/math/MINUS.java @@ -5,6 +5,7 @@ import java.math.BigInteger; import function.*; import sexpression.*; +@FunctionNames({ "-" }) public class MINUS extends LispFunction { private ArgumentValidator argumentValidator; diff --git a/src/function/builtin/math/MULTIPLY.java b/src/function/builtin/math/MULTIPLY.java index 75de4d6..5ada86e 100644 --- a/src/function/builtin/math/MULTIPLY.java +++ b/src/function/builtin/math/MULTIPLY.java @@ -3,6 +3,7 @@ package function.builtin.math; import function.*; import sexpression.*; +@FunctionNames({ "*" }) public class MULTIPLY extends LispFunction { private ArgumentValidator argumentValidator; diff --git a/src/function/builtin/math/PLUS.java b/src/function/builtin/math/PLUS.java index 3efb2a5..8e20c08 100644 --- a/src/function/builtin/math/PLUS.java +++ b/src/function/builtin/math/PLUS.java @@ -3,6 +3,7 @@ package function.builtin.math; import function.*; import sexpression.*; +@FunctionNames({ "+" }) public class PLUS extends LispFunction { private ArgumentValidator argumentValidator; diff --git a/src/function/builtin/predicate/ATOM.java b/src/function/builtin/predicate/ATOM.java index 29c931c..a6bdb36 100644 --- a/src/function/builtin/predicate/ATOM.java +++ b/src/function/builtin/predicate/ATOM.java @@ -3,6 +3,7 @@ package function.builtin.predicate; import function.*; import sexpression.*; +@FunctionNames({ "ATOM" }) public class ATOM extends LispFunction { private ArgumentValidator argumentValidator; diff --git a/src/function/builtin/predicate/EQ.java b/src/function/builtin/predicate/EQ.java index d18c384..0fd581f 100644 --- a/src/function/builtin/predicate/EQ.java +++ b/src/function/builtin/predicate/EQ.java @@ -3,6 +3,7 @@ package function.builtin.predicate; import function.*; import sexpression.*; +@FunctionNames({ "EQ" }) public class EQ extends LispFunction { private ArgumentValidator argumentValidator; diff --git a/src/function/builtin/predicate/EQUAL.java b/src/function/builtin/predicate/EQUAL.java index 6dea5c7..eccbd38 100644 --- a/src/function/builtin/predicate/EQUAL.java +++ b/src/function/builtin/predicate/EQUAL.java @@ -4,6 +4,7 @@ import function.*; import function.builtin.cons.LIST; import sexpression.*; +@FunctionNames({ "EQUAL" }) public class EQUAL extends LispFunction { private ArgumentValidator argumentValidator; diff --git a/src/function/builtin/predicate/EQUALSP.java b/src/function/builtin/predicate/EQUALSP.java index 2ab3912..90c1084 100644 --- a/src/function/builtin/predicate/EQUALSP.java +++ b/src/function/builtin/predicate/EQUALSP.java @@ -3,6 +3,7 @@ package function.builtin.predicate; import function.*; import sexpression.*; +@FunctionNames({ "=" }) public class EQUALSP extends LispFunction { private ArgumentValidator argumentValidator; diff --git a/src/function/builtin/predicate/GREATERP.java b/src/function/builtin/predicate/GREATERP.java index 357363e..d144861 100644 --- a/src/function/builtin/predicate/GREATERP.java +++ b/src/function/builtin/predicate/GREATERP.java @@ -3,6 +3,7 @@ package function.builtin.predicate; import function.*; import sexpression.*; +@FunctionNames({ ">" }) public class GREATERP extends LispFunction { private ArgumentValidator argumentValidator; diff --git a/src/function/builtin/predicate/LESSP.java b/src/function/builtin/predicate/LESSP.java index 089b461..19090d1 100644 --- a/src/function/builtin/predicate/LESSP.java +++ b/src/function/builtin/predicate/LESSP.java @@ -3,6 +3,7 @@ package function.builtin.predicate; import function.*; import sexpression.*; +@FunctionNames({ "<" }) public class LESSP extends LispFunction { private ArgumentValidator argumentValidator; diff --git a/src/function/builtin/predicate/LISTP.java b/src/function/builtin/predicate/LISTP.java index ac8eefa..d465b6b 100644 --- a/src/function/builtin/predicate/LISTP.java +++ b/src/function/builtin/predicate/LISTP.java @@ -3,6 +3,7 @@ package function.builtin.predicate; import function.*; import sexpression.*; +@FunctionNames({ "LISTP" }) public class LISTP extends LispFunction { private ArgumentValidator argumentValidator; diff --git a/src/function/builtin/predicate/NULL.java b/src/function/builtin/predicate/NULL.java index fab770b..74f67fe 100644 --- a/src/function/builtin/predicate/NULL.java +++ b/src/function/builtin/predicate/NULL.java @@ -3,6 +3,7 @@ package function.builtin.predicate; import function.*; import sexpression.*; +@FunctionNames({ "NULL" }) public class NULL extends LispFunction { private ArgumentValidator argumentValidator; diff --git a/src/function/builtin/special/AND.java b/src/function/builtin/special/AND.java index 6c2abe3..9d33d40 100644 --- a/src/function/builtin/special/AND.java +++ b/src/function/builtin/special/AND.java @@ -5,6 +5,7 @@ import static function.builtin.EVAL.eval; import function.*; import sexpression.*; +@FunctionNames({ "AND" }) public class AND extends LispSpecialFunction { private ArgumentValidator argumentValidator; diff --git a/src/function/builtin/special/COND.java b/src/function/builtin/special/COND.java index e0e1d78..c8a33b8 100644 --- a/src/function/builtin/special/COND.java +++ b/src/function/builtin/special/COND.java @@ -5,6 +5,7 @@ import static function.builtin.EVAL.eval; import function.*; import sexpression.*; +@FunctionNames({ "COND" }) public class COND extends LispSpecialFunction { private ArgumentValidator argumentValidator; diff --git a/src/function/builtin/special/DEFINE_MACRO.java b/src/function/builtin/special/DEFINE_MACRO.java index 51d5ac6..42665e0 100644 --- a/src/function/builtin/special/DEFINE_MACRO.java +++ b/src/function/builtin/special/DEFINE_MACRO.java @@ -3,6 +3,7 @@ package function.builtin.special; import function.*; import sexpression.*; +@FunctionNames({ "DEFINE-MACRO" }) public class DEFINE_MACRO extends Define { public DEFINE_MACRO() { diff --git a/src/function/builtin/special/DEFUN.java b/src/function/builtin/special/DEFUN.java index 42407d8..403469b 100644 --- a/src/function/builtin/special/DEFUN.java +++ b/src/function/builtin/special/DEFUN.java @@ -1,8 +1,9 @@ package function.builtin.special; -import function.UserDefinedFunction; +import function.*; import sexpression.*; +@FunctionNames({ "DEFUN" }) public class DEFUN extends Define { public DEFUN() { diff --git a/src/function/builtin/special/IF.java b/src/function/builtin/special/IF.java index 79a0f89..c3fdc9f 100644 --- a/src/function/builtin/special/IF.java +++ b/src/function/builtin/special/IF.java @@ -5,6 +5,7 @@ import static function.builtin.EVAL.eval; import function.*; import sexpression.*; +@FunctionNames({ "IF" }) public class IF extends LispSpecialFunction { private ArgumentValidator argumentValidator; diff --git a/src/function/builtin/special/LAMBDA.java b/src/function/builtin/special/LAMBDA.java index 84d6e6d..e1c974f 100644 --- a/src/function/builtin/special/LAMBDA.java +++ b/src/function/builtin/special/LAMBDA.java @@ -5,6 +5,7 @@ import static function.builtin.cons.LIST.makeList; import function.*; import sexpression.*; +@FunctionNames({ "LAMBDA" }) public class LAMBDA extends LispSpecialFunction { public static boolean isLambdaExpression(SExpression sexpr) { diff --git a/src/function/builtin/special/LET.java b/src/function/builtin/special/LET.java index ce0df32..839dd2e 100644 --- a/src/function/builtin/special/LET.java +++ b/src/function/builtin/special/LET.java @@ -6,6 +6,7 @@ import function.*; import sexpression.*; import table.*; +@FunctionNames({ "LET" }) public class LET extends LispSpecialFunction { private ArgumentValidator argumentValidator; diff --git a/src/function/builtin/special/OR.java b/src/function/builtin/special/OR.java index 7d2d2eb..695331f 100644 --- a/src/function/builtin/special/OR.java +++ b/src/function/builtin/special/OR.java @@ -5,6 +5,7 @@ import static function.builtin.EVAL.eval; import function.*; import sexpression.*; +@FunctionNames({ "OR" }) public class OR extends LispSpecialFunction { private ArgumentValidator argumentValidator; diff --git a/src/function/builtin/special/QUOTE.java b/src/function/builtin/special/QUOTE.java index 345218a..ba6f9fa 100644 --- a/src/function/builtin/special/QUOTE.java +++ b/src/function/builtin/special/QUOTE.java @@ -3,6 +3,7 @@ package function.builtin.special; import function.*; import sexpression.*; +@FunctionNames({ "QUOTE" }) public class QUOTE extends LispSpecialFunction { private ArgumentValidator argumentValidator; diff --git a/src/function/builtin/special/SETF.java b/src/function/builtin/special/SETF.java index 83086d3..2f78bca 100644 --- a/src/function/builtin/special/SETF.java +++ b/src/function/builtin/special/SETF.java @@ -7,6 +7,7 @@ import static function.builtin.cons.LIST.makeList; import function.*; import sexpression.*; +@FunctionNames({ "SETF", "SETQ" }) public class SETF extends LispSpecialFunction { private ArgumentValidator argumentValidator; diff --git a/src/table/FunctionTable.java b/src/table/FunctionTable.java index d70063e..cf874ed 100644 --- a/src/table/FunctionTable.java +++ b/src/table/FunctionTable.java @@ -1,8 +1,10 @@ package table; -import java.util.HashMap; +import java.text.MessageFormat; +import java.util.*; -import function.LispFunction; +import error.CriticalLispException; +import function.*; import function.builtin.*; import function.builtin.cons.*; import function.builtin.math.*; @@ -11,72 +13,132 @@ import function.builtin.special.*; public class FunctionTable { - private static FunctionTable uniqueInstance = new FunctionTable(); - public static LispFunction lookupFunction(String functionName) { - return uniqueInstance.functionTable.get(functionName); + return getTable().get(functionName); } public static boolean isAlreadyDefined(String functionName) { - return uniqueInstance.functionTable.containsKey(functionName); + return getTable().containsKey(functionName); } public static void defineFunction(String functionName, LispFunction function) { - uniqueInstance.functionTable.put(functionName, function); + getTable().put(functionName, function); } public static void reset() { - uniqueInstance.initializeFunctionTable(); + getUniqueInstance().initializeFunctionTable(allBuiltIns); } - private HashMap functionTable; + static void reset(Set> builtIns) { + getUniqueInstance().initializeFunctionTable(builtIns); + } + + private static Set> allBuiltIns = new HashSet<>(); + + static { + allBuiltIns.add(AND.class); + allBuiltIns.add(APPLY.class); + allBuiltIns.add(ATOM.class); + allBuiltIns.add(COND.class); + allBuiltIns.add(CONS.class); + allBuiltIns.add(DEFINE_MACRO.class); + allBuiltIns.add(DEFUN.class); + allBuiltIns.add(DIVIDE.class); + allBuiltIns.add(EQ.class); + allBuiltIns.add(EQUAL.class); + allBuiltIns.add(EQUALSP.class); + allBuiltIns.add(EVAL.class); + allBuiltIns.add(EXIT.class); + allBuiltIns.add(FIRST.class); + allBuiltIns.add(FUNCALL.class); + allBuiltIns.add(GREATERP.class); + allBuiltIns.add(IF.class); + allBuiltIns.add(LAMBDA.class); + allBuiltIns.add(LENGTH.class); + allBuiltIns.add(LESSP.class); + allBuiltIns.add(LET.class); + allBuiltIns.add(LIST.class); + allBuiltIns.add(LISTP.class); + allBuiltIns.add(LOAD.class); + allBuiltIns.add(MINUS.class); + allBuiltIns.add(MULTIPLY.class); + allBuiltIns.add(NULL.class); + allBuiltIns.add(OR.class); + allBuiltIns.add(PLUS.class); + allBuiltIns.add(PRINT.class); + allBuiltIns.add(QUOTE.class); + allBuiltIns.add(REST.class); + allBuiltIns.add(SET.class); + allBuiltIns.add(SETF.class); + allBuiltIns.add(SYMBOL_FUNCTION.class); + } + + private static FunctionTable uniqueInstance; + + private static FunctionTable getUniqueInstance() { + if (uniqueInstance == null) { + uniqueInstance = new FunctionTable(); + } + + return uniqueInstance; + } + + private static Map getTable() { + return getUniqueInstance().table; + } + + private Map table; private FunctionTable() { - initializeFunctionTable(); + initializeFunctionTable(allBuiltIns); } - private void initializeFunctionTable() { - functionTable = new HashMap<>(); + private void initializeFunctionTable(Set> builtIns) { + table = new HashMap<>(); - functionTable.put("*", new MULTIPLY()); - functionTable.put("+", new PLUS()); - functionTable.put("-", new MINUS()); - functionTable.put("/", new DIVIDE()); - functionTable.put("<", new LESSP()); - functionTable.put("=", new EQUALSP()); - functionTable.put(">", new GREATERP()); - functionTable.put("AND", new AND()); - functionTable.put("APPLY", new APPLY()); - functionTable.put("ATOM", new ATOM()); - functionTable.put("CAR", new FIRST()); - functionTable.put("CDR", new REST()); - functionTable.put("COND", new COND()); - functionTable.put("CONS", new CONS()); - functionTable.put("DEFINE-MACRO", new DEFINE_MACRO()); - functionTable.put("DEFUN", new DEFUN()); - functionTable.put("EQ", new EQ()); - functionTable.put("EQUAL", new EQUAL()); - functionTable.put("EVAL", new EVAL()); - functionTable.put("EXIT", new EXIT()); - functionTable.put("FIRST", new FIRST()); - functionTable.put("FUNCALL", new FUNCALL()); - functionTable.put("GREATERP", new GREATERP()); - functionTable.put("IF", new IF()); - functionTable.put("LAMBDA", new LAMBDA()); - functionTable.put("LENGTH", new LENGTH()); - functionTable.put("LET", new LET()); - functionTable.put("LIST", new LIST()); - functionTable.put("LISTP", new LISTP()); - functionTable.put("LOAD", new LOAD()); - functionTable.put("NULL", new NULL()); - functionTable.put("OR", new OR()); - functionTable.put("PRINT", new PRINT()); - functionTable.put("QUOTE", new QUOTE()); - functionTable.put("REST", new REST()); - functionTable.put("SET", new SET()); - functionTable.put("SETF", new SETF()); - functionTable.put("SETQ", new SETF()); - functionTable.put("SYMBOL-FUNCTION", new SYMBOL_FUNCTION()); + for (Class function : builtIns) + addBuiltInFunctionToTable(function); + } + + private void addBuiltInFunctionToTable(Class function) { + FunctionNames functionNames = function.getAnnotation(FunctionNames.class); + + if (functionNames != null) + addAllFunctionNamesToTable(function, functionNames.value()); + } + + private void addAllFunctionNamesToTable(Class function, String[] names) { + LispFunction instance = createInstance(function); + + for (String name : names) + table.put(name, instance); + } + + private LispFunction createInstance(Class function) { + LispFunction instance = null; + + try { + instance = function.getConstructor().newInstance(); + } catch (Exception e) { + throw new LispFunctionInstantiationException(function.getName()); + } + + return instance; + } + + public static class LispFunctionInstantiationException extends CriticalLispException { + + private static final long serialVersionUID = 1L; + private String functionName; + + public LispFunctionInstantiationException(String functionName) { + this.functionName = functionName; + } + + @Override + public String getMessage() { + return MessageFormat.format("Could not create an instance of ''{0}''", functionName); + } } } diff --git a/test/table/FunctionTableTester.java b/test/table/FunctionTableTester.java index 6528834..91e2896 100644 --- a/test/table/FunctionTableTester.java +++ b/test/table/FunctionTableTester.java @@ -2,13 +2,47 @@ package table; import static org.junit.Assert.*; +import java.util.*; + import org.junit.*; -import function.LispFunction; +import error.ErrorManager; +import function.*; import sexpression.*; +import table.FunctionTable.LispFunctionInstantiationException; public class FunctionTableTester { + @FunctionNames({ "GOOD" }) + public static class GoodFunction extends LispFunction { + + @Override + public SExpression call(Cons argList) { + return Nil.getInstance(); + } + } + + @FunctionNames({ "BAD" }) + public static class BadFunction extends LispFunction { + + public BadFunction() { + throw new IllegalArgumentException("bad function"); + } + + @Override + public SExpression call(Cons argList) { + return Nil.getInstance(); + } + } + + public static class NamelessFunction extends LispFunction { + + @Override + public SExpression call(Cons argList) { + return Nil.getInstance(); + } + } + private LispFunction createLispFunction() { return new LispFunction() { @@ -30,7 +64,7 @@ public class FunctionTableTester { } @Test - public void builtinFunctionIsDefined() { + public void builtInFunctionIsDefined() { assertTrue(FunctionTable.isAlreadyDefined("CONS")); } @@ -40,7 +74,7 @@ public class FunctionTableTester { } @Test - public void lookupBuiltinFunction_ReturnsFunction() { + public void lookupBuiltInFunction_ReturnsFunction() { assertNotNull(FunctionTable.lookupFunction("CONS")); } @@ -68,10 +102,50 @@ public class FunctionTableTester { String functionName = "testFunction"; LispFunction testFunction = createLispFunction(); FunctionTable.defineFunction(functionName, testFunction); + FunctionTable.reset(); assertFalse(FunctionTable.isAlreadyDefined(functionName)); assertNull(FunctionTable.lookupFunction(functionName)); } + @Test + public void resetWithCustomBuitIns() { + Set> goodBuiltIns = new HashSet<>(); + goodBuiltIns.add(GoodFunction.class); + + FunctionTable.reset(goodBuiltIns); + + assertTrue(FunctionTable.isAlreadyDefined("GOOD")); + assertNotNull(FunctionTable.lookupFunction("GOOD")); + } + + @Test(expected = LispFunctionInstantiationException.class) + public void unableToInitializeBuiltIn() { + Set> badBuiltIns = new HashSet<>(); + badBuiltIns.add(BadFunction.class); + + FunctionTable.reset(badBuiltIns); + } + + @Test + public void lispFunctionInstantiationException_HasCorrectAttributes() { + LispFunctionInstantiationException e = new LispFunctionInstantiationException("Bad"); + + assertNotNull(e.getMessage()); + assertTrue(e.getMessage().length() > 0); + assertEquals(ErrorManager.Severity.CRITICAL, e.getSeverity()); + } + + @Test + public void namelessBuiltIn_DoesNotCauseNPE() { + Set> namelessBuiltins = new HashSet<>(); + namelessBuiltins.add(NamelessFunction.class); + + FunctionTable.reset(namelessBuiltins); + + assertFalse(FunctionTable.isAlreadyDefined("NAMELESS")); + assertNull(FunctionTable.lookupFunction("NAMELESS")); + } + }