Add modulo function

This commit is contained in:
Mike Cifelli 2018-01-12 21:02:29 -05:00
parent 89b4c0804a
commit 6a4d19517e
7 changed files with 169 additions and 7 deletions

View File

@ -5,7 +5,7 @@ import sexpression.SExpression;
public abstract class LispFunction {
public abstract SExpression call(Cons argList);
public abstract SExpression call(Cons argumentList);
public boolean isArgumentListEvaluated() {
return true;

View File

@ -0,0 +1,45 @@
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

@ -26,6 +26,7 @@ import function.builtin.cons.LIST;
import function.builtin.cons.REST;
import function.builtin.math.DIVIDE;
import function.builtin.math.MINUS;
import function.builtin.math.MODULO;
import function.builtin.math.MULTIPLY;
import function.builtin.math.PLUS;
import function.builtin.predicate.ATOM;
@ -88,6 +89,7 @@ public class FunctionTable {
allBuiltIns.add(LISTP.class);
allBuiltIns.add(LOAD.class);
allBuiltIns.add(MINUS.class);
allBuiltIns.add(MODULO.class);
allBuiltIns.add(MULTIPLY.class);
allBuiltIns.add(NULL.class);
allBuiltIns.add(OR.class);

View File

@ -14,7 +14,7 @@ public class LispFunctionTest {
LispFunction lispFunction = new LispFunction() {
@Override
public SExpression call(Cons argList) {
public SExpression call(Cons argumentList) {
return null;
}
};

View File

@ -14,7 +14,7 @@ public class LispSpecialFunctionTest {
LispFunction lispFunction = new LispSpecialFunction() {
@Override
public SExpression call(Cons argList) {
public SExpression call(Cons argumentList) {
return null;
}
};

View File

@ -0,0 +1,115 @@
package function.builtin.math;
import static testutil.TestUtilities.assertSExpressionsMatch;
import static testutil.TestUtilities.evaluateString;
import org.junit.Test;
import function.ArgumentValidator.BadArgumentTypeException;
import function.ArgumentValidator.TooFewArgumentsException;
import function.ArgumentValidator.TooManyArgumentsException;
import function.builtin.math.MODULO.ModulusNotPositiveException;
import sexpression.LispNumber;
import testutil.SymbolAndFunctionCleaner;
public class MODULOTest extends SymbolAndFunctionCleaner {
@Test
public void mod() {
String input = "(mod 5 3)";
assertSExpressionsMatch(new LispNumber("2"), evaluateString(input));
}
@Test
public void modulo() {
String input = "(modulo 11 7)";
assertSExpressionsMatch(new LispNumber("4"), evaluateString(input));
}
@Test
public void moduloSymbol() {
String input = "(% 8 5)";
assertSExpressionsMatch(new LispNumber("3"), evaluateString(input));
}
@Test
public void dividendGreaterThanDivisor() {
String input = "(mod 21 19)";
assertSExpressionsMatch(new LispNumber("2"), evaluateString(input));
}
@Test
public void dividendLessThanDivisor() {
String input = "(mod 5 239)";
assertSExpressionsMatch(new LispNumber("5"), evaluateString(input));
}
@Test
public void dividendEqualToDivisor() {
String input = "(mod 5 5)";
assertSExpressionsMatch(new LispNumber("0"), evaluateString(input));
}
@Test
public void dividendMultipleOfDivisor() {
String input = "(mod 20 5)";
assertSExpressionsMatch(new LispNumber("0"), evaluateString(input));
}
@Test
public void divisorOfOne() {
String input = "(mod 5 1)";
assertSExpressionsMatch(new LispNumber("0"), evaluateString(input));
}
@Test
public void dividendOfZero() {
String input = "(mod 0 2309)";
assertSExpressionsMatch(new LispNumber("0"), evaluateString(input));
}
@Test
public void negativeDividend() {
String input = "(mod -23 25)";
assertSExpressionsMatch(new LispNumber("2"), evaluateString(input));
}
@Test(expected = ModulusNotPositiveException.class)
public void divisorOfZero() {
String input = "(mod 5 0)";
assertSExpressionsMatch(new LispNumber("0"), evaluateString(input));
}
@Test(expected = ModulusNotPositiveException.class)
public void negativeDivisor() {
String input = "(mod 5 -10)";
assertSExpressionsMatch(new LispNumber("0"), evaluateString(input));
}
@Test(expected = BadArgumentTypeException.class)
public void modWithNonNumber() {
evaluateString("(mod 'a 'b)");
}
@Test(expected = TooFewArgumentsException.class)
public void modWithTooFewArguments() {
evaluateString("(mod 1)");
}
@Test(expected = TooManyArgumentsException.class)
public void modWithTooManyArguments() {
evaluateString("(mod 1 2 3)");
}
}

View File

@ -34,7 +34,7 @@ public class FunctionTableTest {
public GoodFunction(String name) {}
@Override
public SExpression call(Cons argList) {
public SExpression call(Cons argumentList) {
return NIL;
}
}
@ -43,7 +43,7 @@ public class FunctionTableTest {
public static class BadFunction extends LispFunction {
@Override
public SExpression call(Cons argList) {
public SExpression call(Cons argumentList) {
return NIL;
}
}
@ -51,7 +51,7 @@ public class FunctionTableTest {
public static class UglyFunction extends LispFunction {
@Override
public SExpression call(Cons argList) {
public SExpression call(Cons argumentList) {
return NIL;
}
}
@ -60,7 +60,7 @@ public class FunctionTableTest {
return new LispFunction() {
@Override
public SExpression call(Cons argList) {
public SExpression call(Cons argumentList) {
return T;
}
};