001: package gnu.bytecode;
002:
003: import java.io.*;
004:
005: public class PrimType extends Type {
006:
007: public PrimType(String nam, String sig, int siz, Class reflectClass) {
008: super (nam, sig);
009: size = siz;
010: this .reflectClass = reflectClass;
011: Type.registerTypeForClass(reflectClass, this );
012: }
013:
014: protected PrimType(PrimType type) {
015: this (type.this _name, type.signature, type.size,
016: type.reflectClass);
017: }
018:
019: public Object coerceFromObject(Object obj) {
020: if (obj.getClass() == reflectClass)
021: return obj;
022: char sig1 = (signature == null || signature.length() != 1) ? ' '
023: : signature.charAt(0);
024: switch (sig1) {
025: case 'B':
026: return new Byte(((Number) obj).byteValue());
027: case 'S':
028: return new Short(((Number) obj).shortValue());
029: case 'I':
030: return new Integer(intValue(obj));
031: case 'J':
032: return new Long(longValue(obj));
033: case 'F':
034: return new Float(((Number) obj).floatValue());
035: case 'D':
036: return new Double(((Number) obj).doubleValue());
037: }
038: throw new ClassCastException("don't know how to coerce "
039: + obj.getClass().getName() + " to " + getName());
040: }
041:
042: /** Coerce value to an int.
043: * Only defined if getSignature() is "I". */
044: public int intValue(Object value) {
045: try {
046: return ((Number) value).intValue();
047: } catch (ClassCastException e) {
048: return ((Character) value).charValue();
049: }
050: }
051:
052: /** Coerce value to a long.
053: * Only defined if getSignature() is "L". */
054: public long longValue(Object value) {
055: try {
056: return ((Number) value).longValue();
057: } catch (ClassCastException e) {
058: return ((Character) value).charValue();
059: }
060: }
061:
062: /** Coerce value to a char.
063: * Only defined if getSignature() is "C". */
064: public char charValue(Object value) {
065: return ((Character) value).charValue();
066: }
067:
068: /** Coerce value to a boolean.
069: * Only defined if getSignature() is "Z". */
070: public static boolean booleanValue(Object value) {
071: return !(value instanceof Boolean)
072: || ((Boolean) value).booleanValue();
073: }
074:
075: public void emitCoerceFromObject(CodeAttr code) {
076: char sig1 = (signature == null || signature.length() != 1) ? ' '
077: : signature.charAt(0);
078: if (sig1 == 'Z') // boolean
079: {
080: code.emitCheckcast(boolean_ctype);
081: code.emitInvokeVirtual(booleanValue_method);
082: } else if (sig1 == 'V')
083: code.emitPop(1);
084: else if (sig1 == 'C') {
085: code.emitCheckcast(character_type);
086: code.emitInvokeVirtual(charValue_method);
087: } else {
088: code.emitCheckcast(number_type);
089: if (sig1 == 'I' || sig1 == 'S' || sig1 == 'B')
090: code.emitInvokeVirtual(intValue_method);
091: else if (sig1 == 'J')
092: code.emitInvokeVirtual(longValue_method);
093: else if (sig1 == 'D')
094: code.emitInvokeVirtual(doubleValue_method);
095: else if (sig1 == 'F')
096: code.emitInvokeVirtual(floatValue_method);
097: else
098: super .emitCoerceFromObject(code);
099: }
100: }
101:
102: private static Field trueBoolean;
103: private static Field falseBoolean;
104: private static Method int_init, long_init, char_init;
105: private static Method float_init, double_init;
106:
107: public void emitCoerceToObject(CodeAttr code) {
108: char sig1 = (signature == null || signature.length() != 1) ? ' '
109: : signature.charAt(0);
110: switch (sig1) {
111: case 'Z': // boolean
112: if (trueBoolean == null) {
113: trueBoolean = boolean_ctype.getDeclaredField("TRUE");
114: falseBoolean = boolean_ctype.getDeclaredField("FALSE");
115: }
116:
117: code.emitIfIntNotZero();
118: code.emitGetStatic(trueBoolean);
119: code.emitElse();
120: code.emitGetStatic(falseBoolean);
121: code.emitFi();
122: return;
123: case 'I':
124: case 'S':
125: case 'B': // int, short, byte
126: if (int_init == null) {
127: int_init = int_ctype.getDeclaredMethod("<init>",
128: new Type[] { int_type });
129: }
130:
131: code.emitNew(int_ctype);
132: code.emitDupX();
133: code.emitSwap();
134: code.emitInvokeSpecial(int_init);
135: return;
136: case 'J': // long
137: if (long_init == null) {
138: long_init = long_ctype.getDeclaredMethod("<init>",
139: new Type[] { this });
140: }
141:
142: code.emitNew(long_ctype);
143: code.emitDupX();
144: code.emitDupX();
145: code.emitPop(1);
146: code.emitInvokeSpecial(long_init);
147: return;
148: case 'F': // float
149: if (float_init == null) {
150: float_init = float_ctype.getDeclaredMethod("<init>",
151: new Type[] { float_type });
152: }
153:
154: code.emitNew(float_ctype);
155: code.emitDupX();
156: code.emitSwap();
157: code.emitInvokeSpecial(float_init);
158: return;
159: case 'D': // double
160: if (double_init == null) {
161: double_init = double_ctype.getDeclaredMethod("<init>",
162: new Type[] { double_type });
163: }
164:
165: code.emitNew(double_ctype);
166: code.emitDupX();
167: code.emitDupX();
168: code.emitPop(1);
169: code.emitInvokeSpecial(double_init);
170: return;
171: case 'C': // char
172: if (char_init == null) {
173: char_init = char_ctype.getDeclaredMethod("<init>",
174: new Type[] { this });
175: }
176:
177: code.emitNew(char_ctype);
178: code.emitDupX();
179: code.emitSwap();
180: code.emitInvokeSpecial(char_init);
181: return;
182: }
183:
184: throw new Error("unimplemented emitCoerceToObject for " + this );
185: }
186:
187: public static int compare(PrimType type1, PrimType type2) {
188: char sig1 = type1.signature.charAt(0);
189: char sig2 = type2.signature.charAt(0);
190:
191: if (sig1 == sig2)
192: return 0;
193:
194: // Anything can be converted to void, but not vice versa.
195: if (sig1 == 'V')
196: return 1;
197: if (sig2 == 'V')
198: return -1;
199:
200: // In Java, no other type can be converted to/from boolean.
201: // Other languages, including C and Scheme are different:
202: // "everything" can be converted to a boolean.
203: if (sig1 == 'Z' || sig2 == 'Z')
204: return -3;
205:
206: if (sig1 == 'C')
207: return type2.size > 2 ? -1 : -3;
208: if (sig2 == 'C')
209: return type1.size > 2 ? 1 : -3;
210:
211: if (sig1 == 'D')
212: return 1;
213: if (sig2 == 'D')
214: return -1;
215: if (sig1 == 'F')
216: return 1;
217: if (sig2 == 'F')
218: return -1;
219: if (sig1 == 'J')
220: return 1;
221: if (sig2 == 'J')
222: return -1;
223: if (sig1 == 'I')
224: return 1;
225: if (sig2 == 'I')
226: return -1;
227: if (sig1 == 'S')
228: return 1;
229: if (sig2 == 'S')
230: return -1;
231: // Can we get here?
232: return -3;
233: }
234:
235: public int compare(Type other) {
236: if (other instanceof PrimType)
237: return compare(this , (PrimType) other);
238: if (!(other instanceof ClassType))
239: return -3;
240: char sig1 = signature.charAt(0);
241: String otherName = other.getName();
242: // This is very incomplete! FIXME.
243: switch (sig1) {
244: case 'V':
245: return 1;
246: case 'D':
247: if (otherName.equals("java.lang.Double")
248: || otherName.equals("gnu.math.DFloat"))
249: return 0; // Or maybe 1?
250: break;
251: case 'I':
252: if (otherName.equals("java.lang.Integer"))
253: return 0; // Or maybe 1?
254: if (otherName.equals("gnu.math.IntNum"))
255: return -1;
256: break;
257: }
258: if (otherName.equals("java.lang.Object"))
259: return -1;
260: return -2;
261: }
262:
263: /** @return true if values of this type can be assigned to other
264: <b>without widening nor conversion</b>.
265: */
266: public boolean isAssignableTo(Type other) {
267: return this == other;
268: }
269: }
|