transcendental-lisp/src/function/UserDefinedFunction.java

85 lines
2.7 KiB
Java
Raw Normal View History

2016-12-19 13:05:53 -05:00
package function;
2016-12-07 16:38:26 -05:00
import java.util.ArrayList;
import function.builtin.EVAL;
import function.builtin.special.SETF;
import sexpression.*;
2016-12-19 13:05:53 -05:00
import table.SymbolTable;
public class UserDefinedFunction extends LispFunction {
2016-12-07 16:38:26 -05:00
private String name;
private Cons body;
private Cons lambdaExpression;
private SymbolTable scope;
private ArrayList<String> formalParameters;
private ArgumentValidator argumentValidator;
2016-12-07 16:38:26 -05:00
public UserDefinedFunction(String name, Cons lambdaList, Cons body) {
2016-12-07 16:38:26 -05:00
this.name = name;
this.body = body;
this.lambdaExpression = new Cons(new Symbol(name), new Cons(lambdaList, body));
this.scope = SETF.getSymbolTable();
2016-12-07 16:38:26 -05:00
for (this.formalParameters = new ArrayList<>(); lambdaList.consp(); lambdaList = (Cons) lambdaList.getCdr())
this.formalParameters.add(lambdaList.getCar().toString());
2016-12-07 16:38:26 -05:00
this.argumentValidator = new ArgumentValidator(this.name);
this.argumentValidator.setExactNumberOfArguments(this.formalParameters.size());
2016-12-07 16:38:26 -05:00
}
public SExpression call(Cons argumentList) {
argumentValidator.validate(argumentList);
2016-12-07 16:38:26 -05:00
// bind the values of the arguments to the formal parameter names
bindParameterValues(argumentList);
2016-12-07 16:38:26 -05:00
// store the environment of the S-expression that called this function
// (the current environment)
SymbolTable callingScope = SETF.getSymbolTable();
2016-12-07 16:38:26 -05:00
// replace the current environment with the environment of this
// function
SETF.setSymbolTable(scope);
2016-12-07 16:38:26 -05:00
Cons currentSExpression = body;
SExpression lastValue = null;
2016-12-07 16:38:26 -05:00
// evaluate all the S-expressions making up this function's body
while (currentSExpression.consp()) {
lastValue = EVAL.eval(currentSExpression.getCar());
2016-12-07 16:38:26 -05:00
currentSExpression = (Cons) currentSExpression.getCdr();
}
// replace the environment of the S-expression that called this
// function
SETF.setSymbolTable(callingScope);
2016-12-07 16:38:26 -05:00
// remove the bindings of the arguments to the formal parameter names
// in the environment of this function
releaseParameterValues();
return lastValue;
}
private void bindParameterValues(Cons argumentList) {
scope = new SymbolTable(scope);
for (String parameter : formalParameters) {
SExpression currentArg = argumentList.getCar();
scope.put(parameter, currentArg);
argumentList = (Cons) argumentList.getCdr();
}
}
2016-12-07 16:38:26 -05:00
private void releaseParameterValues() {
scope = new SymbolTable(scope.getParent());
2016-12-07 16:38:26 -05:00
}
public Cons getLambdaExpression() {
return lambdaExpression;
2016-12-07 16:38:26 -05:00
}
}