transcendental-lisp/src/main/kotlin/table/FunctionTable.kt

157 lines
5.0 KiB
Kotlin

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_GREATER
import function.builtin.predicate.NUMERIC_LESS
import function.builtin.predicate.NumericEqual
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.LET
import function.builtin.special.LET_STAR
import function.builtin.special.Lambda
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
object FunctionTable {
private val allBuiltIns = setOf(
AND::class.java,
APPEND::class.java,
APPLY::class.java,
ATOM::class.java,
CASE::class.java,
COND::class.java,
CONS::class.java,
DEFINE_SPECIAL::class.java,
DEFMACRO::class.java,
DEFUN::class.java,
DIVIDE::class.java,
EQ::class.java,
EQUAL::class.java,
NumericEqual::class.java,
EVAL::class.java,
Exit::class.java,
FIRST::class.java,
FUNCALL::class.java,
FUSE::class.java,
GENSYM::class.java,
GENSYM_EQUAL::class.java,
NUMERIC_GREATER::class.java,
IF::class.java,
Lambda::class.java,
LENGTH::class.java,
NUMERIC_LESS::class.java,
LET::class.java,
LET_STAR::class.java,
LIST::class.java,
LISTP::class.java,
LOAD::class.java,
MINUS::class.java,
MODULO::class.java,
MULTIPLY::class.java,
NULL::class.java,
OR::class.java,
PLUS::class.java,
PRINT::class.java,
PROGN::class.java,
QUOTE::class.java,
RECUR::class.java,
REMAINDER::class.java,
REST::class.java,
SET::class.java,
SETQ::class.java,
SYMBOL_FUNCTION::class.java,
SYMBOLS::class.java)
private val table = mutableMapOf<String, LispFunction>()
init {
initializeFunctionTable(allBuiltIns)
}
private fun initializeFunctionTable(builtIns: Set<Class<out LispFunction>>) {
table.clear()
for (function in builtIns)
addBuiltInFunctionToTable(function)
}
private fun addBuiltInFunctionToTable(function: Class<out LispFunction>) {
val functionNames = function.getAnnotation(FunctionNames::class.java)
if (functionNames != null)
addAllFunctionNamesToTable(function, functionNames.value)
}
private fun addAllFunctionNamesToTable(function: Class<out LispFunction>, names: Array<out String>) {
for (name in names)
table[name] = createInstance(function, name)
}
private fun createInstance(function: Class<out LispFunction>, 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<Class<out LispFunction>>) {
initializeFunctionTable(builtIns)
}
class LispFunctionInstantiationException(private val functionName: String) : CriticalLispException() {
override val message: String
get() = "Could not create an instance of '$functionName'"
}
}