Convert Begin and If to kotlin

This commit is contained in:
Mike Cifelli 2018-10-28 20:22:45 -04:00
parent 2e314f9ff0
commit 73bcd4da38
15 changed files with 260 additions and 271 deletions

View File

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

View File

@ -1,52 +0,0 @@
package function.builtin.special;
import function.ArgumentValidator;
import function.FunctionNames;
import function.LispSpecialFunction;
import sexpression.Cons;
import sexpression.SExpression;
import static function.builtin.Eval.eval;
@FunctionNames({ "IF" })
public class IF extends LispSpecialFunction {
private ArgumentValidator argumentValidator;
public IF(String name) {
this.argumentValidator = new ArgumentValidator(name);
this.argumentValidator.setMinimumNumberOfArguments(2);
this.argumentValidator.setMaximumNumberOfArguments(3);
}
@Override
public SExpression call(Cons argumentList) {
argumentValidator.validate(argumentList);
SExpression test = eval(argumentList.getFirst());
SExpression thenForm = getThenForm(argumentList);
SExpression elseForm = getElseForm(argumentList);
return isNil(test) ? eval(elseForm) : eval(thenForm);
}
private boolean isNil(SExpression test) {
return test.isNull();
}
private SExpression getThenForm(Cons argumentList) {
Cons expressions = getRestOfList(argumentList);
return expressions.getFirst();
}
private Cons getRestOfList(Cons argumentList) {
return (Cons) argumentList.getRest();
}
private SExpression getElseForm(Cons argumentList) {
Cons expressions = getRestOfList(argumentList);
return getRestOfList(expressions).getFirst();
}
}

View File

@ -0,0 +1,31 @@
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("IF")
class If(name: String) : LispSpecialFunction() {
private val argumentValidator = ArgumentValidator(name).apply {
setMinimumNumberOfArguments(2)
setMaximumNumberOfArguments(3)
}
override fun call(argumentList: Cons): SExpression {
argumentValidator.validate(argumentList)
val test = eval(argumentList.first)
val thenForm = getThenForm(argumentList)
val elseForm = getElseForm(argumentList)
return if (test.isNull) eval(elseForm) else eval(thenForm)
}
private fun getRestOfList(argumentList: Cons) = argumentList.rest as Cons
private fun getThenForm(argumentList: Cons) = getRestOfList(argumentList).first
private fun getElseForm(argumentList: Cons) = getRestOfList(argumentList).let { getRestOfList(it).first }
}

View File

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

View File

@ -1,25 +0,0 @@
package function.builtin.special;
import function.ArgumentValidator;
import function.FunctionNames;
import function.LispSpecialFunction;
import sexpression.Cons;
import sexpression.SExpression;
@FunctionNames({ "QUOTE" })
public class QUOTE extends LispSpecialFunction {
private ArgumentValidator argumentValidator;
public QUOTE(String name) {
this.argumentValidator = new ArgumentValidator(name);
this.argumentValidator.setExactNumberOfArguments(1);
}
@Override
public SExpression call(Cons argumentList) {
argumentValidator.validate(argumentList);
return argumentList.getFirst();
}
}

View File

@ -0,0 +1,21 @@
package function.builtin.special
import function.ArgumentValidator
import function.FunctionNames
import function.LispSpecialFunction
import sexpression.Cons
import sexpression.SExpression
@FunctionNames("QUOTE")
class Quote(name: String) : LispSpecialFunction() {
private val argumentValidator = ArgumentValidator(name).apply {
setExactNumberOfArguments(1)
}
override fun call(argumentList: Cons): SExpression {
argumentValidator.validate(argumentList)
return argumentList.first
}
}

View File

@ -0,0 +1,43 @@
package function.builtin.special
import org.junit.jupiter.api.Test
import testutil.LispTestInstance
import testutil.SymbolAndFunctionCleaner
import testutil.TestUtilities.assertSExpressionsMatch
import testutil.TestUtilities.evaluateString
import testutil.TestUtilities.parseString
import testutil.TypeAssertions.assertNil
@LispTestInstance
class BeginTest : SymbolAndFunctionCleaner() {
@Test
fun prognWithNoArguments() {
assertNil(evaluateString("(progn)"))
}
@Test
fun prognWithOneArgument() {
assertSExpressionsMatch(parseString("1"), evaluateString("(progn 1)"))
}
@Test
fun prognWithSeveralArguments() {
assertSExpressionsMatch(parseString("5"), evaluateString("(progn 1 2 3 4 5)"))
}
@Test
fun beginWithSeveralArguments() {
assertSExpressionsMatch(parseString("5"), evaluateString("(begin 1 2 3 4 5)"))
}
@Test
fun prognEvaluatesArgument() {
assertSExpressionsMatch(parseString("1"), evaluateString("(progn (car '(1 2 3)))"))
}
@Test
fun prognWithDifferentArgumentTypes() {
assertSExpressionsMatch(parseString("pear"), evaluateString("(progn t nil '(1 2) 'pear)"))
}
}

View File

@ -10,6 +10,7 @@ import function.UserDefinedFunction.IllegalKeywordRestPositionException
import org.assertj.core.api.Assertions.assertThat
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
@ -17,6 +18,7 @@ import testutil.TestUtilities.parseString
import java.io.ByteArrayOutputStream
import java.io.PrintStream
@LispTestInstance
class DefineSpecialTest : SymbolAndFunctionCleaner() {
private var outputStream = ByteArrayOutputStream()

View File

@ -10,6 +10,7 @@ import function.UserDefinedFunction.IllegalKeywordRestPositionException
import org.assertj.core.api.Assertions.assertThat
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
@ -17,6 +18,7 @@ import testutil.TestUtilities.parseString
import java.io.ByteArrayOutputStream
import java.io.PrintStream
@LispTestInstance
class DefmacroTest : SymbolAndFunctionCleaner() {
private var outputStream = ByteArrayOutputStream()

View File

@ -10,6 +10,7 @@ import function.UserDefinedFunction.IllegalKeywordRestPositionException
import org.assertj.core.api.Assertions.assertThat
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
@ -17,6 +18,7 @@ import testutil.TestUtilities.parseString
import java.io.ByteArrayOutputStream
import java.io.PrintStream
@LispTestInstance
class DefunTest : SymbolAndFunctionCleaner() {
private var outputStream = ByteArrayOutputStream()

View File

@ -1,75 +0,0 @@
package function.builtin.special;
import function.ArgumentValidator.TooFewArgumentsException;
import function.ArgumentValidator.TooManyArgumentsException;
import function.builtin.Eval.UndefinedSymbolException;
import org.junit.Test;
import testutil.SymbolAndFunctionCleaner;
import static testutil.TestUtilities.evaluateString;
import static testutil.TypeAssertions.assertNil;
import static testutil.TypeAssertions.assertT;
public class IFTest extends SymbolAndFunctionCleaner {
@Test
public void ifWithOneExpression_ReturnsExpression() {
String input = "(if t t)";
assertT(evaluateString(input));
}
@Test
public void ifWithOneExpression_ReturnsNil() {
String input = "(if nil t)";
assertNil(evaluateString(input));
}
@Test
public void ifWithTwoExpressions_ReturnsFirst() {
String input = "(if t t nil)";
assertT(evaluateString(input));
}
@Test
public void ifWithTwoExpressions_ReturnsSecond() {
String input = "(if nil nil t)";
assertT(evaluateString(input));
}
@Test
public void ifWithNumericConditional() {
String input = "(if 23 t nil)";
assertT(evaluateString(input));
}
@Test(expected = UndefinedSymbolException.class)
public void ifWithNilCondition_DoesNotEvaluateThenForm() {
String input = "(if nil (setq x 22))";
assertNil(evaluateString(input));
evaluateString("x");
}
@Test(expected = UndefinedSymbolException.class)
public void ifWithTrueCondition_DoesNotEvaluateElseForm() {
String input = "(if t nil (setq x 22))";
assertNil(evaluateString(input));
evaluateString("x");
}
@Test(expected = TooFewArgumentsException.class)
public void ifWithTooFewArguments() {
evaluateString("(if t)");
}
@Test(expected = TooManyArgumentsException.class)
public void ifWithTooManyArguments() {
evaluateString("(if t t t t)");
}
}

View File

@ -0,0 +1,85 @@
package function.builtin.special
import function.ArgumentValidator.TooFewArgumentsException
import function.ArgumentValidator.TooManyArgumentsException
import function.builtin.Eval.UndefinedSymbolException
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 IfTest : SymbolAndFunctionCleaner() {
@Test
fun ifWithOneExpression_ReturnsExpression() {
val input = "(if t t)"
assertT(evaluateString(input))
}
@Test
fun ifWithOneExpression_ReturnsNil() {
val input = "(if nil t)"
assertNil(evaluateString(input))
}
@Test
fun ifWithTwoExpressions_ReturnsFirst() {
val input = "(if t t nil)"
assertT(evaluateString(input))
}
@Test
fun ifWithTwoExpressions_ReturnsSecond() {
val input = "(if nil nil t)"
assertT(evaluateString(input))
}
@Test
fun ifWithNumericConditional() {
val input = "(if 23 t nil)"
assertT(evaluateString(input))
}
@Test
fun ifWithNilCondition_DoesNotEvaluateThenForm() {
val input = "(if nil (setq x 22))"
assertNil(evaluateString(input))
assertThrows(UndefinedSymbolException::class.java) {
evaluateString("x")
}
}
@Test
fun ifWithTrueCondition_DoesNotEvaluateElseForm() {
val input = "(if t nil (setq x 22))"
assertNil(evaluateString(input))
assertThrows(UndefinedSymbolException::class.java) {
evaluateString("x")
}
}
@Test
fun ifWithTooFewArguments() {
assertThrows(TooFewArgumentsException::class.java) {
evaluateString("(if t)")
}
}
@Test
fun ifWithTooManyArguments() {
assertThrows(TooManyArgumentsException::class.java) {
evaluateString("(if t t t t)")
}
}
}

View File

@ -1,42 +0,0 @@
package function.builtin.special;
import org.junit.Test;
import testutil.SymbolAndFunctionCleaner;
import static testutil.TestUtilities.assertSExpressionsMatch;
import static testutil.TestUtilities.evaluateString;
import static testutil.TestUtilities.parseString;
import static testutil.TypeAssertions.assertNil;
public class PROGNTest extends SymbolAndFunctionCleaner {
@Test
public void prognWithNoArguments() {
assertNil(evaluateString("(progn)"));
}
@Test
public void prognWithOneArgument() {
assertSExpressionsMatch(parseString("1"), evaluateString("(progn 1)"));
}
@Test
public void prognWithSeveralArguments() {
assertSExpressionsMatch(parseString("5"), evaluateString("(progn 1 2 3 4 5)"));
}
@Test
public void beginWithSeveralArguments() {
assertSExpressionsMatch(parseString("5"), evaluateString("(begin 1 2 3 4 5)"));
}
@Test
public void prognEvaluatesArgument() {
assertSExpressionsMatch(parseString("1"), evaluateString("(progn (car '(1 2 3)))"));
}
@Test
public void prognWithDifferentArgumentTypes() {
assertSExpressionsMatch(parseString("pear"), evaluateString("(progn t nil '(1 2) 'pear)"));
}
}

View File

@ -1,37 +0,0 @@
package function.builtin.special;
import function.ArgumentValidator.TooFewArgumentsException;
import function.ArgumentValidator.TooManyArgumentsException;
import org.junit.Test;
import testutil.SymbolAndFunctionCleaner;
import static testutil.TestUtilities.assertSExpressionsMatch;
import static testutil.TestUtilities.evaluateString;
import static testutil.TestUtilities.parseString;
public class QUOTETest extends SymbolAndFunctionCleaner {
@Test
public void quoteSymbol() {
String input = "'a";
assertSExpressionsMatch(parseString("a"), evaluateString(input));
}
@Test
public void quoteList() {
String input = "'(l i s t)";
assertSExpressionsMatch(parseString("(l i s t)"), evaluateString(input));
}
@Test(expected = TooFewArgumentsException.class)
public void quoteWithTooFewArguments() {
evaluateString("(quote)");
}
@Test(expected = TooManyArgumentsException.class)
public void quoteWithTooManyArguments() {
evaluateString("(quote a b)");
}
}

View File

@ -0,0 +1,43 @@
package function.builtin.special
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.assertSExpressionsMatch
import testutil.TestUtilities.evaluateString
import testutil.TestUtilities.parseString
@LispTestInstance
class QuoteTest : SymbolAndFunctionCleaner() {
@Test
fun quoteSymbol() {
val input = "'a"
assertSExpressionsMatch(parseString("a"), evaluateString(input))
}
@Test
fun quoteList() {
val input = "'(l i s t)"
assertSExpressionsMatch(parseString("(l i s t)"), evaluateString(input))
}
@Test
fun quoteWithTooFewArguments() {
assertThrows(TooFewArgumentsException::class.java) {
evaluateString("(quote)")
}
}
@Test
fun quoteWithTooManyArguments() {
assertThrows(TooManyArgumentsException::class.java) {
evaluateString("(quote a b)")
}
}
}