001: /*
002: * TclInteger.java
003: *
004: * Copyright (c) 1997 Sun Microsystems, Inc.
005: *
006: * See the file "license.terms" for information on usage and
007: * redistribution of this file, and for a DISCLAIMER OF ALL
008: * WARRANTIES.
009: *
010: * RCS: @(#) $Id: TclInteger.java,v 1.17 2006/06/13 06:52:47 mdejong Exp $
011: *
012: */
013:
014: package tcl.lang;
015:
016: /**
017: * This class implements the integer object type in Tcl.
018: */
019:
020: public class TclInteger implements InternalRep {
021:
022: // The int value for a TclInteger type is stored
023: // in the TclObject instance. The TclObject API
024: // requires that every TclObject have a non-null
025: // internal rep, so this dummy value is used
026: // for every TclObject with an int value.
027: // The dummy value also maintains compatibility with
028: // old code that might check for an internal
029: // rep via:
030: //
031: // if (tobj.getInternalRep() instanceof TclInteger) {...}
032:
033: final static TclInteger dummy = new TclInteger();
034:
035: // Extra debug checking
036: private static final boolean validate = false;
037:
038: private TclInteger() {
039: }
040:
041: /**
042: * Should never be invoked.
043: */
044:
045: public InternalRep duplicate() {
046: throw new TclRuntimeError(
047: "TclInteger.duplicate() should not be invoked");
048: }
049:
050: /**
051: * Implement this no-op for the InternalRep interface.
052: */
053:
054: public void dispose() {
055: }
056:
057: /**
058: * Should never be invoked.
059: */
060: public String toString() {
061: throw new TclRuntimeError(
062: "TclInteger.toString() should not be invoked");
063: }
064:
065: /**
066: * Tcl_NewIntObj -> TclInteger.newInstance
067: *
068: * Creates a new instance of a TclObject with a TclInteger internal
069: * representation.
070: *
071: * @param b initial value of the integer object.
072: * @return the TclObject with the given integer value.
073: */
074:
075: public static TclObject newInstance(int i) {
076: return new TclObject(i);
077: }
078:
079: /**
080: * SetIntFromAny -> TclInteger.setIntegerFromAny
081: *
082: * Called to convert the other object's internal rep to this type.
083: *
084: * @param interp current interpreter.
085: * @param tobj the TclObject to convert to use the
086: * representation provided by this class.
087: */
088:
089: private static void setIntegerFromAny(Interp interp, TclObject tobj)
090: throws TclException {
091: // Note that this method is never invoked when the
092: // object is already an integer type. This method
093: // does not check for a TclBoolean internal rep
094: // since it would typically only be used only for
095: // the "true" and "false" string values. An
096: // int value like "1" or "0" that can be a boolean
097: // value will not be converted to TclBoolean.
098: //
099: // This method also does not check for a TclDouble
100: // internal rep since a double like "1.0" can't
101: // be converted to an integer. An octal like
102: // "040" could be parsed as both a double and
103: // an integer, but the TclDouble module should
104: // not allow conversion to TclDouble in that case.
105:
106: int ivalue = Util.getInt(interp, tobj.toString());
107: tobj.setInternalRep(dummy);
108: tobj.ivalue = ivalue;
109:
110: if (TclObject.saveObjRecords) {
111: String key = "TclString -> TclInteger";
112: Integer num = (Integer) TclObject.objRecordMap.get(key);
113: if (num == null) {
114: num = new Integer(1);
115: } else {
116: num = new Integer(num.intValue() + 1);
117: }
118: TclObject.objRecordMap.put(key, num);
119: }
120: }
121:
122: /**
123: * Tcl_GetIntFromObj -> TclInteger.get
124: *
125: * Returns the integer value of the object.
126: *
127: * @param interp current interpreter.
128: * @param tobj the object to operate on.
129: * @return the integer value of the object.
130: */
131:
132: public static int get(final Interp interp, final TclObject tobj)
133: throws TclException {
134: if (!tobj.isIntType()) {
135: setIntegerFromAny(interp, tobj);
136: }
137: return tobj.ivalue;
138: }
139:
140: /**
141: * Changes the integer value of the object.
142: *
143: * @param interp current interpreter.
144: * @param tobj the object to operate on.
145: * @param i the new integer value.
146: */
147: public static void set(TclObject tobj, int i) {
148: if (!tobj.isIntType()) {
149: // Change the internal rep if not an integer.
150: // Note that this method does not reparse
151: // an int value from the string rep.
152: tobj.setInternalRep(dummy);
153: }
154: tobj.invalidateStringRep();
155: tobj.ivalue = i;
156: }
157:
158: /**
159: * Increments the integer value of the object by the given
160: * amount. One could implement this same operation by
161: * calling get() and then set(), this method provides an
162: * optimized implementation. This method is not public
163: * since it will only be invoked by the incr command.
164: *
165: * @param interp current interpreter.
166: * @param tobj the object to operate on.
167: * @param incrAmount amount to increment
168: */
169: static void incr(final Interp interp, final TclObject tobj,
170: final int incrAmount) throws TclException {
171: if (!tobj.isIntType()) {
172: setIntegerFromAny(interp, tobj);
173: }
174: tobj.invalidateStringRep();
175: tobj.ivalue += incrAmount;
176: }
177:
178: /**
179: * This special helper method is used only by
180: * the Expression module. This method will
181: * change the internal rep to a TclInteger with
182: * the passed in int value. This method does
183: * not invalidate the string rep since the
184: * object's value is not being changed.
185: *
186: * @param tobj the object to operate on.
187: * @param i the new int value.
188: */
189:
190: static void exprSetInternalRep(final TclObject tobj, final int i) {
191: if (validate) {
192:
193: // Double check that the internal rep is not
194: // already of type TclInteger.
195:
196: if (tobj.isIntType()) {
197: throw new TclRuntimeError(
198: "exprSetInternalRep() called with object"
199: + " that is already of type TclInteger");
200: }
201:
202: // Double check that the new int value and the
203: // string rep would parse to the same integer.
204:
205: int i2;
206: try {
207: i2 = Util.getInt(null, tobj.toString());
208: } catch (TclException te) {
209: throw new TclRuntimeError(
210: "exprSetInternalRep() called with int"
211: + " value that could not be parsed from the string");
212: }
213: if (i != i2) {
214: throw new TclRuntimeError(
215: "exprSetInternalRep() called with int value "
216: + i
217: + " that does not match parsed int value "
218: + i2 + ", parsed from str \""
219: + tobj.toString() + "\"");
220: }
221: }
222:
223: tobj.setInternalRep(dummy);
224: tobj.ivalue = i;
225: }
226:
227: }
|