2016-12-07 16:38:26 -05:00
|
|
|
package eval;
|
|
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
2016-12-15 11:19:03 -05:00
|
|
|
import sexpression.*;
|
|
|
|
|
|
|
|
public class UserDefinedFunction extends LispFunction {
|
2016-12-07 16:38:26 -05:00
|
|
|
|
|
|
|
// the number of arguments that this user-defined function takes.
|
|
|
|
private final int NUM_ARGS;
|
|
|
|
|
|
|
|
private String name;
|
|
|
|
private Cons body;
|
|
|
|
private Cons lexpr;
|
|
|
|
private SymbolTable environment;
|
|
|
|
private ArrayList<String> parameters;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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)
|
|
|
|
*/
|
2016-12-15 11:19:03 -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.lexpr = new Cons(new Symbol(name), new Cons(lambdaList, body));
|
|
|
|
this.environment = SETF.getEnvironment();
|
|
|
|
this.parameters = new ArrayList<String>();
|
|
|
|
|
|
|
|
// retrieve the names of all the formal parameters of this function
|
|
|
|
while (lambdaList.consp()) {
|
|
|
|
this.parameters.add(lambdaList.getCar().toString());
|
|
|
|
|
|
|
|
lambdaList = (Cons) lambdaList.getCdr();
|
|
|
|
}
|
|
|
|
|
|
|
|
this.NUM_ARGS = this.parameters.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
public SExpression call(Cons argList) {
|
|
|
|
// retrieve the number of arguments passed to this function
|
|
|
|
int argListLength = LENGTH.getLength(argList);
|
|
|
|
|
|
|
|
// make sure we have received the proper number of arguments
|
|
|
|
if (argListLength != NUM_ARGS) {
|
|
|
|
Cons originalSExpr = new Cons(new Symbol(name), argList);
|
|
|
|
String errMsg = "too " +
|
|
|
|
((argListLength > NUM_ARGS) ? "many" : "few") +
|
|
|
|
" arguments given to " + name + ": " +
|
|
|
|
originalSExpr;
|
|
|
|
|
|
|
|
throw new RuntimeException(errMsg);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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 : parameters) {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the lambda expression that represents this user-defined function.
|
|
|
|
*
|
|
|
|
* @return
|
|
|
|
* the lambda expression that represents this user-defined function
|
|
|
|
*/
|
|
|
|
public Cons getLexpr() {
|
|
|
|
return lexpr;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|