/** JamVal and Token Data Definitions */ /** * Interface for a Jam value. */ interface JamVal { /** * Visitor hook. * @param jvv visitor to execute * @return visitor-specific return value */ RtnType accept(JamValVisitor jvv); } /** * Interface of a visitor to a Jam value. */ interface JamValVisitor { /** * Case for IntConstants. * @param ji host * @return visitor-specific return value */ RtnType forIntConstant(IntConstant ji); /** * Case for BoolConstants. * @param jb host * @return visitor-specific return value */ RtnType forBoolConstant(BoolConstant jb); /** * Case for JamLists. * @param jl host * @return visitor-specific return value */ RtnType forJamList(JamList jl); /** * Case for JamFuns. * @param jf host * @return visitor-specific return value */ RtnType forJamFun(JamFun jf); /** * Case for JamVoids. * @param jf host * @return visitor-specific return value */ RtnType forJamVoid(JamVoid jf); } /** JamVal classes */ /** * A Jam integer constant, also used to represent an integer token for parsing. */ class IntConstant implements Token, Constant, JamVal { /** * Value. */ private int value; /** * Constructor for an IntConstant. * @param i value */ IntConstant(int i) { value = i; } // duplicates can occur! /** * Accessor for the value. * @return value */ public int value() { return value; } /** * Visitor hook for AST visitors. * @param v visitor to execute * @return visitor-specific return value */ public RtnType accept(ASTVisitor v) { return v.forIntConstant(this); } /** * Visitor hook for JamVal visitors. * @param v visitor to execute * @return visitor-specific return value */ public RtnType accept(JamValVisitor v) { return v.forIntConstant(this); } /** * Redefines equals so that equal integers are recognized as equal. * @param other other object * @return true if both objects are IntConstants and their values are equal */ public boolean equals(Object other) { return (other != null && this.getClass() == other.getClass()) && (value == ((IntConstant)other).value()); } /** * Computes the obvious hashcode for this consistent with equals. */ public int hashCode() { return value; } /** * Return the string representation of the value. * @return string representation */ public String toString() { return String.valueOf(value); } } /** * A Jam boolean constant, also used to represent a boolean token for parsing. */ class BoolConstant implements Token, Constant, JamVal { /** * Value. */ private boolean value; /** * Constructor for BoolConstants. * @param b value */ private BoolConstant(boolean b) { value = b; } //Singleton pattern definitions /** * Singleton instance for false. */ public static final BoolConstant FALSE = new BoolConstant(false); /** * Singleton instance for true. */ public static final BoolConstant TRUE = new BoolConstant(true); /** * Factory method that returns BoolConstant corresponding to b. * @param b value * @return corresponding BoolConstant */ public static BoolConstant toBoolConstant(boolean b) { if (b) { return TRUE; } else { return FALSE; } } /** * Accessor for the value. * @return value */ public boolean value() { return value; } /** * Returns the negation of this BoolConstant. * @return negation */ public BoolConstant not() { if (this == FALSE) { return TRUE; } else { return FALSE; } } /** * Visitor hook for AST visitors. * @param av visitor to execute * @return visitor-specific return value */ public RtnType accept(ASTVisitor av) { return av.forBoolConstant(this); } /** * Visitor hook for JamVal visitors. * @param jv visitor to execute * @return visitor-specific return value */ public RtnType accept(JamValVisitor jv) { return jv.forBoolConstant(this); } public String toString() { return String.valueOf(value); } /** * Redefines equals so that equal boolean constants are recognized as equal. * @param other other object * @return true if both objects are BoolConstants with equal values */ public boolean equals(Object other) { return (other != null && this.getClass() == other.getClass()) && (value == ((BoolConstant)other).value()); } /** * Computes the obvious hashcode for this consistent with equals. */ public int hashCode() { return value ? 1 : 0; } } /** * Immutable list interface. */ interface PureList { /** * Factory method for a non-empty lists with this list as rest. * @param o object for the first of the list * @return non-empty list with the specified first and this list as rest */ PureList cons(ElemType o); /** * Factory method for an empty list. * @return empty list */ PureList empty(); /** * Visitor hook. * @param v visitor to execute * @return visitor-specific return value */ RtnType accept(PureListVisitor v); /** * Helper method for returning the string representation. * @return string representation */ String toStringHelp(); /** * Append two lists * @param addedElts other list * @return list with this list followed by the other list */ PureList append(PureList addedElts); /** * Check whether an element exists in the list. * @param e element * @return true if the element is found in the list */ boolean hasMember(ElemType e); } /** * The visitor interface for the type PureList. */ interface PureListVisitor { /** * Case for empty lists. * @param e host * @return visitor-specific return value */ RtnType forEmpty(Empty e); /** * Case for non-empty lists. * @param c host * @return visitor-specific return value */ RtnType forCons(Cons c); } /** * An abstract class that factors out code common to classes Empty and Cons. */ abstract class PureListClass implements PureList { /** * Factory method for a non-empty lists with this list as rest. * @param o object for the first of the list * @return non-empty list with the specified first and this list as rest */ public Cons cons(ElemType o) { return new Cons(o, this); } /** * Factory method for an empty list. * @return empty list */ public Empty empty() { return new Empty(); } /** * Helper method to convert an array to a list. * @param array array of elements * @return list of elements */ public static PureListClass arrayToList(T[] array) { int n = array.length; PureListClass list = new Empty(); for(int i = n - 1; i >= 0; i--) { list = list.cons(array[i]); } return list; } } /** * The empty PureList class. */ class Empty extends PureListClass { /** * Visitor hook. * @param v visitor to execute * @return visitor-specific return value */ public RtnType accept(PureListVisitor v) { return v.forEmpty(this); } /** * Append two lists * @param addedElts other list * @return list with this list followed by the other list */ public PureList append(PureList addedElts) { return addedElts; } /** * Check whether an element exists in the list. * @param e element * @return true if the element is found in the list */ public boolean hasMember(ElemType e) { return false; } /** * Overrides inherited equals because Empty is not a singleton! * @param other other object * @return true if both objects are empty lists */ public boolean equals(Object other) { return (other != null && other.getClass() == this.getClass()); } /** * Return the string representation. * @return string representation */ public String toString() { return "()"; } /** * Helper method for returning the string representation. * @return string representation */ public String toStringHelp() { return ""; } } /** * The non-empty PureList class. */ class Cons extends PureListClass { /** * First of this list. */ protected ElemType first; /** * Rest of this list. */ protected PureList rest; /** * Constructor for a non-empty list. * @param f first * @param r rest */ Cons(ElemType f, PureList r) { first = f; rest = r; } /** * Visitor hook. * @param v visitor to execute * @return visitor-specific return value */ public RtnType accept(PureListVisitor v) { return v.forCons(this); } /** * Append two lists * @param addedElts other list * @return list with this list followed by the other list */ public PureList append(PureList addedElts) { return new Cons(first, rest.append(addedElts)); } /** * Accessor for first. * @return first */ public ElemType first() { return first; } /** * Accessor for the rest. * @return rest */ public PureList rest() { return rest; } /** * Check whether an element exists in the list. * @param e element * @return true if the element is found in the list */ public boolean hasMember(ElemType e) { if (first().equals(e)) { return true; } return rest().hasMember(e); } /** * Overrides inherited equals to compare first and rest. * @param other other object * @return true if both objects are non-empty lists with equal firsts and rests. */ public boolean equals(Object other) { if (other == null || this.getClass() != other.getClass()) { return false; } Cons otherCons = (Cons)other; return first().equals(otherCons.first()) && rest().equals(otherCons.rest()); } /** * Override hash code in accordance with equals. * @return hash code */ public int hashCode() { return first.hashCode() + rest.hashCode(); } /** * Return the string representation. * @return string representation */ public String toString() { return "(" + first + rest.toStringHelp() + ")"; } /** * Helper method for returning the string representation. * @return string representation */ public String toStringHelp() { return " " + first + rest.toStringHelp(); } } /** * Class for a suspension, i.e. an AST that will be evaluated later using the specified evaluation visitor. */ class Suspension { /** * Expression to evaluate later. */ private AST exp; /** * Visitor to use later. */ private EvalVisitor ev; /** * Constructor for a suspension. * @param a expression * @param e evaluation visitor */ Suspension(AST a, EvalVisitor e) { exp = a; ev = e; } /** * Accessor for the expression. * @return expression */ public AST exp() { return exp; } /** * Accessor for the evaluation visitor. * @return evaluation visitor */ public EvalVisitor ev() { return ev; } /** * Mutator for the evaluation visitor * @param e new evaluation visitor. */ public void putEv(EvalVisitor e) { ev = e; } /** * Evaluates the suspension. * @return result of the evaluation */ JamVal eval() { // System.err.println("eval() called on the susp with AST = " + exp); return exp.accept(ev); } /** * Return the string representation. * @return string representation */ public String toString() { return "<" + exp + ", " + ev + ">"; } } /** * Interface for a Jam list. */ interface JamList extends PureList, JamVal { /** * Factory method for empty lists. * @return empty list */ JamEmpty empty(); /** * Factory method for non-empty list. * @param v Jam value for the first. * @return Jam list with the specified first and this list as rest. */ JamCons cons(JamVal v); /** * Helper method for returning the string representation. * @return string representation */ String toStringHelp(int maxDepth); } /** * Class for an empty Jam list. */ class JamEmpty extends Empty implements JamList { /** * Singleton instance. */ public static final JamEmpty ONLY = new JamEmpty(); /** * Singleton constructor. */ private JamEmpty() { } /** * Factory method for empty lists. * @return empty list */ public JamEmpty empty() { return ONLY; } /** * Factory method for non-empty list. * @param v Jam value for the first. * @return Jam list with the specified first and this list as rest. */ public JamCons cons(JamVal v) { return new JamCons(v, this); } /** * Visitor hook for JamVal visitors. * @param v visitor to execute * @return visitor-specific return value */ public RtnType accept(JamValVisitor v) { return v.forJamList(this); } /** * Helper method for returning the string representation. * @return string representation */ public String toStringHelp(int maxDepth) { return ""; } } /** * Class for non-empty Jam lists. */ class JamCons extends Cons implements JamList { /** * Maximum depth of printing. */ private static final int MAX_DEPTH = 1000; /** * Constructor for a JamCons. * @param f first * @param r rest */ public JamCons(JamVal f, JamList r) { super(f, r); } /** * Factory method for empty lists. * @return empty list */ public JamEmpty empty() { return JamEmpty.ONLY; } /** * Factory method for non-empty list. * @param v Jam value for the first. * @return Jam list with the specified first and this list as rest. */ public JamCons cons(JamVal v) { return new JamCons(v, this); } /** * Visitor hook for JamVal visitors. * @param v visitor to execute * @return visitor-specific return value */ public RtnType accept(JamValVisitor v) { return v.forJamList(this); } /** * Accessor for first. * @return first */ public JamVal first() { return first; } // work-around for bridge method bug in compiler /** * Accessor for rest. * @return rest */ public JamList rest() { return (JamList)rest; } // overridden method has narrower return type /** * Helper method that returns the value if it is a JamList. Otherwise it throws an EvalException. * @param val value * @return value */ public static JamList checkList(JamVal val) { if (val instanceof JamList) { return (JamList)val; } throw new EvalException("The second argument to lazy cons is `" + val + "' which is not a list"); } /** * Return the string representation. * @return string representation */ public String toString() { return "(" + first() + rest().toStringHelp(MAX_DEPTH) + ")"; } /** * Helper method for returning the string representation. * @return string representation */ public String toStringHelp(int maxDepth) { if (maxDepth == 0) { return " ..."; } return " " + first() + rest().toStringHelp(maxDepth - 1); } /** * Overrides inherited equals to compare first and rest. * @param other other object * @return true if both objects are non-empty lists with equal firsts and rests. */ public boolean equals(Object other) { if (other == null || this.getClass() != other.getClass()) { return false; } JamCons otherCons = (JamCons)other; return first.equals(otherCons.first) && rest.equals(otherCons.rest); } /** * Override hash code in accordance with equals. * @return hash code */ public int hashCode() { return first.hashCode() + rest.hashCode(); } } /** * Class for a lazy cons. */ class JamLazyNameCons extends JamCons { /** * Suspension for the first. */ protected Suspension firstSusp; /** * Suspension for the rest. */ protected Suspension restSusp; /** * Constructor for a lazy cons. * @param f expression for first * @param r expression for rest * @param ev evaluation visitor to use */ public JamLazyNameCons(AST f, AST r, EvalVisitor ev) { super(null, null); firstSusp = new Suspension(f, ev); restSusp = new Suspension(r, ev); } /** * Accessor for the first. This evaluates the suspension. * @return value of first */ public JamVal first() { return firstSusp.eval(); } /** * Accessor for the rest. This evaluates the suspension. * @return value of rest */ public JamList rest() { return checkList(restSusp.eval()); } } /** * Class for a lazy cons with optimization. */ class JamLazyNeedCons extends JamLazyNameCons { /** * Constructor for a lazy cons with optimization. * @param f expression for first * @param r expression for rest * @param ev evaluation visitor to use */ public JamLazyNeedCons(AST f, AST r, EvalVisitor ev) { super(f, r, ev); } /** * Accessor for the first. This evaluates the suspension if it hasn't been evaluated before * and then caches the result. * @return value of first */ public JamVal first() { if (first == null) { first = firstSusp.eval(); firstSusp = null; } return first; } /** * Accessor for the rest. This evaluates the suspension if it hasn't been evaluated before * and then caches the result. * @return value of rest */ public JamList rest() { if (rest == null) { rest = checkList(restSusp.eval()); restSusp = null; } return (JamList)rest; } } /** * A Jam binding. */ interface Binding extends WithVariable { /** * Accessor for the value. */ public JamVal value(); /** * Mutator for the expression. * @param exp expression to be bound * @param ev evaluation visitor to use for the evaluation */ public void setBinding(AST exp, EvalVisitor ev); } /** * Defines an object representing a callByValue binding in an environment. */ class ValueBinding implements Binding { /** * Variable. */ private Variable var; /** * Value of the binding. */ private JamVal value; /** * Constructor for a ValueBinding. * @param v variable * @param jv value */ ValueBinding(Variable v, JamVal jv) { var = v; value = jv; } /** * Accessor for the variable. * @return variable */ public Variable var() { return var; } /** * Accessor for the value. * @return value */ public JamVal value() { return value; } /** * Return the string representation of this binding. * @return string representation */ public String toString() { return "[" + var + ", " + value + "]"; } /** * Mutator for the expression. * @param exp expression to be bound * @param ev evaluation visitor to use for the evaluation */ public void setBinding(AST exp, EvalVisitor ev) { value = exp.accept(ev); } } /** * Defines an object representing a callByName binding in an environment. */ class NameBinding implements Binding { /** * Variable. */ private Variable var; /** * Suspension. */ private Suspension susp; /** * Constructor for a NameBinding. * @param v variable * @param s suspension */ NameBinding(Variable v, Suspension s) { var = v; susp = s; } /** * Accessor for the variable. * @return variable */ public Variable var() { return var; } /** * Accessor for the value. This evaluates the suspension. * @return value */ public JamVal value() { return susp.eval(); } /** * Return the string representation of this binding. * @return string representation */ public String toString() { return "[" + var + ", " + susp + "]"; } /** * Mutator for the expression. * @param exp expression to be bound * @param ev evaluation visitor to use for the evaluation */ public void setBinding(AST exp, EvalVisitor ev) { susp = new Suspension(exp, ev); } } /** Defines an object representing a callByNeed binding in an environment. */ class NeedBinding implements Binding { /** * Variable. */ private Variable var; /** * Value, or null if the suspension hasn't been evaluated yet */ private JamVal value; /** * Suspension. */ private Suspension susp; /** * Constructor for a NameBinding. * @param v variable * @param s suspension */ NeedBinding(Variable v, Suspension s) { var = v; susp = s; value = null; } /** * Accessor for the variable. * @return variable */ public Variable var() { return var; } /** * Accessor for the value. This evaluates the suspension if value is still null, then stores the result in value. * @return value */ public JamVal value() { if (value == null) { // a legitimate JamVal CANNOT be null value = susp.eval(); susp = null; // release susp object for GC! } return value; } /** * Return the string representation of this binding. * @return string representation */ public String toString() { return "[" + var + ", " + value + ", " + susp + "]"; } /** * Mutator for the expression. * @param exp expression to be bound * @param ev evaluation visitor to use for the evaluation */ public void setBinding(AST exp, EvalVisitor ev) { susp = new Suspension(exp, ev); value = null; } } /** Other JamVal classes */ /** * Abstract class for a Jam function (closure or primitive function). */ abstract class JamFun implements JamVal { /** * Visitor hook for JamVal visitors. * @param jvv visitor to execute * @return visitor-specific return value */ public RtnType accept(JamValVisitor jvv) { return jvv.forJamFun(this); } /** * Visitor hook for FunVisitors. * @param jfv visitor to execute * @return visitor-specific return value */ abstract public RtnType accept(FunVisitor jfv); } /** * The visitor interface for the JamFun type. */ interface FunVisitor { /** * Case for closures. * @param c host * @return visitor-specific return value */ RtnType forJamClosure(JamClosure c); /** * Case for PrimFuns. * @param pf host * @return visitor-specific return value */ RtnType forPrimFun(PrimFun pf); } /** * A Jam closure. */ class JamClosure extends JamFun { /** * Body of the closure. */ private Map body; /** * Environment the closure closes over. */ private PureList env; /** * Constructor for a JamClosure. * @param b body * @param e environment */ JamClosure(Map b, PureList e) { body = b; env = e; } /** * Accessor for the body. * @return body */ Map body() { return body; } /** * Accessor for the environment. * @return environment */ PureList env() { return env; } /** * Visitor hook for FunVisitors. * @param jfv visitor to execute * @return visitor-specific return value */ public RtnType accept(FunVisitor jfv) { return jfv.forJamClosure(this); } /** * Return a string representation of the closure. * @return string representation */ public String toString() { return "JamClosure<" + body + ", " + env + ">"; } } /** * An abstract class for Jam Primitive Function. */ abstract class PrimFun extends JamFun implements Token, Term { /** * Name of the function. */ private String name; /** * Constructor for a PrimFun. * @param n name */ PrimFun(String n) { name = n; } /** * Accessor for the name. * @return name */ public String name() { return name; } /** * Visitor hook for AST visitors. * @param v visitor to execute * @return visitor-specific return value */ public RtnType accept(ASTVisitor v) { return v.forPrimFun(this); } /** * Visitor hook for FunVisitors. * @param v visitor to execute * @return visitor-specific return value */ public RtnType accept(FunVisitor v) { return v.forPrimFun(this); } /** * Visitor hook for PrimFunVisitors. * @param pfv visitor to execute * @return visitor-specific return value */ abstract public RtnType accept(PrimFunVisitor pfv); /** * Return a string representation of the closure. * @return string representation */ public String toString() { return name; } } /** * A dummy Jam value used to implement recursive let. */ class JamVoid implements JamVal { /** * Singleton instance. */ public static final JamVoid ONLY = new JamVoid(); /** * Singleton constructor. */ private JamVoid() { } /** * Visitor hook. * @param jvv visitor to execute * @return visitor-specific return value */ public RtnType accept(JamValVisitor jvv) { return jvv.forJamVoid(this); } } /** * Interface for a visitor to PrimFun classes. */ interface PrimFunVisitor { /** * Case for function? * @return visitor-specific return value */ RtnType forFunctionPPrim(); /** * Case for number? * @return visitor-specific return value */ RtnType forNumberPPrim(); /** * Case for list? * @return visitor-specific return value */ RtnType forListPPrim(); /** * Case for cons? * @return visitor-specific return value */ RtnType forConsPPrim(); /** * Case for null? * @return visitor-specific return value */ RtnType forNullPPrim(); // /** // * Case for ref? // * @return visitor-specific return value // */ // RtnType forRefPPrim(); /** * Case for arity * @return visitor-specific return value */ RtnType forArityPrim(); /** * Case for cons * @return visitor-specific return value */ RtnType forConsPrim(); /** * Case for first * @return visitor-specific return value */ RtnType forFirstPrim(); /** * Case for rest * @return visitor-specific return value */ RtnType forRestPrim(); } /** * function? PrimFun. */ class FunctionPPrim extends PrimFun { /** * Singleton instance. */ public static final FunctionPPrim ONLY = new FunctionPPrim(); /** * Singleton constructor. */ private FunctionPPrim() { super("function?"); } /** * Visitor hook. * @param pfv visitor to execute * @return visitor-specific return value */ public RtnType accept(PrimFunVisitor pfv) { return pfv.forFunctionPPrim(); } } /** * number? PrimFun. */ class NumberPPrim extends PrimFun { /** * Singleton instance. */ public static final NumberPPrim ONLY = new NumberPPrim(); /** * Singleton constructor. */ private NumberPPrim() { super("number?"); } /** * Visitor hook. * @param pfv visitor to execute * @return visitor-specific return value */ public RtnType accept(PrimFunVisitor pfv) { return pfv.forNumberPPrim(); } } /** * list? PrimFun. */ class ListPPrim extends PrimFun { /** * Singleton instance. */ public static final ListPPrim ONLY = new ListPPrim(); /** * Singleton constructor. */ private ListPPrim() { super("list?"); } /** * Visitor hook. * @param pfv visitor to execute * @return visitor-specific return value */ public RtnType accept(PrimFunVisitor pfv) { return pfv.forListPPrim(); } } /** * cons? PrimFun. */ class ConsPPrim extends PrimFun { /** * Singleton instance. */ public static final ConsPPrim ONLY = new ConsPPrim(); /** * Singleton constructor. */ private ConsPPrim() { super("cons?"); } /** * Visitor hook. * @param pfv visitor to execute * @return visitor-specific return value */ public RtnType accept(PrimFunVisitor pfv) { return pfv.forConsPPrim(); } } /** * null? PrimFun. */ class NullPPrim extends PrimFun { /** * Singleton instance. */ public static final NullPPrim ONLY = new NullPPrim(); /** * Singleton constructor. */ private NullPPrim() { super("null?"); } /** * Visitor hook. * @param pfv visitor to execute * @return visitor-specific return value */ public RtnType accept(PrimFunVisitor pfv) { return pfv.forNullPPrim(); } } ///** // * ref? PrimFun. // */ //class RefPPrim extends PrimFun { // /** // * Singleton instance. // */ // public static final RefPPrim ONLY = new RefPPrim(); // // /** // * Singleton constructor. // */ // private RefPPrim() { // super("ref?"); // } // // /** // * Visitor hook. // * @param pfv visitor to execute // * @return visitor-specific return value // */ // public RtnType accept(PrimFunVisitor pfv) { // return pfv.forRefPPrim(); // } //} /** * arity PrimFun. */ class ArityPrim extends PrimFun { /** * Singleton instance. */ public static final ArityPrim ONLY = new ArityPrim(); /** * Singleton constructor. */ private ArityPrim() { super("arity"); } /** * Visitor hook. * @param pfv visitor to execute * @return visitor-specific return value */ public RtnType accept(PrimFunVisitor pfv) { return pfv.forArityPrim(); } } /** * cons PrimFun. */ class ConsPrim extends PrimFun { /** * Singleton instance. */ public static final ConsPrim ONLY = new ConsPrim(); /** * Singleton constructor. */ private ConsPrim() { super("cons"); } /** * Visitor hook. * @param pfv visitor to execute * @return visitor-specific return value */ public RtnType accept(PrimFunVisitor pfv) { return pfv.forConsPrim(); } } /** * first PrimFun. */ class FirstPrim extends PrimFun { /** * Singleton instance. */ public static final FirstPrim ONLY = new FirstPrim(); /** * Singleton constructor. */ private FirstPrim() { super("first"); } /** * Visitor hook. * @param pfv visitor to execute * @return visitor-specific return value */ public RtnType accept(PrimFunVisitor pfv) { return pfv.forFirstPrim(); } } /** * rest PrimFun. */ class RestPrim extends PrimFun { public static final RestPrim ONLY = new RestPrim(); private RestPrim() { super("rest"); } /** * Visitor hook. * @param pfv visitor to execute * @return visitor-specific return value */ public RtnType accept(PrimFunVisitor pfv) { return pfv.forRestPrim(); } }