/*
 * Name: Mike Cifelli
 * Course: CIS 443 - Programming Languages
 * Assignment: Lisp Interpreter 1
 */

package eval;

import parser.*;
import sexpression.Cons;
import sexpression.Nil;
import sexpression.SExpression;

/**
 * <code>COND</code> represents the COND form in Lisp.
 */
public class COND extends LispFunction {

    public SExpression call(Cons argList) {
        if (argList.nullp()) {
            // return NIL if there are were no arguments passed to COND
            return Nil.getUniqueInstance();
        }

        SExpression argCar = argList.getCar();  // first clause
        Cons argCdr = (Cons) argList.getCdr();  // list of remaining clauses

        // make sure the first clause is a list and is not NIL
        if (argCar.consp()) {
            Cons clause = (Cons) argCar;
            SExpression test = EVAL.eval(clause.getCar());

            if (test != Nil.getUniqueInstance()) {
                // the car of this clause is true, so we evaluate its cdr

                SExpression cdr = clause.getCdr();
                SExpression retval = test;

                // evaluate all the S-expressions in the cdr of the clause
                while (cdr.consp()) {
                    retval = EVAL.eval(((Cons) cdr).getCar());
                    cdr = ((Cons) cdr).getCdr();
                }

                // return the value of the last S-expression evaluated
                return retval;
            }

            // the car of this clause is false, so we test any remaining
            // clauses

            // check if the list of remaining clauses is a list and is not NIL
            if (argCdr.consp()) {
                return call(argCdr);
            }

            // there are no remaining clauses, so we return NIL
            return Nil.getUniqueInstance();
        }

        throw new RuntimeException("COND: clause " + argCar +
                                   " should be a list");
    }

    /**
     * Determine if the arguments passed to this Lisp function should be
     * evaluated.
     *
     * @return
     *  <code>false</code>
     */
    public boolean evaluateArguments() {
        return false;
    }

}