/* Author: Jeff Dalton <J.Dalton@ed.ac.uk>
 * Updated: Wed Dec  5 00:21:16 2001 by Jeff Dalton
 */

package ix.util.lisp;

import java.util.*;
import ix.util.*;


/** The class for static Lisp utilities. */

public class Lisp {

    private Lisp() { }		// can't instantiate


    public static final Null NIL = new Null();

    public static final Object EOF = new Object();


    /* cons */

    public static final Cons cons(Object car, LList cdr) {
	// /\/: maybe Object cdr and cast to LList.
	return new Cons(car, cdr);
    }


    /* list */

    public static final Null list() {
	return NIL;
    }

    public static final Cons list(Object a) {
	return new Cons(a, NIL);
    }

    public static final Cons list(Object a, Object b) {
	return new Cons(a, new Cons(b, NIL));
    }

    public static final Cons list(Object a, Object b, Object c) {
	return new Cons(a, new Cons(b, new Cons(c, NIL)));
    }

    public static final Cons list(Object a, Object b, Object c, Object d) {
	return new Cons(a, new Cons(b, new Cons(c, new Cons(d, NIL))));
    }

    public static final Cons list(Object a, Object b, Object c,
				  Object d, Object e) {
	return new Cons(a, new Cons(b, new Cons(c, 
                 new Cons(d, new Cons(e, NIL)))));
    }


    /* equal */

    public static final boolean equal(Object a, Object b) {
	if (a == b)
	    return true;
	else if (a instanceof Cons)
	    return b instanceof Cons
		   ? equal(((Cons)a).car, ((Cons)b).car) &&
		     equal(((Cons)a).cdr, ((Cons)b).cdr)
		   : false;
	else if (a instanceof String)
	    return b instanceof String ? a.equals(b) : false;
	else if (a instanceof Number)
	    return b instanceof Number ? a.equals(b) : false;
	else
	    return false;
    }


    /* readFromString */

    public static Object readFromString(String s) {
	LispReader lr = new LispReader(s);
	return lr.readObject();
    }

    public static LList elementsFromString(String s) {
	return (LList)Lisp.readFromString("(" + s + ")");
    }


    /* printToString */

    public static String printToString(Object a) {
	if (a == null)
	    return "#<null>";
	else if (a instanceof Number)
	    return a.toString();
	else if (a instanceof String)
	    return "\"" + a + "\"";
	else if (a instanceof Symbol)
	    return a.toString();
	else if (a instanceof Null)
	    // return "()";
	    return "nil";
	else if (a instanceof Cons) {
	    LList at = (Cons)a;
	    String s = "(" + printToString(at.car());
	    for (; at.cdr() instanceof Cons; at = at.cdr()) {
		s += " " + printToString(at.cdr().car());
	    }
	    return s + ")";
	}
	else {
	    // Debug.warn("printToString got a " + a.getClass() + ":" + a);
	    // return "#<" + a.getClass() + ">";
	    // return "#<" /* + a.getClass() +": " */ + a.toString() + ">";
	    return a.toString();
	}
    }

    public static String elementsToString(LList elts) {
	String text = printToString(elts);
	// Remove outermost parens.
	return text.substring(1, text.length() - 1);
    }

}

