/* Alloy Analyzer 4 -- Copyright (c) 2006-2009, Felix Chang * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package edu.mit.csail.sdg.alloy4compiler.ast; import java.util.ArrayList; import java.util.Collection; import java.util.List; import edu.mit.csail.sdg.alloy4.Pos; import edu.mit.csail.sdg.alloy4.Err; import edu.mit.csail.sdg.alloy4.ErrorWarning; import static edu.mit.csail.sdg.alloy4compiler.ast.Sig.UNIV; /** Immutable; represents a constant in the AST. */ public final class ExprConstant extends Expr { /** The type of constant. */ public final Op op; /** If this node is a String constant, then this field stores the String, else this field stores "". */ public final String string; /** If this node is a number constant, then this field stores the number, else this field stores 0. */ public final int num; /** Return the number if this node is a number constant, otherwise return 0. */ public int num() { return num; } /** {@inheritDoc} */ @Override public Pos span() { return pos; } /** {@inheritDoc} */ @Override public void toString(StringBuilder out, int indent) { if (indent<0) { if (op==Op.NUMBER) out.append(num); else if (op==Op.STRING) out.append(string); else out.append(op); } else { for(int i=0; i<indent; i++) { out.append(' '); } if (op==Op.NUMBER) out.append(num); else if (op==Op.STRING) out.append(string); else out.append(op); out.append('\n'); } } /** Constructs an ExprConstant node. * * @param pos - the original position in the file * @param op - the choice of which constant it is * @param num - the number (this argument is ignored if op!=NUMBER) */ private ExprConstant(Pos pos, Op op, int num, String string) { super(pos, null, false, (op==Op.IDEN ? Type.make2(UNIV) : (op==Op.NEXT ? Type.make2(Sig.SIGINT) : (op==Op.TRUE || op==Op.FALSE ? Type.FORMULA : (op==Op.EMPTYNESS ? UNIV.type : (op==Op.STRING ? Sig.STRING.type : Type.smallIntType()))))), 0, 0, null); this.op = op; this.num = (op==Op.NUMBER ? num : 0); this.string = (op==Op.STRING ? string : ""); } /** Returns true if we can determine the two expressions are equivalent; may sometimes return false. */ @Override public boolean isSame(Expr obj) { while(obj instanceof ExprUnary && ((ExprUnary)obj).op==ExprUnary.Op.NOOP) obj=((ExprUnary)obj).sub; if (obj==this) return true; if (!(obj instanceof ExprConstant)) return false; ExprConstant x=(ExprConstant)obj; if (op==Op.STRING) return op==x.op && string.equals(x.string); else return op==x.op && num==x.num; } /** The "TRUE" boolean value. */ public static final Expr TRUE = new ExprConstant(null, Op.TRUE, 0, ""); /** The "FALSE" boolean value. */ public static final Expr FALSE = new ExprConstant(null, Op.FALSE, 0, ""); /** The "iden" relation. */ public static final Expr IDEN = new ExprConstant(null, Op.IDEN, 0, ""); /** The smallest integer value allowed by the current bitwidth. */ public static final Expr MIN = new ExprConstant(null, Op.MIN, 0, ""); /** The largest integer value allowed by the current bitwidth. */ public static final Expr MAX = new ExprConstant(null, Op.MAX, 0, ""); /** The "next" relation relating each integer to its next larger integer. */ public static final Expr NEXT = new ExprConstant(null, Op.NEXT, 0, ""); /** The "0" integer. */ public static final Expr ZERO = new ExprConstant(null, Op.NUMBER, 0, ""); /** The "1" integer. */ public static final Expr ONE = new ExprConstant(null, Op.NUMBER, 1, ""); /** The "emptyness" constant. */ public static final Expr EMPTYNESS = new ExprConstant(null, Op.EMPTYNESS, 0, ""); /** Constructs the integer "n" */ public static Expr makeNUMBER(int n) { if (n==0) return ZERO; if (n==1) return ONE; return new ExprConstant(null, Op.NUMBER, n, ""); } /** This class contains all possible constant types. */ public enum Op { /** true */ TRUE("true"), /** false */ FALSE("false"), /** the builtin "iden" relation */ IDEN("iden"), /** the minimum integer constant */ MIN("min"), /** the maximum integer constant */ MAX("max"), /** the "next" relation between integers */ NEXT("next"), /** the emptyness relation whose type is UNIV */ EMPTYNESS("none"), /** a String constant */ STRING("STRING"), /** an integer constant */ NUMBER("NUMBER"); /** The constructor. */ private Op(String label) {this.label=label;} /** The human readable label for this operator. */ private final String label; /** Makes an ExprConstant node * @param pos - the original position in the source file (can be null if unknown) * @param number - the number (this argument is ignored if op!=NUMBER) */ public final ExprConstant make(Pos pos, int number) { return new ExprConstant(pos, this, number, ""); } /** Makes an ExprConstant node * @param pos - the original position in the source file (can be null if unknown) * @param string - the string (this argument is ignored if op!=STRING) */ public final ExprConstant make(Pos pos, String string) { return new ExprConstant(pos, this, 0, string); } /** Returns the human readable label for this operator. */ @Override public final String toString() { return label; } } /** {@inheritDoc} */ @Override public Expr resolve(Type type, Collection<ErrorWarning> warns) { return this; } /** {@inheritDoc} */ @Override public final<T> T accept(VisitReturn<T> visitor) throws Err { return visitor.visit(this); } /** {@inheritDoc} */ public int getDepth() { return 1; } /** {@inheritDoc} */ @Override public String getHTML() { switch(op) { case TRUE: return "<b>true</b>"; case FALSE: return "<b>false</b>"; case IDEN: return "<b>iden</b>"; case MAX: return "<b>fun/max</b>"; case MIN: return "<b>fun/min</b>"; case NEXT: return "<b>fun/next</b>"; case EMPTYNESS: return "<b>none</b>"; case STRING: return "<b>\"" + string + "\"</b>"; } return "<b>" + num + "</b>"; } /** {@inheritDoc} */ @Override public List<? extends Browsable> getSubnodes() { return new ArrayList<Browsable>(0); } }