transcendental-lisp/src/eval/UDFunction.java

127 lines
3.9 KiB
Java

/*
* Name: Mike Cifelli
* Course: CIS 443 - Programming Languages
* Assignment: Lisp Interpreter 2
*/
package eval;
import parser.*;
import sexpression.Cons;
import sexpression.SExpression;
import sexpression.Symbol;
import java.util.ArrayList;
/**
* A <code>UDFunction</code> is an internal representation of a user-defined
* function in the Lisp programming language.
*/
public class UDFunction extends LispFunction {
// 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)
*/
public UDFunction(String name, Cons lambdaList, Cons body) {
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;
}
}