Convert And and Or to kotlin

This commit is contained in:
Mike Cifelli 2018-10-24 08:47:09 -04:00
parent ac821abde2
commit 8ca2eb199c
11 changed files with 307 additions and 304 deletions

View File

@ -1,43 +0,0 @@
package function.builtin.special;
import function.ArgumentValidator;
import function.FunctionNames;
import function.LispSpecialFunction;
import recursion.TailCall;
import sexpression.Cons;
import sexpression.SExpression;
import sexpression.Symbol;
import static function.builtin.Eval.eval;
import static recursion.TailCalls.done;
import static recursion.TailCalls.tailCall;
@FunctionNames({ "AND" })
public class AND extends LispSpecialFunction {
private ArgumentValidator argumentValidator;
public AND(String name) {
this.argumentValidator = new ArgumentValidator(name);
}
@Override
public SExpression call(Cons argumentList) {
argumentValidator.validate(argumentList);
return callTailRecursive(argumentList, Symbol.Companion.getT()).invoke();
}
private TailCall<SExpression> callTailRecursive(Cons argumentList, SExpression lastValue) {
SExpression currentValue = eval(argumentList.getFirst());
Cons remainingValues = (Cons) argumentList.getRest();
if (argumentList.isNull())
return done(lastValue);
if (currentValue.isNull())
return done(currentValue);
return tailCall(() -> callTailRecursive(remainingValues, currentValue));
}
}

View File

@ -0,0 +1,32 @@
package function.builtin.special
import function.ArgumentValidator
import function.FunctionNames
import function.LispSpecialFunction
import function.builtin.Eval.Companion.eval
import sexpression.Cons
import sexpression.SExpression
import sexpression.Symbol.Companion.T
@FunctionNames("AND")
class And(name: String) : LispSpecialFunction() {
private val argumentValidator = ArgumentValidator(name)
override fun call(argumentList: Cons): SExpression {
argumentValidator.validate(argumentList)
return callTailRecursive(argumentList, T)
}
private tailrec fun callTailRecursive(argumentList: Cons, lastValue: SExpression): SExpression {
val currentValue = eval(argumentList.first)
val remainingValues = argumentList.rest as Cons
return when {
argumentList.isNull -> lastValue
currentValue.isNull -> currentValue
else -> callTailRecursive(remainingValues, currentValue)
}
}
}

View File

@ -1,39 +0,0 @@
package function.builtin.special;
import function.ArgumentValidator;
import function.FunctionNames;
import function.LispSpecialFunction;
import recursion.TailCall;
import sexpression.Cons;
import sexpression.SExpression;
import static function.builtin.Eval.eval;
import static recursion.TailCalls.done;
import static recursion.TailCalls.tailCall;
@FunctionNames({ "OR" })
public class OR extends LispSpecialFunction {
private ArgumentValidator argumentValidator;
public OR(String name) {
this.argumentValidator = new ArgumentValidator(name);
}
@Override
public SExpression call(Cons argumentList) {
argumentValidator.validate(argumentList);
return callTailRecursive(argumentList).invoke();
}
private TailCall<SExpression> callTailRecursive(Cons argumentList) {
SExpression currentValue = eval(argumentList.getFirst());
Cons remainingValues = (Cons) argumentList.getRest();
if (remainingValues.isNull() || !currentValue.isNull())
return done(currentValue);
return tailCall(() -> callTailRecursive(remainingValues));
}
}

View File

@ -0,0 +1,30 @@
package function.builtin.special
import function.ArgumentValidator
import function.FunctionNames
import function.LispSpecialFunction
import function.builtin.Eval.Companion.eval
import sexpression.Cons
import sexpression.SExpression
@FunctionNames("OR")
class Or(name: String) : LispSpecialFunction() {
private val argumentValidator = ArgumentValidator(name)
override fun call(argumentList: Cons): SExpression {
argumentValidator.validate(argumentList)
return callTailRecursive(argumentList)
}
private tailrec fun callTailRecursive(argumentList: Cons): SExpression {
val currentValue = eval(argumentList.first)
val remainingValues = argumentList.rest as Cons
return if (remainingValues.isNull || !currentValue.isNull)
currentValue
else
callTailRecursive(remainingValues)
}
}

View File

@ -1,64 +0,0 @@
package function.builtin.special;
import function.builtin.Eval.UndefinedSymbolException;
import org.junit.Test;
import sexpression.LispNumber;
import testutil.SymbolAndFunctionCleaner;
import static testutil.TestUtilities.assertSExpressionsMatch;
import static testutil.TestUtilities.evaluateString;
import static testutil.TypeAssertions.assertNil;
import static testutil.TypeAssertions.assertT;
public class ANDTest extends SymbolAndFunctionCleaner {
@Test
public void andByItself() {
String input = "(and)";
assertT(evaluateString(input));
}
@Test
public void andWithNil() {
String input = "(and nil)";
assertNil(evaluateString(input));
}
@Test
public void andWithT() {
String input = "(and t)";
assertT(evaluateString(input));
}
@Test
public void andWithNumber() {
String input = "(and 7)";
assertSExpressionsMatch(new LispNumber("7"), evaluateString(input));
}
@Test
public void andWithSeveralValues() {
String input = "(and t t nil t t)";
assertNil(evaluateString(input));
}
@Test
public void andWithSeveralNumbers() {
String input = "(and 1 2 3)";
assertSExpressionsMatch(new LispNumber("3"), evaluateString(input));
}
@Test(expected = UndefinedSymbolException.class)
public void andShortCircuits() {
String input = "(and nil (setq x 22))";
assertNil(evaluateString(input));
evaluateString("x");
}
}

View File

@ -0,0 +1,69 @@
package function.builtin.special
import function.builtin.Eval.UndefinedSymbolException
import org.junit.jupiter.api.Assertions.assertThrows
import org.junit.jupiter.api.Test
import sexpression.LispNumber
import testutil.LispTestInstance
import testutil.SymbolAndFunctionCleaner
import testutil.TestUtilities.assertSExpressionsMatch
import testutil.TestUtilities.evaluateString
import testutil.TypeAssertions.assertNil
import testutil.TypeAssertions.assertT
@LispTestInstance
class AndTest : SymbolAndFunctionCleaner() {
@Test
fun andByItself() {
val input = "(and)"
assertT(evaluateString(input))
}
@Test
fun andWithNil() {
val input = "(and nil)"
assertNil(evaluateString(input))
}
@Test
fun andWithT() {
val input = "(and t)"
assertT(evaluateString(input))
}
@Test
fun andWithNumber() {
val input = "(and 7)"
assertSExpressionsMatch(LispNumber("7"), evaluateString(input))
}
@Test
fun andWithSeveralValues() {
val input = "(and t t nil t t)"
assertNil(evaluateString(input))
}
@Test
fun andWithSeveralNumbers() {
val input = "(and 1 2 3)"
assertSExpressionsMatch(LispNumber("3"), evaluateString(input))
}
@Test
fun andShortCircuits() {
val input = "(and nil (setq x 22))"
assertNil(evaluateString(input))
assertThrows(UndefinedSymbolException::class.java) {
evaluateString("x")
}
}
}

View File

@ -16,11 +16,13 @@ import sexpression.LispNumber.Companion.ONE
import sexpression.Nil import sexpression.Nil
import sexpression.Symbol import sexpression.Symbol
import sexpression.Symbol.Companion.T import sexpression.Symbol.Companion.T
import testutil.LispTestInstance
import testutil.SymbolAndFunctionCleaner import testutil.SymbolAndFunctionCleaner
import testutil.TestUtilities.assertSExpressionsMatch import testutil.TestUtilities.assertSExpressionsMatch
import testutil.TestUtilities.evaluateString import testutil.TestUtilities.evaluateString
import testutil.TestUtilities.parseString import testutil.TestUtilities.parseString
@LispTestInstance
class LambdaTest : SymbolAndFunctionCleaner() { class LambdaTest : SymbolAndFunctionCleaner() {
@Test @Test

View File

@ -1,64 +0,0 @@
package function.builtin.special;
import function.builtin.Eval.UndefinedSymbolException;
import org.junit.Test;
import sexpression.LispNumber;
import testutil.SymbolAndFunctionCleaner;
import static testutil.TestUtilities.assertSExpressionsMatch;
import static testutil.TestUtilities.evaluateString;
import static testutil.TypeAssertions.assertNil;
import static testutil.TypeAssertions.assertT;
public class ORTest extends SymbolAndFunctionCleaner {
@Test
public void orByItself() {
String input = "(or)";
assertNil(evaluateString(input));
}
@Test
public void orWithNil() {
String input = "(or nil)";
assertNil(evaluateString(input));
}
@Test
public void orWithT() {
String input = "(or t)";
assertT(evaluateString(input));
}
@Test
public void orWithNumber() {
String input = "(or 7)";
assertSExpressionsMatch(new LispNumber("7"), evaluateString(input));
}
@Test
public void orWithSeveralValues() {
String input = "(or nil nil nil t nil)";
assertT(evaluateString(input));
}
@Test
public void orWithSeveralNumbers() {
String input = "(or 1 2 3)";
assertSExpressionsMatch(new LispNumber("1"), evaluateString(input));
}
@Test(expected = UndefinedSymbolException.class)
public void orShortCircuits() {
String input = "(or t (setq x 22))";
assertT(evaluateString(input));
evaluateString("x");
}
}

View File

@ -0,0 +1,69 @@
package function.builtin.special
import function.builtin.Eval.UndefinedSymbolException
import org.junit.jupiter.api.Assertions.assertThrows
import org.junit.jupiter.api.Test
import sexpression.LispNumber
import testutil.LispTestInstance
import testutil.SymbolAndFunctionCleaner
import testutil.TestUtilities.assertSExpressionsMatch
import testutil.TestUtilities.evaluateString
import testutil.TypeAssertions.assertNil
import testutil.TypeAssertions.assertT
@LispTestInstance
class OrTest : SymbolAndFunctionCleaner() {
@Test
fun orByItself() {
val input = "(or)"
assertNil(evaluateString(input))
}
@Test
fun orWithNil() {
val input = "(or nil)"
assertNil(evaluateString(input))
}
@Test
fun orWithT() {
val input = "(or t)"
assertT(evaluateString(input))
}
@Test
fun orWithNumber() {
val input = "(or 7)"
assertSExpressionsMatch(LispNumber("7"), evaluateString(input))
}
@Test
fun orWithSeveralValues() {
val input = "(or nil nil nil t nil)"
assertT(evaluateString(input))
}
@Test
fun orWithSeveralNumbers() {
val input = "(or 1 2 3)"
assertSExpressionsMatch(LispNumber("1"), evaluateString(input))
}
@Test
fun orShortCircuits() {
val input = "(or t (setq x 22))"
assertT(evaluateString(input))
assertThrows(UndefinedSymbolException::class.java) {
evaluateString("x")
}
}
}

View File

@ -1,94 +0,0 @@
package function.builtin.special;
import function.ArgumentValidator.BadArgumentTypeException;
import function.ArgumentValidator.TooFewArgumentsException;
import function.ArgumentValidator.TooManyArgumentsException;
import function.builtin.Eval.UndefinedSymbolException;
import org.junit.Test;
import sexpression.LispNumber;
import table.SymbolTable;
import testutil.SymbolAndFunctionCleaner;
import static org.junit.Assert.assertNull;
import static testutil.TestUtilities.assertSExpressionsMatch;
import static testutil.TestUtilities.evaluateString;
public class SetqTest extends SymbolAndFunctionCleaner {
@Test
public void setq() {
evaluateString("(setq a 23)");
assertSExpressionsMatch(new LispNumber("23"), evaluateString("a"));
}
@Test
public void lookupDefinedSymbol() {
evaluateString("(setq a 23)");
assertSExpressionsMatch(new LispNumber("23"), getExecutionContext().lookupSymbolValue("A"));
}
@Test
public void lookupUndefinedSymbol() {
assertNull(getExecutionContext().lookupSymbolValue("A"));
}
@Test
public void setqGlobalVariable() {
evaluateString("(setq a 23)");
SymbolTable global = getExecutionContext().getScope();
getExecutionContext().setScope(new SymbolTable(global));
evaluateString("(setq a 94)");
getExecutionContext().setScope(global);
assertSExpressionsMatch(new LispNumber("94"), evaluateString("a"));
}
@Test
public void setqLocalVariable() {
SymbolTable global = getExecutionContext().getScope();
SymbolTable local = new SymbolTable(global);
local.set("A", new LispNumber("99"));
getExecutionContext().setScope(local);
evaluateString("(setq a 94)");
assertSExpressionsMatch(new LispNumber("94"), evaluateString("a"));
}
@Test(expected = UndefinedSymbolException.class)
public void setqLocalVariableDefined_DoesNotSetGlobal() {
SymbolTable global = getExecutionContext().getScope();
SymbolTable local = new SymbolTable(global);
local.set("A", new LispNumber("99"));
getExecutionContext().setScope(local);
evaluateString("(setq a 94)");
getExecutionContext().setScope(global);
evaluateString("a");
}
@Test
public void setqLocalVariableUndefined_SetsGlobal() {
SymbolTable global = getExecutionContext().getScope();
SymbolTable local = new SymbolTable(global);
getExecutionContext().setScope(local);
evaluateString("(setq a 94)");
getExecutionContext().setScope(global);
assertSExpressionsMatch(new LispNumber("94"), evaluateString("a"));
}
@Test(expected = BadArgumentTypeException.class)
public void setqWithNonSymbol() {
evaluateString("(setq 1 2)");
}
@Test(expected = TooFewArgumentsException.class)
public void setqWithTooFewArguments() {
evaluateString("(setq x)");
}
@Test(expected = TooManyArgumentsException.class)
public void setqWithTooManyArguments() {
evaluateString("(setq a b c)");
}
}

View File

@ -0,0 +1,105 @@
package function.builtin.special
import function.ArgumentValidator.BadArgumentTypeException
import function.ArgumentValidator.TooFewArgumentsException
import function.ArgumentValidator.TooManyArgumentsException
import function.builtin.Eval.UndefinedSymbolException
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Assertions.assertThrows
import org.junit.jupiter.api.Test
import sexpression.LispNumber
import table.SymbolTable
import testutil.LispTestInstance
import testutil.SymbolAndFunctionCleaner
import testutil.TestUtilities.assertSExpressionsMatch
import testutil.TestUtilities.evaluateString
@LispTestInstance
class SetqTest : SymbolAndFunctionCleaner() {
@Test
fun setq() {
evaluateString("(setq a 23)")
assertSExpressionsMatch(LispNumber("23"), evaluateString("a"))
}
@Test
fun lookupDefinedSymbol() {
evaluateString("(setq a 23)")
assertSExpressionsMatch(LispNumber("23"), executionContext.lookupSymbolValue("A")!!)
}
@Test
fun lookupUndefinedSymbol() {
assertThat(executionContext.lookupSymbolValue("A")).isNull()
}
@Test
fun setqGlobalVariable() {
evaluateString("(setq a 23)")
val global = executionContext.scope
executionContext.scope = SymbolTable(global)
evaluateString("(setq a 94)")
executionContext.scope = global
assertSExpressionsMatch(LispNumber("94"), evaluateString("a"))
}
@Test
fun setqLocalVariable() {
val global = executionContext.scope
val local = SymbolTable(global)
local["A"] = LispNumber("99")
executionContext.scope = local
evaluateString("(setq a 94)")
assertSExpressionsMatch(LispNumber("94"), evaluateString("a"))
}
@Test
fun setqLocalVariableDefined_DoesNotSetGlobal() {
val global = executionContext.scope
val local = SymbolTable(global)
local["A"] = LispNumber("99")
executionContext.scope = local
evaluateString("(setq a 94)")
executionContext.scope = global
assertThrows(UndefinedSymbolException::class.java) {
evaluateString("a")
}
}
@Test
fun setqLocalVariableUndefined_SetsGlobal() {
val global = executionContext.scope
val local = SymbolTable(global)
executionContext.scope = local
evaluateString("(setq a 94)")
executionContext.scope = global
assertSExpressionsMatch(LispNumber("94"), evaluateString("a"))
}
@Test
fun setqWithNonSymbol() {
assertThrows(BadArgumentTypeException::class.java) {
evaluateString("(setq 1 2)")
}
}
@Test
fun setqWithTooFewArguments() {
assertThrows(TooFewArgumentsException::class.java) {
evaluateString("(setq x)")
}
}
@Test
fun setqWithTooManyArguments() {
assertThrows(TooManyArgumentsException::class.java) {
evaluateString("(setq a b c)")
}
}
}