77 lines
2.5 KiB
Java
77 lines
2.5 KiB
Java
package function;
|
|
|
|
import static function.builtin.EVAL.eval;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
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.isCons(); lambdaList = (Cons) lambdaList.getRest())
|
|
this.formalParameters.add(lambdaList.getFirst().toString());
|
|
|
|
this.argumentValidator = new ArgumentValidator(this.name);
|
|
this.argumentValidator.setExactNumberOfArguments(this.formalParameters.size());
|
|
}
|
|
|
|
public SExpression call(Cons argumentList) {
|
|
argumentValidator.validate(argumentList);
|
|
|
|
return evaluateInFunctionScope(argumentList);
|
|
}
|
|
|
|
private SExpression evaluateInFunctionScope(Cons argumentList) {
|
|
SymbolTable callingScope = executionContext.getScope();
|
|
SymbolTable executionScope = bindParameterValuesToFunctionScope(argumentList);
|
|
|
|
executionContext.setScope(executionScope);
|
|
SExpression lastEvaluation = evaluateBody();
|
|
executionContext.setScope(callingScope);
|
|
|
|
return lastEvaluation;
|
|
}
|
|
|
|
private SymbolTable bindParameterValuesToFunctionScope(Cons argumentList) {
|
|
SymbolTable executionScope = new SymbolTable(functionScope);
|
|
|
|
for (String parameter : formalParameters) {
|
|
SExpression currentArg = argumentList.getFirst();
|
|
executionScope.put(parameter, currentArg);
|
|
argumentList = (Cons) argumentList.getRest();
|
|
}
|
|
|
|
return executionScope;
|
|
}
|
|
|
|
private SExpression evaluateBody() {
|
|
SExpression lastEvaluation = Nil.getInstance();
|
|
|
|
for (Cons expression = body; expression.isCons(); expression = (Cons) expression.getRest())
|
|
lastEvaluation = eval(expression.getFirst());
|
|
|
|
return lastEvaluation;
|
|
}
|
|
|
|
public Cons getLambdaExpression() {
|
|
return lambdaExpression;
|
|
}
|
|
|
|
}
|