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