diff --git a/src/main/kotlin/function/builtin/APPLY.java b/src/main/kotlin/function/builtin/APPLY.java deleted file mode 100644 index c2b35a8..0000000 --- a/src/main/kotlin/function/builtin/APPLY.java +++ /dev/null @@ -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); - } -} diff --git a/src/main/kotlin/function/builtin/Apply.kt b/src/main/kotlin/function/builtin/Apply.kt new file mode 100644 index 0000000..afe7766 --- /dev/null +++ b/src/main/kotlin/function/builtin/Apply.kt @@ -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) + } + } +} diff --git a/src/main/kotlin/function/builtin/FUNCALL.java b/src/main/kotlin/function/builtin/FUNCALL.java deleted file mode 100644 index c21194a..0000000 --- a/src/main/kotlin/function/builtin/FUNCALL.java +++ /dev/null @@ -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); - } -} diff --git a/src/main/kotlin/function/builtin/Funcall.kt b/src/main/kotlin/function/builtin/Funcall.kt new file mode 100644 index 0000000..aaa9b48 --- /dev/null +++ b/src/main/kotlin/function/builtin/Funcall.kt @@ -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) + } +} diff --git a/src/main/kotlin/function/builtin/GENSYM.java b/src/main/kotlin/function/builtin/GENSYM.java deleted file mode 100644 index a07d74d..0000000 --- a/src/main/kotlin/function/builtin/GENSYM.java +++ /dev/null @@ -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(); - } -} diff --git a/src/main/kotlin/function/builtin/Gensym.kt b/src/main/kotlin/function/builtin/Gensym.kt new file mode 100644 index 0000000..434c266 --- /dev/null +++ b/src/main/kotlin/function/builtin/Gensym.kt @@ -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) + } + } +} diff --git a/src/main/kotlin/function/builtin/SYMBOLS.java b/src/main/kotlin/function/builtin/SYMBOLS.java deleted file mode 100644 index 834fb86..0000000 --- a/src/main/kotlin/function/builtin/SYMBOLS.java +++ /dev/null @@ -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(); - } -} diff --git a/src/main/kotlin/function/builtin/SYMBOL_FUNCTION.java b/src/main/kotlin/function/builtin/SYMBOL_FUNCTION.java deleted file mode 100644 index 69ecc57..0000000 --- a/src/main/kotlin/function/builtin/SYMBOL_FUNCTION.java +++ /dev/null @@ -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); - } - } -} diff --git a/src/main/kotlin/function/builtin/SymbolFunction.kt b/src/main/kotlin/function/builtin/SymbolFunction.kt new file mode 100644 index 0000000..ae49af7 --- /dev/null +++ b/src/main/kotlin/function/builtin/SymbolFunction.kt @@ -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" + } +} diff --git a/src/main/kotlin/function/builtin/Symbols.kt b/src/main/kotlin/function/builtin/Symbols.kt new file mode 100644 index 0000000..6f6fd60 --- /dev/null +++ b/src/main/kotlin/function/builtin/Symbols.kt @@ -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() + } +} diff --git a/src/main/kotlin/function/builtin/predicate/GENSYM_EQUAL.java b/src/main/kotlin/function/builtin/predicate/GENSYM_EQUAL.java deleted file mode 100644 index d87f352..0000000 --- a/src/main/kotlin/function/builtin/predicate/GENSYM_EQUAL.java +++ /dev/null @@ -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 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 entry : gensymAliases.entrySet()) - equalizedExpression = equalizedExpression.replace(entry.getKey(), entry.getValue()); - - return equalizedExpression; - } - } -} diff --git a/src/main/kotlin/function/builtin/predicate/GensymEqual.kt b/src/main/kotlin/function/builtin/predicate/GensymEqual.kt new file mode 100644 index 0000000..93d3a8d --- /dev/null +++ b/src/main/kotlin/function/builtin/predicate/GensymEqual.kt @@ -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() + 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]+" + } + } +} diff --git a/src/test/kotlin/function/builtin/APPLYTest.java b/src/test/kotlin/function/builtin/APPLYTest.java deleted file mode 100644 index 561c7b4..0000000 --- a/src/test/kotlin/function/builtin/APPLYTest.java +++ /dev/null @@ -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))")); - } -} diff --git a/src/test/kotlin/function/builtin/ApplyTest.kt b/src/test/kotlin/function/builtin/ApplyTest.kt new file mode 100644 index 0000000..058a3ce --- /dev/null +++ b/src/test/kotlin/function/builtin/ApplyTest.kt @@ -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))")) + } +} diff --git a/src/test/kotlin/function/builtin/FUNCALLTest.java b/src/test/kotlin/function/builtin/FUNCALLTest.java deleted file mode 100644 index 5d2d7b1..0000000 --- a/src/test/kotlin/function/builtin/FUNCALLTest.java +++ /dev/null @@ -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)"); - } -} diff --git a/src/test/kotlin/function/builtin/FuncallTest.kt b/src/test/kotlin/function/builtin/FuncallTest.kt new file mode 100644 index 0000000..227d539 --- /dev/null +++ b/src/test/kotlin/function/builtin/FuncallTest.kt @@ -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)") + } + } +} diff --git a/src/test/kotlin/function/builtin/GENSYMTest.java b/src/test/kotlin/function/builtin/GENSYMTest.java deleted file mode 100644 index 5befff7..0000000 --- a/src/test/kotlin/function/builtin/GENSYMTest.java +++ /dev/null @@ -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)"); - } -} diff --git a/src/test/kotlin/function/builtin/GensymTest.kt b/src/test/kotlin/function/builtin/GensymTest.kt new file mode 100644 index 0000000..63baa3e --- /dev/null +++ b/src/test/kotlin/function/builtin/GensymTest.kt @@ -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)") + } + } +} diff --git a/src/test/kotlin/function/builtin/SYMBOLSTest.java b/src/test/kotlin/function/builtin/SYMBOLSTest.java deleted file mode 100644 index 1c47a78..0000000 --- a/src/test/kotlin/function/builtin/SYMBOLSTest.java +++ /dev/null @@ -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)"); - } -} diff --git a/src/test/kotlin/function/builtin/SYMBOL_FUNCTIONTest.java b/src/test/kotlin/function/builtin/SYMBOL_FUNCTIONTest.java deleted file mode 100644 index e27ff9a..0000000 --- a/src/test/kotlin/function/builtin/SYMBOL_FUNCTIONTest.java +++ /dev/null @@ -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("#", evaluateString(input).toString()); - } - - @Test - public void symbolFunction_BuiltInSpecialFunction() { - String input = "(symbol-function 'if)"; - - assertEquals("#", 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); - } -} diff --git a/src/test/kotlin/function/builtin/SymbolFunctionTest.kt b/src/test/kotlin/function/builtin/SymbolFunctionTest.kt new file mode 100644 index 0000000..0ab6429 --- /dev/null +++ b/src/test/kotlin/function/builtin/SymbolFunctionTest.kt @@ -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("#") + } + + @Test + fun symbolFunction_BuiltInSpecialFunction() { + val input = "(symbol-function 'if)" + + assertThat(evaluateString(input).toString()).isEqualTo("#") + } + + @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)) + } +} diff --git a/src/test/kotlin/function/builtin/SymbolsTest.kt b/src/test/kotlin/function/builtin/SymbolsTest.kt new file mode 100644 index 0000000..c946a57 --- /dev/null +++ b/src/test/kotlin/function/builtin/SymbolsTest.kt @@ -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)") + } + } +} diff --git a/src/test/kotlin/function/builtin/predicate/GENSYM_EQUALTest.java b/src/test/kotlin/function/builtin/predicate/GENSYM_EQUALTest.java deleted file mode 100644 index 154d201..0000000 --- a/src/test/kotlin/function/builtin/predicate/GENSYM_EQUALTest.java +++ /dev/null @@ -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)); - } -} diff --git a/src/test/kotlin/function/builtin/predicate/GensymEqualTest.kt b/src/test/kotlin/function/builtin/predicate/GensymEqualTest.kt new file mode 100644 index 0000000..2b00f06 --- /dev/null +++ b/src/test/kotlin/function/builtin/predicate/GensymEqualTest.kt @@ -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)) + } +}