/*
 * Name: Mike Cifelli
 * Course: CIS 443 - Programming Languages
 * Assignment: Lisp Interpreter 1
 */
package eval;
import parser.*;
/**
 * LENGTH represents the LENGTH function in Lisp.
 */
public class LENGTH extends LispFunction {
    /**
     * Returns the length of the given list.
     *
     * @param list
     *  the list to determine the length of
     * @return
     *  the length of list
     */
    public static int getLength(Cons list) {
        LENGTH lengthFunction = new LENGTH();
        LispNumber length = lengthFunction.call(LIST.makeList(list));
        return length.getValue();
    }
    public LispNumber call(Cons argList) {
        // make sure we have received at least one argument
        if (argList.nullp()) {
            Cons originalSExpr = new Cons(new Symbol("LENGTH"), argList);
            throw new RuntimeException("too few arguments given to LENGTH: " +
                                       originalSExpr);
        }
        SExpression argCar = argList.getCar();
        SExpression argCdr = argList.getCdr();
        // make sure we have received only one argument
        if (! argCdr.nullp()) {
            Cons originalSExpr = new Cons(new Symbol("LENGTH"), argList);
            throw new RuntimeException("too many arguments given to LENGTH: " +
                                       originalSExpr);
        }
        // make sure that the argument is a list
        if (argCar.listp()) {
            Cons arg = (Cons) argCar;
            if (arg.nullp()) {
                return new LispNumber(0);
            }
            Cons cdr = LIST.makeList(arg.getCdr());
            LispNumber cdrLength = call(cdr);
            return new LispNumber(1 + cdrLength.getValue());
        }
        throw new RuntimeException("LENGTH: a proper list must not end with " +
                                   argCar);
    }
}