Resolves #12 - &rest keyword added to lambda lists
Added unit tests and cleaned up some code The setup for acceptance tests now cleans up the environment
This commit is contained in:
		
							parent
							
								
									42191ec69d
								
							
						
					
					
						commit
						64e18fe076
					
				| @ -3,6 +3,7 @@ package fixture; | |||||||
| import java.io.*; | import java.io.*; | ||||||
| 
 | 
 | ||||||
| import interpreter.*; | import interpreter.*; | ||||||
|  | import table.*; | ||||||
| 
 | 
 | ||||||
| public class LispInterpreterFixture { | public class LispInterpreterFixture { | ||||||
| 
 | 
 | ||||||
| @ -20,6 +21,11 @@ public class LispInterpreterFixture { | |||||||
|         interpreter = builder.build(); |         interpreter = builder.build(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public void reset() { | ||||||
|  |         FunctionTable.reset(); | ||||||
|  |         ExecutionContext.getInstance().clearContext(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public String evaluate(String input) throws IOException { |     public String evaluate(String input) throws IOException { | ||||||
|         interpreter.setInput(new ByteArrayInputStream(input.getBytes()), "fitnesse"); |         interpreter.setInput(new ByteArrayInputStream(input.getBytes()), "fitnesse"); | ||||||
|         interpreter.interpret(); |         interpreter.interpret(); | ||||||
|  | |||||||
| @ -5,7 +5,7 @@ Test | |||||||
| | #    | Object with multiple methods                        | | | #    | Object with multiple methods                        | | ||||||
| | show | evaluate  |!- | | show | evaluate  |!- | ||||||
| 
 | 
 | ||||||
| (defun counter-class-multi () | (defun counter-class () | ||||||
|   (let ((counter 0)) |   (let ((counter 0)) | ||||||
|     (lambda (msg) |     (lambda (msg) | ||||||
|       (case msg |       (case msg | ||||||
| @ -15,7 +15,7 @@ Test | |||||||
|           (setq counter (- counter 1))))))) |           (setq counter (- counter 1))))))) | ||||||
| 
 | 
 | ||||||
|                                                            -!| |                                                            -!| | ||||||
| | show  | evaluate | (setq my-counter (counter-class-multi)) | | | show  | evaluate | (setq my-counter (counter-class))       | | ||||||
| | check | evaluate | (funcall my-counter :inc)               | 1 | | | check | evaluate | (funcall my-counter :inc)               | 1 | | ||||||
| | check | evaluate | (funcall my-counter :inc)               | 2 | | | check | evaluate | (funcall my-counter :inc)               | 2 | | ||||||
| | check | evaluate | (funcall my-counter :inc)               | 3 | | | check | evaluate | (funcall my-counter :inc)               | 3 | | ||||||
|  | |||||||
| @ -3,3 +3,6 @@ Test | |||||||
| --- | --- | ||||||
| | import  | | | import  | | ||||||
| | fixture | | | fixture | | ||||||
|  | 
 | ||||||
|  | | script | lisp interpreter fixture | | ||||||
|  | | reset                             | | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| |LispInterpreter.MultipleMethodClosure||11:52:11 Tue, Feb 28, 2017| | |LispInterpreter.MultipleMethodClosure||11:04:53 Wed, Mar 01, 2017| | ||||||
|  | |LispInterpreter.SetUp||11:04:36 Wed, Mar 01, 2017| | ||||||
| |LispInterpreter.LexicalClosures||12:10:13 Mon, Feb 27, 2017| | |LispInterpreter.LexicalClosures||12:10:13 Mon, Feb 27, 2017| | ||||||
| |LispInterpreter.TestClosure||11:24:27 Mon, Feb 27, 2017| | |LispInterpreter.TestClosure||11:24:27 Mon, Feb 27, 2017| | ||||||
| |LispInterpreter.TestOne||09:26:08 Fri, Feb 24, 2017| | |LispInterpreter.TestOne||09:26:08 Fri, Feb 24, 2017| | ||||||
|  | |||||||
| @ -2,13 +2,17 @@ package function; | |||||||
| 
 | 
 | ||||||
| import static function.builtin.EVAL.eval; | import static function.builtin.EVAL.eval; | ||||||
| 
 | 
 | ||||||
|  | import java.text.MessageFormat; | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| 
 | 
 | ||||||
|  | import error.LispException; | ||||||
| import sexpression.*; | import sexpression.*; | ||||||
| import table.*; | import table.*; | ||||||
| 
 | 
 | ||||||
| public class UserDefinedFunction extends LispFunction { | public class UserDefinedFunction extends LispFunction { | ||||||
| 
 | 
 | ||||||
|  |     private static final String KEYWORD_REST = "&REST"; | ||||||
|  | 
 | ||||||
|     private String name; |     private String name; | ||||||
|     private Cons body; |     private Cons body; | ||||||
|     private Cons lambdaExpression; |     private Cons lambdaExpression; | ||||||
| @ -16,6 +20,8 @@ public class UserDefinedFunction extends LispFunction { | |||||||
|     private SymbolTable functionScope; |     private SymbolTable functionScope; | ||||||
|     private ArrayList<String> formalParameters; |     private ArrayList<String> formalParameters; | ||||||
|     private ArgumentValidator argumentValidator; |     private ArgumentValidator argumentValidator; | ||||||
|  |     private String keywordRestParameter; | ||||||
|  |     private boolean isKeywordRest; | ||||||
| 
 | 
 | ||||||
|     public UserDefinedFunction(String name, Cons lambdaList, Cons body) { |     public UserDefinedFunction(String name, Cons lambdaList, Cons body) { | ||||||
|         this.name = name; |         this.name = name; | ||||||
| @ -23,12 +29,55 @@ public class UserDefinedFunction extends LispFunction { | |||||||
|         this.lambdaExpression = new Cons(new Symbol(name), new Cons(lambdaList, body)); |         this.lambdaExpression = new Cons(new Symbol(name), new Cons(lambdaList, body)); | ||||||
|         this.executionContext = ExecutionContext.getInstance(); |         this.executionContext = ExecutionContext.getInstance(); | ||||||
|         this.functionScope = executionContext.getScope(); |         this.functionScope = executionContext.getScope(); | ||||||
|  |         this.keywordRestParameter = null; | ||||||
|  |         this.isKeywordRest = false; | ||||||
| 
 | 
 | ||||||
|         for (this.formalParameters = new ArrayList<>(); lambdaList.isCons(); lambdaList = (Cons) lambdaList.getRest()) |         createFormalParameters(lambdaList); | ||||||
|             this.formalParameters.add(lambdaList.getFirst().toString()); |         setupArgumentValidator(); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|         this.argumentValidator = new ArgumentValidator(this.name); |     private void createFormalParameters(Cons lambdaList) { | ||||||
|         this.argumentValidator.setExactNumberOfArguments(this.formalParameters.size()); |         for (formalParameters = new ArrayList<>(); lambdaList.isCons(); lambdaList = advanceCons(lambdaList)) { | ||||||
|  |             String parameter = lambdaList.getFirst().toString(); | ||||||
|  | 
 | ||||||
|  |             if (isKeywordRest(parameter)) | ||||||
|  |                 lambdaList = extractKeywordRestParameter(lambdaList); | ||||||
|  |             else | ||||||
|  |                 formalParameters.add(parameter); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private Cons advanceCons(Cons cons) { | ||||||
|  |         return (Cons) cons.getRest(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private boolean isKeywordRest(String parameter) { | ||||||
|  |         return KEYWORD_REST.equals(parameter); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private Cons extractKeywordRestParameter(Cons lambdaList) { | ||||||
|  |         isKeywordRest = true; | ||||||
|  |         lambdaList = advanceCons(lambdaList); | ||||||
|  |         keywordRestParameter = lambdaList.getFirst().toString(); | ||||||
|  |         lambdaList = advanceCons(lambdaList); | ||||||
|  | 
 | ||||||
|  |         if (containsMoreParameters(lambdaList)) | ||||||
|  |             throw new IllegalKeywordRestPositionException(this.name, lambdaList); | ||||||
|  | 
 | ||||||
|  |         return lambdaList; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private boolean containsMoreParameters(Cons lambdaList) { | ||||||
|  |         return lambdaList.isCons(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void setupArgumentValidator() { | ||||||
|  |         argumentValidator = new ArgumentValidator(this.name); | ||||||
|  | 
 | ||||||
|  |         if (isKeywordRest) | ||||||
|  |             argumentValidator.setMinimumNumberOfArguments(this.formalParameters.size()); | ||||||
|  |         else | ||||||
|  |             argumentValidator.setExactNumberOfArguments(this.formalParameters.size()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public SExpression call(Cons argumentList) { |     public SExpression call(Cons argumentList) { | ||||||
| @ -57,6 +106,9 @@ public class UserDefinedFunction extends LispFunction { | |||||||
|             argumentList = (Cons) argumentList.getRest(); |             argumentList = (Cons) argumentList.getRest(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         if (isKeywordRest) | ||||||
|  |             executionScope.put(keywordRestParameter, argumentList); | ||||||
|  | 
 | ||||||
|         return executionScope; |         return executionScope; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -73,4 +125,22 @@ public class UserDefinedFunction extends LispFunction { | |||||||
|         return lambdaExpression; |         return lambdaExpression; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public static class IllegalKeywordRestPositionException extends LispException { | ||||||
|  | 
 | ||||||
|  |         private static final long serialVersionUID = 1L; | ||||||
|  |         private String functionName; | ||||||
|  |         private Cons parameters; | ||||||
|  | 
 | ||||||
|  |         public IllegalKeywordRestPositionException(String functionName, Cons parameters) { | ||||||
|  |             this.functionName = functionName; | ||||||
|  |             this.parameters = parameters; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         @Override | ||||||
|  |         public String getMessage() { | ||||||
|  |             return MessageFormat.format("unexpected parameters following ''&rest'' in definition of {0}: {1}", | ||||||
|  |                                         functionName, parameters); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -35,4 +35,5 @@ public class ExecutionContext { | |||||||
| 
 | 
 | ||||||
|         return null; |         return null; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -13,26 +13,6 @@ import function.builtin.special.*; | |||||||
| 
 | 
 | ||||||
| public class FunctionTable { | public class FunctionTable { | ||||||
| 
 | 
 | ||||||
|     public static LispFunction lookupFunction(String functionName) { |  | ||||||
|         return getTable().get(functionName); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public static boolean isAlreadyDefined(String functionName) { |  | ||||||
|         return getTable().containsKey(functionName); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public static void defineFunction(String functionName, LispFunction function) { |  | ||||||
|         getTable().put(functionName, function); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public static void reset() { |  | ||||||
|         getUniqueInstance().initializeFunctionTable(allBuiltIns); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     static void reset(Set<Class<? extends LispFunction>> builtIns) { |  | ||||||
|         getUniqueInstance().initializeFunctionTable(builtIns); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private static Set<Class<? extends LispFunction>> allBuiltIns = new HashSet<>(); |     private static Set<Class<? extends LispFunction>> allBuiltIns = new HashSet<>(); | ||||||
| 
 | 
 | ||||||
|     static { |     static { | ||||||
| @ -75,6 +55,26 @@ public class FunctionTable { | |||||||
|         allBuiltIns.add(SYMBOL_FUNCTION.class); |         allBuiltIns.add(SYMBOL_FUNCTION.class); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public static LispFunction lookupFunction(String functionName) { | ||||||
|  |         return getTable().get(functionName); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static boolean isAlreadyDefined(String functionName) { | ||||||
|  |         return getTable().containsKey(functionName); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static void defineFunction(String functionName, LispFunction function) { | ||||||
|  |         getTable().put(functionName, function); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static void reset() { | ||||||
|  |         getUniqueInstance().initializeFunctionTable(allBuiltIns); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     static void reset(Set<Class<? extends LispFunction>> builtIns) { | ||||||
|  |         getUniqueInstance().initializeFunctionTable(builtIns); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     private static FunctionTable uniqueInstance; |     private static FunctionTable uniqueInstance; | ||||||
| 
 | 
 | ||||||
|     private static FunctionTable getUniqueInstance() { |     private static FunctionTable getUniqueInstance() { | ||||||
|  | |||||||
| @ -9,7 +9,7 @@ import sexpression.*; | |||||||
| public class LispFunctionTester { | public class LispFunctionTester { | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void testEvaluateArguments() { |     public void evaluateArguments() { | ||||||
|         LispFunction lispFunction = new LispFunction() { |         LispFunction lispFunction = new LispFunction() { | ||||||
| 
 | 
 | ||||||
|             @Override |             @Override | ||||||
|  | |||||||
							
								
								
									
										24
									
								
								test/function/LispSpecialFunctionTester.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								test/function/LispSpecialFunctionTester.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | |||||||
|  | package function; | ||||||
|  | 
 | ||||||
|  | import static org.junit.Assert.assertFalse; | ||||||
|  | 
 | ||||||
|  | import org.junit.Test; | ||||||
|  | 
 | ||||||
|  | import sexpression.*; | ||||||
|  | 
 | ||||||
|  | public class LispSpecialFunctionTester { | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void evaluateArguments() { | ||||||
|  |         LispFunction lispFunction = new LispSpecialFunction() { | ||||||
|  | 
 | ||||||
|  |             @Override | ||||||
|  |             public SExpression call(Cons argList) { | ||||||
|  |                 return null; | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         assertFalse(lispFunction.evaluateArguments()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -1,11 +1,13 @@ | |||||||
| package function; | package function; | ||||||
| 
 | 
 | ||||||
| import static org.junit.Assert.assertEquals; | import static org.junit.Assert.*; | ||||||
| import static testutil.TestUtilities.assertSExpressionsMatch; | import static testutil.TestUtilities.assertSExpressionsMatch; | ||||||
| 
 | 
 | ||||||
| import org.junit.Test; | import org.junit.Test; | ||||||
| 
 | 
 | ||||||
|  | import error.ErrorManager; | ||||||
| import function.ArgumentValidator.*; | import function.ArgumentValidator.*; | ||||||
|  | import function.UserDefinedFunction.IllegalKeywordRestPositionException; | ||||||
| import sexpression.*; | import sexpression.*; | ||||||
| 
 | 
 | ||||||
| public class UserDefinedFunctionTester { | public class UserDefinedFunctionTester { | ||||||
| @ -23,14 +25,14 @@ public class UserDefinedFunctionTester { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void testNilFunctionCall() { |     public void nilFunctionCall() { | ||||||
|         UserDefinedFunction function = createNoArgumentFunctionThatReturnsNil(); |         UserDefinedFunction function = createNoArgumentFunctionThatReturnsNil(); | ||||||
| 
 | 
 | ||||||
|         assertEquals(Nil.getInstance(), function.call(Nil.getInstance())); |         assertEquals(Nil.getInstance(), function.call(Nil.getInstance())); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void testNilFunctionToString() { |     public void nilFunctionToString() { | ||||||
|         UserDefinedFunction function = createNoArgumentFunctionThatReturnsNil(); |         UserDefinedFunction function = createNoArgumentFunctionThatReturnsNil(); | ||||||
|         Cons expected = new Cons(new Symbol(FUNCTION_NAME), |         Cons expected = new Cons(new Symbol(FUNCTION_NAME), | ||||||
|                                  new Cons(Nil.getInstance(), new Cons(Nil.getInstance(), Nil.getInstance()))); |                                  new Cons(Nil.getInstance(), new Cons(Nil.getInstance(), Nil.getInstance()))); | ||||||
| @ -63,4 +65,14 @@ public class UserDefinedFunctionTester { | |||||||
|         function.call(Nil.getInstance()); |         function.call(Nil.getInstance()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     @Test | ||||||
|  |     public void illegalKeywordRestPositionException_HasCorrectAttributes() { | ||||||
|  |         IllegalKeywordRestPositionException e = new IllegalKeywordRestPositionException(FUNCTION_NAME, | ||||||
|  |                                                                                         Nil.getInstance()); | ||||||
|  | 
 | ||||||
|  |         assertNotNull(e.getMessage()); | ||||||
|  |         assertTrue(e.getMessage().length() > 0); | ||||||
|  |         assertEquals(ErrorManager.Severity.ERROR, e.getSeverity()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -10,6 +10,7 @@ import org.junit.*; | |||||||
| import environment.RuntimeEnvironment; | import environment.RuntimeEnvironment; | ||||||
| import error.ErrorManager; | import error.ErrorManager; | ||||||
| import function.ArgumentValidator.*; | import function.ArgumentValidator.*; | ||||||
|  | import function.UserDefinedFunction.IllegalKeywordRestPositionException; | ||||||
| import table.FunctionTable; | import table.FunctionTable; | ||||||
| 
 | 
 | ||||||
| public class DEFINE_MACROTester { | public class DEFINE_MACROTester { | ||||||
| @ -130,4 +131,46 @@ public class DEFINE_MACROTester { | |||||||
|         evaluateString("(define-macro x)"); |         evaluateString("(define-macro x)"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     @Test(expected = TooFewArgumentsException.class) | ||||||
|  |     public void defineMacroAndCallWithTooFewArguments() { | ||||||
|  |         evaluateString("(define-macro x (a b))"); | ||||||
|  |         evaluateString("(x a)"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test(expected = TooManyArgumentsException.class) | ||||||
|  |     public void defineMacroAndCallWithTooManyArguments() { | ||||||
|  |         evaluateString("(define-macro x (a b))"); | ||||||
|  |         evaluateString("(x a b c)"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void defineMacroWithKeywordRestParameter() { | ||||||
|  |         evaluateString("(define-macro f (&rest x) (car x))"); | ||||||
|  |         assertSExpressionsMatch(parseString("1"), evaluateString("(f 1 2 3 4 5)")); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void defineMacroWithNormalAndKeywordRestParameter() { | ||||||
|  |         evaluateString("(define-macro f (a &rest b) (cons a b))"); | ||||||
|  |         assertSExpressionsMatch(parseString("(1 2 3 4 5)"), evaluateString("(f 1 2 3 4 5)")); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test(expected = IllegalKeywordRestPositionException.class) | ||||||
|  |     public void defineMacroWithParametersFollowingKeywordRest() { | ||||||
|  |         evaluateString("(define-macro f (a &rest b c) (cons a b))"); | ||||||
|  |         evaluateString("(f 1 2 3)"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void defineMacroWithKeywordRest_CallWithNoArguments() { | ||||||
|  |         evaluateString("(define-macro f (&rest a) (car a))"); | ||||||
|  |         assertSExpressionsMatch(parseString("nil"), evaluateString("(f)")); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test(expected = TooFewArgumentsException.class) | ||||||
|  |     public void defineMacroWithNormalAndKeywordRest_CallWithNoArguments() { | ||||||
|  |         evaluateString("(define-macro f (a &rest b) a)"); | ||||||
|  |         evaluateString("(f)"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -10,6 +10,7 @@ import org.junit.*; | |||||||
| import environment.RuntimeEnvironment; | import environment.RuntimeEnvironment; | ||||||
| import error.ErrorManager; | import error.ErrorManager; | ||||||
| import function.ArgumentValidator.*; | import function.ArgumentValidator.*; | ||||||
|  | import function.UserDefinedFunction.IllegalKeywordRestPositionException; | ||||||
| import table.FunctionTable; | import table.FunctionTable; | ||||||
| 
 | 
 | ||||||
| public class DEFUNTester { | public class DEFUNTester { | ||||||
| @ -124,4 +125,46 @@ public class DEFUNTester { | |||||||
|         evaluateString("(defun x)"); |         evaluateString("(defun x)"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     @Test(expected = TooFewArgumentsException.class) | ||||||
|  |     public void defunFunctionAndCallWithTooFewArguments() { | ||||||
|  |         evaluateString("(defun x (a b))"); | ||||||
|  |         evaluateString("(x 'a)"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test(expected = TooManyArgumentsException.class) | ||||||
|  |     public void defunFunctionAndCallWithTooManyArguments() { | ||||||
|  |         evaluateString("(defun x (a b))"); | ||||||
|  |         evaluateString("(x 'a 'b 'c)"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void defunWithKeywordRestParameter() { | ||||||
|  |         evaluateString("(defun f (&rest x) (car x))"); | ||||||
|  |         assertSExpressionsMatch(parseString("1"), evaluateString("(f 1 2 3 4 5)")); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void defunWithNormalAndKeywordRestParameter() { | ||||||
|  |         evaluateString("(defun f (a &rest b) (cons a b))"); | ||||||
|  |         assertSExpressionsMatch(parseString("(1 2 3 4 5)"), evaluateString("(f 1 2 3 4 5)")); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test(expected = IllegalKeywordRestPositionException.class) | ||||||
|  |     public void defunWithParametersFollowingKeywordRest() { | ||||||
|  |         evaluateString("(defun f (a &rest b c) (cons a b))"); | ||||||
|  |         evaluateString("(f 1 2 3)"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void defunWithKeywordRest_CallWithNoArguments() { | ||||||
|  |         evaluateString("(defun f (&rest a) (car a))"); | ||||||
|  |         assertSExpressionsMatch(parseString("nil"), evaluateString("(f)")); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test(expected = TooFewArgumentsException.class) | ||||||
|  |     public void defunWithNormalAndKeywordRest_CallWithNoArguments() { | ||||||
|  |         evaluateString("(defun f (a &rest b) a)"); | ||||||
|  |         evaluateString("(f)"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user