transcendental-lisp/src/function/UserDefinedFunction.java

80 lines
2.6 KiB
Java

package function;
import java.util.ArrayList;
import function.builtin.*;
import sexpression.*;
import table.SymbolTable;
public class UserDefinedFunction extends LispFunction {
private String name;
private Cons body;
private Cons lambdaExpression;
private SymbolTable environment;
private ArrayList<String> formalParameters;
private ArgumentValidator argumentValidator;
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();
for (this.formalParameters = new ArrayList<>(); 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;
}
}