Convert function table to kotlin
This commit is contained in:
parent
fd322a385f
commit
d74e472780
|
@ -5,16 +5,16 @@ import function.FunctionNames;
|
||||||
import function.LispFunction;
|
import function.LispFunction;
|
||||||
import sexpression.Cons;
|
import sexpression.Cons;
|
||||||
import sexpression.SExpression;
|
import sexpression.SExpression;
|
||||||
|
import table.FunctionTable;
|
||||||
|
|
||||||
import static function.builtin.EVAL.applyFunction;
|
import static function.builtin.EVAL.applyFunction;
|
||||||
import static function.builtin.EVAL.lookupFunctionOrLambda;
|
import static function.builtin.EVAL.lookupFunctionOrLambda;
|
||||||
import static table.FunctionTable.lookupFunction;
|
|
||||||
|
|
||||||
@FunctionNames({ "APPLY" })
|
@FunctionNames({ "APPLY" })
|
||||||
public class APPLY extends LispFunction {
|
public class APPLY extends LispFunction {
|
||||||
|
|
||||||
public static SExpression apply(Cons argumentList) {
|
public static SExpression apply(Cons argumentList) {
|
||||||
return lookupFunction("APPLY").call(argumentList);
|
return FunctionTable.INSTANCE.lookupFunction("APPLY").call(argumentList);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ArgumentValidator argumentValidator;
|
private ArgumentValidator argumentValidator;
|
||||||
|
|
|
@ -4,7 +4,6 @@ import error.LispException;
|
||||||
import function.ArgumentValidator;
|
import function.ArgumentValidator;
|
||||||
import function.FunctionNames;
|
import function.FunctionNames;
|
||||||
import function.LispFunction;
|
import function.LispFunction;
|
||||||
import function.builtin.special.LAMBDA;
|
|
||||||
import function.builtin.special.RECUR.RecurNotInTailPositionException;
|
import function.builtin.special.RECUR.RecurNotInTailPositionException;
|
||||||
import sexpression.BackquoteExpression;
|
import sexpression.BackquoteExpression;
|
||||||
import sexpression.Cons;
|
import sexpression.Cons;
|
||||||
|
@ -12,13 +11,13 @@ import sexpression.LambdaExpression;
|
||||||
import sexpression.SExpression;
|
import sexpression.SExpression;
|
||||||
import sexpression.Symbol;
|
import sexpression.Symbol;
|
||||||
import table.ExecutionContext;
|
import table.ExecutionContext;
|
||||||
|
import table.FunctionTable;
|
||||||
|
|
||||||
import static function.builtin.cons.LIST.makeList;
|
import static function.builtin.cons.LIST.makeList;
|
||||||
import static function.builtin.special.LAMBDA.Lambda;
|
import static function.builtin.special.LAMBDA.Lambda;
|
||||||
import static java.text.MessageFormat.format;
|
import static java.text.MessageFormat.format;
|
||||||
import static sexpression.Nil.NIL;
|
import static sexpression.Nil.NIL;
|
||||||
import static sexpression.Symbol.T;
|
import static sexpression.Symbol.T;
|
||||||
import static table.FunctionTable.lookupFunction;
|
|
||||||
|
|
||||||
@FunctionNames({ "EVAL" })
|
@FunctionNames({ "EVAL" })
|
||||||
public class EVAL extends LispFunction {
|
public class EVAL extends LispFunction {
|
||||||
|
@ -45,11 +44,11 @@ public class EVAL extends LispFunction {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static EVAL lookupEval() {
|
private static EVAL lookupEval() {
|
||||||
return (EVAL) lookupFunction("EVAL");
|
return (EVAL) FunctionTable.INSTANCE.lookupFunction("EVAL");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LispFunction lookupFunctionOrLambda(SExpression functionExpression) {
|
public static LispFunction lookupFunctionOrLambda(SExpression functionExpression) {
|
||||||
LispFunction function = lookupFunction(functionExpression.toString());
|
LispFunction function = FunctionTable.INSTANCE.lookupFunction(functionExpression.toString());
|
||||||
|
|
||||||
if (function == null)
|
if (function == null)
|
||||||
function = createLambdaFunction(functionExpression);
|
function = createLambdaFunction(functionExpression);
|
||||||
|
|
|
@ -7,15 +7,14 @@ import sexpression.Cons;
|
||||||
import sexpression.SExpression;
|
import sexpression.SExpression;
|
||||||
import sexpression.Symbol;
|
import sexpression.Symbol;
|
||||||
import table.ExecutionContext;
|
import table.ExecutionContext;
|
||||||
|
import table.FunctionTable;
|
||||||
import table.SymbolTable;
|
import table.SymbolTable;
|
||||||
|
|
||||||
import static table.FunctionTable.lookupFunction;
|
|
||||||
|
|
||||||
@FunctionNames({ "SET" })
|
@FunctionNames({ "SET" })
|
||||||
public class SET extends LispFunction {
|
public class SET extends LispFunction {
|
||||||
|
|
||||||
public static SExpression set(Cons argumentList) {
|
public static SExpression set(Cons argumentList) {
|
||||||
return lookupFunction("SET").call(argumentList);
|
return FunctionTable.INSTANCE.lookupFunction("SET").call(argumentList);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ArgumentValidator argumentValidator;
|
private ArgumentValidator argumentValidator;
|
||||||
|
|
|
@ -9,9 +9,9 @@ import function.UserDefinedFunction;
|
||||||
import sexpression.Cons;
|
import sexpression.Cons;
|
||||||
import sexpression.SExpression;
|
import sexpression.SExpression;
|
||||||
import sexpression.Symbol;
|
import sexpression.Symbol;
|
||||||
|
import table.FunctionTable;
|
||||||
|
|
||||||
import static java.text.MessageFormat.format;
|
import static java.text.MessageFormat.format;
|
||||||
import static table.FunctionTable.lookupFunction;
|
|
||||||
|
|
||||||
@FunctionNames({ "SYMBOL-FUNCTION" })
|
@FunctionNames({ "SYMBOL-FUNCTION" })
|
||||||
public class SYMBOL_FUNCTION extends LispFunction {
|
public class SYMBOL_FUNCTION extends LispFunction {
|
||||||
|
@ -29,7 +29,7 @@ public class SYMBOL_FUNCTION extends LispFunction {
|
||||||
argumentValidator.validate(argumentList);
|
argumentValidator.validate(argumentList);
|
||||||
|
|
||||||
SExpression symbol = argumentList.getFirst();
|
SExpression symbol = argumentList.getFirst();
|
||||||
LispFunction function = lookupFunction(symbol.toString());
|
LispFunction function = FunctionTable.INSTANCE.lookupFunction(symbol.toString());
|
||||||
|
|
||||||
if (function != null)
|
if (function != null)
|
||||||
return createRepresentation(symbol, function);
|
return createRepresentation(symbol, function);
|
||||||
|
|
|
@ -4,9 +4,9 @@ import function.ArgumentValidator;
|
||||||
import function.FunctionNames;
|
import function.FunctionNames;
|
||||||
import function.LispFunction;
|
import function.LispFunction;
|
||||||
import sexpression.Cons;
|
import sexpression.Cons;
|
||||||
|
import table.FunctionTable;
|
||||||
|
|
||||||
import static sexpression.Nil.NIL;
|
import static sexpression.Nil.NIL;
|
||||||
import static table.FunctionTable.lookupFunction;
|
|
||||||
|
|
||||||
@FunctionNames({ "APPEND" })
|
@FunctionNames({ "APPEND" })
|
||||||
public class APPEND extends LispFunction {
|
public class APPEND extends LispFunction {
|
||||||
|
@ -16,7 +16,7 @@ public class APPEND extends LispFunction {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static APPEND lookupAppend() {
|
private static APPEND lookupAppend() {
|
||||||
return (APPEND) lookupFunction("APPEND");
|
return (APPEND) FunctionTable.INSTANCE.lookupFunction("APPEND");
|
||||||
}
|
}
|
||||||
|
|
||||||
private ArgumentValidator argumentValidator;
|
private ArgumentValidator argumentValidator;
|
||||||
|
|
|
@ -6,13 +6,13 @@ import function.LispFunction;
|
||||||
import recursion.TailCall;
|
import recursion.TailCall;
|
||||||
import sexpression.Cons;
|
import sexpression.Cons;
|
||||||
import sexpression.LispNumber;
|
import sexpression.LispNumber;
|
||||||
|
import table.FunctionTable;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
|
||||||
import static function.builtin.cons.LIST.makeList;
|
import static function.builtin.cons.LIST.makeList;
|
||||||
import static recursion.TailCalls.done;
|
import static recursion.TailCalls.done;
|
||||||
import static recursion.TailCalls.tailCall;
|
import static recursion.TailCalls.tailCall;
|
||||||
import static table.FunctionTable.lookupFunction;
|
|
||||||
|
|
||||||
@FunctionNames({ "LENGTH" })
|
@FunctionNames({ "LENGTH" })
|
||||||
public class LENGTH extends LispFunction {
|
public class LENGTH extends LispFunction {
|
||||||
|
@ -24,7 +24,7 @@ public class LENGTH extends LispFunction {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static LENGTH lookupLength() {
|
private static LENGTH lookupLength() {
|
||||||
return (LENGTH) lookupFunction("LENGTH");
|
return (LENGTH) FunctionTable.INSTANCE.lookupFunction("LENGTH");
|
||||||
}
|
}
|
||||||
|
|
||||||
private ArgumentValidator argumentValidator;
|
private ArgumentValidator argumentValidator;
|
||||||
|
|
|
@ -8,11 +8,10 @@ import function.UserDefinedFunction;
|
||||||
import sexpression.Cons;
|
import sexpression.Cons;
|
||||||
import sexpression.SExpression;
|
import sexpression.SExpression;
|
||||||
import sexpression.Symbol;
|
import sexpression.Symbol;
|
||||||
|
import table.FunctionTable;
|
||||||
|
|
||||||
import static function.builtin.cons.LIST.makeList;
|
import static function.builtin.cons.LIST.makeList;
|
||||||
import static java.text.MessageFormat.format;
|
import static java.text.MessageFormat.format;
|
||||||
import static table.FunctionTable.defineFunction;
|
|
||||||
import static table.FunctionTable.isAlreadyDefined;
|
|
||||||
|
|
||||||
public abstract class Define extends LispSpecialFunction {
|
public abstract class Define extends LispSpecialFunction {
|
||||||
|
|
||||||
|
@ -50,10 +49,10 @@ public abstract class Define extends LispSpecialFunction {
|
||||||
Cons functionBody = (Cons) remainingArguments.getRest();
|
Cons functionBody = (Cons) remainingArguments.getRest();
|
||||||
UserDefinedFunction function = createFunction(functionName, lambdaList, functionBody);
|
UserDefinedFunction function = createFunction(functionName, lambdaList, functionBody);
|
||||||
|
|
||||||
if (isAlreadyDefined(functionName.toString()))
|
if (FunctionTable.INSTANCE.isAlreadyDefined(functionName.toString()))
|
||||||
environment.getErrorManager().handle(new RedefiningFunctionWarning(functionName.toString()));
|
environment.getErrorManager().handle(new RedefiningFunctionWarning(functionName.toString()));
|
||||||
|
|
||||||
defineFunction(functionName.toString(), function);
|
FunctionTable.INSTANCE.defineFunction(functionName.toString(), function);
|
||||||
|
|
||||||
return functionName;
|
return functionName;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,200 +0,0 @@
|
||||||
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.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import static java.text.MessageFormat.format;
|
|
||||||
|
|
||||||
public class FunctionTable {
|
|
||||||
|
|
||||||
private static Set<Class<? extends LispFunction>> allBuiltIns = new HashSet<>();
|
|
||||||
|
|
||||||
static {
|
|
||||||
allBuiltIns.add(AND.class);
|
|
||||||
allBuiltIns.add(APPEND.class);
|
|
||||||
allBuiltIns.add(APPLY.class);
|
|
||||||
allBuiltIns.add(ATOM.class);
|
|
||||||
allBuiltIns.add(CASE.class);
|
|
||||||
allBuiltIns.add(COND.class);
|
|
||||||
allBuiltIns.add(CONS.class);
|
|
||||||
allBuiltIns.add(DEFINE_SPECIAL.class);
|
|
||||||
allBuiltIns.add(DEFMACRO.class);
|
|
||||||
allBuiltIns.add(DEFUN.class);
|
|
||||||
allBuiltIns.add(DIVIDE.class);
|
|
||||||
allBuiltIns.add(EQ.class);
|
|
||||||
allBuiltIns.add(EQUAL.class);
|
|
||||||
allBuiltIns.add(NUMERIC_EQUAL.class);
|
|
||||||
allBuiltIns.add(EVAL.class);
|
|
||||||
allBuiltIns.add(EXIT.class);
|
|
||||||
allBuiltIns.add(FIRST.class);
|
|
||||||
allBuiltIns.add(FUNCALL.class);
|
|
||||||
allBuiltIns.add(FUSE.class);
|
|
||||||
allBuiltIns.add(GENSYM.class);
|
|
||||||
allBuiltIns.add(GENSYM_EQUAL.class);
|
|
||||||
allBuiltIns.add(NUMERIC_GREATER.class);
|
|
||||||
allBuiltIns.add(IF.class);
|
|
||||||
allBuiltIns.add(LAMBDA.class);
|
|
||||||
allBuiltIns.add(LENGTH.class);
|
|
||||||
allBuiltIns.add(NUMERIC_LESS.class);
|
|
||||||
allBuiltIns.add(LET.class);
|
|
||||||
allBuiltIns.add(LET_STAR.class);
|
|
||||||
allBuiltIns.add(LIST.class);
|
|
||||||
allBuiltIns.add(LISTP.class);
|
|
||||||
allBuiltIns.add(LOAD.class);
|
|
||||||
allBuiltIns.add(MINUS.class);
|
|
||||||
allBuiltIns.add(MODULO.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(RECUR.class);
|
|
||||||
allBuiltIns.add(REMAINDER.class);
|
|
||||||
allBuiltIns.add(REST.class);
|
|
||||||
allBuiltIns.add(SET.class);
|
|
||||||
allBuiltIns.add(SETQ.class);
|
|
||||||
allBuiltIns.add(SYMBOL_FUNCTION.class);
|
|
||||||
allBuiltIns.add(SYMBOLS.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 resetFunctionTable() {
|
|
||||||
getUniqueInstance().initializeFunctionTable(allBuiltIns);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void resetFunctionTable(Set<Class<? extends LispFunction>> builtIns) {
|
|
||||||
getUniqueInstance().initializeFunctionTable(builtIns);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static FunctionTable uniqueInstance;
|
|
||||||
|
|
||||||
private static FunctionTable getUniqueInstance() {
|
|
||||||
if (uniqueInstance == null) {
|
|
||||||
uniqueInstance = new FunctionTable();
|
|
||||||
}
|
|
||||||
|
|
||||||
return uniqueInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Map<String, LispFunction> getTable() {
|
|
||||||
return getUniqueInstance().table;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<String, LispFunction> table;
|
|
||||||
|
|
||||||
private FunctionTable() {
|
|
||||||
initializeFunctionTable(allBuiltIns);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initializeFunctionTable(Set<Class<? extends LispFunction>> builtIns) {
|
|
||||||
table = new HashMap<>();
|
|
||||||
|
|
||||||
for (Class<? extends LispFunction> function : builtIns)
|
|
||||||
addBuiltInFunctionToTable(function);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addBuiltInFunctionToTable(Class<? extends LispFunction> function) {
|
|
||||||
FunctionNames functionNames = function.getAnnotation(FunctionNames.class);
|
|
||||||
|
|
||||||
if (functionNames != null)
|
|
||||||
addAllFunctionNamesToTable(function, functionNames.value());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addAllFunctionNamesToTable(Class<? extends LispFunction> function, String[] names) {
|
|
||||||
for (String name : names)
|
|
||||||
table.put(name, createInstance(function, name));
|
|
||||||
}
|
|
||||||
|
|
||||||
private LispFunction createInstance(Class<? extends LispFunction> function, String name) {
|
|
||||||
LispFunction instance = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
instance = function.getConstructor(String.class).newInstance(name);
|
|
||||||
} 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 format("Could not create an instance of ''{0}''", functionName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,159 @@
|
||||||
|
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<String, LispFunction> = HashMap()
|
||||||
|
private val allBuiltIns = HashSet<Class<out LispFunction>>()
|
||||||
|
|
||||||
|
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<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<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() = format("Could not create an instance of ''{0}''", functionName)
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ import interpreter.LispInterpreter;
|
||||||
import interpreter.LispInterpreterBuilder;
|
import interpreter.LispInterpreterBuilder;
|
||||||
import interpreter.LispInterpreterBuilderImpl;
|
import interpreter.LispInterpreterBuilderImpl;
|
||||||
import table.ExecutionContext;
|
import table.ExecutionContext;
|
||||||
|
import table.FunctionTable;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
@ -13,7 +14,6 @@ import java.io.FileNotFoundException;
|
||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
|
|
||||||
import static application.LispMain.LANGUAGE_FILE_NAMES;
|
import static application.LispMain.LANGUAGE_FILE_NAMES;
|
||||||
import static table.FunctionTable.resetFunctionTable;
|
|
||||||
import static util.Path.getPathPrefix;
|
import static util.Path.getPathPrefix;
|
||||||
|
|
||||||
public class LispInterpreterFixture {
|
public class LispInterpreterFixture {
|
||||||
|
@ -29,7 +29,7 @@ public class LispInterpreterFixture {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void cleanUp() {
|
public static void cleanUp() {
|
||||||
resetFunctionTable();
|
FunctionTable.INSTANCE.resetFunctionTable();
|
||||||
executionContext.clearContext();
|
executionContext.clearContext();
|
||||||
environment.reset();
|
environment.reset();
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,88 +13,86 @@ import table.SymbolTable.NullSymbolTable
|
||||||
@TestInstance(PER_CLASS)
|
@TestInstance(PER_CLASS)
|
||||||
class ExecutionContextTest {
|
class ExecutionContextTest {
|
||||||
|
|
||||||
private val executionContext: ExecutionContext = ExecutionContext
|
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
executionContext.clearContext()
|
ExecutionContext.clearContext()
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
fun tearDown() {
|
fun tearDown() {
|
||||||
executionContext.clearContext()
|
ExecutionContext.clearContext()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `assign a new scope`() {
|
fun `assign a new scope`() {
|
||||||
val scope = SymbolTable()
|
val scope = SymbolTable()
|
||||||
executionContext.scope = scope
|
ExecutionContext.scope = scope
|
||||||
|
|
||||||
assertThat(executionContext.scope).isEqualTo(scope)
|
assertThat(ExecutionContext.scope).isEqualTo(scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `clear the context`() {
|
fun `clear the context`() {
|
||||||
val scope = SymbolTable()
|
val scope = SymbolTable()
|
||||||
executionContext.scope = scope
|
ExecutionContext.scope = scope
|
||||||
|
|
||||||
assertThat(executionContext.scope).isEqualTo(scope)
|
assertThat(ExecutionContext.scope).isEqualTo(scope)
|
||||||
executionContext.clearContext()
|
ExecutionContext.clearContext()
|
||||||
assertThat(executionContext.scope).isNotEqualTo(scope)
|
assertThat(ExecutionContext.scope).isNotEqualTo(scope)
|
||||||
assertThat(executionContext.scope.parent).isEqualTo(NullSymbolTable)
|
assertThat(ExecutionContext.scope.parent).isEqualTo(NullSymbolTable)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `lookup a variable`() {
|
fun `lookup a variable`() {
|
||||||
executionContext.scope["test"] = T
|
ExecutionContext.scope["test"] = T
|
||||||
|
|
||||||
assertThat(executionContext.lookupSymbolValue("test")).isEqualTo(T)
|
assertThat(ExecutionContext.lookupSymbolValue("test")).isEqualTo(T)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `lookup a local variable`() {
|
fun `lookup a local variable`() {
|
||||||
val scope = SymbolTable(executionContext.scope)
|
val scope = SymbolTable(ExecutionContext.scope)
|
||||||
|
|
||||||
scope["local"] = T
|
scope["local"] = T
|
||||||
executionContext.scope = scope
|
ExecutionContext.scope = scope
|
||||||
|
|
||||||
assertThat(executionContext.lookupSymbolValue("local")).isEqualTo(T)
|
assertThat(ExecutionContext.lookupSymbolValue("local")).isEqualTo(T)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `lookup a global variable`() {
|
fun `lookup a global variable`() {
|
||||||
val global = executionContext.scope
|
val global = ExecutionContext.scope
|
||||||
val scope1 = SymbolTable(global)
|
val scope1 = SymbolTable(global)
|
||||||
val scope2 = SymbolTable(scope1)
|
val scope2 = SymbolTable(scope1)
|
||||||
val scope3 = SymbolTable(scope2)
|
val scope3 = SymbolTable(scope2)
|
||||||
executionContext.scope["global"] = T
|
ExecutionContext.scope["global"] = T
|
||||||
executionContext.scope = scope3
|
ExecutionContext.scope = scope3
|
||||||
|
|
||||||
assertThat(executionContext.lookupSymbolValue("global")).isEqualTo(T)
|
assertThat(ExecutionContext.lookupSymbolValue("global")).isEqualTo(T)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `lookup a shadowed variable`() {
|
fun `lookup a shadowed variable`() {
|
||||||
val scope = SymbolTable(executionContext.scope)
|
val scope = SymbolTable(ExecutionContext.scope)
|
||||||
|
|
||||||
scope["shadowed"] = NIL
|
scope["shadowed"] = NIL
|
||||||
executionContext.scope["shadowed"] = T
|
ExecutionContext.scope["shadowed"] = T
|
||||||
executionContext.scope = scope
|
ExecutionContext.scope = scope
|
||||||
|
|
||||||
assertThat(executionContext.lookupSymbolValue("shadowed")).isEqualTo(NIL)
|
assertThat(ExecutionContext.lookupSymbolValue("shadowed")).isEqualTo(NIL)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `restore the global context`() {
|
fun `restore the global context`() {
|
||||||
val global = executionContext.scope
|
val global = ExecutionContext.scope
|
||||||
val scope1 = SymbolTable(global)
|
val scope1 = SymbolTable(global)
|
||||||
val scope2 = SymbolTable(scope1)
|
val scope2 = SymbolTable(scope1)
|
||||||
val scope3 = SymbolTable(scope2)
|
val scope3 = SymbolTable(scope2)
|
||||||
executionContext.scope = scope3
|
ExecutionContext.scope = scope3
|
||||||
|
|
||||||
assertThat(executionContext.scope.isGlobal()).isFalse()
|
assertThat(ExecutionContext.scope.isGlobal()).isFalse()
|
||||||
executionContext.restoreGlobalScope()
|
ExecutionContext.restoreGlobalScope()
|
||||||
assertThat(executionContext.scope.isGlobal()).isTrue()
|
assertThat(ExecutionContext.scope.isGlobal()).isTrue()
|
||||||
assertThat(executionContext.scope).isEqualTo(global)
|
assertThat(ExecutionContext.scope).isEqualTo(global)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,7 @@ package testutil;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import table.ExecutionContext;
|
import table.ExecutionContext;
|
||||||
|
import table.FunctionTable;
|
||||||
import static table.FunctionTable.resetFunctionTable;
|
|
||||||
|
|
||||||
public abstract class SymbolAndFunctionCleaner {
|
public abstract class SymbolAndFunctionCleaner {
|
||||||
|
|
||||||
|
@ -17,14 +16,14 @@ public abstract class SymbolAndFunctionCleaner {
|
||||||
@Before
|
@Before
|
||||||
public final void setUp() {
|
public final void setUp() {
|
||||||
executionContext.clearContext();
|
executionContext.clearContext();
|
||||||
resetFunctionTable();
|
FunctionTable.INSTANCE.resetFunctionTable();
|
||||||
additionalSetUp();
|
additionalSetUp();
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public final void tearDown() {
|
public final void tearDown() {
|
||||||
executionContext.clearContext();
|
executionContext.clearContext();
|
||||||
resetFunctionTable();
|
FunctionTable.INSTANCE.resetFunctionTable();
|
||||||
additionalTearDown();
|
additionalTearDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue