package table import error.CriticalLispException import function.FunctionNames import function.LispFunction import io.github.classgraph.ClassGraph object FunctionTable { private val table = mutableMapOf() private val classGraph = ClassGraph() .disableJarScanning() .enableClassInfo() .enableAnnotationInfo() .whitelistPackages("function.builtin") private val allBuiltIns = with(classGraph.scan()) { getClassesWithAnnotation(FunctionNames::class.qualifiedName) .map { it.loadClass() } .filterIsInstance>() .toSet() } init { 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() = "Could not create an instance of '$functionName'" } }