package table; import java.text.MessageFormat; import java.util.*; import error.CriticalLispException; import function.*; import function.builtin.*; import function.builtin.cons.*; import function.builtin.math.*; import function.builtin.predicate.*; import function.builtin.special.*; public class FunctionTable { public static LispFunction lookupFunction(String functionName) { return getTable().get(functionName); } public static boolean isAlreadyDefined(String functionName) { return getTable().containsKey(functionName); } public static void defineFunction(String functionName, LispFunction function) { getTable().put(functionName, function); } public static void reset() { getUniqueInstance().initializeFunctionTable(allBuiltIns); } 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(PROGN.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(allBuiltIns); } private void initializeFunctionTable(Set> builtIns) { table = new HashMap<>(); 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); } } }