Perform TCO on numerous functions
This commit is contained in:
		
							parent
							
								
									62b2653b2c
								
							
						
					
					
						commit
						a9c13610a2
					
				@ -1,3 +1,4 @@
 | 
				
			|||||||
 | 
					|TranscendentalLisp.Recursion||17:56:26 Sat, Nov 18, 2017|
 | 
				
			||||||
|TranscendentalLisp||16:15:14 Fri, Mar 17, 2017|
 | 
					|TranscendentalLisp||16:15:14 Fri, Mar 17, 2017|
 | 
				
			||||||
|TranscendentalLisp.Macros||10:10:15 Mon, Mar 13, 2017|
 | 
					|TranscendentalLisp.Macros||10:10:15 Mon, Mar 13, 2017|
 | 
				
			||||||
|TranscendentalLisp.MacroTests||10:07:00 Mon, Mar 13, 2017|
 | 
					|TranscendentalLisp.MacroTests||10:07:00 Mon, Mar 13, 2017|
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										17
									
								
								fitnesse/FitNesseRoot/TranscendentalLisp/Recursion.wiki
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								fitnesse/FitNesseRoot/TranscendentalLisp/Recursion.wiki
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					---
 | 
				
			||||||
 | 
					Test
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					Test recursion capabilities of various functions.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					| script                | lisp interpreter fixture                              |
 | 
				
			||||||
 | 
					| show  | evaluate text | (load "lisp/random/list-builder.lisp")                |
 | 
				
			||||||
 | 
					| check | evaluate text | (setq big-list (list-doubler '(1 1 1 1 1 1 1 1) 11))  | =~/1\)$/ |
 | 
				
			||||||
 | 
					| check | evaluate text | (length big-list)                                     | 16384    |
 | 
				
			||||||
 | 
					| check | evaluate text | (length (apply 'list big-list))                       | 16384    |
 | 
				
			||||||
 | 
					| check | evaluate text | (apply '/ big-list)                                   | 1        |
 | 
				
			||||||
 | 
					| check | evaluate text | (apply '* big-list)                                   | 1        |
 | 
				
			||||||
 | 
					| check | evaluate text | (apply '+ big-list)                                   | 16384    |
 | 
				
			||||||
 | 
					| check | evaluate text | (apply '- big-list)                                   | -16382   |
 | 
				
			||||||
 | 
					| check | evaluate text | (apply '= big-list)                                   | T        |
 | 
				
			||||||
 | 
					| check | evaluate text | (apply '> (decreasing-list 0 10000))                  | T        |
 | 
				
			||||||
 | 
					| check | evaluate text | (apply '< (increasing-list 10000 10000))              | T        |
 | 
				
			||||||
@ -3,3 +3,17 @@
 | 
				
			|||||||
(defun list-doubler (seed times-to-double)
 | 
					(defun list-doubler (seed times-to-double)
 | 
				
			||||||
  (if (< times-to-double 1) seed
 | 
					  (if (< times-to-double 1) seed
 | 
				
			||||||
   (recur (append seed seed) (- times-to-double 1))))
 | 
					   (recur (append seed seed) (- times-to-double 1))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(defun decreasing-list (end size)
 | 
				
			||||||
 | 
					  (decreasing-list-tail (list end) (+ end 1) size))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(defun decreasing-list-tail (seed end size)
 | 
				
			||||||
 | 
					  (if (< size 1) seed
 | 
				
			||||||
 | 
					    (recur (cons (+ (car seed) 1) seed) (+ end 1) (- size 1))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(defun increasing-list (end size)
 | 
				
			||||||
 | 
					  (increasing-list-tail (list end) (+ end 1) size))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(defun increasing-list-tail (seed end size)
 | 
				
			||||||
 | 
					  (if (< size 1) seed
 | 
				
			||||||
 | 
					    (recur (cons (- (car seed) 1) seed) (- end 1) (- size 1))))
 | 
				
			||||||
 | 
				
			|||||||
@ -1,11 +0,0 @@
 | 
				
			|||||||
(load "../lang/functions.lisp")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(defun build (n lst)
 | 
					 | 
				
			||||||
  (if (= n 0) lst
 | 
					 | 
				
			||||||
    (build (- n 1) (cons (car lst) lst))))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(defun build2 (n lst)
 | 
					 | 
				
			||||||
  (if (= n 0) lst
 | 
					 | 
				
			||||||
    (build2 (- n 1) (build 200 lst))))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(length (build2 200 (build2 200 (build2 200 (build2 200 '(1 1 1 1 0 0 0 0)))))) 
 | 
					 | 
				
			||||||
@ -1,11 +0,0 @@
 | 
				
			|||||||
(load "../lang/functions.lisp")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(defun build (n lst)
 | 
					 | 
				
			||||||
  (if (= n 0) lst
 | 
					 | 
				
			||||||
    (build (- n 1) (cons (car lst) lst))))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(defun build2 (n lst)
 | 
					 | 
				
			||||||
  (if (= n 0) lst
 | 
					 | 
				
			||||||
    (build2 (- n 1) (build 200 lst))))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(build2 200 (build2 200 (build2 200 (build2 200 '(1 1 1 1 0 0 0 0)))))
 | 
					 | 
				
			||||||
@ -25,17 +25,7 @@ public class LIST extends LispFunction {
 | 
				
			|||||||
    public Cons call(Cons argumentList) {
 | 
					    public Cons call(Cons argumentList) {
 | 
				
			||||||
        argumentValidator.validate(argumentList);
 | 
					        argumentValidator.validate(argumentList);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return callRecursive(argumentList);
 | 
					        return argumentList;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private Cons callRecursive(Cons argumentList) {
 | 
					 | 
				
			||||||
        if (argumentList.isNull())
 | 
					 | 
				
			||||||
            return NIL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        SExpression firstArgument = argumentList.getFirst();
 | 
					 | 
				
			||||||
        Cons remainingArguments = (Cons) argumentList.getRest();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return new Cons(firstArgument, callRecursive(remainingArguments));
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -2,6 +2,7 @@ package function.builtin.math;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import java.math.BigInteger;
 | 
					import java.math.BigInteger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import error.LispException;
 | 
				
			||||||
import function.ArgumentValidator;
 | 
					import function.ArgumentValidator;
 | 
				
			||||||
import function.FunctionNames;
 | 
					import function.FunctionNames;
 | 
				
			||||||
import function.LispFunction;
 | 
					import function.LispFunction;
 | 
				
			||||||
@ -25,7 +26,11 @@ public class DIVIDE extends LispFunction {
 | 
				
			|||||||
    public LispNumber call(Cons argumentList) {
 | 
					    public LispNumber call(Cons argumentList) {
 | 
				
			||||||
        argumentValidator.validate(argumentList);
 | 
					        argumentValidator.validate(argumentList);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return mathFunction.callTailRecursive(argumentList);
 | 
					        try {
 | 
				
			||||||
 | 
					            return mathFunction.callTailRecursive(argumentList).invoke();
 | 
				
			||||||
 | 
					        } catch (ArithmeticException e) {
 | 
				
			||||||
 | 
					            throw new DivideByZeroException();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private LispNumber getReciprocal(LispNumber number) {
 | 
					    private LispNumber getReciprocal(LispNumber number) {
 | 
				
			||||||
@ -36,4 +41,14 @@ public class DIVIDE extends LispFunction {
 | 
				
			|||||||
        return new LispNumber(number1.getValue().divide(number2.getValue()));
 | 
					        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";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -25,7 +25,7 @@ public class MINUS extends LispFunction {
 | 
				
			|||||||
    public LispNumber call(Cons argumentList) {
 | 
					    public LispNumber call(Cons argumentList) {
 | 
				
			||||||
        argumentValidator.validate(argumentList);
 | 
					        argumentValidator.validate(argumentList);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return mathFunction.callTailRecursive(argumentList);
 | 
					        return mathFunction.callTailRecursive(argumentList).invoke();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private LispNumber additiveInverse(LispNumber number) {
 | 
					    private LispNumber additiveInverse(LispNumber number) {
 | 
				
			||||||
 | 
				
			|||||||
@ -24,7 +24,7 @@ public class MULTIPLY extends LispFunction {
 | 
				
			|||||||
    public LispNumber call(Cons argumentList) {
 | 
					    public LispNumber call(Cons argumentList) {
 | 
				
			||||||
        argumentValidator.validate(argumentList);
 | 
					        argumentValidator.validate(argumentList);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return mathFunction.callTailRecursive(new Cons(ONE, argumentList));
 | 
					        return mathFunction.callTailRecursive(new Cons(ONE, argumentList)).invoke();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private LispNumber multiply(LispNumber number1, LispNumber number2) {
 | 
					    private LispNumber multiply(LispNumber number1, LispNumber number2) {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,12 @@
 | 
				
			|||||||
package function.builtin.math;
 | 
					package function.builtin.math;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import static recursion.TailCalls.done;
 | 
				
			||||||
 | 
					import static recursion.TailCalls.tailCall;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.function.BiFunction;
 | 
					import java.util.function.BiFunction;
 | 
				
			||||||
import java.util.function.Function;
 | 
					import java.util.function.Function;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import recursion.TailCall;
 | 
				
			||||||
import sexpression.Cons;
 | 
					import sexpression.Cons;
 | 
				
			||||||
import sexpression.LispNumber;
 | 
					import sexpression.LispNumber;
 | 
				
			||||||
import sexpression.SExpression;
 | 
					import sexpression.SExpression;
 | 
				
			||||||
@ -18,13 +22,13 @@ class MathFunction {
 | 
				
			|||||||
        this.multipleValueOperation = multipleValueOperation;
 | 
					        this.multipleValueOperation = multipleValueOperation;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public LispNumber callTailRecursive(Cons argumentList) {
 | 
					    public TailCall<LispNumber> callTailRecursive(Cons argumentList) {
 | 
				
			||||||
        Cons remainingArguments = (Cons) argumentList.getRest();
 | 
					        Cons remainingArguments = (Cons) argumentList.getRest();
 | 
				
			||||||
        SExpression firstArgument = argumentList.getFirst();
 | 
					        SExpression firstArgument = argumentList.getFirst();
 | 
				
			||||||
        LispNumber number1 = (LispNumber) firstArgument;
 | 
					        LispNumber number1 = (LispNumber) firstArgument;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (remainingArguments.isNull())
 | 
					        if (remainingArguments.isNull())
 | 
				
			||||||
            return singleValueOperation.apply(number1);
 | 
					            return done(singleValueOperation.apply(number1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        SExpression secondArgument = remainingArguments.getFirst();
 | 
					        SExpression secondArgument = remainingArguments.getFirst();
 | 
				
			||||||
        LispNumber number2 = (LispNumber) secondArgument;
 | 
					        LispNumber number2 = (LispNumber) secondArgument;
 | 
				
			||||||
@ -32,9 +36,9 @@ class MathFunction {
 | 
				
			|||||||
        SExpression remainingNumbers = remainingArguments.getRest();
 | 
					        SExpression remainingNumbers = remainingArguments.getRest();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (remainingNumbers.isNull())
 | 
					        if (remainingNumbers.isNull())
 | 
				
			||||||
            return operationResult;
 | 
					            return done(operationResult);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return callTailRecursive(new Cons(operationResult, remainingNumbers));
 | 
					        return tailCall(() -> callTailRecursive(new Cons(operationResult, remainingNumbers)));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -24,7 +24,7 @@ public class PLUS extends LispFunction {
 | 
				
			|||||||
    public LispNumber call(Cons argumentList) {
 | 
					    public LispNumber call(Cons argumentList) {
 | 
				
			||||||
        argumentValidator.validate(argumentList);
 | 
					        argumentValidator.validate(argumentList);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return mathFunction.callTailRecursive(new Cons(ZERO, argumentList));
 | 
					        return mathFunction.callTailRecursive(new Cons(ZERO, argumentList)).invoke();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private LispNumber add(LispNumber number1, LispNumber number2) {
 | 
					    private LispNumber add(LispNumber number1, LispNumber number2) {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,11 +1,14 @@
 | 
				
			|||||||
package function.builtin.predicate;
 | 
					package function.builtin.predicate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import static recursion.TailCalls.done;
 | 
				
			||||||
 | 
					import static recursion.TailCalls.tailCall;
 | 
				
			||||||
import static sexpression.Nil.NIL;
 | 
					import static sexpression.Nil.NIL;
 | 
				
			||||||
import static sexpression.Symbol.T;
 | 
					import static sexpression.Symbol.T;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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.SExpression;
 | 
					import sexpression.SExpression;
 | 
				
			||||||
@ -25,14 +28,14 @@ public class NUMERIC_EQUAL extends LispFunction {
 | 
				
			|||||||
    public SExpression call(Cons argumentList) {
 | 
					    public SExpression call(Cons argumentList) {
 | 
				
			||||||
        argumentValidator.validate(argumentList);
 | 
					        argumentValidator.validate(argumentList);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return callTailRecursive(argumentList);
 | 
					        return callTailRecursive(argumentList).invoke();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private SExpression callTailRecursive(Cons argumentList) {
 | 
					    private TailCall<SExpression> callTailRecursive(Cons argumentList) {
 | 
				
			||||||
        Cons remainingArguments = (Cons) argumentList.getRest();
 | 
					        Cons remainingArguments = (Cons) argumentList.getRest();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (remainingArguments.isNull())
 | 
					        if (remainingArguments.isNull())
 | 
				
			||||||
            return T;
 | 
					            return done(T);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        SExpression firstArgument = argumentList.getFirst();
 | 
					        SExpression firstArgument = argumentList.getFirst();
 | 
				
			||||||
        LispNumber number1 = (LispNumber) firstArgument;
 | 
					        LispNumber number1 = (LispNumber) firstArgument;
 | 
				
			||||||
@ -40,9 +43,9 @@ public class NUMERIC_EQUAL extends LispFunction {
 | 
				
			|||||||
        LispNumber number2 = (LispNumber) secondArgument;
 | 
					        LispNumber number2 = (LispNumber) secondArgument;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!isEqual(number1, number2))
 | 
					        if (!isEqual(number1, number2))
 | 
				
			||||||
            return NIL;
 | 
					            return done(NIL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return callTailRecursive(remainingArguments);
 | 
					        return tailCall(() -> callTailRecursive(remainingArguments));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private boolean isEqual(LispNumber number1, LispNumber number2) {
 | 
					    private boolean isEqual(LispNumber number1, LispNumber number2) {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,11 +1,14 @@
 | 
				
			|||||||
package function.builtin.predicate;
 | 
					package function.builtin.predicate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import static recursion.TailCalls.done;
 | 
				
			||||||
 | 
					import static recursion.TailCalls.tailCall;
 | 
				
			||||||
import static sexpression.Nil.NIL;
 | 
					import static sexpression.Nil.NIL;
 | 
				
			||||||
import static sexpression.Symbol.T;
 | 
					import static sexpression.Symbol.T;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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.SExpression;
 | 
					import sexpression.SExpression;
 | 
				
			||||||
@ -25,14 +28,14 @@ public class NUMERIC_GREATER extends LispFunction {
 | 
				
			|||||||
    public SExpression call(Cons argumentList) {
 | 
					    public SExpression call(Cons argumentList) {
 | 
				
			||||||
        argumentValidator.validate(argumentList);
 | 
					        argumentValidator.validate(argumentList);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return callTailRecursive(argumentList);
 | 
					        return callTailRecursive(argumentList).invoke();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private SExpression callTailRecursive(Cons argumentList) {
 | 
					    private TailCall<SExpression> callTailRecursive(Cons argumentList) {
 | 
				
			||||||
        Cons remainingArguments = (Cons) argumentList.getRest();
 | 
					        Cons remainingArguments = (Cons) argumentList.getRest();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (remainingArguments.isNull())
 | 
					        if (remainingArguments.isNull())
 | 
				
			||||||
            return T;
 | 
					            return done(T);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        SExpression firstArgument = argumentList.getFirst();
 | 
					        SExpression firstArgument = argumentList.getFirst();
 | 
				
			||||||
        SExpression secondArgument = remainingArguments.getFirst();
 | 
					        SExpression secondArgument = remainingArguments.getFirst();
 | 
				
			||||||
@ -40,9 +43,9 @@ public class NUMERIC_GREATER extends LispFunction {
 | 
				
			|||||||
        LispNumber number2 = (LispNumber) secondArgument;
 | 
					        LispNumber number2 = (LispNumber) secondArgument;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!isFirstGreater(number1, number2))
 | 
					        if (!isFirstGreater(number1, number2))
 | 
				
			||||||
            return NIL;
 | 
					            return done(NIL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return callTailRecursive(remainingArguments);
 | 
					        return tailCall(() -> callTailRecursive(remainingArguments));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private boolean isFirstGreater(LispNumber number1, LispNumber number2) {
 | 
					    private boolean isFirstGreater(LispNumber number1, LispNumber number2) {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,11 +1,14 @@
 | 
				
			|||||||
package function.builtin.predicate;
 | 
					package function.builtin.predicate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import static recursion.TailCalls.done;
 | 
				
			||||||
 | 
					import static recursion.TailCalls.tailCall;
 | 
				
			||||||
import static sexpression.Nil.NIL;
 | 
					import static sexpression.Nil.NIL;
 | 
				
			||||||
import static sexpression.Symbol.T;
 | 
					import static sexpression.Symbol.T;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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.SExpression;
 | 
					import sexpression.SExpression;
 | 
				
			||||||
@ -25,14 +28,14 @@ public class NUMERIC_LESS extends LispFunction {
 | 
				
			|||||||
    public SExpression call(Cons argumentList) {
 | 
					    public SExpression call(Cons argumentList) {
 | 
				
			||||||
        argumentValidator.validate(argumentList);
 | 
					        argumentValidator.validate(argumentList);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return callTailRecursive(argumentList);
 | 
					        return callTailRecursive(argumentList).invoke();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private SExpression callTailRecursive(Cons argumentList) {
 | 
					    private TailCall<SExpression> callTailRecursive(Cons argumentList) {
 | 
				
			||||||
        Cons remainingArguments = (Cons) argumentList.getRest();
 | 
					        Cons remainingArguments = (Cons) argumentList.getRest();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (remainingArguments.isNull())
 | 
					        if (remainingArguments.isNull())
 | 
				
			||||||
            return T;
 | 
					            return done(T);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        SExpression firstArgument = argumentList.getFirst();
 | 
					        SExpression firstArgument = argumentList.getFirst();
 | 
				
			||||||
        SExpression secondArgument = remainingArguments.getFirst();
 | 
					        SExpression secondArgument = remainingArguments.getFirst();
 | 
				
			||||||
@ -40,9 +43,9 @@ public class NUMERIC_LESS extends LispFunction {
 | 
				
			|||||||
        LispNumber number2 = (LispNumber) secondArgument;
 | 
					        LispNumber number2 = (LispNumber) secondArgument;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!isFirstLesser(number1, number2))
 | 
					        if (!isFirstLesser(number1, number2))
 | 
				
			||||||
            return NIL;
 | 
					            return done(NIL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return callTailRecursive(remainingArguments);
 | 
					        return tailCall(() -> callTailRecursive(remainingArguments));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private boolean isFirstLesser(LispNumber number1, LispNumber number2) {
 | 
					    private boolean isFirstLesser(LispNumber number1, LispNumber number2) {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,6 @@
 | 
				
			|||||||
package function.builtin.math;
 | 
					package function.builtin.math;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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;
 | 
				
			||||||
import static testutil.TestUtilities.parseString;
 | 
					import static testutil.TestUtilities.parseString;
 | 
				
			||||||
@ -8,6 +9,7 @@ import org.junit.Test;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import function.ArgumentValidator.BadArgumentTypeException;
 | 
					import function.ArgumentValidator.BadArgumentTypeException;
 | 
				
			||||||
import function.ArgumentValidator.TooFewArgumentsException;
 | 
					import function.ArgumentValidator.TooFewArgumentsException;
 | 
				
			||||||
 | 
					import function.builtin.math.DIVIDE.DivideByZeroException;
 | 
				
			||||||
import testutil.SymbolAndFunctionCleaner;
 | 
					import testutil.SymbolAndFunctionCleaner;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class DIVIDETest extends SymbolAndFunctionCleaner {
 | 
					public class DIVIDETest extends SymbolAndFunctionCleaner {
 | 
				
			||||||
@ -64,4 +66,14 @@ public class DIVIDETest extends SymbolAndFunctionCleaner {
 | 
				
			|||||||
        evaluateString("(/)");
 | 
					        evaluateString("(/)");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test(expected = DivideByZeroException.class)
 | 
				
			||||||
 | 
					    public void divideByZero() {
 | 
				
			||||||
 | 
					        evaluateString("(/ 2 0)");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    public void divideByZeroException_HasCorrectAttributes() {
 | 
				
			||||||
 | 
					        assertIsErrorWithMessage(new DivideByZeroException());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user