Started major refactoring of several built in functions
This commit is contained in:
parent
35ef281733
commit
217c215efe
|
@ -0,0 +1,51 @@
|
|||
package function;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import function.builtin.*;
|
||||
import function.builtin.cons.*;
|
||||
import function.builtin.math.*;
|
||||
import function.builtin.predicate.*;
|
||||
import function.builtin.special.*;
|
||||
|
||||
public class FunctionTable {
|
||||
|
||||
public static final HashMap<String, LispFunction> functionTable = new HashMap<String, LispFunction>();
|
||||
|
||||
static {
|
||||
functionTable.put("*", new MULTIPLY());
|
||||
functionTable.put("+", new PLUS());
|
||||
functionTable.put("-", new MINUS());
|
||||
functionTable.put("/", new DIVIDE());
|
||||
functionTable.put("<", new LESSP());
|
||||
functionTable.put("=", new EQUALSP());
|
||||
functionTable.put(">", new GREATERP());
|
||||
functionTable.put("APPLY", new APPLY());
|
||||
functionTable.put("ATOM", new ATOM());
|
||||
functionTable.put("CAR", new CAR());
|
||||
functionTable.put("CDR", new CDR());
|
||||
functionTable.put("COND", new COND());
|
||||
functionTable.put("CONS", new CONS());
|
||||
functionTable.put("DEFUN", new DEFUN());
|
||||
functionTable.put("EQ", new EQ());
|
||||
functionTable.put("EQUAL", new EQUAL());
|
||||
functionTable.put("EVAL", new EVAL());
|
||||
functionTable.put("EXIT", new EXIT());
|
||||
functionTable.put("FIRST", new CAR());
|
||||
functionTable.put("FUNCALL", new FUNCALL());
|
||||
functionTable.put("GREATERP", new GREATERP());
|
||||
functionTable.put("LAMBDA", new LAMBDA());
|
||||
functionTable.put("LENGTH", new LENGTH());
|
||||
functionTable.put("LET", new LET());
|
||||
functionTable.put("LIST", new LIST());
|
||||
functionTable.put("LISTP", new LISTP());
|
||||
functionTable.put("LOAD", new LOAD());
|
||||
functionTable.put("NULL", new NULL());
|
||||
functionTable.put("PRINT", new PRINT());
|
||||
functionTable.put("QUOTE", new QUOTE());
|
||||
functionTable.put("REST", new CDR());
|
||||
functionTable.put("SETF", new SETF());
|
||||
functionTable.put("SYMBOL-FUNCTION", new SYMBOL_FUNCTION());
|
||||
}
|
||||
|
||||
}
|
|
@ -1,62 +1,22 @@
|
|||
package function.builtin;
|
||||
|
||||
import static function.FunctionTable.functionTable;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.HashMap;
|
||||
|
||||
import function.LispFunction;
|
||||
import function.builtin.cons.*;
|
||||
import function.builtin.math.*;
|
||||
import function.builtin.predicate.*;
|
||||
import error.LispException;
|
||||
import function.*;
|
||||
import function.builtin.cons.LIST;
|
||||
import function.builtin.special.*;
|
||||
import sexpression.*;
|
||||
|
||||
public class EVAL extends LispFunction {
|
||||
|
||||
private static HashMap<String, LispFunction> functionTable = new HashMap<String, LispFunction>();
|
||||
|
||||
static {
|
||||
functionTable.put("*", new MULTIPLY());
|
||||
functionTable.put("+", new PLUS());
|
||||
functionTable.put("-", new MINUS());
|
||||
functionTable.put("/", new DIVIDE());
|
||||
functionTable.put("<", new LESSP());
|
||||
functionTable.put("=", new EQUALSP());
|
||||
functionTable.put(">", new GREATERP());
|
||||
functionTable.put("APPLY", new APPLY());
|
||||
functionTable.put("ATOM", new ATOM());
|
||||
functionTable.put("CAR", new CAR());
|
||||
functionTable.put("CDR", new CDR());
|
||||
functionTable.put("COND", new COND());
|
||||
functionTable.put("CONS", new CONS());
|
||||
functionTable.put("DEFUN", new DEFUN());
|
||||
functionTable.put("EQ", new EQ());
|
||||
functionTable.put("EQUAL", new EQUAL());
|
||||
functionTable.put("EVAL", new EVAL());
|
||||
functionTable.put("EXIT", new EXIT());
|
||||
functionTable.put("FIRST", new CAR());
|
||||
functionTable.put("FUNCALL", new FUNCALL());
|
||||
functionTable.put("GREATERP", new GREATERP());
|
||||
functionTable.put("LAMBDA", new LAMBDA());
|
||||
functionTable.put("LENGTH", new LENGTH());
|
||||
functionTable.put("LET", new LET());
|
||||
functionTable.put("LIST", new LIST());
|
||||
functionTable.put("LISTP", new LISTP());
|
||||
functionTable.put("LOAD", new LOAD());
|
||||
functionTable.put("NULL", new NULL());
|
||||
functionTable.put("PRINT", new PRINT());
|
||||
functionTable.put("QUOTE", new QUOTE());
|
||||
functionTable.put("REST", new CDR());
|
||||
functionTable.put("SETF", new SETF());
|
||||
functionTable.put("SYMBOL-FUNCTION", new SYMBOL_FUNCTION());
|
||||
}
|
||||
|
||||
public static HashMap<String, LispFunction> getFunctionTable() {
|
||||
return functionTable;
|
||||
}
|
||||
|
||||
public static LispFunction lookupFunction(String functionName) {
|
||||
return functionTable.get(functionName);
|
||||
}
|
||||
|
||||
public static LispFunction lookupFunctionOrLambda(SExpression functionExpression) {
|
||||
LispFunction function = lookupFunction(functionExpression.toString());
|
||||
|
||||
|
@ -66,13 +26,17 @@ public class EVAL extends LispFunction {
|
|||
return function;
|
||||
}
|
||||
|
||||
public static LispFunction lookupFunction(String functionName) {
|
||||
return functionTable.get(functionName);
|
||||
}
|
||||
|
||||
private static LispFunction createLambdaFunction(SExpression lambdaExpression) {
|
||||
if (lambdaExpression.functionp())
|
||||
return ((LambdaExpression) lambdaExpression).getFunction();
|
||||
else if (LAMBDA.isLambdaExpression(lambdaExpression))
|
||||
return LAMBDA.createFunction((Cons) lambdaExpression);
|
||||
else
|
||||
throw new RuntimeException("undefined function " + lambdaExpression);
|
||||
throw new UndefinedFunctionException(lambdaExpression);
|
||||
}
|
||||
|
||||
public static SExpression lookupSymbol(String symbolName) {
|
||||
|
@ -102,94 +66,98 @@ public class EVAL extends LispFunction {
|
|||
return true;
|
||||
}
|
||||
|
||||
public static SExpression eval(SExpression sexpr) {
|
||||
Cons expList = LIST.makeList(sexpr);
|
||||
EVAL evalFunction = new EVAL();
|
||||
public static SExpression eval(SExpression sExpression) {
|
||||
Cons argumentList = LIST.makeList(sExpression);
|
||||
EVAL eval = new EVAL();
|
||||
|
||||
return evalFunction.call(expList);
|
||||
return eval.call(argumentList);
|
||||
}
|
||||
|
||||
private static final int NUM_ARGS = 1;
|
||||
private ArgumentValidator argumentValidator;
|
||||
|
||||
public SExpression call(Cons argList) {
|
||||
// retrieve the number of arguments passed to EVAL
|
||||
int argListLength = LENGTH.getLength(argList);
|
||||
|
||||
// make sure we have received the proper number of arguments
|
||||
if (argListLength != NUM_ARGS) {
|
||||
Cons originalSExpr = new Cons(new Symbol("EVAL"), argList);
|
||||
String errMsg = "too " + ((argListLength > NUM_ARGS) ? "many" : "few") + " arguments given to EVAL: "
|
||||
+ originalSExpr;
|
||||
|
||||
throw new RuntimeException(errMsg);
|
||||
public EVAL() {
|
||||
this.argumentValidator = new ArgumentValidator("EVAL");
|
||||
this.argumentValidator.setExactNumberOfArguments(1);
|
||||
}
|
||||
|
||||
SExpression arg = argList.getCar();
|
||||
public SExpression call(Cons argumentList) {
|
||||
argumentValidator.validate(argumentList);
|
||||
|
||||
if (arg.listp()) {
|
||||
if (arg.consp()) {
|
||||
return evaluateList((Cons) arg);
|
||||
SExpression argument = argumentList.getCar();
|
||||
|
||||
if (argument.listp()) {
|
||||
if (argument.consp())
|
||||
return evaluateList((Cons) argument);
|
||||
|
||||
return argument; // NIL
|
||||
}
|
||||
|
||||
return arg; // 'arg' is NIL
|
||||
}
|
||||
if (argument.symbolp()) {
|
||||
SExpression symbolValue = lookupSymbol(argument.toString());
|
||||
|
||||
if (arg.symbolp()) {
|
||||
SExpression symbolValue = lookupSymbol(arg.toString());
|
||||
|
||||
if (symbolValue != null) {
|
||||
if (symbolValue != null)
|
||||
return symbolValue;
|
||||
|
||||
throw new UndefinedSymbolException(argument);
|
||||
}
|
||||
|
||||
throw new RuntimeException("variable " + arg + " has no value");
|
||||
}
|
||||
|
||||
return arg; // 'arg' is a NUMBER or a STRING
|
||||
return argument; // NUMBER or STRING
|
||||
}
|
||||
|
||||
private SExpression evaluateList(Cons list) {
|
||||
SExpression car = list.getCar();
|
||||
SExpression cdr = list.getCdr();
|
||||
SExpression functionName = list.getCar();
|
||||
SExpression arguments = list.getCdr();
|
||||
LispFunction function = lookupFunctionOrLambda(functionName);
|
||||
|
||||
LispFunction function = lookupFunctionOrLambda(car);
|
||||
ArgumentValidator functionListValidator = new ArgumentValidator(functionName.toString());
|
||||
functionListValidator.validate(list);
|
||||
|
||||
// make sure the list of arguments for 'function' is a list
|
||||
if (cdr.listp()) {
|
||||
Cons args = (Cons) cdr;
|
||||
Cons argumentList = (Cons) arguments;
|
||||
|
||||
// make sure the list of arguments is not dotted
|
||||
if (isDotted(args)) {
|
||||
throw new RuntimeException("argument list given to " + car + " is dotted: " + list);
|
||||
}
|
||||
if (function.evaluateArguments())
|
||||
argumentList = evaluateArgList(argumentList);
|
||||
|
||||
// determine if we should evaluate the arguments that will be
|
||||
// passed to 'function'
|
||||
if (function.evaluateArguments()) {
|
||||
args = evaluateArgList(args);
|
||||
}
|
||||
|
||||
return function.call(args);
|
||||
}
|
||||
|
||||
// the list of arguments is not a list!
|
||||
throw new RuntimeException("argument list given to " + car + " is dotted: " + list);
|
||||
return function.call(argumentList);
|
||||
}
|
||||
|
||||
private Cons evaluateArgList(Cons arguments) {
|
||||
if (arguments.nullp()) {
|
||||
if (arguments.nullp())
|
||||
return Nil.getInstance();
|
||||
}
|
||||
|
||||
SExpression car = eval(arguments.getCar());
|
||||
SExpression cdr = arguments.getCdr();
|
||||
|
||||
if (cdr.listp()) {
|
||||
return new Cons(car, evaluateArgList((Cons) cdr));
|
||||
}
|
||||
|
||||
// remove any parameters found after a dot (put here in case the check
|
||||
// for a dotted parameter list is not done prior to this call)
|
||||
return new Cons(car, Nil.getInstance());
|
||||
public static class UndefinedFunctionException extends LispException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private SExpression function;
|
||||
|
||||
public UndefinedFunctionException(SExpression function) {
|
||||
this.function = function;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return MessageFormat.format("undefined function: {0}", function);
|
||||
}
|
||||
}
|
||||
|
||||
public static class UndefinedSymbolException extends LispException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private SExpression symbol;
|
||||
|
||||
public UndefinedSymbolException(SExpression symbol) {
|
||||
this.symbol = symbol;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return MessageFormat.format("symbol {0} has no value", symbol);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,27 +1,21 @@
|
|||
package function.builtin;
|
||||
|
||||
import function.LispFunction;
|
||||
import function.builtin.cons.LENGTH;
|
||||
import function.*;
|
||||
import sexpression.*;
|
||||
|
||||
public class EXIT extends LispFunction {
|
||||
|
||||
// The number of arguments that EXIT takes.
|
||||
private static final int NUM_ARGS = 0;
|
||||
private ArgumentValidator argumentValidator;
|
||||
|
||||
public SExpression call(Cons argList) {
|
||||
// retrieve the number of arguments passed to EXIT
|
||||
int argListLength = LENGTH.getLength(argList);
|
||||
|
||||
// make sure we have received the proper number of arguments
|
||||
if (argListLength > NUM_ARGS) {
|
||||
Cons originalSExpr = new Cons(new Symbol("EXIT"), argList);
|
||||
String errMsg = "too many arguments given to EXIT: " + originalSExpr;
|
||||
|
||||
throw new RuntimeException(errMsg);
|
||||
public EXIT() {
|
||||
this.argumentValidator = new ArgumentValidator("EXIT");
|
||||
this.argumentValidator.setMaximumNumberOfArguments(0);
|
||||
}
|
||||
|
||||
public SExpression call(Cons argumentList) {
|
||||
argumentValidator.validate(argumentList);
|
||||
System.exit(0);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,48 +4,47 @@ import java.util.HashMap;
|
|||
|
||||
import function.*;
|
||||
import function.builtin.EVAL;
|
||||
import function.builtin.cons.LIST;
|
||||
import sexpression.*;
|
||||
|
||||
public class DEFUN extends LispFunction {
|
||||
|
||||
private ArgumentValidator argumentValidator;
|
||||
private ArgumentValidator lambdaListIsListValidator;
|
||||
private ArgumentValidator lambdaListValidator;
|
||||
|
||||
public DEFUN() {
|
||||
this.argumentValidator = new ArgumentValidator("DEFUN");
|
||||
this.argumentValidator.setMinimumNumberOfArguments(3);
|
||||
this.argumentValidator.setFirstArgumentExpectedType(Symbol.class);
|
||||
|
||||
this.lambdaListIsListValidator = new ArgumentValidator("DEFUN|lambda_list|");
|
||||
this.lambdaListIsListValidator.setEveryArgumentExpectedType(Cons.class);
|
||||
|
||||
this.lambdaListValidator = new ArgumentValidator("DEFUN|lambda_list|");
|
||||
this.lambdaListValidator.setEveryArgumentExpectedType(Symbol.class);
|
||||
}
|
||||
|
||||
public SExpression call(Cons argumentList) {
|
||||
argumentValidator.validate(argumentList);
|
||||
|
||||
Cons cdr = (Cons) argumentList.getCdr();
|
||||
SExpression name = argumentList.getCar(); // name of the function
|
||||
SExpression cadr = cdr.getCar();
|
||||
Cons remainingArguments = (Cons) argumentList.getCdr();
|
||||
SExpression functionName = argumentList.getCar();
|
||||
SExpression secondArgument = remainingArguments.getCar();
|
||||
lambdaListIsListValidator.validate(LIST.makeList(secondArgument));
|
||||
|
||||
// make sure the list of arguments (lambda list) is a proper list
|
||||
if (!cadr.listp()) {
|
||||
throw new RuntimeException("DEFUN: " + cadr + " is not a list");
|
||||
} else if (EVAL.isDotted((Cons) cadr)) {
|
||||
throw new RuntimeException("DEFUN: " + cadr + " is not a proper list");
|
||||
}
|
||||
|
||||
Cons lambdaList = (Cons) cadr; // lambda list of the function
|
||||
|
||||
// list of S-expressions making up the body of the function
|
||||
Cons body = (Cons) cdr.getCdr();
|
||||
Cons lambdaList = (Cons) secondArgument;
|
||||
lambdaListValidator.validate(lambdaList);
|
||||
|
||||
Cons functionBody = (Cons) remainingArguments.getCdr();
|
||||
HashMap<String, LispFunction> functionTable = EVAL.getFunctionTable();
|
||||
|
||||
// give a warning if this function has already been defined
|
||||
if (functionTable.containsKey(name.toString())) {
|
||||
System.out.println("WARNING: redefining function " + name.toString());
|
||||
}
|
||||
if (functionTable.containsKey(functionName.toString()))
|
||||
System.out.println("WARNING: redefining function " + functionName.toString());
|
||||
|
||||
// place the function in the function table
|
||||
functionTable.put(name.toString(), new UserDefinedFunction(name.toString(), lambdaList, body));
|
||||
functionTable.put(functionName.toString(), new UserDefinedFunction(functionName.toString(), lambdaList, functionBody));
|
||||
|
||||
return name;
|
||||
return functionName;
|
||||
}
|
||||
|
||||
public boolean evaluateArguments() {
|
||||
|
|
|
@ -5,19 +5,8 @@ import function.builtin.*;
|
|||
import function.builtin.cons.LENGTH;
|
||||
import sexpression.*;
|
||||
|
||||
/**
|
||||
* <code>LAMBDA</code> represents the LAMBDA form in Lisp.
|
||||
*/
|
||||
public class LAMBDA extends LispFunction {
|
||||
|
||||
/**
|
||||
* Determine if the given S-expression is a lambda expression.
|
||||
*
|
||||
* @param sexpr
|
||||
* the S-expression to test (must not be null)
|
||||
* @return <code>true</code> if <code>sexpr</code> is a valid lambda expression;
|
||||
* <code>false</code> otherwise
|
||||
*/
|
||||
public static boolean isLambdaExpression(SExpression sexpr) {
|
||||
if (sexpr.consp()) {
|
||||
SExpression first = ((Cons) sexpr).getCar();
|
||||
|
@ -28,16 +17,6 @@ public class LAMBDA extends LispFunction {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an internal representation of a user-defined function from the specified lambda
|
||||
* expression.
|
||||
*
|
||||
* @param lexpr
|
||||
* the lambda expression to create the function from (must not be null)
|
||||
* @return an internal representation of a user-defined function created from <code>lexpr</code>
|
||||
* @throws RuntimeException
|
||||
* Indicates that <code>lexpr</code> is not a valid lambda expression.
|
||||
*/
|
||||
public static UserDefinedFunction createFunction(Cons lexpr) {
|
||||
LAMBDA lambda = new LAMBDA();
|
||||
SExpression cdr = lexpr.getCdr();
|
||||
|
@ -86,11 +65,6 @@ public class LAMBDA extends LispFunction {
|
|||
return new LambdaExpression(lexpr, function);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the arguments passed to this Lisp function should be evaluated.
|
||||
*
|
||||
* @return <code>false</code>
|
||||
*/
|
||||
public boolean evaluateArguments() {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
package function.builtin;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static testutil.TestUtilities.*;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import function.ArgumentValidator.*;
|
||||
import function.builtin.EVAL.*;
|
||||
import sexpression.Nil;
|
||||
|
||||
public class EVALTester {
|
||||
|
||||
@Test
|
||||
public void testEval() {
|
||||
String input = "(eval 9)";
|
||||
|
||||
assertSExpressionsMatch(evaluateString(input), parseString("9"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvalNil() {
|
||||
String input = "(eval ())";
|
||||
|
||||
assertSExpressionsMatch(evaluateString(input), parseString("()"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLookupSymbol() {
|
||||
String symbol = ":symbol";
|
||||
assertSExpressionsMatch(EVAL.lookupSymbol(symbol), parseString(symbol));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLookupT() {
|
||||
String symbol = "T";
|
||||
assertSExpressionsMatch(EVAL.lookupSymbol(symbol), parseString(symbol));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLookupUndefinedSymbol() {
|
||||
assertNull(EVAL.lookupSymbol("undefined"));
|
||||
}
|
||||
|
||||
@Test(expected = UndefinedFunctionException.class)
|
||||
public void testEvalUndefinedFunction() {
|
||||
String input = "(funcall 'eval '(undefined))";
|
||||
|
||||
evaluateString(input);
|
||||
}
|
||||
|
||||
@Test(expected = UndefinedSymbolException.class)
|
||||
public void testEvalUndefinedSymbol() {
|
||||
String input = "(eval undefined)";
|
||||
|
||||
evaluateString(input);
|
||||
}
|
||||
|
||||
@Test(expected = DottedArgumentListException.class)
|
||||
public void testEvalWithDottedLambdaList() {
|
||||
String input = "(funcall 'eval (cons '+ 1))";
|
||||
|
||||
evaluateString(input);
|
||||
}
|
||||
|
||||
@Test(expected = TooManyArgumentsException.class)
|
||||
public void testEvalWithTooManyArguments() {
|
||||
evaluateString("(eval '1 '2 '3)");
|
||||
}
|
||||
|
||||
@Test(expected = TooFewArgumentsException.class)
|
||||
public void testEvalWithTooFewArguments() {
|
||||
evaluateString("(eval)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void undefinedFunctionException_HasMessageText() {
|
||||
UndefinedFunctionException e = new UndefinedFunctionException(Nil.getInstance());
|
||||
|
||||
assertNotNull(e.getMessage());
|
||||
assertTrue(e.getMessage().length() > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void undefinedSymbolException_HasMessageText() {
|
||||
UndefinedSymbolException e = new UndefinedSymbolException(Nil.getInstance());
|
||||
|
||||
assertNotNull(e.getMessage());
|
||||
assertTrue(e.getMessage().length() > 0);
|
||||
}
|
||||
|
||||
}
|
|
@ -16,14 +16,26 @@ public class DEFUNTester {
|
|||
assertSExpressionsMatch(evaluateString("(f)"), parseString("()"));
|
||||
}
|
||||
|
||||
@Test(expected = DottedArgumentListException.class)
|
||||
public void testDefunWithDottedLambdaList() {
|
||||
String input = "(funcall 'defun 'x (cons 'a 'b) ())";
|
||||
|
||||
evaluateString(input);
|
||||
}
|
||||
|
||||
@Test(expected = BadArgumentTypeException.class)
|
||||
public void testDefunWithNonSymbolName() {
|
||||
evaluateString("(defun 1 () ())");
|
||||
}
|
||||
|
||||
@Test(expected = BadArgumentTypeException.class)
|
||||
public void testDefunWithBadLambdaList() {
|
||||
evaluateString("(defun x a ())");
|
||||
}
|
||||
|
||||
@Test(expected = TooFewArgumentsException.class)
|
||||
public void testApplyWithTooFewArguments() {
|
||||
evaluateString("(defun 1 ())");
|
||||
evaluateString("(defun x ())");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
package function.builtin.special;
|
||||
|
||||
import static testutil.TestUtilities.*;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import function.ArgumentValidator.*;
|
||||
|
||||
public class QUOTETester {
|
||||
|
||||
@Test
|
||||
public void testQuoteSymbol() {
|
||||
String input = "'a";
|
||||
|
||||
assertSExpressionsMatch(evaluateString(input), parseString("a"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQuoteList() {
|
||||
String input = "'(l i s t)";
|
||||
|
||||
assertSExpressionsMatch(evaluateString(input), parseString("(l i s t)"));
|
||||
}
|
||||
|
||||
@Test(expected = TooFewArgumentsException.class)
|
||||
public void testQuoteWithTooFewArguments() {
|
||||
evaluateString("(quote)");
|
||||
}
|
||||
|
||||
@Test(expected = TooManyArgumentsException.class)
|
||||
public void testQuoteWithTooManyArguments() {
|
||||
evaluateString("(quote a b)");
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue