package table import error.CriticalLispException import function.FunctionNames import function.LispFunction import function.builtin.APPLY import function.builtin.EVAL import function.builtin.EXIT import function.builtin.FUNCALL import function.builtin.FUSE import function.builtin.GENSYM import function.builtin.LOAD import function.builtin.PRINT import function.builtin.SET import function.builtin.SYMBOLS import function.builtin.SYMBOL_FUNCTION import function.builtin.cons.APPEND import function.builtin.cons.CONS import function.builtin.cons.FIRST import function.builtin.cons.LENGTH import function.builtin.cons.LIST import function.builtin.cons.REST import function.builtin.math.DIVIDE import function.builtin.math.MINUS import function.builtin.math.MODULO import function.builtin.math.MULTIPLY import function.builtin.math.PLUS import function.builtin.math.REMAINDER import function.builtin.predicate.ATOM import function.builtin.predicate.EQ import function.builtin.predicate.EQUAL import function.builtin.predicate.GENSYM_EQUAL import function.builtin.predicate.LISTP import function.builtin.predicate.NULL import function.builtin.predicate.NUMERIC_EQUAL import function.builtin.predicate.NUMERIC_GREATER import function.builtin.predicate.NUMERIC_LESS import function.builtin.special.AND import function.builtin.special.CASE import function.builtin.special.COND import function.builtin.special.DEFINE_SPECIAL import function.builtin.special.DEFMACRO import function.builtin.special.DEFUN import function.builtin.special.IF import function.builtin.special.LAMBDA import function.builtin.special.LET import function.builtin.special.LET_STAR import function.builtin.special.OR import function.builtin.special.PROGN import function.builtin.special.QUOTE import function.builtin.special.RECUR import function.builtin.special.SETQ import java.text.MessageFormat.format import java.util.HashMap import java.util.HashSet object FunctionTable { private var table: MutableMap = HashMap() private val allBuiltIns = HashSet>() init { allBuiltIns.add(AND::class.java) allBuiltIns.add(APPEND::class.java) allBuiltIns.add(APPLY::class.java) allBuiltIns.add(ATOM::class.java) allBuiltIns.add(CASE::class.java) allBuiltIns.add(COND::class.java) allBuiltIns.add(CONS::class.java) allBuiltIns.add(DEFINE_SPECIAL::class.java) allBuiltIns.add(DEFMACRO::class.java) allBuiltIns.add(DEFUN::class.java) allBuiltIns.add(DIVIDE::class.java) allBuiltIns.add(EQ::class.java) allBuiltIns.add(EQUAL::class.java) allBuiltIns.add(NUMERIC_EQUAL::class.java) allBuiltIns.add(EVAL::class.java) allBuiltIns.add(EXIT::class.java) allBuiltIns.add(FIRST::class.java) allBuiltIns.add(FUNCALL::class.java) allBuiltIns.add(FUSE::class.java) allBuiltIns.add(GENSYM::class.java) allBuiltIns.add(GENSYM_EQUAL::class.java) allBuiltIns.add(NUMERIC_GREATER::class.java) allBuiltIns.add(IF::class.java) allBuiltIns.add(LAMBDA::class.java) allBuiltIns.add(LENGTH::class.java) allBuiltIns.add(NUMERIC_LESS::class.java) allBuiltIns.add(LET::class.java) allBuiltIns.add(LET_STAR::class.java) allBuiltIns.add(LIST::class.java) allBuiltIns.add(LISTP::class.java) allBuiltIns.add(LOAD::class.java) allBuiltIns.add(MINUS::class.java) allBuiltIns.add(MODULO::class.java) allBuiltIns.add(MULTIPLY::class.java) allBuiltIns.add(NULL::class.java) allBuiltIns.add(OR::class.java) allBuiltIns.add(PLUS::class.java) allBuiltIns.add(PRINT::class.java) allBuiltIns.add(PROGN::class.java) allBuiltIns.add(QUOTE::class.java) allBuiltIns.add(RECUR::class.java) allBuiltIns.add(REMAINDER::class.java) allBuiltIns.add(REST::class.java) allBuiltIns.add(SET::class.java) allBuiltIns.add(SETQ::class.java) allBuiltIns.add(SYMBOL_FUNCTION::class.java) allBuiltIns.add(SYMBOLS::class.java) initializeFunctionTable(allBuiltIns) } private fun initializeFunctionTable(builtIns: Set>) { table.clear() for (function in builtIns) addBuiltInFunctionToTable(function) } private fun addBuiltInFunctionToTable(function: Class) { val functionNames = function.getAnnotation(FunctionNames::class.java) if (functionNames != null) addAllFunctionNamesToTable(function, functionNames.value) } private fun addAllFunctionNamesToTable(function: Class, names: Array) { for (name in names) table[name] = createInstance(function, name) } private fun createInstance(function: Class, name: String) = try { function.getConstructor(String::class.java).newInstance(name) } catch (e: Exception) { throw LispFunctionInstantiationException(function.name) } fun lookupFunction(functionName: String) = table[functionName] fun isAlreadyDefined(functionName: String) = table.containsKey(functionName) fun defineFunction(functionName: String, function: LispFunction) { table[functionName] = function } fun resetFunctionTable() { initializeFunctionTable(allBuiltIns) } internal fun resetFunctionTable(builtIns: Set>) { initializeFunctionTable(builtIns) } class LispFunctionInstantiationException(private val functionName: String) : CriticalLispException() { override val message: String get() = format("Could not create an instance of ''{0}''", functionName) } }