Convert Begin and If to kotlin
This commit is contained in:
parent
2e314f9ff0
commit
73bcd4da38
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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 }
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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)"))
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)");
|
||||
}
|
||||
}
|
|
@ -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)")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)"));
|
||||
}
|
||||
}
|
|
@ -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)");
|
||||
}
|
||||
}
|
|
@ -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)")
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue