Add more advanced lisp objects
Added a class to compute compound interest. An alias for FUNCALL has been added: CALL Refactored some acceptance tests to load code from files.
This commit is contained in:
		
							parent
							
								
									aa13394548
								
							
						
					
					
						commit
						77a341a1a7
					
				| @ -4,18 +4,7 @@ Test | |||||||
| An object with multiple methods. | An object with multiple methods. | ||||||
| 
 | 
 | ||||||
| | script                | lisp interpreter fixture | | | script                | lisp interpreter fixture | | ||||||
| | show | evaluate text |!- | | show  | evaluate text | (load "lisp/object/multiple-methods.lisp") | | ||||||
| 
 |  | ||||||
| (defun counter-class () |  | ||||||
|   (let ((counter 0)) |  | ||||||
|     (lambda (msg) |  | ||||||
|       (case msg |  | ||||||
|         ((:inc) |  | ||||||
|           (setq counter (+ counter 1))) |  | ||||||
|         ((:dec) |  | ||||||
|           (setq counter (- counter 1))))))) |  | ||||||
| 
 |  | ||||||
|                                                        -!| |  | ||||||
| | show  | evaluate text | (setq my-counter (counter-class))          | | | show  | evaluate text | (setq my-counter (counter-class))          | | ||||||
| | check | evaluate text | (funcall my-counter :inc)                  | 1 | | | check | evaluate text | (funcall my-counter :inc)                  | 1 | | ||||||
| | check | evaluate text | (funcall my-counter :inc)                  | 2 | | | check | evaluate text | (funcall my-counter :inc)                  | 2 | | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ Test | |||||||
| Shows object composition, a default method, and two different ways of referencing objects. | Shows object composition, a default method, and two different ways of referencing objects. | ||||||
| 
 | 
 | ||||||
| | script                | lisp interpreter fixture                 | | | script                | lisp interpreter fixture                 | | ||||||
| | check | evaluate text | (load "lisp/object/fruit-counter.lisp")  | T    | | | check | evaluate text | (load "lisp/object/composition.lisp")    | T    | | ||||||
| | check | evaluate text | (my-fruits :inc-apples)                  | 1    | | | check | evaluate text | (my-fruits :inc-apples)                  | 1    | | ||||||
| | check | evaluate text | (my-fruits :inc-apples)                  | 2    | | | check | evaluate text | (my-fruits :inc-apples)                  | 2    | | ||||||
| | check | evaluate text | (funcall my-fruits2 :dec-bananas)        | 9999 | | | check | evaluate text | (funcall my-fruits2 :dec-bananas)        | 9999 | | ||||||
|  | |||||||
| @ -5,22 +5,7 @@ Shows the usage of a static variable. | |||||||
| ''"Let Over Lambda Over Let Over Lambda"'' | ''"Let Over Lambda Over Let Over Lambda"'' | ||||||
| 
 | 
 | ||||||
| | script | lisp interpreter fixture | | | script | lisp interpreter fixture | | ||||||
| | show   | evaluate text | !- | | show   | evaluate text | (load "lisp/object/static.lisp")  | | ||||||
| 
 |  | ||||||
| (let ((direction 'up)) |  | ||||||
|   (defun toggle-counter-direction () |  | ||||||
|     (setq direction |  | ||||||
|           (if (eq direction 'up) |  | ||||||
|             'down |  | ||||||
|             'up))) |  | ||||||
| 
 |  | ||||||
| (defun counter-class () |  | ||||||
|     (let ((counter 0)) |  | ||||||
|       (lambda () |  | ||||||
|         (if (eq direction 'up) |  | ||||||
|           (setq counter (+ counter 1)) |  | ||||||
|           (setq counter (- counter 1))))))) |  | ||||||
|                                                            -!| |  | ||||||
| | show   | evaluate text | (setq my-counter (counter-class)) | | | show   | evaluate text | (setq my-counter (counter-class)) | | ||||||
| | check  | evaluate text | (funcall my-counter)              | 1 | | | check  | evaluate text | (funcall my-counter)              | 1 | | ||||||
| | check  | evaluate text | (funcall my-counter)              | 2 | | | check  | evaluate text | (funcall my-counter)              | 2 | | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
|  | |LispInterpreter.MultipleMethodObject||16:50:19 Mon, Mar 06, 2017| | ||||||
|  | |LispInterpreter.ObjectComposition||16:35:10 Mon, Mar 06, 2017| | ||||||
|  | |LispInterpreter.StaticVariable||16:33:23 Mon, Mar 06, 2017| | ||||||
| |LispInterpreter.LexicalClosures||12:38:02 Mon, Mar 06, 2017| | |LispInterpreter.LexicalClosures||12:38:02 Mon, Mar 06, 2017| | ||||||
| |LispInterpreter.ObjectComposition||12:30:58 Mon, Mar 06, 2017| |  | ||||||
| |LispInterpreter.StaticVariable||12:30:28 Mon, Mar 06, 2017| |  | ||||||
| |LispInterpreter.MultipleMethodObject||12:28:58 Mon, Mar 06, 2017| |  | ||||||
| |LispInterpreter.SuiteSetUp||12:20:29 Mon, Mar 06, 2017| | |LispInterpreter.SuiteSetUp||12:20:29 Mon, Mar 06, 2017| | ||||||
| |LispInterpreter.SuiteTearDown||12:17:37 Mon, Mar 06, 2017| | |LispInterpreter.SuiteTearDown||12:17:37 Mon, Mar 06, 2017| | ||||||
| |LispInterpreter.SetUp||12:17:15 Mon, Mar 06, 2017| | |LispInterpreter.SetUp||12:17:15 Mon, Mar 06, 2017| | ||||||
|  | |||||||
							
								
								
									
										80
									
								
								lisp/finance/interest-compounder-test.lisp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								lisp/finance/interest-compounder-test.lisp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,80 @@ | |||||||
|  | (load "../unit/unit-test.lisp") | ||||||
|  | (load "interest-compounder.lisp") | ||||||
|  | 
 | ||||||
|  | (unit | ||||||
|  |   (let ((compounder)) | ||||||
|  |     (list | ||||||
|  | 
 | ||||||
|  |       (defun principal-initialized () | ||||||
|  |         (setf compounder (interest-compounder 1000 0)) | ||||||
|  |         (assert= 1000 (funcall compounder :get-principal))) | ||||||
|  | 
 | ||||||
|  |       (defun interest-rate-initialized () | ||||||
|  |         (setf compounder (interest-compounder 0 10)) | ||||||
|  |         (assert= 10 (funcall compounder :get-interest-rate))) | ||||||
|  | 
 | ||||||
|  |       (defun many-years-with-no-interest-rate () | ||||||
|  |         (setf compounder (interest-compounder 1000 0)) | ||||||
|  |         (funcall compounder :move-forward-years 83) | ||||||
|  |         (assert= 1000 (funcall compounder :get-principal))) | ||||||
|  | 
 | ||||||
|  |       (defun no-years-with-positive-interest-rate () | ||||||
|  |         (setf compounder (interest-compounder 1000 10)) | ||||||
|  |         (assert= 1000 (funcall compounder :get-principal))) | ||||||
|  | 
 | ||||||
|  |       (defun one-year-with-positive-interest-rate () | ||||||
|  |         (setf compounder (interest-compounder 100000 5)) | ||||||
|  |         (funcall compounder :move-forward-one-year) | ||||||
|  |         (assert= 105000 (funcall compounder :get-principal))) | ||||||
|  | 
 | ||||||
|  |       (defun two-years-with-positive-interest-rate () | ||||||
|  |         (setf compounder (interest-compounder 100000 5)) | ||||||
|  |         (funcall compounder :move-forward-one-year) | ||||||
|  |         (funcall compounder :move-forward-one-year) | ||||||
|  |         (assert= 110250 (funcall compounder :get-principal))) | ||||||
|  | 
 | ||||||
|  |       (defun three-years-with-positive-interest-rate () | ||||||
|  |         (setf compounder (interest-compounder 100000 5)) | ||||||
|  |         (funcall compounder :move-forward-years 3) | ||||||
|  |         (assert= 115763 (funcall compounder :get-principal))) | ||||||
|  | 
 | ||||||
|  |       (defun four-years-with-positive-interest-rate () | ||||||
|  |         (setf compounder (interest-compounder 100000 5)) | ||||||
|  |         (funcall compounder :move-forward-years 4) | ||||||
|  |         (assert= 121551 (funcall compounder :get-principal))) | ||||||
|  | 
 | ||||||
|  |       (defun one-year-with-negative-interest-rate () | ||||||
|  |         (setf compounder (interest-compounder 100000 -5)) | ||||||
|  |         (funcall compounder :move-forward-years 1) | ||||||
|  |         (assert= 95000 (funcall compounder :get-principal))) | ||||||
|  | 
 | ||||||
|  |       (defun two-years-with-negative-interest-rate () | ||||||
|  |         (setf compounder (interest-compounder 100000 -5)) | ||||||
|  |         (funcall compounder :move-forward-years 2) | ||||||
|  |         (assert= 90250 (funcall compounder :get-principal))) | ||||||
|  | 
 | ||||||
|  |       (defun three-years-with-negative-interest-rate () | ||||||
|  |         (setf compounder (interest-compounder 100000 -5)) | ||||||
|  |         (funcall compounder :move-forward-years 3) | ||||||
|  |         (assert= 85737 (funcall compounder :get-principal))) | ||||||
|  | 
 | ||||||
|  |       (defun four-years-with-negative-interest-rate () | ||||||
|  |         (setf compounder (interest-compounder 100000 -5)) | ||||||
|  |         (funcall compounder :move-forward-years 4) | ||||||
|  |         (assert= 81450 (funcall compounder :get-principal))) | ||||||
|  | 
 | ||||||
|  |       (defun negative-number-of-years-does-nothing () | ||||||
|  |         (setf compounder (interest-compounder 100000 5)) | ||||||
|  |         (funcall compounder :move-forward-years -4) | ||||||
|  |         (assert= 100000 (funcall compounder :get-principal)) | ||||||
|  |         (funcall compounder :move-forward-years 1) | ||||||
|  |         (funcall compounder :move-forward-years -4) | ||||||
|  |         (assert= 105000 (funcall compounder :get-principal))) | ||||||
|  | 
 | ||||||
|  |       (defun zero-number-of-years-does-nothing () | ||||||
|  |         (setf compounder (interest-compounder 100000 5)) | ||||||
|  |         (funcall compounder :move-forward-years 0) | ||||||
|  |         (assert= 100000 (funcall compounder :get-principal)) | ||||||
|  |         (funcall compounder :move-forward-years 1) | ||||||
|  |         (funcall compounder :move-forward-years 0) | ||||||
|  |         (assert= 105000 (funcall compounder :get-principal)))))) | ||||||
							
								
								
									
										39
									
								
								lisp/finance/interest-compounder.lisp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								lisp/finance/interest-compounder.lisp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,39 @@ | |||||||
|  | (load "../lang/dlambda.lisp") | ||||||
|  | 
 | ||||||
|  | (defun interest-compounder (initial-principal initial-interest-rate) | ||||||
|  |   (let ((private) (public) | ||||||
|  |         (principal initial-principal) | ||||||
|  |         (interest-rate initial-interest-rate)) | ||||||
|  | 
 | ||||||
|  |     (setf private | ||||||
|  |       (eval | ||||||
|  |         (dlambda | ||||||
|  | 
 | ||||||
|  |           (:percent-of-number (n percentage) | ||||||
|  |             (if (> percentage 0) | ||||||
|  |               (/ (+ (* n percentage) 50) 100) | ||||||
|  |               (/ (- (* n percentage) 50) 100))) | ||||||
|  | 
 | ||||||
|  |           (:compound-interest (years) | ||||||
|  |             (if (> years 0) | ||||||
|  |               (progn | ||||||
|  |                 (setf principal | ||||||
|  |                   (+ principal | ||||||
|  |                     (call private :percent-of-number principal interest-rate))) | ||||||
|  |                 (call private :compound-interest (- years 1)))))))) | ||||||
|  | 
 | ||||||
|  |     (setf public | ||||||
|  |       (eval | ||||||
|  |         (dlambda | ||||||
|  | 
 | ||||||
|  |           (:get-principal () | ||||||
|  |             principal) | ||||||
|  | 
 | ||||||
|  |           (:get-interest-rate () | ||||||
|  |             interest-rate) | ||||||
|  | 
 | ||||||
|  |           (:move-forward-one-year () | ||||||
|  |             (call private :compound-interest 1)) | ||||||
|  | 
 | ||||||
|  |           (:move-forward-years (years) | ||||||
|  |             (call private :compound-interest years))))))) | ||||||
| @ -30,51 +30,39 @@ | |||||||
|         (:inc-apples () |         (:inc-apples () | ||||||
|           (funcall apple-counter :inc)) |           (funcall apple-counter :inc)) | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|         (:dec-apples () |         (:dec-apples () | ||||||
|           (funcall apple-counter :dec)) |           (funcall apple-counter :dec)) | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|         (:get-apples () |         (:get-apples () | ||||||
|           (funcall apple-counter :get)) |           (funcall apple-counter :get)) | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|         (:set-apples (value) |         (:set-apples (value) | ||||||
|           (funcall apple-counter :set value)) |           (funcall apple-counter :set value)) | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|         (:inc-bananas () |         (:inc-bananas () | ||||||
|           (funcall banana-counter :inc)) |           (funcall banana-counter :inc)) | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|         (:dec-bananas () |         (:dec-bananas () | ||||||
|           (funcall banana-counter :dec)) |           (funcall banana-counter :dec)) | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|         (:get-bananas () |         (:get-bananas () | ||||||
|           (funcall banana-counter :get)) |           (funcall banana-counter :get)) | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|         (:set-bananas (value) |         (:set-bananas (value) | ||||||
|           (funcall banana-counter :set value)) |           (funcall banana-counter :set value)) | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|         (:inc-coconuts () |         (:inc-coconuts () | ||||||
|           (funcall coconut-counter :inc)) |           (funcall coconut-counter :inc)) | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|         (:dec-coconuts () |         (:dec-coconuts () | ||||||
|           (funcall coconut-counter :dec)) |           (funcall coconut-counter :dec)) | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|         (:get-coconuts () |         (:get-coconuts () | ||||||
|           (funcall coconut-counter :get)) |           (funcall coconut-counter :get)) | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|         (:set-coconuts (value) |         (:set-coconuts (value) | ||||||
|           (funcall coconut-counter :set value)) |           (funcall coconut-counter :set value)) | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|         (t (&rest arguments) |         (t (&rest arguments) | ||||||
|           (list |           (list | ||||||
|             (list 'apples   (funcall apple-counter :get)) |             (list 'apples   (funcall apple-counter :get)) | ||||||
							
								
								
									
										6
									
								
								lisp/object/multiple-methods.lisp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								lisp/object/multiple-methods.lisp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | |||||||
|  | (defun counter-class () | ||||||
|  |   (let ((counter 0)) | ||||||
|  |     (lambda (msg) | ||||||
|  |       (case msg | ||||||
|  |         ((:inc) (setq counter (+ counter 1))) | ||||||
|  |         ((:dec) (setq counter (- counter 1))))))) | ||||||
							
								
								
									
										13
									
								
								lisp/object/static.lisp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								lisp/object/static.lisp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | |||||||
|  | (let ((direction 'up)) | ||||||
|  |   (defun toggle-counter-direction () | ||||||
|  |     (setq direction | ||||||
|  |           (if (eq direction 'up) | ||||||
|  |             'down | ||||||
|  |             'up))) | ||||||
|  | 
 | ||||||
|  |   (defun counter-class () | ||||||
|  |     (let ((counter 0)) | ||||||
|  |       (lambda () | ||||||
|  |         (if (eq direction 'up) | ||||||
|  |           (setq counter (+ counter 1)) | ||||||
|  |           (setq counter (- counter 1))))))) | ||||||
| @ -6,7 +6,7 @@ import static function.builtin.cons.LIST.makeList; | |||||||
| import function.*; | import function.*; | ||||||
| import sexpression.*; | import sexpression.*; | ||||||
| 
 | 
 | ||||||
| @FunctionNames({ "FUNCALL" }) | @FunctionNames({ "FUNCALL", "CALL" }) | ||||||
| public class FUNCALL extends LispFunction { | public class FUNCALL extends LispFunction { | ||||||
| 
 | 
 | ||||||
|     private ArgumentValidator argumentValidator; |     private ArgumentValidator argumentValidator; | ||||||
|  | |||||||
| @ -24,7 +24,8 @@ public class LET extends LispSpecialFunction { | |||||||
|         this.variableDefinitionListValidator.setEveryArgumentExpectedType(Cons.class); |         this.variableDefinitionListValidator.setEveryArgumentExpectedType(Cons.class); | ||||||
| 
 | 
 | ||||||
|         this.pairValidator = new ArgumentValidator("LET|pair|"); |         this.pairValidator = new ArgumentValidator("LET|pair|"); | ||||||
|         this.pairValidator.setExactNumberOfArguments(2); |         this.pairValidator.setMinimumNumberOfArguments(1); | ||||||
|  |         this.pairValidator.setMaximumNumberOfArguments(2); | ||||||
|         this.pairValidator.setFirstArgumentExpectedType(Symbol.class); |         this.pairValidator.setFirstArgumentExpectedType(Symbol.class); | ||||||
| 
 | 
 | ||||||
|         this.executionContext = ExecutionContext.getInstance(); |         this.executionContext = ExecutionContext.getInstance(); | ||||||
|  | |||||||
| @ -26,6 +26,13 @@ public class FUNCALLTester { | |||||||
|         assertSExpressionsMatch(parseString("6"), evaluateString(input)); |         assertSExpressionsMatch(parseString("6"), evaluateString(input)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     @Test | ||||||
|  |     public void callWithNumbers() { | ||||||
|  |         String input = "(call '+ 1 2 3)"; | ||||||
|  | 
 | ||||||
|  |         assertSExpressionsMatch(parseString("6"), evaluateString(input)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void funcallWithUserDefinedFunction() { |     public void funcallWithUserDefinedFunction() { | ||||||
|         String defineUserFunction = "(defun x (n m) (+ n m))"; |         String defineUserFunction = "(defun x (n m) (+ n m))"; | ||||||
|  | |||||||
| @ -7,7 +7,7 @@ import org.junit.*; | |||||||
| 
 | 
 | ||||||
| import function.ArgumentValidator.*; | import function.ArgumentValidator.*; | ||||||
| import function.builtin.EVAL.UndefinedSymbolException; | import function.builtin.EVAL.UndefinedSymbolException; | ||||||
| import sexpression.LispNumber; | import sexpression.*; | ||||||
| import table.ExecutionContext; | import table.ExecutionContext; | ||||||
| 
 | 
 | ||||||
| public class LETTester { | public class LETTester { | ||||||
| @ -42,6 +42,13 @@ public class LETTester { | |||||||
|         assertSExpressionsMatch(NIL, evaluateString(input)); |         assertSExpressionsMatch(NIL, evaluateString(input)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     @Test | ||||||
|  |     public void letWithSymbolsOnly_SetsValuesToNil() { | ||||||
|  |         String input = "(let ((x) (y)) (list x y))"; | ||||||
|  | 
 | ||||||
|  |         assertSExpressionsMatch(new Cons(NIL, new Cons(NIL, NIL)), evaluateString(input)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void letWithSetf_DoesNotAlterGlobalVariable() { |     public void letWithSetf_DoesNotAlterGlobalVariable() { | ||||||
|         String before = "(setf x 22)"; |         String before = "(setf x 22)"; | ||||||
| @ -122,7 +129,7 @@ public class LETTester { | |||||||
| 
 | 
 | ||||||
|     @Test(expected = TooFewArgumentsException.class) |     @Test(expected = TooFewArgumentsException.class) | ||||||
|     public void letWithTooFewItemsInPair() { |     public void letWithTooFewItemsInPair() { | ||||||
|         evaluateString("(let ((a)))"); |         evaluateString("(let (()))"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Test(expected = TooManyArgumentsException.class) |     @Test(expected = TooManyArgumentsException.class) | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user