/* * xtc - The eXTensible Compiler * Copyright (C) 2006-2007 Robert Grimm * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. */ package xtc.type; import java.math.BigInteger; /** * Representation of a type's constant value. A constant value may be * one of the following:<ul> * <li>A boxed byte, short, int, or long.</li> * <li>A big integer.</li> * <li>A boxed char.</li> * <li>A string.</li> * <li>A {@link Reference}.</li> * </ul> * This class treats a zero as a null value. It also treats a zero as * a boolean false value and any other number as a boolean true value. * * @author Robert Grimm * @version $Revision: 1.11 $ */ public class Constant { /** The kind. */ public static enum Kind { /** An integer. */ INTEGER, /** A big integer. */ BIG_INTEGER, /** A double. */ DOUBLE, /** A character. */ CHARACTER, /** A string. */ STRING, /** A reference. */ REFERENCE } // ========================================================================= /** The kind. */ private Kind kind; /** The value. */ private Object value; /** * Create a new constant value. * * @param value The value. * @throws IllegalArgumentException Signals an invalid value. */ public Constant(Object value) { this.value = value; if (null == value) { throw new NullPointerException(); } else if (value instanceof Number) { if ((value instanceof Byte) || (value instanceof Short) || (value instanceof Integer) || (value instanceof Long)) { kind = Kind.INTEGER; } else if (value instanceof BigInteger) { kind = Kind.BIG_INTEGER; } else if ((value instanceof Float) || (value instanceof Double)) { kind = Kind.DOUBLE; } else { throw new IllegalArgumentException("Invalid number " + value); } } else if (value instanceof Character) { kind = Kind.CHARACTER; } else if (value instanceof String) { kind = Kind.STRING; } else if (value instanceof Reference) { kind = Kind.REFERENCE; } else { throw new IllegalArgumentException("invalid value " + value); } } /** * Get this constant's kind. * * @return The kind. */ public Kind getKind() { return kind; } /** * Determine whether this constant's value can be treated as a * number. * * @return <code>true</code> if this constant's kind is an integer, * big integer, double, or character. */ public boolean isNumber() { switch (kind) { case CHARACTER: case INTEGER: case BIG_INTEGER: case DOUBLE: return true; default: return false; } } /** * Determine whether this constant's value is a string. * * @return <code>true</code> if this constant's value is a string. */ public boolean isString() { return Kind.STRING == kind; } /** * Determine whether this constant's value is a reference. * * @return <code>true</code> if this constant's value is a * reference. */ public boolean isReference() { return Kind.REFERENCE == kind; } /** * Get this constant's value. * * @return The value. */ public Object getValue() { return value; } /** * Get this constant's value as a long. * * @return The value as a long. * @throws IllegalStateException Signals that this constant cannot * be converted to a long. */ public long longValue() { switch (kind) { case INTEGER: case BIG_INTEGER: case DOUBLE: return ((Number)value).longValue(); case CHARACTER: return ((Character)value).charValue(); default: throw new IllegalStateException("Not a number " + kind); } } /** * Get this constant's value as a big integer. * * @return The value as a big integer. * @throws IllegalStateException Signals that this constant cannot * be converted to a big integer. */ public BigInteger bigIntValue() { switch (kind) { case INTEGER: return BigInteger.valueOf(((Number)value).longValue()); case BIG_INTEGER: return (BigInteger)value; case CHARACTER: return BigInteger.valueOf(((Character)value).charValue()); default: throw new IllegalStateException("Not a big integer " + kind); } } /** * Get this constant's value as a double. * * @return The value as a double. * @throws IllegalStateException Signals that this constant cannot * be converted to a double. */ public double doubleValue() { switch (kind) { case INTEGER: case BIG_INTEGER: case DOUBLE: return ((Number)value).doubleValue(); case CHARACTER: return ((Character)value).charValue(); default: throw new IllegalStateException("Not a number " + kind); } } /** * Get this constant's value as a reference. * * @return The value as a reference. * @throws IllegalStateException Signals that this constant is not a * reference. */ public Reference refValue() { switch (kind) { case REFERENCE: return (Reference)value; default: throw new IllegalStateException("Not a reference " + kind); } } /** * Get this constant's value as a string. * * @return The value as a string. * @throws IllegalStateException Signals that this constant is not a * string. */ public String stringValue() { switch (kind) { case STRING: return (String)value; default: throw new IllegalStateException("Not a string " + kind); } } /** * Determine whether this constant represents a boolean true value. * * @return <code>true</code> if this constant represents true. */ public boolean isTrue() { switch (kind) { case INTEGER: return 0 != ((Number)value).longValue(); case BIG_INTEGER: return 0 != ((BigInteger)value).signum(); case DOUBLE: return 0 != ((Number)value).doubleValue(); case CHARACTER: return 0 != ((Character)value).charValue(); case STRING: return true; case REFERENCE: return ! ((Reference)value).isNull(); default: throw new AssertionError("Invalid kind " + kind); } } /** * Determine whether this constant represents a null value. * * @return <code>true</code> if this constant represents null. */ public boolean isNull() { switch (kind) { case INTEGER: return 0 == ((Number)value).longValue(); case BIG_INTEGER: return 0 == ((BigInteger)value).signum(); case DOUBLE: return 0 == ((Number)value).doubleValue(); case CHARACTER: return 0 == ((Character)value).charValue(); case STRING: return false; case REFERENCE: return ((Reference)value).isNull(); default: throw new AssertionError("Invalid kind " + kind); } } }