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 package function
import error.LispException import error.LispException
import function.builtin.cons.LENGTH.getLength import function.builtin.cons.Length.Companion.getLength
import sexpression.Cons import sexpression.Cons
import sexpression.DisplayName import sexpression.DisplayName
import sexpression.SExpression import sexpression.SExpression

View File

@ -4,7 +4,7 @@ import error.LispException
import function.ArgumentValidator import function.ArgumentValidator
import function.FunctionNames import function.FunctionNames
import function.LispFunction 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.createFunction
import function.builtin.special.Lambda.Lambda.isLambdaExpression import function.builtin.special.Lambda.Lambda.isLambdaExpression
import function.builtin.special.Recur.RecurNotInTailPositionException import function.builtin.special.Recur.RecurNotInTailPositionException

View File

@ -4,7 +4,7 @@ import function.ArgumentValidator
import function.FunctionNames import function.FunctionNames
import function.LispFunction import function.LispFunction
import function.builtin.Apply.Companion.apply import function.builtin.Apply.Companion.apply
import function.builtin.cons.LIST.makeList import function.builtin.cons.List.Companion.makeList
import sexpression.Cons import sexpression.Cons
import sexpression.SExpression 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.ArgumentValidator
import function.FunctionNames import function.FunctionNames
import function.LispFunction import function.LispFunction
import recursion.TailCall
import sexpression.Cons import sexpression.Cons
import sexpression.LispNumber import sexpression.LispNumber
import sexpression.Nil import sexpression.Nil
import sexpression.SExpression import sexpression.SExpression
import recursion.TailCalls.done
import recursion.TailCalls.tailCall
import sexpression.Symbol.Companion.T import sexpression.Symbol.Companion.T
@FunctionNames("<") @FunctionNames("<")
@ -39,7 +35,7 @@ class NumericLess(name: String) : LispFunction() {
val number2 = secondArgument as LispNumber val number2 = secondArgument as LispNumber
return if (number1.value < number2.value) return if (number1.value < number2.value)
callTailRecursive(remainingArguments) callTailRecursive(remainingArguments)
else else
Nil Nil
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,12 +3,12 @@ package function.builtin.cons;
import org.junit.Test; import org.junit.Test;
import testutil.SymbolAndFunctionCleaner; 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.assertSExpressionsMatch;
import static testutil.TestUtilities.evaluateString; import static testutil.TestUtilities.evaluateString;
import static testutil.TestUtilities.parseString; import static testutil.TestUtilities.parseString;
public class LISTTest extends SymbolAndFunctionCleaner { public class ListTest extends SymbolAndFunctionCleaner {
@Test @Test
public void listWithNoArguments() { public void listWithNoArguments() {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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