Started major refactoring of several built in functions
This commit is contained in:
		
							parent
							
								
									35ef281733
								
							
						
					
					
						commit
						217c215efe
					
				
							
								
								
									
										51
									
								
								src/function/FunctionTable.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/function/FunctionTable.java
									
									
									
									
									
										Normal file
									
								
							@ -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;
 | 
					package function.builtin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import static function.FunctionTable.functionTable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.text.MessageFormat;
 | 
				
			||||||
import java.util.HashMap;
 | 
					import java.util.HashMap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import function.LispFunction;
 | 
					import error.LispException;
 | 
				
			||||||
import function.builtin.cons.*;
 | 
					import function.*;
 | 
				
			||||||
import function.builtin.math.*;
 | 
					import function.builtin.cons.LIST;
 | 
				
			||||||
import function.builtin.predicate.*;
 | 
					 | 
				
			||||||
import function.builtin.special.*;
 | 
					import function.builtin.special.*;
 | 
				
			||||||
import sexpression.*;
 | 
					import sexpression.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class EVAL extends LispFunction {
 | 
					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() {
 | 
					    public static HashMap<String, LispFunction> getFunctionTable() {
 | 
				
			||||||
        return functionTable;
 | 
					        return functionTable;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static LispFunction lookupFunction(String functionName) {
 | 
					 | 
				
			||||||
        return functionTable.get(functionName);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public static LispFunction lookupFunctionOrLambda(SExpression functionExpression) {
 | 
					    public static LispFunction lookupFunctionOrLambda(SExpression functionExpression) {
 | 
				
			||||||
        LispFunction function = lookupFunction(functionExpression.toString());
 | 
					        LispFunction function = lookupFunction(functionExpression.toString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -66,13 +26,17 @@ public class EVAL extends LispFunction {
 | 
				
			|||||||
        return function;
 | 
					        return function;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static LispFunction lookupFunction(String functionName) {
 | 
				
			||||||
 | 
					        return functionTable.get(functionName);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static LispFunction createLambdaFunction(SExpression lambdaExpression) {
 | 
					    private static LispFunction createLambdaFunction(SExpression lambdaExpression) {
 | 
				
			||||||
        if (lambdaExpression.functionp())
 | 
					        if (lambdaExpression.functionp())
 | 
				
			||||||
            return ((LambdaExpression) lambdaExpression).getFunction();
 | 
					            return ((LambdaExpression) lambdaExpression).getFunction();
 | 
				
			||||||
        else if (LAMBDA.isLambdaExpression(lambdaExpression))
 | 
					        else if (LAMBDA.isLambdaExpression(lambdaExpression))
 | 
				
			||||||
            return LAMBDA.createFunction((Cons) lambdaExpression);
 | 
					            return LAMBDA.createFunction((Cons) lambdaExpression);
 | 
				
			||||||
        else
 | 
					        else
 | 
				
			||||||
            throw new RuntimeException("undefined function " + lambdaExpression);
 | 
					            throw new UndefinedFunctionException(lambdaExpression);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static SExpression lookupSymbol(String symbolName) {
 | 
					    public static SExpression lookupSymbol(String symbolName) {
 | 
				
			||||||
@ -102,94 +66,98 @@ public class EVAL extends LispFunction {
 | 
				
			|||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static SExpression eval(SExpression sexpr) {
 | 
					    public static SExpression eval(SExpression sExpression) {
 | 
				
			||||||
        Cons expList = LIST.makeList(sexpr);
 | 
					        Cons argumentList = LIST.makeList(sExpression);
 | 
				
			||||||
        EVAL evalFunction = new EVAL();
 | 
					        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) {
 | 
					    public EVAL() {
 | 
				
			||||||
        // retrieve the number of arguments passed to EVAL
 | 
					        this.argumentValidator = new ArgumentValidator("EVAL");
 | 
				
			||||||
        int argListLength = LENGTH.getLength(argList);
 | 
					        this.argumentValidator.setExactNumberOfArguments(1);
 | 
				
			||||||
 | 
					 | 
				
			||||||
        // 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);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        SExpression arg = argList.getCar();
 | 
					    public SExpression call(Cons argumentList) {
 | 
				
			||||||
 | 
					        argumentValidator.validate(argumentList);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (arg.listp()) {
 | 
					        SExpression argument = argumentList.getCar();
 | 
				
			||||||
            if (arg.consp()) {
 | 
					
 | 
				
			||||||
                return evaluateList((Cons) arg);
 | 
					        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()) {
 | 
					            if (symbolValue != null)
 | 
				
			||||||
            SExpression symbolValue = lookupSymbol(arg.toString());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (symbolValue != null) {
 | 
					 | 
				
			||||||
                return symbolValue;
 | 
					                return symbolValue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            throw new UndefinedSymbolException(argument);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            throw new RuntimeException("variable " + arg + " has no value");
 | 
					        return argument; // NUMBER or STRING
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return arg; // 'arg' is a NUMBER or a STRING
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private SExpression evaluateList(Cons list) {
 | 
					    private SExpression evaluateList(Cons list) {
 | 
				
			||||||
        SExpression car = list.getCar();
 | 
					        SExpression functionName = list.getCar();
 | 
				
			||||||
        SExpression cdr = list.getCdr();
 | 
					        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
 | 
					        Cons argumentList = (Cons) arguments;
 | 
				
			||||||
        if (cdr.listp()) {
 | 
					 | 
				
			||||||
            Cons args = (Cons) cdr;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // make sure the list of arguments is not dotted
 | 
					        if (function.evaluateArguments())
 | 
				
			||||||
            if (isDotted(args)) {
 | 
					            argumentList = evaluateArgList(argumentList);
 | 
				
			||||||
                throw new RuntimeException("argument list given to " + car + " is dotted: " + list);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // determine if we should evaluate the arguments that will be
 | 
					        return function.call(argumentList);
 | 
				
			||||||
            // 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);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private Cons evaluateArgList(Cons arguments) {
 | 
					    private Cons evaluateArgList(Cons arguments) {
 | 
				
			||||||
        if (arguments.nullp()) {
 | 
					        if (arguments.nullp())
 | 
				
			||||||
            return Nil.getInstance();
 | 
					            return Nil.getInstance();
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        SExpression car = eval(arguments.getCar());
 | 
					        SExpression car = eval(arguments.getCar());
 | 
				
			||||||
        SExpression cdr = arguments.getCdr();
 | 
					        SExpression cdr = arguments.getCdr();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (cdr.listp()) {
 | 
					 | 
				
			||||||
        return new Cons(car, evaluateArgList((Cons) cdr));
 | 
					        return new Cons(car, evaluateArgList((Cons) cdr));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // remove any parameters found after a dot (put here in case the check
 | 
					    public static class UndefinedFunctionException extends LispException {
 | 
				
			||||||
        // for a dotted parameter list is not done prior to this call)
 | 
					
 | 
				
			||||||
        return new Cons(car, Nil.getInstance());
 | 
					        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;
 | 
					package function.builtin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import function.LispFunction;
 | 
					import function.*;
 | 
				
			||||||
import function.builtin.cons.LENGTH;
 | 
					 | 
				
			||||||
import sexpression.*;
 | 
					import sexpression.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class EXIT extends LispFunction {
 | 
					public class EXIT extends LispFunction {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // The number of arguments that EXIT takes.
 | 
					    private ArgumentValidator argumentValidator;
 | 
				
			||||||
    private static final int NUM_ARGS = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public SExpression call(Cons argList) {
 | 
					    public EXIT() {
 | 
				
			||||||
        // retrieve the number of arguments passed to EXIT
 | 
					        this.argumentValidator = new ArgumentValidator("EXIT");
 | 
				
			||||||
        int argListLength = LENGTH.getLength(argList);
 | 
					        this.argumentValidator.setMaximumNumberOfArguments(0);
 | 
				
			||||||
 | 
					 | 
				
			||||||
        // 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 SExpression call(Cons argumentList) {
 | 
				
			||||||
 | 
					        argumentValidator.validate(argumentList);
 | 
				
			||||||
        System.exit(0);
 | 
					        System.exit(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return null;
 | 
					        return null;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -4,48 +4,47 @@ import java.util.HashMap;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import function.*;
 | 
					import function.*;
 | 
				
			||||||
import function.builtin.EVAL;
 | 
					import function.builtin.EVAL;
 | 
				
			||||||
 | 
					import function.builtin.cons.LIST;
 | 
				
			||||||
import sexpression.*;
 | 
					import sexpression.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class DEFUN extends LispFunction {
 | 
					public class DEFUN extends LispFunction {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private ArgumentValidator argumentValidator;
 | 
					    private ArgumentValidator argumentValidator;
 | 
				
			||||||
 | 
					    private ArgumentValidator lambdaListIsListValidator;
 | 
				
			||||||
 | 
					    private ArgumentValidator lambdaListValidator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public DEFUN() {
 | 
					    public DEFUN() {
 | 
				
			||||||
        this.argumentValidator = new ArgumentValidator("DEFUN");
 | 
					        this.argumentValidator = new ArgumentValidator("DEFUN");
 | 
				
			||||||
        this.argumentValidator.setMinimumNumberOfArguments(3);
 | 
					        this.argumentValidator.setMinimumNumberOfArguments(3);
 | 
				
			||||||
        this.argumentValidator.setFirstArgumentExpectedType(Symbol.class);
 | 
					        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) {
 | 
					    public SExpression call(Cons argumentList) {
 | 
				
			||||||
        argumentValidator.validate(argumentList);
 | 
					        argumentValidator.validate(argumentList);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Cons cdr = (Cons) argumentList.getCdr();
 | 
					        Cons remainingArguments = (Cons) argumentList.getCdr();
 | 
				
			||||||
        SExpression name = argumentList.getCar(); // name of the function
 | 
					        SExpression functionName = argumentList.getCar();
 | 
				
			||||||
        SExpression cadr = cdr.getCar();
 | 
					        SExpression secondArgument = remainingArguments.getCar();
 | 
				
			||||||
 | 
					        lambdaListIsListValidator.validate(LIST.makeList(secondArgument));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // make sure the list of arguments (lambda list) is a proper list
 | 
					        Cons lambdaList = (Cons) secondArgument;
 | 
				
			||||||
        if (!cadr.listp()) {
 | 
					        lambdaListValidator.validate(lambdaList);
 | 
				
			||||||
            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 functionBody = (Cons) remainingArguments.getCdr();
 | 
				
			||||||
        HashMap<String, LispFunction> functionTable = EVAL.getFunctionTable();
 | 
					        HashMap<String, LispFunction> functionTable = EVAL.getFunctionTable();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // give a warning if this function has already been defined
 | 
					        if (functionTable.containsKey(functionName.toString()))
 | 
				
			||||||
        if (functionTable.containsKey(name.toString())) {
 | 
					            System.out.println("WARNING: redefining function " + functionName.toString());
 | 
				
			||||||
            System.out.println("WARNING: redefining function " + name.toString());
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // place the function in the function table
 | 
					        functionTable.put(functionName.toString(), new UserDefinedFunction(functionName.toString(), lambdaList, functionBody));
 | 
				
			||||||
        functionTable.put(name.toString(), new UserDefinedFunction(name.toString(), lambdaList, body));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return name;
 | 
					        return functionName;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public boolean evaluateArguments() {
 | 
					    public boolean evaluateArguments() {
 | 
				
			||||||
 | 
				
			|||||||
@ -5,19 +5,8 @@ import function.builtin.*;
 | 
				
			|||||||
import function.builtin.cons.LENGTH;
 | 
					import function.builtin.cons.LENGTH;
 | 
				
			||||||
import sexpression.*;
 | 
					import sexpression.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * <code>LAMBDA</code> represents the LAMBDA form in Lisp.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
public class LAMBDA extends LispFunction {
 | 
					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) {
 | 
					    public static boolean isLambdaExpression(SExpression sexpr) {
 | 
				
			||||||
        if (sexpr.consp()) {
 | 
					        if (sexpr.consp()) {
 | 
				
			||||||
            SExpression first = ((Cons) sexpr).getCar();
 | 
					            SExpression first = ((Cons) sexpr).getCar();
 | 
				
			||||||
@ -28,16 +17,6 @@ public class LAMBDA extends LispFunction {
 | 
				
			|||||||
        return false;
 | 
					        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) {
 | 
					    public static UserDefinedFunction createFunction(Cons lexpr) {
 | 
				
			||||||
        LAMBDA lambda = new LAMBDA();
 | 
					        LAMBDA lambda = new LAMBDA();
 | 
				
			||||||
        SExpression cdr = lexpr.getCdr();
 | 
					        SExpression cdr = lexpr.getCdr();
 | 
				
			||||||
@ -86,11 +65,6 @@ public class LAMBDA extends LispFunction {
 | 
				
			|||||||
        return new LambdaExpression(lexpr, function);
 | 
					        return new LambdaExpression(lexpr, function);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Determine if the arguments passed to this Lisp function should be evaluated.
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @return <code>false</code>
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public boolean evaluateArguments() {
 | 
					    public boolean evaluateArguments() {
 | 
				
			||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										92
									
								
								test/function/builtin/EVALTester.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								test/function/builtin/EVALTester.java
									
									
									
									
									
										Normal file
									
								
							@ -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("()"));
 | 
					        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)
 | 
					    @Test(expected = BadArgumentTypeException.class)
 | 
				
			||||||
    public void testDefunWithNonSymbolName() {
 | 
					    public void testDefunWithNonSymbolName() {
 | 
				
			||||||
        evaluateString("(defun 1 () ())");
 | 
					        evaluateString("(defun 1 () ())");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test(expected = BadArgumentTypeException.class)
 | 
				
			||||||
 | 
					    public void testDefunWithBadLambdaList() {
 | 
				
			||||||
 | 
					        evaluateString("(defun x a ())");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Test(expected = TooFewArgumentsException.class)
 | 
					    @Test(expected = TooFewArgumentsException.class)
 | 
				
			||||||
    public void testApplyWithTooFewArguments() {
 | 
					    public void testApplyWithTooFewArguments() {
 | 
				
			||||||
        evaluateString("(defun 1 ())");
 | 
					        evaluateString("(defun x ())");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										35
									
								
								test/function/builtin/special/QUOTETester.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								test/function/builtin/special/QUOTETester.java
									
									
									
									
									
										Normal file
									
								
							@ -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
	
	Block a user