package function; import java.util.ArrayList; import function.builtin.*; import sexpression.*; import table.SymbolTable; public class UserDefinedFunction extends LispFunction { private ArgumentValidator argumentValidator; private String name; private Cons body; private Cons lambdaExpression; private SymbolTable environment; private ArrayList formalParameters; /** * Create a new user-defined function with the specified name, lambda list and body. * * @param name * the name of this user-defined function * @param lambdaList * a list of the formal parameters of this user-defined function (MUST BE A PROPER * LIST) * @param body * the body of this user-defined function (MUST BE A PROPER LIST) */ public UserDefinedFunction(String name, Cons lambdaList, Cons body) { this.name = name; this.body = body; this.lambdaExpression = new Cons(new Symbol(name), new Cons(lambdaList, body)); this.environment = SETF.getEnvironment(); this.formalParameters = new ArrayList(); for (; lambdaList.consp(); lambdaList = (Cons) lambdaList.getCdr()) this.formalParameters.add(lambdaList.getCar().toString()); this.argumentValidator = new ArgumentValidator(this.name); this.argumentValidator.setExactNumberOfArguments(this.formalParameters.size()); } public SExpression call(Cons argList) { argumentValidator.validate(argList); // push a new symbol table onto this function's environment (for its // parameters) environment = new SymbolTable(environment); // bind the values of the arguments to the formal parameter names for (String param : formalParameters) { SExpression currentArg = argList.getCar(); environment.put(param, currentArg); argList = (Cons) argList.getCdr(); } // store the environment of the S-expression that called this function // (the current environment) SymbolTable currentEnvironment = SETF.getEnvironment(); // replace the current environment with the environment of this // function SETF.setEnvironment(environment); Cons currentSExpression = body; SExpression retval = null; // evaluate all the S-expressions making up this function's body while (currentSExpression.consp()) { retval = EVAL.eval(currentSExpression.getCar()); currentSExpression = (Cons) currentSExpression.getCdr(); } // replace the environment of the S-expression that called this // function SETF.setEnvironment(currentEnvironment); // remove the bindings of the arguments to the formal parameter names // in the environment of this function environment = new SymbolTable(environment.getParent()); return retval; } public Cons getLambdaExpression() { return lambdaExpression; } }