Convert more builtins to kotlin
This commit is contained in:
parent
b2867042fe
commit
d95b5cc46f
|
@ -1,39 +0,0 @@
|
||||||
package function.builtin;
|
|
||||||
|
|
||||||
import function.ArgumentValidator;
|
|
||||||
import function.FunctionNames;
|
|
||||||
import function.LispFunction;
|
|
||||||
import sexpression.Cons;
|
|
||||||
import sexpression.SExpression;
|
|
||||||
import table.FunctionTable;
|
|
||||||
|
|
||||||
import static function.builtin.Eval.applyFunction;
|
|
||||||
import static function.builtin.Eval.lookupFunctionOrLambda;
|
|
||||||
|
|
||||||
@FunctionNames({ "APPLY" })
|
|
||||||
public class APPLY extends LispFunction {
|
|
||||||
|
|
||||||
public static SExpression apply(Cons argumentList) {
|
|
||||||
return FunctionTable.INSTANCE.lookupFunction("APPLY").call(argumentList);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ArgumentValidator argumentValidator;
|
|
||||||
|
|
||||||
public APPLY(String name) {
|
|
||||||
this.argumentValidator = new ArgumentValidator(name);
|
|
||||||
this.argumentValidator.setExactNumberOfArguments(2);
|
|
||||||
this.argumentValidator.setTrailingArgumentExpectedType(Cons.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SExpression call(Cons argumentList) {
|
|
||||||
argumentValidator.validate(argumentList);
|
|
||||||
|
|
||||||
Cons rest = (Cons) argumentList.getRest();
|
|
||||||
Cons functionArguments = (Cons) rest.getFirst();
|
|
||||||
SExpression functionName = argumentList.getFirst();
|
|
||||||
LispFunction function = lookupFunctionOrLambda(functionName);
|
|
||||||
|
|
||||||
return applyFunction(function, functionArguments);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
package function.builtin
|
||||||
|
|
||||||
|
import function.ArgumentValidator
|
||||||
|
import function.FunctionNames
|
||||||
|
import function.LispFunction
|
||||||
|
import sexpression.Cons
|
||||||
|
import sexpression.SExpression
|
||||||
|
import table.FunctionTable
|
||||||
|
|
||||||
|
import function.builtin.Eval.Companion.applyFunction
|
||||||
|
import function.builtin.Eval.Companion.lookupFunctionOrLambda
|
||||||
|
|
||||||
|
@FunctionNames("APPLY")
|
||||||
|
class Apply(name: String) : LispFunction() {
|
||||||
|
|
||||||
|
private val argumentValidator: ArgumentValidator = ArgumentValidator(name).apply {
|
||||||
|
setExactNumberOfArguments(2)
|
||||||
|
setTrailingArgumentExpectedType(Cons::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun call(argumentList: Cons): SExpression {
|
||||||
|
argumentValidator.validate(argumentList)
|
||||||
|
|
||||||
|
val rest = argumentList.rest as Cons
|
||||||
|
val functionArguments = rest.first as Cons
|
||||||
|
val functionName = argumentList.first
|
||||||
|
val function = lookupFunctionOrLambda(functionName)
|
||||||
|
|
||||||
|
return applyFunction(function, functionArguments)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
fun apply(argumentList: Cons): SExpression {
|
||||||
|
return FunctionTable.lookupFunction("APPLY")!!.call(argumentList)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,29 +0,0 @@
|
||||||
package function.builtin;
|
|
||||||
|
|
||||||
import function.ArgumentValidator;
|
|
||||||
import function.FunctionNames;
|
|
||||||
import function.LispFunction;
|
|
||||||
import sexpression.Cons;
|
|
||||||
import sexpression.SExpression;
|
|
||||||
|
|
||||||
import static function.builtin.APPLY.apply;
|
|
||||||
import static function.builtin.cons.LIST.makeList;
|
|
||||||
|
|
||||||
@FunctionNames({ "FUNCALL", "CALL" })
|
|
||||||
public class FUNCALL extends LispFunction {
|
|
||||||
|
|
||||||
private ArgumentValidator argumentValidator;
|
|
||||||
|
|
||||||
public FUNCALL(String name) {
|
|
||||||
this.argumentValidator = new ArgumentValidator(name);
|
|
||||||
this.argumentValidator.setMinimumNumberOfArguments(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SExpression call(Cons argumentList) {
|
|
||||||
argumentValidator.validate(argumentList);
|
|
||||||
Cons applyArgs = new Cons(argumentList.getFirst(), makeList(argumentList.getRest()));
|
|
||||||
|
|
||||||
return apply(applyArgs);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
package function.builtin
|
||||||
|
|
||||||
|
import function.ArgumentValidator
|
||||||
|
import function.FunctionNames
|
||||||
|
import function.LispFunction
|
||||||
|
import function.builtin.Apply.Companion.apply
|
||||||
|
import function.builtin.cons.LIST.makeList
|
||||||
|
import sexpression.Cons
|
||||||
|
import sexpression.SExpression
|
||||||
|
|
||||||
|
@FunctionNames("FUNCALL", "CALL")
|
||||||
|
class Funcall(name: String) : LispFunction() {
|
||||||
|
|
||||||
|
private val argumentValidator: ArgumentValidator = ArgumentValidator(name).apply {
|
||||||
|
setMinimumNumberOfArguments(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun call(argumentList: Cons): SExpression {
|
||||||
|
argumentValidator.validate(argumentList)
|
||||||
|
val applyArgs = Cons(argumentList.first, makeList(argumentList.rest))
|
||||||
|
|
||||||
|
return apply(applyArgs)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,42 +0,0 @@
|
||||||
package function.builtin;
|
|
||||||
|
|
||||||
import function.ArgumentValidator;
|
|
||||||
import function.FunctionNames;
|
|
||||||
import function.LispFunction;
|
|
||||||
import sexpression.Cons;
|
|
||||||
import sexpression.SExpression;
|
|
||||||
import sexpression.Symbol;
|
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
|
|
||||||
@FunctionNames({ "GENSYM" })
|
|
||||||
public class GENSYM extends LispFunction {
|
|
||||||
|
|
||||||
public static final String GENSYM_PREFIX = "#G";
|
|
||||||
|
|
||||||
private static BigInteger counter = BigInteger.ZERO;
|
|
||||||
|
|
||||||
private static Symbol generateSymbol() {
|
|
||||||
incrementCounter();
|
|
||||||
|
|
||||||
return new Symbol(GENSYM_PREFIX + counter);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void incrementCounter() {
|
|
||||||
counter = counter.add(BigInteger.ONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ArgumentValidator argumentValidator;
|
|
||||||
|
|
||||||
public GENSYM(String name) {
|
|
||||||
this.argumentValidator = new ArgumentValidator(name);
|
|
||||||
this.argumentValidator.setMaximumNumberOfArguments(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SExpression call(Cons argumentList) {
|
|
||||||
argumentValidator.validate(argumentList);
|
|
||||||
|
|
||||||
return generateSymbol();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
package function.builtin
|
||||||
|
|
||||||
|
import function.ArgumentValidator
|
||||||
|
import function.FunctionNames
|
||||||
|
import function.LispFunction
|
||||||
|
import sexpression.Cons
|
||||||
|
import sexpression.SExpression
|
||||||
|
import sexpression.Symbol
|
||||||
|
import java.math.BigInteger.ONE
|
||||||
|
import java.math.BigInteger.ZERO
|
||||||
|
|
||||||
|
@FunctionNames("GENSYM")
|
||||||
|
class Gensym(name: String) : LispFunction() {
|
||||||
|
|
||||||
|
private val argumentValidator: ArgumentValidator = ArgumentValidator(name).apply {
|
||||||
|
setMaximumNumberOfArguments(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun call(argumentList: Cons): SExpression {
|
||||||
|
argumentValidator.validate(argumentList)
|
||||||
|
|
||||||
|
return generateSymbol()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
const val GENSYM_PREFIX = "#G"
|
||||||
|
|
||||||
|
private var counter = ZERO
|
||||||
|
|
||||||
|
private fun generateSymbol(): Symbol {
|
||||||
|
incrementCounter()
|
||||||
|
|
||||||
|
return Symbol(GENSYM_PREFIX + counter)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun incrementCounter() {
|
||||||
|
counter = counter.add(ONE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,28 +0,0 @@
|
||||||
package function.builtin;
|
|
||||||
|
|
||||||
import function.ArgumentValidator;
|
|
||||||
import function.FunctionNames;
|
|
||||||
import function.LispFunction;
|
|
||||||
import sexpression.Cons;
|
|
||||||
import sexpression.SExpression;
|
|
||||||
import table.ExecutionContext;
|
|
||||||
|
|
||||||
@FunctionNames({ "SYMBOLS" })
|
|
||||||
public class SYMBOLS extends LispFunction {
|
|
||||||
|
|
||||||
private ArgumentValidator argumentValidator;
|
|
||||||
private ExecutionContext executionContext;
|
|
||||||
|
|
||||||
public SYMBOLS(String name) {
|
|
||||||
this.argumentValidator = new ArgumentValidator(name);
|
|
||||||
this.argumentValidator.setExactNumberOfArguments(0);
|
|
||||||
this.executionContext = ExecutionContext.INSTANCE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SExpression call(Cons argumentList) {
|
|
||||||
argumentValidator.validate(argumentList);
|
|
||||||
|
|
||||||
return executionContext.toList();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
package function.builtin;
|
|
||||||
|
|
||||||
import error.LispException;
|
|
||||||
import function.ArgumentValidator;
|
|
||||||
import function.FunctionNames;
|
|
||||||
import function.LispFunction;
|
|
||||||
import function.LispSpecialFunction;
|
|
||||||
import function.UserDefinedFunction;
|
|
||||||
import sexpression.Cons;
|
|
||||||
import sexpression.SExpression;
|
|
||||||
import sexpression.Symbol;
|
|
||||||
import table.FunctionTable;
|
|
||||||
|
|
||||||
import static java.text.MessageFormat.format;
|
|
||||||
|
|
||||||
@FunctionNames({ "SYMBOL-FUNCTION" })
|
|
||||||
public class SYMBOL_FUNCTION extends LispFunction {
|
|
||||||
|
|
||||||
private ArgumentValidator argumentValidator;
|
|
||||||
|
|
||||||
public SYMBOL_FUNCTION(String name) {
|
|
||||||
this.argumentValidator = new ArgumentValidator(name);
|
|
||||||
this.argumentValidator.setExactNumberOfArguments(1);
|
|
||||||
this.argumentValidator.setEveryArgumentExpectedType(Symbol.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SExpression call(Cons argumentList) {
|
|
||||||
argumentValidator.validate(argumentList);
|
|
||||||
|
|
||||||
SExpression symbol = argumentList.getFirst();
|
|
||||||
LispFunction function = FunctionTable.INSTANCE.lookupFunction(symbol.toString());
|
|
||||||
|
|
||||||
if (function != null)
|
|
||||||
return createRepresentation(symbol, function);
|
|
||||||
|
|
||||||
throw new UndefinedSymbolFunctionException(symbol);
|
|
||||||
}
|
|
||||||
|
|
||||||
private SExpression createRepresentation(SExpression symbol, LispFunction function) {
|
|
||||||
if (function instanceof UserDefinedFunction)
|
|
||||||
return ((UserDefinedFunction) function).getLambdaExpression();
|
|
||||||
|
|
||||||
String typeIndicator = function instanceof LispSpecialFunction ? "SPECIAL-FUNCTION" : "FUNCTION";
|
|
||||||
|
|
||||||
return new Symbol(format("#<{0} {1}>", typeIndicator, symbol));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class UndefinedSymbolFunctionException extends LispException {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
private SExpression function;
|
|
||||||
|
|
||||||
public UndefinedSymbolFunctionException(SExpression function) {
|
|
||||||
this.function = function;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getMessage() {
|
|
||||||
return format("SYMBOL-FUNCTION: undefined function: {0}", function);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
package function.builtin
|
||||||
|
|
||||||
|
import error.LispException
|
||||||
|
import function.ArgumentValidator
|
||||||
|
import function.FunctionNames
|
||||||
|
import function.LispFunction
|
||||||
|
import function.LispSpecialFunction
|
||||||
|
import function.UserDefinedFunction
|
||||||
|
import sexpression.Cons
|
||||||
|
import sexpression.SExpression
|
||||||
|
import sexpression.Symbol
|
||||||
|
import table.FunctionTable
|
||||||
|
|
||||||
|
@FunctionNames("SYMBOL-FUNCTION")
|
||||||
|
class SymbolFunction(name: String) : LispFunction() {
|
||||||
|
|
||||||
|
private val argumentValidator: ArgumentValidator = ArgumentValidator(name).apply {
|
||||||
|
setExactNumberOfArguments(1)
|
||||||
|
setEveryArgumentExpectedType(Symbol::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun call(argumentList: Cons): SExpression {
|
||||||
|
argumentValidator.validate(argumentList)
|
||||||
|
|
||||||
|
val symbol = argumentList.first
|
||||||
|
val function = FunctionTable.lookupFunction(symbol.toString())
|
||||||
|
|
||||||
|
if (function != null)
|
||||||
|
return createRepresentation(symbol, function)
|
||||||
|
|
||||||
|
throw UndefinedSymbolFunctionException(symbol)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createRepresentation(symbol: SExpression, function: LispFunction): SExpression {
|
||||||
|
if (function is UserDefinedFunction)
|
||||||
|
return function.lambdaExpression
|
||||||
|
|
||||||
|
val typeIndicator = if (function is LispSpecialFunction) "SPECIAL-FUNCTION" else "FUNCTION"
|
||||||
|
|
||||||
|
return Symbol("#<$typeIndicator $symbol>")
|
||||||
|
}
|
||||||
|
|
||||||
|
class UndefinedSymbolFunctionException(function: SExpression) : LispException() {
|
||||||
|
|
||||||
|
override val message = "SYMBOL-FUNCTION: undefined function: $function"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package function.builtin
|
||||||
|
|
||||||
|
import function.ArgumentValidator
|
||||||
|
import function.FunctionNames
|
||||||
|
import function.LispFunction
|
||||||
|
import sexpression.Cons
|
||||||
|
import sexpression.SExpression
|
||||||
|
import table.ExecutionContext
|
||||||
|
|
||||||
|
@FunctionNames("SYMBOLS")
|
||||||
|
class Symbols(name: String) : LispFunction() {
|
||||||
|
|
||||||
|
private val argumentValidator: ArgumentValidator = ArgumentValidator(name).apply {
|
||||||
|
setExactNumberOfArguments(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun call(argumentList: Cons): SExpression {
|
||||||
|
argumentValidator.validate(argumentList)
|
||||||
|
|
||||||
|
return ExecutionContext.toList()
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,100 +0,0 @@
|
||||||
package function.builtin.predicate;
|
|
||||||
|
|
||||||
import function.ArgumentValidator;
|
|
||||||
import function.FunctionNames;
|
|
||||||
import function.LispFunction;
|
|
||||||
import sexpression.Cons;
|
|
||||||
import sexpression.Nil;
|
|
||||||
import sexpression.SExpression;
|
|
||||||
import sexpression.Symbol;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import static function.builtin.GENSYM.GENSYM_PREFIX;
|
|
||||||
|
|
||||||
@FunctionNames({ "GENSYM-EQUAL", "GENSYM-EQUAL?" })
|
|
||||||
public class GENSYM_EQUAL extends LispFunction {
|
|
||||||
|
|
||||||
private ArgumentValidator argumentValidator;
|
|
||||||
|
|
||||||
public GENSYM_EQUAL(String name) {
|
|
||||||
this.argumentValidator = new ArgumentValidator(name);
|
|
||||||
this.argumentValidator.setExactNumberOfArguments(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SExpression call(Cons argumentList) {
|
|
||||||
argumentValidator.validate(argumentList);
|
|
||||||
|
|
||||||
Cons rest = (Cons) argumentList.getRest();
|
|
||||||
SExpression firstArgument = argumentList.getFirst();
|
|
||||||
SExpression secondArgument = rest.getFirst();
|
|
||||||
|
|
||||||
return gensymEqual(firstArgument, secondArgument);
|
|
||||||
}
|
|
||||||
|
|
||||||
private SExpression gensymEqual(SExpression firstArgument, SExpression secondArgument) {
|
|
||||||
String firstEqualized = equalizeGensyms(firstArgument);
|
|
||||||
String secondEqualized = equalizeGensyms(secondArgument);
|
|
||||||
|
|
||||||
return firstEqualized.equals(secondEqualized) ? Symbol.Companion.getT() : Nil.INSTANCE;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String equalizeGensyms(SExpression expression) {
|
|
||||||
GensymEqualizer equalizer = new GensymEqualizer(expression.toString());
|
|
||||||
|
|
||||||
return equalizer.equalize();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class GensymEqualizer {
|
|
||||||
|
|
||||||
private static final String GENSYM_REGEX = Pattern.quote(GENSYM_PREFIX) + "[0-9]+";
|
|
||||||
|
|
||||||
Map<String, String> gensymAliases;
|
|
||||||
Matcher matcher;
|
|
||||||
String expression;
|
|
||||||
int counter;
|
|
||||||
|
|
||||||
public GensymEqualizer(String expression) {
|
|
||||||
this.gensymAliases = new HashMap<>();
|
|
||||||
this.matcher = Pattern.compile(GENSYM_REGEX).matcher(expression);
|
|
||||||
this.expression = expression;
|
|
||||||
this.counter = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String equalize() {
|
|
||||||
createGensymAliases();
|
|
||||||
|
|
||||||
return equalizeGensyms();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createGensymAliases() {
|
|
||||||
while (matcher.find())
|
|
||||||
createAliasForGensym();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createAliasForGensym() {
|
|
||||||
String gensym = matcher.group();
|
|
||||||
|
|
||||||
if (isNewGensym(gensym))
|
|
||||||
gensymAliases.put(gensym, GENSYM_PREFIX + (counter++));
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isNewGensym(String gensym) {
|
|
||||||
return !gensymAliases.containsKey(gensym);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String equalizeGensyms() {
|
|
||||||
String equalizedExpression = expression;
|
|
||||||
|
|
||||||
for (Entry<String, String> entry : gensymAliases.entrySet())
|
|
||||||
equalizedExpression = equalizedExpression.replace(entry.getKey(), entry.getValue());
|
|
||||||
|
|
||||||
return equalizedExpression;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
package function.builtin.predicate
|
||||||
|
|
||||||
|
import function.ArgumentValidator
|
||||||
|
import function.FunctionNames
|
||||||
|
import function.LispFunction
|
||||||
|
import function.builtin.Gensym.Companion.GENSYM_PREFIX
|
||||||
|
import sexpression.Cons
|
||||||
|
import sexpression.Nil
|
||||||
|
import sexpression.SExpression
|
||||||
|
import sexpression.Symbol
|
||||||
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
|
@FunctionNames("GENSYM-EQUAL", "GENSYM-EQUAL?")
|
||||||
|
class GensymEqual(name: String) : LispFunction() {
|
||||||
|
|
||||||
|
private val argumentValidator: ArgumentValidator = ArgumentValidator(name).apply {
|
||||||
|
setExactNumberOfArguments(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun call(argumentList: Cons): SExpression {
|
||||||
|
argumentValidator.validate(argumentList)
|
||||||
|
|
||||||
|
val rest = argumentList.rest as Cons
|
||||||
|
val firstArgument = argumentList.first
|
||||||
|
val secondArgument = rest.first
|
||||||
|
|
||||||
|
return gensymEqual(firstArgument, secondArgument)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun gensymEqual(firstArgument: SExpression, secondArgument: SExpression): SExpression {
|
||||||
|
val firstEqualized = equalizeGensyms(firstArgument)
|
||||||
|
val secondEqualized = equalizeGensyms(secondArgument)
|
||||||
|
|
||||||
|
return if (firstEqualized == secondEqualized) Symbol.T else Nil
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun equalizeGensyms(expression: SExpression) =
|
||||||
|
GensymEqualizer(expression.toString()).equalize()
|
||||||
|
|
||||||
|
private class GensymEqualizer(internal var expression: String) {
|
||||||
|
|
||||||
|
internal val gensymAliases = mutableMapOf<String, String>()
|
||||||
|
internal var matcher = Pattern.compile(GENSYM_REGEX).matcher(expression)
|
||||||
|
internal var counter: Int = 0
|
||||||
|
|
||||||
|
fun equalize(): String {
|
||||||
|
createGensymAliases()
|
||||||
|
|
||||||
|
return equalizeGensyms()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createGensymAliases() {
|
||||||
|
while (matcher.find())
|
||||||
|
createAliasForGensym()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createAliasForGensym() {
|
||||||
|
val gensym = matcher.group()
|
||||||
|
|
||||||
|
if (isNewGensym(gensym))
|
||||||
|
gensymAliases[gensym] = GENSYM_PREFIX + counter++
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isNewGensym(gensym: String): Boolean {
|
||||||
|
return !gensymAliases.containsKey(gensym)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun equalizeGensyms(): String {
|
||||||
|
var equalizedExpression = expression
|
||||||
|
|
||||||
|
for ((key, value) in gensymAliases)
|
||||||
|
equalizedExpression = equalizedExpression.replace(key, value)
|
||||||
|
|
||||||
|
return equalizedExpression
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private val GENSYM_REGEX = Pattern.quote(GENSYM_PREFIX) + "[0-9]+"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,78 +0,0 @@
|
||||||
package function.builtin;
|
|
||||||
|
|
||||||
import function.ArgumentValidator.BadArgumentTypeException;
|
|
||||||
import function.ArgumentValidator.DottedArgumentListException;
|
|
||||||
import function.ArgumentValidator.TooFewArgumentsException;
|
|
||||||
import function.ArgumentValidator.TooManyArgumentsException;
|
|
||||||
import function.builtin.Eval.UndefinedFunctionException;
|
|
||||||
import org.junit.Test;
|
|
||||||
import sexpression.Cons;
|
|
||||||
import testutil.SymbolAndFunctionCleaner;
|
|
||||||
|
|
||||||
import static function.builtin.APPLY.apply;
|
|
||||||
import static testutil.TestUtilities.assertSExpressionsMatch;
|
|
||||||
import static testutil.TestUtilities.evaluateString;
|
|
||||||
import static testutil.TestUtilities.parseString;
|
|
||||||
|
|
||||||
public class APPLYTest extends SymbolAndFunctionCleaner {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void applyWithSymbol() {
|
|
||||||
String input = "(apply '+ '(1 2 3))";
|
|
||||||
|
|
||||||
assertSExpressionsMatch(parseString("6"), evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void applyWithLambdaExpression() {
|
|
||||||
String input = "(apply (lambda (x) (+ x 1)) '(25))";
|
|
||||||
|
|
||||||
assertSExpressionsMatch(parseString("26"), evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void applyWithQuotedLambdaExpression() {
|
|
||||||
String input = "(apply '(lambda (x) (+ x 1)) '(25))";
|
|
||||||
|
|
||||||
assertSExpressionsMatch(parseString("26"), evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void staticApplyCall() {
|
|
||||||
String argumentList = "(+ (25 10))";
|
|
||||||
Cons parsedArgumentList = (Cons) parseString(argumentList);
|
|
||||||
|
|
||||||
assertSExpressionsMatch(parseString("35"), apply(parsedArgumentList));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = UndefinedFunctionException.class)
|
|
||||||
public void applyWithUndefinedFunction() {
|
|
||||||
evaluateString("(apply 'f '(1 2 3))");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = BadArgumentTypeException.class)
|
|
||||||
public void applyWithNonListSecondArgument() {
|
|
||||||
evaluateString("(apply '+ '2)");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = TooManyArgumentsException.class)
|
|
||||||
public void applyWithTooManyArguments() {
|
|
||||||
evaluateString("(apply '1 '2 '3)");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = TooFewArgumentsException.class)
|
|
||||||
public void applyWithTooFewArguments() {
|
|
||||||
evaluateString("(apply '1)");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = DottedArgumentListException.class)
|
|
||||||
public void applyWithDottedArgumentList_ThrowsException() {
|
|
||||||
evaluateString("(apply 'apply (cons 'T 'T))");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void applyWithMacro() {
|
|
||||||
evaluateString("(defmacro m (x) `(+ 2 ,x))");
|
|
||||||
assertSExpressionsMatch(parseString("27"), evaluateString("(apply 'm '(25))"));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
package function.builtin
|
||||||
|
|
||||||
|
import function.ArgumentValidator.BadArgumentTypeException
|
||||||
|
import function.ArgumentValidator.DottedArgumentListException
|
||||||
|
import function.ArgumentValidator.TooFewArgumentsException
|
||||||
|
import function.ArgumentValidator.TooManyArgumentsException
|
||||||
|
import function.builtin.Apply.Companion.apply
|
||||||
|
import function.builtin.Eval.UndefinedFunctionException
|
||||||
|
import org.junit.jupiter.api.Assertions.assertThrows
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import sexpression.Cons
|
||||||
|
import testutil.LispTestInstance
|
||||||
|
import testutil.SymbolAndFunctionCleaner
|
||||||
|
import testutil.TestUtilities.assertSExpressionsMatch
|
||||||
|
import testutil.TestUtilities.evaluateString
|
||||||
|
import testutil.TestUtilities.parseString
|
||||||
|
|
||||||
|
@LispTestInstance
|
||||||
|
class ApplyTest : SymbolAndFunctionCleaner() {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun applyWithSymbol() {
|
||||||
|
val input = "(apply '+ '(1 2 3))"
|
||||||
|
|
||||||
|
assertSExpressionsMatch(parseString("6"), evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun applyWithLambdaExpression() {
|
||||||
|
val input = "(apply (lambda (x) (+ x 1)) '(25))"
|
||||||
|
|
||||||
|
assertSExpressionsMatch(parseString("26"), evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun applyWithQuotedLambdaExpression() {
|
||||||
|
val input = "(apply '(lambda (x) (+ x 1)) '(25))"
|
||||||
|
|
||||||
|
assertSExpressionsMatch(parseString("26"), evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun staticApplyCall() {
|
||||||
|
val argumentList = "(+ (25 10))"
|
||||||
|
val parsedArgumentList = parseString(argumentList) as Cons
|
||||||
|
|
||||||
|
assertSExpressionsMatch(parseString("35"), apply(parsedArgumentList))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun applyWithUndefinedFunction() {
|
||||||
|
assertThrows(UndefinedFunctionException::class.java) {
|
||||||
|
evaluateString("(apply 'f '(1 2 3))")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun applyWithNonListSecondArgument() {
|
||||||
|
assertThrows(BadArgumentTypeException::class.java) {
|
||||||
|
evaluateString("(apply '+ '2)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun applyWithTooManyArguments() {
|
||||||
|
assertThrows(TooManyArgumentsException::class.java) {
|
||||||
|
evaluateString("(apply '1 '2 '3)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun applyWithTooFewArguments() {
|
||||||
|
assertThrows(TooFewArgumentsException::class.java) {
|
||||||
|
evaluateString("(apply '1)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun applyWithDottedArgumentList_ThrowsException() {
|
||||||
|
assertThrows(DottedArgumentListException::class.java) {
|
||||||
|
evaluateString("(apply 'apply (cons 'T 'T))")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun applyWithMacro() {
|
||||||
|
evaluateString("(defmacro m (x) `(+ 2 ,x))")
|
||||||
|
assertSExpressionsMatch(parseString("27"), evaluateString("(apply 'm '(25))"))
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,40 +0,0 @@
|
||||||
package function.builtin;
|
|
||||||
|
|
||||||
import function.ArgumentValidator.TooFewArgumentsException;
|
|
||||||
import org.junit.Test;
|
|
||||||
import testutil.SymbolAndFunctionCleaner;
|
|
||||||
|
|
||||||
import static testutil.TestUtilities.assertSExpressionsMatch;
|
|
||||||
import static testutil.TestUtilities.evaluateString;
|
|
||||||
import static testutil.TestUtilities.parseString;
|
|
||||||
|
|
||||||
public class FUNCALLTest extends SymbolAndFunctionCleaner {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void funcallWithNumbers() {
|
|
||||||
String input = "(funcall '+ 1 2 3)";
|
|
||||||
|
|
||||||
assertSExpressionsMatch(parseString("6"), evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void callWithNumbers() {
|
|
||||||
String input = "(call '+ 1 2 3)";
|
|
||||||
|
|
||||||
assertSExpressionsMatch(parseString("6"), evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void funcallWithUserDefinedFunction() {
|
|
||||||
String defineUserFunction = "(defun x (n m) (+ n m))";
|
|
||||||
String input = "(funcall 'x 2 30)";
|
|
||||||
|
|
||||||
evaluateString(defineUserFunction);
|
|
||||||
assertSExpressionsMatch(parseString("32"), evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = TooFewArgumentsException.class)
|
|
||||||
public void funcallWithTooFewArguments() {
|
|
||||||
evaluateString("(funcall)");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
package function.builtin
|
||||||
|
|
||||||
|
import function.ArgumentValidator.TooFewArgumentsException
|
||||||
|
import org.junit.jupiter.api.Assertions.assertThrows
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import testutil.LispTestInstance
|
||||||
|
import testutil.SymbolAndFunctionCleaner
|
||||||
|
import testutil.TestUtilities.assertSExpressionsMatch
|
||||||
|
import testutil.TestUtilities.evaluateString
|
||||||
|
import testutil.TestUtilities.parseString
|
||||||
|
|
||||||
|
@LispTestInstance
|
||||||
|
class FuncallTest : SymbolAndFunctionCleaner() {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun funcallWithNumbers() {
|
||||||
|
val input = "(funcall '+ 1 2 3)"
|
||||||
|
|
||||||
|
assertSExpressionsMatch(parseString("6"), evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun callWithNumbers() {
|
||||||
|
val input = "(call '+ 1 2 3)"
|
||||||
|
|
||||||
|
assertSExpressionsMatch(parseString("6"), evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun funcallWithUserDefinedFunction() {
|
||||||
|
val defineUserFunction = "(defun x (n m) (+ n m))"
|
||||||
|
val input = "(funcall 'x 2 30)"
|
||||||
|
|
||||||
|
evaluateString(defineUserFunction)
|
||||||
|
assertSExpressionsMatch(parseString("32"), evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun funcallWithTooFewArguments() {
|
||||||
|
assertThrows(TooFewArgumentsException::class.java) {
|
||||||
|
evaluateString("(funcall)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,42 +0,0 @@
|
||||||
package function.builtin;
|
|
||||||
|
|
||||||
import function.ArgumentValidator.TooManyArgumentsException;
|
|
||||||
import org.junit.Test;
|
|
||||||
import testutil.SymbolAndFunctionCleaner;
|
|
||||||
import token.TokenFactory.BadCharacterException;
|
|
||||||
|
|
||||||
import static function.builtin.GENSYM.GENSYM_PREFIX;
|
|
||||||
import static testutil.TestUtilities.assertSExpressionsDoNotMatch;
|
|
||||||
import static testutil.TestUtilities.assertSExpressionsMatch;
|
|
||||||
import static testutil.TestUtilities.evaluateString;
|
|
||||||
import static testutil.TypeAssertions.assertSymbol;
|
|
||||||
|
|
||||||
public class GENSYMTest extends SymbolAndFunctionCleaner {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void gensymCreatesSymbol() {
|
|
||||||
assertSymbol(evaluateString("(gensym)"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void gensymCreatesUniqueSymbol() {
|
|
||||||
assertSExpressionsDoNotMatch(evaluateString("(gensym)"), evaluateString("(gensym)"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void simpleGensymUsage() {
|
|
||||||
String input = "(let ((x (gensym))) (set x 23) (eval x))";
|
|
||||||
assertSExpressionsMatch(evaluateString("23"), evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = BadCharacterException.class)
|
|
||||||
public void cannotUseGensymValueManually() {
|
|
||||||
String variableName = GENSYM_PREFIX + 1;
|
|
||||||
evaluateString("(setq " + variableName + " 100)");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = TooManyArgumentsException.class)
|
|
||||||
public void gensymWithTooManyArguments() {
|
|
||||||
evaluateString("(gensym 1)");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
package function.builtin
|
||||||
|
|
||||||
|
import function.ArgumentValidator.TooManyArgumentsException
|
||||||
|
import function.builtin.Gensym.Companion.GENSYM_PREFIX
|
||||||
|
import org.junit.jupiter.api.Assertions.assertThrows
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import testutil.SymbolAndFunctionCleaner
|
||||||
|
import testutil.TestUtilities.assertSExpressionsDoNotMatch
|
||||||
|
import testutil.TestUtilities.assertSExpressionsMatch
|
||||||
|
import testutil.TestUtilities.evaluateString
|
||||||
|
import testutil.TypeAssertions.assertSymbol
|
||||||
|
import token.TokenFactory.BadCharacterException
|
||||||
|
|
||||||
|
class GensymTest : SymbolAndFunctionCleaner() {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun gensymCreatesSymbol() {
|
||||||
|
assertSymbol(evaluateString("(gensym)"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun gensymCreatesUniqueSymbol() {
|
||||||
|
assertSExpressionsDoNotMatch(evaluateString("(gensym)"), evaluateString("(gensym)"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun simpleGensymUsage() {
|
||||||
|
val input = "(let ((x (gensym))) (set x 23) (eval x))"
|
||||||
|
assertSExpressionsMatch(evaluateString("23"), evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun cannotUseGensymValueManually() {
|
||||||
|
val variableName = GENSYM_PREFIX + 1
|
||||||
|
|
||||||
|
assertThrows(BadCharacterException::class.java) {
|
||||||
|
evaluateString("(setq $variableName 100)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun gensymWithTooManyArguments() {
|
||||||
|
assertThrows(TooManyArgumentsException::class.java) {
|
||||||
|
evaluateString("(gensym 1)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,56 +0,0 @@
|
||||||
package function.builtin;
|
|
||||||
|
|
||||||
import function.ArgumentValidator.TooManyArgumentsException;
|
|
||||||
import org.junit.Test;
|
|
||||||
import testutil.SymbolAndFunctionCleaner;
|
|
||||||
|
|
||||||
import static testutil.TestUtilities.assertSExpressionsMatch;
|
|
||||||
import static testutil.TestUtilities.evaluateString;
|
|
||||||
|
|
||||||
public class SYMBOLSTest extends SymbolAndFunctionCleaner {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void noSymbols() {
|
|
||||||
assertSExpressionsMatch(evaluateString("'(nil)"), evaluateString("(symbols)"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void globalSymbol() {
|
|
||||||
evaluateString("(setq x 10)");
|
|
||||||
assertSExpressionsMatch(evaluateString("'(((x 10)))"), evaluateString("(symbols)"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void multipleSymbolsSorted() {
|
|
||||||
evaluateString("(setq x 10)");
|
|
||||||
evaluateString("(setq a 20)");
|
|
||||||
evaluateString("(setq y 30)");
|
|
||||||
evaluateString("(setq w 40)");
|
|
||||||
evaluateString("(setq e 50)");
|
|
||||||
|
|
||||||
assertSExpressionsMatch(evaluateString("'(((a 20) (e 50) (w 40) (x 10) (y 30)))"), evaluateString("(symbols)"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void fullExecutionContext() {
|
|
||||||
evaluateString("(setq x 10)");
|
|
||||||
evaluateString("(setq y 30)");
|
|
||||||
|
|
||||||
assertSExpressionsMatch(evaluateString("'(((x 10) (y 30)) ((a 100) (q 99) (z nil)))"),
|
|
||||||
evaluateString("(let ((q 99) (a 100) (z)) (symbols))"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void updateSymbolInLet() {
|
|
||||||
evaluateString("(setq x 10)");
|
|
||||||
evaluateString("(setq y 30)");
|
|
||||||
|
|
||||||
assertSExpressionsMatch(evaluateString("'(((x 10) (y 30)) ((q 99) (x 1) (z 2)))"),
|
|
||||||
evaluateString("(let ((q 99) (x 100) (z 2)) (setq x 1) (symbols))"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = TooManyArgumentsException.class)
|
|
||||||
public void symbolsWithTooManyArguments() {
|
|
||||||
evaluateString("(symbols 1)");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,72 +0,0 @@
|
||||||
package function.builtin;
|
|
||||||
|
|
||||||
import function.ArgumentValidator.BadArgumentTypeException;
|
|
||||||
import function.ArgumentValidator.TooFewArgumentsException;
|
|
||||||
import function.ArgumentValidator.TooManyArgumentsException;
|
|
||||||
import function.builtin.SYMBOL_FUNCTION.UndefinedSymbolFunctionException;
|
|
||||||
import org.junit.Test;
|
|
||||||
import sexpression.Nil;
|
|
||||||
import testutil.SymbolAndFunctionCleaner;
|
|
||||||
|
|
||||||
import static error.Severity.ERROR;
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
import static testutil.TestUtilities.evaluateString;
|
|
||||||
|
|
||||||
public class SYMBOL_FUNCTIONTest extends SymbolAndFunctionCleaner {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void symbolFunction_BuiltInFunction() {
|
|
||||||
String input = "(symbol-function '+)";
|
|
||||||
|
|
||||||
assertEquals("#<FUNCTION +>", evaluateString(input).toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void symbolFunction_BuiltInSpecialFunction() {
|
|
||||||
String input = "(symbol-function 'if)";
|
|
||||||
|
|
||||||
assertEquals("#<SPECIAL-FUNCTION IF>", evaluateString(input).toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void symbolFunction_UserDefinedFunction() {
|
|
||||||
String defineUserFunction = "(defun y (n m) (+ n m))";
|
|
||||||
String input = "(symbol-function 'y)";
|
|
||||||
|
|
||||||
evaluateString(defineUserFunction);
|
|
||||||
assertEquals("(Y (N M) (+ N M))", evaluateString(input).toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = UndefinedSymbolFunctionException.class)
|
|
||||||
public void symbolFunction_NonFunction() {
|
|
||||||
String input = "(symbol-function 'a)";
|
|
||||||
|
|
||||||
evaluateString(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = BadArgumentTypeException.class)
|
|
||||||
public void symbolFunctionWithBadArgumentType() {
|
|
||||||
evaluateString("(symbol-function 2)");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = TooManyArgumentsException.class)
|
|
||||||
public void symbolFunctionWithTooManyArguments() {
|
|
||||||
evaluateString("(symbol-function 'a 'b)");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = TooFewArgumentsException.class)
|
|
||||||
public void symbolFunctionWithTooFewArguments() {
|
|
||||||
evaluateString("(symbol-function)");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void undefinedSymbolFunctionException_HasCorrectAttributes() {
|
|
||||||
UndefinedSymbolFunctionException e = new UndefinedSymbolFunctionException(Nil.INSTANCE);
|
|
||||||
|
|
||||||
assertEquals(ERROR, e.getSeverity());
|
|
||||||
assertNotNull(e.getMessage());
|
|
||||||
assertTrue(e.getMessage().length() > 0);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
package function.builtin
|
||||||
|
|
||||||
|
import function.ArgumentValidator.BadArgumentTypeException
|
||||||
|
import function.ArgumentValidator.TooFewArgumentsException
|
||||||
|
import function.ArgumentValidator.TooManyArgumentsException
|
||||||
|
import function.builtin.SymbolFunction.UndefinedSymbolFunctionException
|
||||||
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
|
import org.junit.jupiter.api.Assertions.assertThrows
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import sexpression.Nil
|
||||||
|
import testutil.LispTestInstance
|
||||||
|
import testutil.SymbolAndFunctionCleaner
|
||||||
|
import testutil.TestUtilities.assertIsErrorWithMessage
|
||||||
|
import testutil.TestUtilities.evaluateString
|
||||||
|
|
||||||
|
@LispTestInstance
|
||||||
|
class SymbolFunctionTest : SymbolAndFunctionCleaner() {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun symbolFunction_BuiltInFunction() {
|
||||||
|
val input = "(symbol-function '+)"
|
||||||
|
|
||||||
|
assertThat(evaluateString(input).toString()).isEqualTo("#<FUNCTION +>")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun symbolFunction_BuiltInSpecialFunction() {
|
||||||
|
val input = "(symbol-function 'if)"
|
||||||
|
|
||||||
|
assertThat(evaluateString(input).toString()).isEqualTo("#<SPECIAL-FUNCTION IF>")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun symbolFunction_UserDefinedFunction() {
|
||||||
|
val defineUserFunction = "(defun y (n m) (+ n m))"
|
||||||
|
val input = "(symbol-function 'y)"
|
||||||
|
|
||||||
|
evaluateString(defineUserFunction)
|
||||||
|
assertThat(evaluateString(input).toString()).isEqualTo("(Y (N M) (+ N M))")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun symbolFunction_NonFunction() {
|
||||||
|
val input = "(symbol-function 'a)"
|
||||||
|
|
||||||
|
assertThrows(UndefinedSymbolFunctionException::class.java) {
|
||||||
|
evaluateString(input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun symbolFunctionWithBadArgumentType() {
|
||||||
|
assertThrows(BadArgumentTypeException::class.java) {
|
||||||
|
evaluateString("(symbol-function 2)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun symbolFunctionWithTooManyArguments() {
|
||||||
|
assertThrows(TooManyArgumentsException::class.java) {
|
||||||
|
evaluateString("(symbol-function 'a 'b)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun symbolFunctionWithTooFewArguments() {
|
||||||
|
assertThrows(TooFewArgumentsException::class.java) {
|
||||||
|
evaluateString("(symbol-function)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun undefinedSymbolFunctionException_HasCorrectAttributes() {
|
||||||
|
assertIsErrorWithMessage(UndefinedSymbolFunctionException(Nil))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
package function.builtin
|
||||||
|
|
||||||
|
import function.ArgumentValidator.TooManyArgumentsException
|
||||||
|
import org.junit.jupiter.api.Assertions.assertThrows
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import testutil.LispTestInstance
|
||||||
|
import testutil.SymbolAndFunctionCleaner
|
||||||
|
import testutil.TestUtilities.assertSExpressionsMatch
|
||||||
|
import testutil.TestUtilities.evaluateString
|
||||||
|
|
||||||
|
@LispTestInstance
|
||||||
|
class SymbolsTest : SymbolAndFunctionCleaner() {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun noSymbols() {
|
||||||
|
assertSExpressionsMatch(evaluateString("'(nil)"), evaluateString("(symbols)"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun globalSymbol() {
|
||||||
|
evaluateString("(setq x 10)")
|
||||||
|
assertSExpressionsMatch(evaluateString("'(((x 10)))"), evaluateString("(symbols)"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun multipleSymbolsSorted() {
|
||||||
|
evaluateString("(setq x 10)")
|
||||||
|
evaluateString("(setq a 20)")
|
||||||
|
evaluateString("(setq y 30)")
|
||||||
|
evaluateString("(setq w 40)")
|
||||||
|
evaluateString("(setq e 50)")
|
||||||
|
|
||||||
|
assertSExpressionsMatch(evaluateString("'(((a 20) (e 50) (w 40) (x 10) (y 30)))"), evaluateString("(symbols)"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun fullExecutionContext() {
|
||||||
|
evaluateString("(setq x 10)")
|
||||||
|
evaluateString("(setq y 30)")
|
||||||
|
|
||||||
|
assertSExpressionsMatch(evaluateString("'(((x 10) (y 30)) ((a 100) (q 99) (z nil)))"),
|
||||||
|
evaluateString("(let ((q 99) (a 100) (z)) (symbols))"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun updateSymbolInLet() {
|
||||||
|
evaluateString("(setq x 10)")
|
||||||
|
evaluateString("(setq y 30)")
|
||||||
|
|
||||||
|
assertSExpressionsMatch(evaluateString("'(((x 10) (y 30)) ((q 99) (x 1) (z 2)))"),
|
||||||
|
evaluateString("(let ((q 99) (x 100) (z 2)) (setq x 1) (symbols))"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun symbolsWithTooManyArguments() {
|
||||||
|
assertThrows(TooManyArgumentsException::class.java) {
|
||||||
|
evaluateString("(symbols 1)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,160 +0,0 @@
|
||||||
package function.builtin.predicate;
|
|
||||||
|
|
||||||
import function.ArgumentValidator.TooFewArgumentsException;
|
|
||||||
import function.ArgumentValidator.TooManyArgumentsException;
|
|
||||||
import org.junit.Test;
|
|
||||||
import testutil.SymbolAndFunctionCleaner;
|
|
||||||
|
|
||||||
import static testutil.TestUtilities.evaluateString;
|
|
||||||
import static testutil.TypeAssertions.assertNil;
|
|
||||||
import static testutil.TypeAssertions.assertT;
|
|
||||||
|
|
||||||
public class GENSYM_EQUALTest extends SymbolAndFunctionCleaner {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void gensymEqualWithTwoEqualAtoms() {
|
|
||||||
String input = "(gensym-equal 'a 'a)";
|
|
||||||
|
|
||||||
assertT(evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void gensymEqualWithTwoEqualAtomsAndAlias() {
|
|
||||||
String input = "(gensym-equal? 'a 'a)";
|
|
||||||
|
|
||||||
assertT(evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void gensymEqualWithTwoUnequalAtoms() {
|
|
||||||
String input = "(gensym-equal 'a 'b)";
|
|
||||||
|
|
||||||
assertNil(evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void gensymEqualWithTwoEqualNumbers() {
|
|
||||||
String input = "(gensym-equal -4 -4)";
|
|
||||||
|
|
||||||
assertT(evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void gensymEqualWithTwoUnequalNumbers() {
|
|
||||||
String input = "(gensym-equal +5 +7)";
|
|
||||||
|
|
||||||
assertNil(evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void gensymEqualWithTwoEqualStrings() {
|
|
||||||
String input = "(gensym-equal \"potato\" \"potato\")";
|
|
||||||
|
|
||||||
assertT(evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void gensymEqualWithTwoUnequalStrings() {
|
|
||||||
String input = "(gensym-equal \"tomato\" \"potato\")";
|
|
||||||
|
|
||||||
assertNil(evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void gensymEqualWithTwoDifferentCasedStrings() {
|
|
||||||
String input = "(gensym-equal \"Potato\" \"potato\")";
|
|
||||||
|
|
||||||
assertNil(evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void gensymEqualWithAtomAndList() {
|
|
||||||
String input = "(gensym-equal \"string\" '(m i k e))";
|
|
||||||
|
|
||||||
assertNil(evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void gensymEqualWithListAndAtom() {
|
|
||||||
String input = "(gensym-equal '(m i k e) \"string\")";
|
|
||||||
|
|
||||||
assertNil(evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void gensymEqualWithTwoEqualLists() {
|
|
||||||
String input = "(gensym-equal '(1 2 3) '(1 2 3))";
|
|
||||||
|
|
||||||
assertT(evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void gensymEqualWithTwoUnequalLists() {
|
|
||||||
String input = "(gensym-equal '(1 2 3) '(1 3 3))";
|
|
||||||
|
|
||||||
assertNil(evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void gensymEqualWithTwoEqualNestedLists() {
|
|
||||||
String input = "(gensym-equal '(1 ((2) 3)) '(1 ((2) 3)))";
|
|
||||||
|
|
||||||
assertT(evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = TooManyArgumentsException.class)
|
|
||||||
public void gensymEqualWithTooManyArguments() {
|
|
||||||
evaluateString("(gensym-equal 1 2 3)");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = TooFewArgumentsException.class)
|
|
||||||
public void gensymEqualWithTooFewArguments() {
|
|
||||||
evaluateString("(gensym-equal 1)");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void gensymEqualWithGensyms() {
|
|
||||||
String input = "(gensym-equal (gensym) (gensym))";
|
|
||||||
|
|
||||||
assertT(evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void gensymEqualWithNestedGensyms() {
|
|
||||||
String input = "(gensym-equal `(1 ,(gensym) (2 ,(gensym))) `(1 ,(gensym) (2 ,(gensym))))";
|
|
||||||
|
|
||||||
assertT(evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void gensymEqualWithUnmatchedGensymPositions() {
|
|
||||||
String input = "(gensym-equal (let ((one (gensym))) `(,one ,one))"
|
|
||||||
+ " (let ((one (gensym)) (two (gensym))) `(,one ,two)))";
|
|
||||||
|
|
||||||
assertNil(evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void gensymEqualWithMatchedGensymPositions() {
|
|
||||||
String input = "(gensym-equal (let ((one (gensym))) `(,one ,one))"
|
|
||||||
+ " (let ((one (gensym)) (two (gensym))) `(,one ,one)))";
|
|
||||||
|
|
||||||
assertT(evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void gensymEqualWithComplexMatchedGensymPositions() {
|
|
||||||
String input = "(gensym-equal (let ((x (gensym)) (y (gensym)) (z (gensym))) `(,x (,y ,z)))"
|
|
||||||
+ " (let ((a (gensym)) (b (gensym)) (c (gensym))) `(,c (,a ,b))))";
|
|
||||||
|
|
||||||
assertT(evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void gensymEqualWithComplexUnmatchedGensymPositions() {
|
|
||||||
String input = "(gensym-equal (let ((x (gensym)) (y (gensym)) (z (gensym))) `(,x , y (,z ,z)))"
|
|
||||||
+ " (let ((a (gensym)) (b (gensym)) (c (gensym))) `(,a ,c (,b ,c))))";
|
|
||||||
|
|
||||||
assertNil(evaluateString(input));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,166 @@
|
||||||
|
package function.builtin.predicate
|
||||||
|
|
||||||
|
import function.ArgumentValidator.TooFewArgumentsException
|
||||||
|
import function.ArgumentValidator.TooManyArgumentsException
|
||||||
|
import org.junit.jupiter.api.Assertions.assertThrows
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import testutil.LispTestInstance
|
||||||
|
import testutil.SymbolAndFunctionCleaner
|
||||||
|
import testutil.TestUtilities.evaluateString
|
||||||
|
import testutil.TypeAssertions.assertNil
|
||||||
|
import testutil.TypeAssertions.assertT
|
||||||
|
|
||||||
|
@LispTestInstance
|
||||||
|
class GensymEqualTest : SymbolAndFunctionCleaner() {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun gensymEqualWithTwoEqualAtoms() {
|
||||||
|
val input = "(gensym-equal 'a 'a)"
|
||||||
|
|
||||||
|
assertT(evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun gensymEqualWithTwoEqualAtomsAndAlias() {
|
||||||
|
val input = "(gensym-equal? 'a 'a)"
|
||||||
|
|
||||||
|
assertT(evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun gensymEqualWithTwoUnequalAtoms() {
|
||||||
|
val input = "(gensym-equal 'a 'b)"
|
||||||
|
|
||||||
|
assertNil(evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun gensymEqualWithTwoEqualNumbers() {
|
||||||
|
val input = "(gensym-equal -4 -4)"
|
||||||
|
|
||||||
|
assertT(evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun gensymEqualWithTwoUnequalNumbers() {
|
||||||
|
val input = "(gensym-equal +5 +7)"
|
||||||
|
|
||||||
|
assertNil(evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun gensymEqualWithTwoEqualStrings() {
|
||||||
|
val input = "(gensym-equal \"potato\" \"potato\")"
|
||||||
|
|
||||||
|
assertT(evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun gensymEqualWithTwoUnequalStrings() {
|
||||||
|
val input = "(gensym-equal \"tomato\" \"potato\")"
|
||||||
|
|
||||||
|
assertNil(evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun gensymEqualWithTwoDifferentCasedStrings() {
|
||||||
|
val input = "(gensym-equal \"Potato\" \"potato\")"
|
||||||
|
|
||||||
|
assertNil(evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun gensymEqualWithAtomAndList() {
|
||||||
|
val input = "(gensym-equal \"string\" '(m i k e))"
|
||||||
|
|
||||||
|
assertNil(evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun gensymEqualWithListAndAtom() {
|
||||||
|
val input = "(gensym-equal '(m i k e) \"string\")"
|
||||||
|
|
||||||
|
assertNil(evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun gensymEqualWithTwoEqualLists() {
|
||||||
|
val input = "(gensym-equal '(1 2 3) '(1 2 3))"
|
||||||
|
|
||||||
|
assertT(evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun gensymEqualWithTwoUnequalLists() {
|
||||||
|
val input = "(gensym-equal '(1 2 3) '(1 3 3))"
|
||||||
|
|
||||||
|
assertNil(evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun gensymEqualWithTwoEqualNestedLists() {
|
||||||
|
val input = "(gensym-equal '(1 ((2) 3)) '(1 ((2) 3)))"
|
||||||
|
|
||||||
|
assertT(evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun gensymEqualWithTooManyArguments() {
|
||||||
|
assertThrows(TooManyArgumentsException::class.java) {
|
||||||
|
evaluateString("(gensym-equal 1 2 3)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun gensymEqualWithTooFewArguments() {
|
||||||
|
assertThrows(TooFewArgumentsException::class.java) {
|
||||||
|
evaluateString("(gensym-equal 1)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun gensymEqualWithGensyms() {
|
||||||
|
val input = "(gensym-equal (gensym) (gensym))"
|
||||||
|
|
||||||
|
assertT(evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun gensymEqualWithNestedGensyms() {
|
||||||
|
val input = "(gensym-equal `(1 ,(gensym) (2 ,(gensym))) `(1 ,(gensym) (2 ,(gensym))))"
|
||||||
|
|
||||||
|
assertT(evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun gensymEqualWithUnmatchedGensymPositions() {
|
||||||
|
val input = "(gensym-equal (let ((one (gensym))) `(,one ,one))" +
|
||||||
|
" (let ((one (gensym)) (two (gensym))) `(,one ,two)))"
|
||||||
|
|
||||||
|
assertNil(evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun gensymEqualWithMatchedGensymPositions() {
|
||||||
|
val input = "(gensym-equal (let ((one (gensym))) `(,one ,one))" +
|
||||||
|
" (let ((one (gensym)) (two (gensym))) `(,one ,one)))"
|
||||||
|
|
||||||
|
assertT(evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun gensymEqualWithComplexMatchedGensymPositions() {
|
||||||
|
val input = "(gensym-equal (let ((x (gensym)) (y (gensym)) (z (gensym))) `(,x (,y ,z)))" +
|
||||||
|
" (let ((a (gensym)) (b (gensym)) (c (gensym))) `(,c (,a ,b))))"
|
||||||
|
|
||||||
|
assertT(evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun gensymEqualWithComplexUnmatchedGensymPositions() {
|
||||||
|
val input = "(gensym-equal (let ((x (gensym)) (y (gensym)) (z (gensym))) `(,x , y (,z ,z)))" +
|
||||||
|
" (let ((a (gensym)) (b (gensym)) (c (gensym))) `(,a ,c (,b ,c))))"
|
||||||
|
|
||||||
|
assertNil(evaluateString(input))
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue