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.Symbol
import sexpression.Symbol.Companion.T
import testutil.LispTestInstance
import testutil.SymbolAndFunctionCleaner
import testutil.TestUtilities.assertSExpressionsMatch
import testutil.TestUtilities.evaluateString
import testutil.TestUtilities.parseString
@LispTestInstance
class LambdaTest : SymbolAndFunctionCleaner() {
@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)")
}
}
}