001: /*
002: * xtc - The eXTensible Compiler
003: * Copyright (C) 2006-2007 Robert Grimm
004: *
005: * This program is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU General Public License
007: * version 2 as published by the Free Software Foundation.
008: *
009: * This program is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU General Public License for more details.
013: *
014: * You should have received a copy of the GNU General Public License
015: * along with this program; if not, write to the Free Software
016: * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
017: * USA.
018: */
019: package xtc.type;
020:
021: import java.math.BigInteger;
022:
023: /**
024: * Representation of a type's constant value. A constant value may be
025: * one of the following:<ul>
026: * <li>A boxed byte, short, int, or long.</li>
027: * <li>A big integer.</li>
028: * <li>A boxed char.</li>
029: * <li>A string.</li>
030: * <li>A {@link Reference}.</li>
031: * </ul>
032: * This class treats a zero as a null value. It also treats a zero as
033: * a boolean false value and any other number as a boolean true value.
034: *
035: * @author Robert Grimm
036: * @version $Revision: 1.11 $
037: */
038: public class Constant {
039:
040: /** The kind. */
041: public static enum Kind {
042: /** An integer. */
043: INTEGER,
044: /** A big integer. */
045: BIG_INTEGER,
046: /** A double. */
047: DOUBLE,
048: /** A character. */
049: CHARACTER,
050: /** A string. */
051: STRING,
052: /** A reference. */
053: REFERENCE
054: }
055:
056: // =========================================================================
057:
058: /** The kind. */
059: private Kind kind;
060:
061: /** The value. */
062: private Object value;
063:
064: /**
065: * Create a new constant value.
066: *
067: * @param value The value.
068: * @throws IllegalArgumentException Signals an invalid value.
069: */
070: public Constant(Object value) {
071: this .value = value;
072: if (null == value) {
073: throw new NullPointerException();
074:
075: } else if (value instanceof Number) {
076: if ((value instanceof Byte) || (value instanceof Short)
077: || (value instanceof Integer)
078: || (value instanceof Long)) {
079: kind = Kind.INTEGER;
080:
081: } else if (value instanceof BigInteger) {
082: kind = Kind.BIG_INTEGER;
083:
084: } else if ((value instanceof Float)
085: || (value instanceof Double)) {
086: kind = Kind.DOUBLE;
087:
088: } else {
089: throw new IllegalArgumentException("Invalid number "
090: + value);
091: }
092:
093: } else if (value instanceof Character) {
094: kind = Kind.CHARACTER;
095:
096: } else if (value instanceof String) {
097: kind = Kind.STRING;
098:
099: } else if (value instanceof Reference) {
100: kind = Kind.REFERENCE;
101:
102: } else {
103: throw new IllegalArgumentException("invalid value " + value);
104: }
105: }
106:
107: /**
108: * Get this constant's kind.
109: *
110: * @return The kind.
111: */
112: public Kind getKind() {
113: return kind;
114: }
115:
116: /**
117: * Determine whether this constant's value can be treated as a
118: * number.
119: *
120: * @return <code>true</code> if this constant's kind is an integer,
121: * big integer, double, or character.
122: */
123: public boolean isNumber() {
124: switch (kind) {
125: case CHARACTER:
126: case INTEGER:
127: case BIG_INTEGER:
128: case DOUBLE:
129: return true;
130: default:
131: return false;
132: }
133: }
134:
135: /**
136: * Determine whether this constant's value is a string.
137: *
138: * @return <code>true</code> if this constant's value is a string.
139: */
140: public boolean isString() {
141: return Kind.STRING == kind;
142: }
143:
144: /**
145: * Determine whether this constant's value is a reference.
146: *
147: * @return <code>true</code> if this constant's value is a
148: * reference.
149: */
150: public boolean isReference() {
151: return Kind.REFERENCE == kind;
152: }
153:
154: /**
155: * Get this constant's value.
156: *
157: * @return The value.
158: */
159: public Object getValue() {
160: return value;
161: }
162:
163: /**
164: * Get this constant's value as a long.
165: *
166: * @return The value as a long.
167: * @throws IllegalStateException Signals that this constant cannot
168: * be converted to a long.
169: */
170: public long longValue() {
171: switch (kind) {
172: case INTEGER:
173: case BIG_INTEGER:
174: case DOUBLE:
175: return ((Number) value).longValue();
176: case CHARACTER:
177: return ((Character) value).charValue();
178: default:
179: throw new IllegalStateException("Not a number " + kind);
180: }
181: }
182:
183: /**
184: * Get this constant's value as a big integer.
185: *
186: * @return The value as a big integer.
187: * @throws IllegalStateException Signals that this constant cannot
188: * be converted to a big integer.
189: */
190: public BigInteger bigIntValue() {
191: switch (kind) {
192: case INTEGER:
193: return BigInteger.valueOf(((Number) value).longValue());
194: case BIG_INTEGER:
195: return (BigInteger) value;
196: case CHARACTER:
197: return BigInteger.valueOf(((Character) value).charValue());
198: default:
199: throw new IllegalStateException("Not a big integer " + kind);
200: }
201: }
202:
203: /**
204: * Get this constant's value as a double.
205: *
206: * @return The value as a double.
207: * @throws IllegalStateException Signals that this constant cannot
208: * be converted to a double.
209: */
210: public double doubleValue() {
211: switch (kind) {
212: case INTEGER:
213: case BIG_INTEGER:
214: case DOUBLE:
215: return ((Number) value).doubleValue();
216: case CHARACTER:
217: return ((Character) value).charValue();
218: default:
219: throw new IllegalStateException("Not a number " + kind);
220: }
221: }
222:
223: /**
224: * Get this constant's value as a reference.
225: *
226: * @return The value as a reference.
227: * @throws IllegalStateException Signals that this constant is not a
228: * reference.
229: */
230: public Reference refValue() {
231: switch (kind) {
232: case REFERENCE:
233: return (Reference) value;
234: default:
235: throw new IllegalStateException("Not a reference " + kind);
236: }
237: }
238:
239: /**
240: * Get this constant's value as a string.
241: *
242: * @return The value as a string.
243: * @throws IllegalStateException Signals that this constant is not a
244: * string.
245: */
246: public String stringValue() {
247: switch (kind) {
248: case STRING:
249: return (String) value;
250: default:
251: throw new IllegalStateException("Not a string " + kind);
252: }
253: }
254:
255: /**
256: * Determine whether this constant represents a boolean true value.
257: *
258: * @return <code>true</code> if this constant represents true.
259: */
260: public boolean isTrue() {
261: switch (kind) {
262: case INTEGER:
263: return 0 != ((Number) value).longValue();
264: case BIG_INTEGER:
265: return 0 != ((BigInteger) value).signum();
266: case DOUBLE:
267: return 0 != ((Number) value).doubleValue();
268: case CHARACTER:
269: return 0 != ((Character) value).charValue();
270: case STRING:
271: return true;
272: case REFERENCE:
273: return !((Reference) value).isNull();
274: default:
275: throw new AssertionError("Invalid kind " + kind);
276: }
277: }
278:
279: /**
280: * Determine whether this constant represents a null value.
281: *
282: * @return <code>true</code> if this constant represents null.
283: */
284: public boolean isNull() {
285: switch (kind) {
286: case INTEGER:
287: return 0 == ((Number) value).longValue();
288: case BIG_INTEGER:
289: return 0 == ((BigInteger) value).signum();
290: case DOUBLE:
291: return 0 == ((Number) value).doubleValue();
292: case CHARACTER:
293: return 0 == ((Character) value).charValue();
294: case STRING:
295: return false;
296: case REFERENCE:
297: return ((Reference) value).isNull();
298: default:
299: throw new AssertionError("Invalid kind " + kind);
300: }
301: }
302:
303: }
|