Convert remaining built in functions to kotlin

This commit is contained in:
Mike Cifelli 2018-11-10 08:26:50 -05:00
parent add24979d5
commit 35406b9f03
48 changed files with 445 additions and 556 deletions

View File

@ -1,7 +1,7 @@
package function
import error.LispException
import function.builtin.cons.LENGTH.getLength
import function.builtin.cons.Length.Companion.getLength
import sexpression.Cons
import sexpression.DisplayName
import sexpression.SExpression

View File

@ -4,7 +4,7 @@ import error.LispException
import function.ArgumentValidator
import function.FunctionNames
import function.LispFunction
import function.builtin.cons.LIST.makeList
import function.builtin.cons.List.Companion.makeList
import function.builtin.special.Lambda.Lambda.createFunction
import function.builtin.special.Lambda.Lambda.isLambdaExpression
import function.builtin.special.Recur.RecurNotInTailPositionException

View File

@ -4,7 +4,7 @@ import function.ArgumentValidator
import function.FunctionNames
import function.LispFunction
import function.builtin.Apply.Companion.apply
import function.builtin.cons.LIST.makeList
import function.builtin.cons.List.Companion.makeList
import sexpression.Cons
import sexpression.SExpression

View File

@ -1,74 +0,0 @@
package function.builtin.cons;
import function.ArgumentValidator;
import function.FunctionNames;
import function.LispFunction;
import sexpression.Cons;
import sexpression.Nil;
import table.FunctionTable;
@FunctionNames({ "APPEND" })
public class APPEND extends LispFunction {
public static Cons append(Cons firstList, Cons secondList) {
return lookupAppend().appendLists(firstList, secondList);
}
private static APPEND lookupAppend() {
return (APPEND) FunctionTable.INSTANCE.lookupFunction("APPEND");
}
private ArgumentValidator argumentValidator;
private ArgumentValidator firstListValidator;
public APPEND(String name) {
this.argumentValidator = new ArgumentValidator(name);
this.argumentValidator.setExactNumberOfArguments(2);
this.argumentValidator.setEveryArgumentExpectedType(Cons.class);
this.firstListValidator = new ArgumentValidator(name + "|first-list|");
}
@Override
public Cons call(Cons argumentList) {
argumentValidator.validate(argumentList);
Cons rest = (Cons) argumentList.getRest();
Cons firstList = (Cons) argumentList.getFirst();
Cons secondList = (Cons) rest.getFirst();
return appendLists(firstList, secondList);
}
private Cons appendLists(Cons firstList, Cons secondList) {
firstListValidator.validate(firstList);
if (firstList.isNull())
return secondList;
Cons appendedLists = copy(firstList);
getLastItem(appendedLists).setRest(secondList);
return appendedLists;
}
private Cons copy(Cons list) {
Cons newList = new Cons(list.getFirst(), Nil.INSTANCE);
Cons builder = newList;
for (Cons iterator = (Cons) list.getRest(); iterator.isCons(); iterator = (Cons) iterator.getRest()) {
builder.setRest(new Cons(iterator.getFirst(), Nil.INSTANCE));
builder = (Cons) builder.getRest();
}
return newList;
}
private Cons getLastItem(Cons list) {
Cons tail = list;
while (tail.getRest().isCons())
tail = (Cons) tail.getRest();
return tail;
}
}

View File

@ -0,0 +1,63 @@
package function.builtin.cons
import function.ArgumentValidator
import function.FunctionNames
import function.LispFunction
import sexpression.Cons
import sexpression.Nil
import table.FunctionTable
@FunctionNames("APPEND")
class Append(name: String) : LispFunction() {
private val argumentValidator = ArgumentValidator(name).apply {
setExactNumberOfArguments(2)
setEveryArgumentExpectedType(Cons::class.java)
}
private val firstListValidator = ArgumentValidator("$name|first-list|")
override fun call(argumentList: Cons): Cons {
argumentValidator.validate(argumentList)
val rest = argumentList.rest as Cons
val firstList = argumentList.first as Cons
val secondList = rest.first as Cons
return appendLists(firstList, secondList)
}
private fun appendLists(firstList: Cons, secondList: Cons): Cons {
firstListValidator.validate(firstList)
if (firstList.isNull)
return secondList
val appendedLists = copy(firstList)
appendedLists.last().rest = secondList
return appendedLists
}
private fun copy(list: Cons): Cons {
val newList = Cons(list.first, Nil)
var builder = newList
list.asSequence().drop(1).forEach {
builder.rest = Cons(it.first, Nil)
builder = builder.rest as Cons
}
return newList
}
companion object {
@JvmStatic
fun append(firstList: Cons, secondList: Cons): Cons {
return lookupAppend().appendLists(firstList, secondList)
}
private fun lookupAppend() = FunctionTable.lookupFunction("APPEND") as Append
}
}

View File

@ -1,29 +0,0 @@
package function.builtin.cons;
import function.ArgumentValidator;
import function.FunctionNames;
import function.LispFunction;
import sexpression.Cons;
import sexpression.SExpression;
@FunctionNames({ "CONS" })
public class CONS extends LispFunction {
private ArgumentValidator argumentValidator;
public CONS(String name) {
this.argumentValidator = new ArgumentValidator(name);
this.argumentValidator.setExactNumberOfArguments(2);
}
@Override
public Cons call(Cons argumentList) {
argumentValidator.validate(argumentList);
Cons rest = (Cons) argumentList.getRest();
SExpression firstArgument = argumentList.getFirst();
SExpression secondArgument = rest.getFirst();
return new Cons(firstArgument, secondArgument);
}
}

View File

@ -0,0 +1,24 @@
package function.builtin.cons
import function.ArgumentValidator
import function.FunctionNames
import function.LispFunction
import sexpression.Cons
@FunctionNames("CONS")
class Construct(name: String) : LispFunction() {
private val argumentValidator = ArgumentValidator(name).apply {
setExactNumberOfArguments(2)
}
override fun call(argumentList: Cons): Cons {
argumentValidator.validate(argumentList)
val rest = argumentList.rest as Cons
val firstArgument = argumentList.first
val secondArgument = rest.first
return Cons(firstArgument, secondArgument)
}
}

View File

@ -1,27 +0,0 @@
package function.builtin.cons;
import function.ArgumentValidator;
import function.FunctionNames;
import function.LispFunction;
import sexpression.Cons;
import sexpression.SExpression;
@FunctionNames({ "FIRST", "CAR" })
public class FIRST extends LispFunction {
private ArgumentValidator argumentValidator;
public FIRST(String name) {
this.argumentValidator = new ArgumentValidator(name);
this.argumentValidator.setExactNumberOfArguments(1);
this.argumentValidator.setEveryArgumentExpectedType(Cons.class);
}
@Override
public SExpression call(Cons argumentList) {
argumentValidator.validate(argumentList);
Cons argument = (Cons) argumentList.getFirst();
return argument.getFirst();
}
}

View File

@ -0,0 +1,23 @@
package function.builtin.cons
import function.ArgumentValidator
import function.FunctionNames
import function.LispFunction
import sexpression.Cons
import sexpression.SExpression
@FunctionNames("FIRST", "CAR")
class First(name: String) : LispFunction() {
private val argumentValidator = ArgumentValidator(name).apply {
setExactNumberOfArguments(1)
setEveryArgumentExpectedType(Cons::class.java)
}
override fun call(argumentList: Cons): SExpression {
argumentValidator.validate(argumentList)
val argument = argumentList.first as Cons
return argument.first
}
}

View File

@ -1,65 +0,0 @@
package function.builtin.cons;
import function.ArgumentValidator;
import function.FunctionNames;
import function.LispFunction;
import recursion.TailCall;
import sexpression.Cons;
import sexpression.LispNumber;
import table.FunctionTable;
import java.math.BigInteger;
import static function.builtin.cons.LIST.makeList;
import static recursion.TailCalls.done;
import static recursion.TailCalls.tailCall;
@FunctionNames({ "LENGTH" })
public class LENGTH extends LispFunction {
public static BigInteger getLength(Cons list) {
LispNumber length = lookupLength().callWithoutArgumentValidation(makeList(list));
return length.getValue();
}
private static LENGTH lookupLength() {
return (LENGTH) FunctionTable.INSTANCE.lookupFunction("LENGTH");
}
private ArgumentValidator argumentValidator;
private ArgumentValidator properListValidator;
public LENGTH(String name) {
this.argumentValidator = new ArgumentValidator(name);
this.argumentValidator.setExactNumberOfArguments(1);
this.argumentValidator.setEveryArgumentExpectedType(Cons.class);
this.properListValidator = new ArgumentValidator(name + "|list|");
}
@Override
public LispNumber call(Cons argumentList) {
argumentValidator.validate(argumentList);
properListValidator.validate((Cons) argumentList.getFirst());
return callTailRecursive(BigInteger.ZERO, argumentList).invoke();
}
private LispNumber callWithoutArgumentValidation(Cons argumentList) {
return callTailRecursive(BigInteger.ZERO, argumentList).invoke();
}
private TailCall<LispNumber> callTailRecursive(BigInteger accumulatedLength, Cons argumentList) {
Cons list = (Cons) argumentList.getFirst();
Cons restOfList = makeList(list.getRest());
if (list.isNull())
return done(new LispNumber(accumulatedLength));
return tailCall(() -> callTailRecursive(increment(accumulatedLength), restOfList));
}
private BigInteger increment(BigInteger number) {
return number.add(BigInteger.ONE);
}
}

View File

@ -1,29 +0,0 @@
package function.builtin.cons;
import function.ArgumentValidator;
import function.FunctionNames;
import function.LispFunction;
import sexpression.Cons;
import sexpression.Nil;
import sexpression.SExpression;
@FunctionNames({ "LIST" })
public class LIST extends LispFunction {
public static Cons makeList(SExpression sexpr) {
return new Cons(sexpr, Nil.INSTANCE);
}
private ArgumentValidator argumentValidator;
public LIST(String name) {
this.argumentValidator = new ArgumentValidator(name);
}
@Override
public Cons call(Cons argumentList) {
argumentValidator.validate(argumentList);
return argumentList;
}
}

View File

@ -0,0 +1,39 @@
package function.builtin.cons
import function.ArgumentValidator
import function.FunctionNames
import function.LispFunction
import sexpression.Cons
import sexpression.LispNumber
import table.FunctionTable
import table.FunctionTable.lookupFunction
import java.math.BigInteger.ZERO
@FunctionNames("LENGTH")
class Length(name: String) : LispFunction() {
private val argumentValidator = ArgumentValidator(name).apply {
setExactNumberOfArguments(1)
setEveryArgumentExpectedType(Cons::class.java)
}
private val properListValidator = ArgumentValidator("$name|list|")
override fun call(argumentList: Cons): LispNumber {
argumentValidator.validate(argumentList)
val arguments = argumentList.first as Cons
properListValidator.validate(arguments)
return getLength(arguments)
}
private fun getLength(arguments: Cons) =
LispNumber(arguments.fold(ZERO) { count, _ -> count.inc() })
companion object {
fun getLength(list: Cons) = lookupLength().getLength(list).value
private fun lookupLength() = lookupFunction("LENGTH") as Length
}
}

View File

@ -0,0 +1,28 @@
package function.builtin.cons
import function.ArgumentValidator
import function.FunctionNames
import function.LispFunction
import sexpression.Cons
import sexpression.Nil
import sexpression.SExpression
@FunctionNames("LIST")
class List(name: String) : LispFunction() {
private val argumentValidator = ArgumentValidator(name)
override fun call(argumentList: Cons): Cons {
argumentValidator.validate(argumentList)
return argumentList
}
companion object {
@JvmStatic
fun makeList(sexpr: SExpression): Cons {
return Cons(sexpr, Nil)
}
}
}

View File

@ -1,27 +0,0 @@
package function.builtin.cons;
import function.ArgumentValidator;
import function.FunctionNames;
import function.LispFunction;
import sexpression.Cons;
import sexpression.SExpression;
@FunctionNames({ "REST", "CDR" })
public class REST extends LispFunction {
private ArgumentValidator argumentValidator;
public REST(String name) {
this.argumentValidator = new ArgumentValidator(name);
this.argumentValidator.setExactNumberOfArguments(1);
this.argumentValidator.setEveryArgumentExpectedType(Cons.class);
}
@Override
public SExpression call(Cons argumentList) {
argumentValidator.validate(argumentList);
Cons argument = (Cons) argumentList.getFirst();
return argument.getRest();
}
}

View File

@ -0,0 +1,23 @@
package function.builtin.cons
import function.ArgumentValidator
import function.FunctionNames
import function.LispFunction
import sexpression.Cons
import sexpression.SExpression
@FunctionNames("REST", "CDR")
class Rest(name: String) : LispFunction() {
private val argumentValidator = ArgumentValidator(name).apply {
setExactNumberOfArguments(1)
setEveryArgumentExpectedType(Cons::class.java)
}
override fun call(argumentList: Cons): SExpression {
argumentValidator.validate(argumentList)
val argument = argumentList.first as Cons
return argument.rest
}
}

View File

@ -1,53 +0,0 @@
package function.builtin.math;
import error.LispException;
import function.ArgumentValidator;
import function.FunctionNames;
import function.LispFunction;
import sexpression.Cons;
import sexpression.LispNumber;
import java.math.BigInteger;
@FunctionNames({ "/" })
public class DIVIDE extends LispFunction {
private ArgumentValidator argumentValidator;
private MathFunction mathFunction;
public DIVIDE(String name) {
this.argumentValidator = new ArgumentValidator(name);
this.argumentValidator.setMinimumNumberOfArguments(1);
this.argumentValidator.setEveryArgumentExpectedType(LispNumber.class);
this.mathFunction = new MathFunction(this::getReciprocal, this::divide);
}
@Override
public LispNumber call(Cons argumentList) {
argumentValidator.validate(argumentList);
try {
return mathFunction.callTailRecursive(argumentList).invoke();
} catch (ArithmeticException e) {
throw new DivideByZeroException();
}
}
private LispNumber getReciprocal(LispNumber number) {
return new LispNumber(BigInteger.ONE.divide(number.getValue()));
}
private LispNumber divide(LispNumber number1, LispNumber number2) {
return new LispNumber(number1.getValue().divide(number2.getValue()));
}
public static class DivideByZeroException extends LispException {
private static final long serialVersionUID = 1L;
@Override
public String getMessage() {
return "divide by zero";
}
}
}

View File

@ -0,0 +1,41 @@
package function.builtin.math
import error.LispException
import function.ArgumentValidator
import function.FunctionNames
import function.LispFunction
import sexpression.Cons
import sexpression.LispNumber
import java.math.BigInteger.ONE
@FunctionNames("/")
class Divide(name: String) : LispFunction() {
private val argumentValidator = ArgumentValidator(name).apply {
setMinimumNumberOfArguments(1)
setEveryArgumentExpectedType(LispNumber::class.java)
}
private val mathFunction = MathFunction(this::getReciprocal, this::divide)
override fun call(argumentList: Cons): LispNumber {
argumentValidator.validate(argumentList)
try {
return mathFunction.callTailRecursive(argumentList)
} catch (e: ArithmeticException) {
throw DivideByZeroException()
}
}
private fun getReciprocal(number: LispNumber) =
LispNumber(ONE / number.value)
private fun divide(number1: LispNumber, number2: LispNumber) =
LispNumber(number1.value / number2.value)
class DivideByZeroException : LispException() {
override val message = "divide by zero"
}
}

View File

@ -1,38 +0,0 @@
package function.builtin.math;
import function.ArgumentValidator;
import function.FunctionNames;
import function.LispFunction;
import sexpression.Cons;
import sexpression.LispNumber;
import java.math.BigInteger;
@FunctionNames({ "-" })
public class MINUS extends LispFunction {
private ArgumentValidator argumentValidator;
private MathFunction mathFunction;
public MINUS(String name) {
this.argumentValidator = new ArgumentValidator(name);
this.argumentValidator.setMinimumNumberOfArguments(1);
this.argumentValidator.setEveryArgumentExpectedType(LispNumber.class);
this.mathFunction = new MathFunction(this::additiveInverse, this::subtract);
}
@Override
public LispNumber call(Cons argumentList) {
argumentValidator.validate(argumentList);
return mathFunction.callTailRecursive(argumentList).invoke();
}
private LispNumber additiveInverse(LispNumber number) {
return new LispNumber(BigInteger.ZERO.subtract(number.getValue()));
}
private LispNumber subtract(LispNumber number1, LispNumber number2) {
return new LispNumber(number1.getValue().subtract(number2.getValue()));
}
}

View File

@ -1,44 +0,0 @@
package function.builtin.math;
import error.LispException;
import function.ArgumentValidator;
import function.FunctionNames;
import function.LispFunction;
import sexpression.Cons;
import sexpression.LispNumber;
import sexpression.SExpression;
@FunctionNames({ "MOD", "MODULO", "%" })
public class MODULO extends LispFunction {
private ArgumentValidator argumentValidator;
public MODULO(String name) {
this.argumentValidator = new ArgumentValidator(name);
this.argumentValidator.setExactNumberOfArguments(2);
this.argumentValidator.setEveryArgumentExpectedType(LispNumber.class);
}
@Override
public SExpression call(Cons argumentList) {
argumentValidator.validate(argumentList);
LispNumber dividend = (LispNumber) argumentList.getFirst();
LispNumber divisor = (LispNumber) ((Cons) argumentList.getRest()).getFirst();
try {
return new LispNumber(dividend.getValue().mod(divisor.getValue()));
} catch (ArithmeticException e) {
throw new ModulusNotPositiveException();
}
}
public static class ModulusNotPositiveException extends LispException {
private static final long serialVersionUID = 1L;
@Override
public String getMessage() {
return "modulus not positive";
}
}
}

View File

@ -1,31 +0,0 @@
package function.builtin.math;
import function.ArgumentValidator;
import function.FunctionNames;
import function.LispFunction;
import sexpression.Cons;
import sexpression.LispNumber;
@FunctionNames({ "*" })
public class MULTIPLY extends LispFunction {
private ArgumentValidator argumentValidator;
private MathFunction mathFunction;
public MULTIPLY(String name) {
this.argumentValidator = new ArgumentValidator(name);
this.argumentValidator.setEveryArgumentExpectedType(LispNumber.class);
this.mathFunction = new MathFunction(number -> number, this::multiply);
}
@Override
public LispNumber call(Cons argumentList) {
argumentValidator.validate(argumentList);
return mathFunction.callTailRecursive(new Cons(LispNumber.Companion.getONE(), argumentList)).invoke();
}
private LispNumber multiply(LispNumber number1, LispNumber number2) {
return new LispNumber(number1.getValue().multiply(number2.getValue()));
}
}

View File

@ -1,43 +0,0 @@
package function.builtin.math;
import recursion.TailCall;
import sexpression.Cons;
import sexpression.LispNumber;
import sexpression.SExpression;
import java.util.function.BiFunction;
import java.util.function.Function;
import static recursion.TailCalls.done;
import static recursion.TailCalls.tailCall;
class MathFunction {
Function<LispNumber, LispNumber> singleValueOperation;
BiFunction<LispNumber, LispNumber, LispNumber> multipleValueOperation;
public MathFunction(Function<LispNumber, LispNumber> singleValueOperation,
BiFunction<LispNumber, LispNumber, LispNumber> multipleValueOperation) {
this.singleValueOperation = singleValueOperation;
this.multipleValueOperation = multipleValueOperation;
}
public TailCall<LispNumber> callTailRecursive(Cons argumentList) {
Cons remainingArguments = (Cons) argumentList.getRest();
SExpression firstArgument = argumentList.getFirst();
LispNumber number1 = (LispNumber) firstArgument;
if (remainingArguments.isNull())
return done(singleValueOperation.apply(number1));
SExpression secondArgument = remainingArguments.getFirst();
LispNumber number2 = (LispNumber) secondArgument;
LispNumber operationResult = multipleValueOperation.apply(number1, number2);
SExpression remainingNumbers = remainingArguments.getRest();
if (remainingNumbers.isNull())
return done(operationResult);
return tailCall(() -> callTailRecursive(new Cons(operationResult, remainingNumbers)));
}
}

View File

@ -0,0 +1,27 @@
package function.builtin.math
import sexpression.Cons
import sexpression.LispNumber
internal class MathFunction(private val singleValueOperation: (LispNumber) -> LispNumber,
private val multipleValueOperation: (LispNumber, LispNumber) -> LispNumber) {
tailrec fun callTailRecursive(argumentList: Cons): LispNumber {
val remainingArguments = argumentList.rest as Cons
val firstArgument = argumentList.first
val number1 = firstArgument as LispNumber
if (remainingArguments.isNull)
return singleValueOperation(number1)
val secondArgument = remainingArguments.first
val number2 = secondArgument as LispNumber
val operationResult = multipleValueOperation(number1, number2)
val remainingNumbers = remainingArguments.rest
return if (remainingNumbers.isNull)
operationResult
else
callTailRecursive(Cons(operationResult, remainingNumbers))
}
}

View File

@ -0,0 +1,32 @@
package function.builtin.math
import function.ArgumentValidator
import function.FunctionNames
import function.LispFunction
import sexpression.Cons
import sexpression.LispNumber
import java.math.BigInteger.ZERO
@FunctionNames("-")
class Minus(name: String) : LispFunction() {
private val argumentValidator = ArgumentValidator(name).apply {
setMinimumNumberOfArguments(1)
setEveryArgumentExpectedType(LispNumber::class.java)
}
private val mathFunction: MathFunction = MathFunction(this::additiveInverse, this::subtract)
override fun call(argumentList: Cons): LispNumber {
argumentValidator.validate(argumentList)
return mathFunction.callTailRecursive(argumentList)
}
private fun additiveInverse(number: LispNumber) =
LispNumber(ZERO - number.value)
private fun subtract(number1: LispNumber, number2: LispNumber) =
LispNumber(number1.value - number2.value)
}

View File

@ -0,0 +1,36 @@
package function.builtin.math
import error.LispException
import function.ArgumentValidator
import function.FunctionNames
import function.LispFunction
import sexpression.Cons
import sexpression.LispNumber
import sexpression.SExpression
@FunctionNames("MOD", "MODULO", "%")
class Module(name: String) : LispFunction() {
private val argumentValidator = ArgumentValidator(name).apply {
setExactNumberOfArguments(2)
setEveryArgumentExpectedType(LispNumber::class.java)
}
override fun call(argumentList: Cons): SExpression {
argumentValidator.validate(argumentList)
val dividend = argumentList.first as LispNumber
val divisor = (argumentList.rest as Cons).first as LispNumber
try {
return LispNumber(dividend.value.mod(divisor.value))
} catch (e: ArithmeticException) {
throw ModulusNotPositiveException()
}
}
class ModulusNotPositiveException : LispException() {
override val message = "modulus not positive"
}
}

View File

@ -0,0 +1,27 @@
package function.builtin.math
import function.ArgumentValidator
import function.FunctionNames
import function.LispFunction
import sexpression.Cons
import sexpression.LispNumber
import sexpression.LispNumber.Companion.ONE
@FunctionNames("*")
class Multiply(name: String) : LispFunction() {
private val argumentValidator = ArgumentValidator(name).apply {
setEveryArgumentExpectedType(LispNumber::class.java)
}
private val mathFunction: MathFunction = MathFunction({ it }, this::multiply)
override fun call(argumentList: Cons): LispNumber {
argumentValidator.validate(argumentList)
return mathFunction.callTailRecursive(Cons(ONE, argumentList))
}
private fun multiply(number1: LispNumber, number2: LispNumber) =
LispNumber(number1.value * number2.value)
}

View File

@ -1,31 +0,0 @@
package function.builtin.math;
import function.ArgumentValidator;
import function.FunctionNames;
import function.LispFunction;
import sexpression.Cons;
import sexpression.LispNumber;
@FunctionNames({ "+" })
public class PLUS extends LispFunction {
private ArgumentValidator argumentValidator;
private MathFunction mathFunction;
public PLUS(String name) {
this.argumentValidator = new ArgumentValidator(name);
this.argumentValidator.setEveryArgumentExpectedType(LispNumber.class);
this.mathFunction = new MathFunction(number -> number, this::add);
}
@Override
public LispNumber call(Cons argumentList) {
argumentValidator.validate(argumentList);
return mathFunction.callTailRecursive(new Cons(LispNumber.Companion.getZERO(), argumentList)).invoke();
}
private LispNumber add(LispNumber number1, LispNumber number2) {
return new LispNumber(number1.getValue().add(number2.getValue()));
}
}

View File

@ -0,0 +1,26 @@
package function.builtin.math
import function.ArgumentValidator
import function.FunctionNames
import function.LispFunction
import sexpression.Cons
import sexpression.LispNumber
@FunctionNames("+")
class Plus(name: String) : LispFunction() {
private val argumentValidator = ArgumentValidator(name).apply {
setEveryArgumentExpectedType(LispNumber::class.java)
}
private val mathFunction: MathFunction = MathFunction({ it }, this::add)
override fun call(argumentList: Cons): LispNumber {
argumentValidator.validate(argumentList)
return mathFunction.callTailRecursive(Cons(LispNumber.ZERO, argumentList))
}
private fun add(number1: LispNumber, number2: LispNumber) =
LispNumber(number1.value + number2.value)
}

View File

@ -1,34 +0,0 @@
package function.builtin.math;
import function.ArgumentValidator;
import function.FunctionNames;
import function.LispFunction;
import function.builtin.math.DIVIDE.DivideByZeroException;
import sexpression.Cons;
import sexpression.LispNumber;
import sexpression.SExpression;
@FunctionNames({ "REM", "REMAINDER" })
public class REMAINDER extends LispFunction {
private ArgumentValidator argumentValidator;
public REMAINDER(String name) {
this.argumentValidator = new ArgumentValidator(name);
this.argumentValidator.setExactNumberOfArguments(2);
this.argumentValidator.setEveryArgumentExpectedType(LispNumber.class);
}
@Override
public SExpression call(Cons argumentList) {
argumentValidator.validate(argumentList);
LispNumber dividend = (LispNumber) argumentList.getFirst();
LispNumber divisor = (LispNumber) ((Cons) argumentList.getRest()).getFirst();
try {
return new LispNumber(dividend.getValue().remainder(divisor.getValue()));
} catch (ArithmeticException e) {
throw new DivideByZeroException();
}
}
}

View File

@ -0,0 +1,31 @@
package function.builtin.math
import function.ArgumentValidator
import function.FunctionNames
import function.LispFunction
import function.builtin.math.Divide.DivideByZeroException
import sexpression.Cons
import sexpression.LispNumber
import sexpression.SExpression
@FunctionNames("REM", "REMAINDER")
class Remainder(name: String) : LispFunction() {
private val argumentValidator = ArgumentValidator(name).apply {
setExactNumberOfArguments(2)
setEveryArgumentExpectedType(LispNumber::class.java)
}
override fun call(argumentList: Cons): SExpression {
argumentValidator.validate(argumentList)
val dividend = argumentList.first as LispNumber
val divisor = (argumentList.rest as Cons).first as LispNumber
try {
return LispNumber(dividend.value % divisor.value)
} catch (e: ArithmeticException) {
throw DivideByZeroException()
}
}
}

View File

@ -3,14 +3,10 @@ package function.builtin.predicate
import function.ArgumentValidator
import function.FunctionNames
import function.LispFunction
import recursion.TailCall
import sexpression.Cons
import sexpression.LispNumber
import sexpression.Nil
import sexpression.SExpression
import recursion.TailCalls.done
import recursion.TailCalls.tailCall
import sexpression.Symbol.Companion.T
@FunctionNames("<")

View File

@ -5,7 +5,7 @@ import error.LispWarning
import function.ArgumentValidator
import function.LispSpecialFunction
import function.UserDefinedFunction
import function.builtin.cons.LIST.makeList
import function.builtin.cons.List.Companion.makeList
import sexpression.Cons
import sexpression.SExpression
import sexpression.Symbol

View File

@ -1,7 +1,6 @@
package function.builtin.special
import function.FunctionNames
import function.UserDefinedFunction
import function.UserDefinedSpecialFunction
import sexpression.Cons
import sexpression.SExpression

View File

@ -1,7 +1,6 @@
package function.builtin.special
import function.FunctionNames
import function.UserDefinedFunction
import function.UserDefinedMacro
import sexpression.Cons
import sexpression.SExpression

View File

@ -4,7 +4,7 @@ import function.ArgumentValidator
import function.FunctionNames
import function.LispSpecialFunction
import function.UserDefinedFunction
import function.builtin.cons.LIST.makeList
import function.builtin.cons.List.Companion.makeList
import sexpression.Cons
import sexpression.LambdaExpression
import sexpression.SExpression

View File

@ -5,7 +5,7 @@ import function.FunctionNames
import function.LispSpecialFunction
import function.builtin.Eval.Companion.eval
import function.builtin.Set.Companion.set
import function.builtin.cons.LIST.makeList
import function.builtin.cons.List.Companion.makeList
import sexpression.Cons
import sexpression.SExpression
import sexpression.Symbol

View File

@ -1,7 +1,7 @@
package table
import function.builtin.cons.APPEND.append
import function.builtin.cons.LIST.makeList
import function.builtin.cons.Append.Companion.append
import function.builtin.cons.List.Companion.makeList
import sexpression.Cons
import sexpression.Nil
import sexpression.SExpression

View File

@ -11,7 +11,7 @@ import static testutil.TestUtilities.assertSExpressionsMatch;
import static testutil.TestUtilities.evaluateString;
import static testutil.TestUtilities.parseString;
public class APPENDTest extends SymbolAndFunctionCleaner {
public class AppendTest extends SymbolAndFunctionCleaner {
@Test
public void appendNil() {

View File

@ -11,7 +11,7 @@ import static testutil.TestUtilities.assertSExpressionsMatch;
import static testutil.TestUtilities.evaluateString;
import static testutil.TestUtilities.parseString;
public class CONSTest extends SymbolAndFunctionCleaner {
public class ConstructTest extends SymbolAndFunctionCleaner {
@Test
public void consWithNilValues() {

View File

@ -10,7 +10,7 @@ import static testutil.TestUtilities.assertSExpressionsMatch;
import static testutil.TestUtilities.evaluateString;
import static testutil.TestUtilities.parseString;
public class FIRSTTest extends SymbolAndFunctionCleaner {
public class FirstTest extends SymbolAndFunctionCleaner {
@Test
public void firstOfNil() {

View File

@ -11,7 +11,7 @@ import static testutil.TestUtilities.assertSExpressionsMatch;
import static testutil.TestUtilities.evaluateString;
import static testutil.TestUtilities.parseString;
public class LENGTHTest extends SymbolAndFunctionCleaner {
public class LengthTest extends SymbolAndFunctionCleaner {
@Test
public void lengthOfNil() {

View File

@ -3,12 +3,12 @@ package function.builtin.cons;
import org.junit.Test;
import testutil.SymbolAndFunctionCleaner;
import static function.builtin.cons.LIST.makeList;
import static function.builtin.cons.List.makeList;
import static testutil.TestUtilities.assertSExpressionsMatch;
import static testutil.TestUtilities.evaluateString;
import static testutil.TestUtilities.parseString;
public class LISTTest extends SymbolAndFunctionCleaner {
public class ListTest extends SymbolAndFunctionCleaner {
@Test
public void listWithNoArguments() {

View File

@ -10,7 +10,7 @@ import static testutil.TestUtilities.assertSExpressionsMatch;
import static testutil.TestUtilities.evaluateString;
import static testutil.TestUtilities.parseString;
public class RESTTest extends SymbolAndFunctionCleaner {
public class RestTest extends SymbolAndFunctionCleaner {
@Test
public void restOfNil() {

View File

@ -2,7 +2,7 @@ package function.builtin.math;
import function.ArgumentValidator.BadArgumentTypeException;
import function.ArgumentValidator.TooFewArgumentsException;
import function.builtin.math.DIVIDE.DivideByZeroException;
import function.builtin.math.Divide.DivideByZeroException;
import org.junit.Test;
import testutil.SymbolAndFunctionCleaner;
@ -11,7 +11,7 @@ import static testutil.TestUtilities.assertSExpressionsMatch;
import static testutil.TestUtilities.evaluateString;
import static testutil.TestUtilities.parseString;
public class DIVIDETest extends SymbolAndFunctionCleaner {
public class DivideTest extends SymbolAndFunctionCleaner {
@Test
public void divideWithOne() {

View File

@ -9,7 +9,7 @@ import testutil.SymbolAndFunctionCleaner;
import static testutil.TestUtilities.assertSExpressionsMatch;
import static testutil.TestUtilities.evaluateString;
public class MINUSTest extends SymbolAndFunctionCleaner {
public class MinusTest extends SymbolAndFunctionCleaner {
@Test
public void minusWithOneNumber() {

View File

@ -3,7 +3,7 @@ package function.builtin.math;
import function.ArgumentValidator.BadArgumentTypeException;
import function.ArgumentValidator.TooFewArgumentsException;
import function.ArgumentValidator.TooManyArgumentsException;
import function.builtin.math.MODULO.ModulusNotPositiveException;
import function.builtin.math.Module.ModulusNotPositiveException;
import org.junit.Test;
import sexpression.LispNumber;
import testutil.SymbolAndFunctionCleaner;
@ -12,7 +12,7 @@ import static testutil.TestUtilities.assertIsErrorWithMessage;
import static testutil.TestUtilities.assertSExpressionsMatch;
import static testutil.TestUtilities.evaluateString;
public class MODULOTest extends SymbolAndFunctionCleaner {
public class ModuleTest extends SymbolAndFunctionCleaner {
@Test
public void mod() {

View File

@ -8,7 +8,7 @@ import testutil.SymbolAndFunctionCleaner;
import static testutil.TestUtilities.assertSExpressionsMatch;
import static testutil.TestUtilities.evaluateString;
public class MULTIPLYTest extends SymbolAndFunctionCleaner {
public class MultiplyTest extends SymbolAndFunctionCleaner {
@Test
public void multiplyWithNoArguments() {

View File

@ -8,7 +8,7 @@ import testutil.SymbolAndFunctionCleaner;
import static testutil.TestUtilities.assertSExpressionsMatch;
import static testutil.TestUtilities.evaluateString;
public class PLUSTest extends SymbolAndFunctionCleaner {
public class PlusTest extends SymbolAndFunctionCleaner {
@Test
public void plusWithNoArguments() {

View File

@ -3,7 +3,7 @@ package function.builtin.math;
import function.ArgumentValidator.BadArgumentTypeException;
import function.ArgumentValidator.TooFewArgumentsException;
import function.ArgumentValidator.TooManyArgumentsException;
import function.builtin.math.DIVIDE.DivideByZeroException;
import function.builtin.math.Divide.DivideByZeroException;
import org.junit.Test;
import sexpression.LispNumber;
import testutil.SymbolAndFunctionCleaner;
@ -11,7 +11,7 @@ import testutil.SymbolAndFunctionCleaner;
import static testutil.TestUtilities.assertSExpressionsMatch;
import static testutil.TestUtilities.evaluateString;
public class REMAINDERTest extends SymbolAndFunctionCleaner {
public class RemainderTest extends SymbolAndFunctionCleaner {
@Test
public void rem() {