transcendental-lisp/src/function/UserDefinedFunction.java

70 lines
2.2 KiB
Java

package function;
import java.util.ArrayList;
import function.builtin.EVAL;
import sexpression.*;
import table.*;
public class UserDefinedFunction extends LispFunction {
private String name;
private Cons body;
private Cons lambdaExpression;
private ExecutionContext executionContext;
private SymbolTable functionScope;
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.executionContext = ExecutionContext.getInstance();
this.functionScope = executionContext.getScope();
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 argumentList) {
argumentValidator.validate(argumentList);
bindParameterValues(argumentList);
SymbolTable callingScope = executionContext.getScope();
executionContext.setScope(functionScope);
SExpression lastEvaluation = Nil.getInstance();
for (Cons expression = body; expression.consp(); expression = (Cons) expression.getCdr())
lastEvaluation = EVAL.eval(expression.getCar());
executionContext.setScope(callingScope);
releaseParameterValues();
return lastEvaluation;
}
private void bindParameterValues(Cons argumentList) {
functionScope = new SymbolTable(functionScope);
for (String parameter : formalParameters) {
SExpression currentArg = argumentList.getCar();
functionScope.put(parameter, currentArg);
argumentList = (Cons) argumentList.getCdr();
}
}
private void releaseParameterValues() {
functionScope = new SymbolTable(functionScope.getParent());
}
public Cons getLambdaExpression() {
return lambdaExpression;
}
}