package function.builtin; import function.*; import sexpression.*; /** * APPLY represents the APPLY function in Lisp. */ public class APPLY extends LispFunction { /** * Call APPLY with the specified argument list. * * @param argList * the list of arguments to be sent to APPLY (MUST BE A PROPER LIST) * @return the result of evaluating APPLY on argList */ public static SExpression apply(Cons argList) { return new APPLY().call(argList); } // The number of arguments that APPLY takes. private static final int NUM_ARGS = 2; public SExpression call(Cons argList) { // retrieve the number of arguments passed to APPLY 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("APPLY"), argList); String errMsg = "too " + ((argListLength > NUM_ARGS) ? "many" : "few") + " arguments given to APPLY: " + originalSExpr; throw new RuntimeException(errMsg); } SExpression car = argList.getCar(); // function name Cons cdr = (Cons) argList.getCdr(); SExpression cadr = cdr.getCar(); // argument list // make sure the second argument is a list if (cadr.listp()) { LispFunction function = EVAL.lookupFunction(car.toString()); if (function == null) { // check if the car of the list is a lambda expression if (car.functionp()) { function = ((LambdaExpression) car).getFunction(); } else if (LAMBDA.isLambdaExpression(car)) { Cons lexpr = (Cons) car; function = LAMBDA.createFunction(lexpr); } else { throw new RuntimeException("undefined function " + car); } } // apply the given function to the given argument list return function.call((Cons) cadr); } // the second argument is not a list throw new RuntimeException("APPLY: " + cadr + " is not a list"); } }