001: /*
002: * Janino - An embedded Java[TM] compiler
003: *
004: * Copyright (c) 2001-2007, Arno Unkrig
005: * All rights reserved.
006: *
007: * Redistribution and use in source and binary forms, with or without
008: * modification, are permitted provided that the following conditions
009: * are met:
010: *
011: * 1. Redistributions of source code must retain the above copyright
012: * notice, this list of conditions and the following disclaimer.
013: * 2. Redistributions in binary form must reproduce the above
014: * copyright notice, this list of conditions and the following
015: * disclaimer in the documentation and/or other materials
016: * provided with the distribution.
017: * 3. The name of the author may not be used to endorse or promote
018: * products derived from this software without specific prior
019: * written permission.
020: *
021: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
022: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
023: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
024: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
025: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
026: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
027: * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
028: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
029: * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
030: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
031: * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
032: */
033:
034: package org.codehaus.janino;
035:
036: /**
037: * Helper class that defines useful methods for handling "field descriptors"
038: * (JVMS 4.3.2) and "method descriptors" (JVMS 4.3.3).<p>
039: * Typical descriptors are:
040: * <ul>
041: * <li><code>I</code> Integer
042: * <li><code>[I</code> Array of integer
043: * <li><code>Lpkg1/pkg2/Cls;</code> Class
044: * <li><code>Lpkg1/pkg2/Outer$Inner;</code> Member class
045: * </ul>
046: */
047: public class Descriptor {
048: public static boolean isReference(String d) {
049: return d.length() > 1;
050: }
051:
052: public static boolean isClassOrInterfaceReference(String d) {
053: return d.charAt(0) == 'L';
054: }
055:
056: public static boolean isArrayReference(String d) {
057: return d.charAt(0) == '[';
058: }
059:
060: public static String getComponentDescriptor(String d) {
061: if (d.charAt(0) != '[')
062: throw new RuntimeException(
063: "Cannot determine component descriptor from non-array descriptor \""
064: + d + "\"");
065: return d.substring(1);
066: }
067:
068: public static short size(String d) {
069: if (d.equals(Descriptor.VOID_))
070: return 0;
071: if (Descriptor.hasSize1(d))
072: return 1;
073: if (Descriptor.hasSize2(d))
074: return 2;
075: throw new RuntimeException("No size defined for type \""
076: + Descriptor.toString(d) + "\"");
077: }
078:
079: public static boolean hasSize1(String d) {
080: if (d.length() == 1)
081: return "BCFISZ".indexOf(d) != -1;
082: return Descriptor.isReference(d);
083: }
084:
085: public static boolean hasSize2(String d) {
086: return d.equals(Descriptor.LONG_)
087: || d.equals(Descriptor.DOUBLE_);
088: }
089:
090: // Pretty-print.
091: public static String toString(String d) {
092: int idx = 0;
093: StringBuffer sb = new StringBuffer();
094: if (d.charAt(0) == '(') {
095: ++idx;
096: sb.append("(");
097: while (idx < d.length() && d.charAt(idx) != ')') {
098: if (idx != 1)
099: sb.append(", ");
100: idx = Descriptor.toString(d, idx, sb);
101: }
102: if (idx >= d.length())
103: throw new RuntimeException("Invalid descriptor \"" + d
104: + "\"");
105: sb.append(") => ");
106: ++idx;
107: }
108: Descriptor.toString(d, idx, sb);
109: return sb.toString();
110: }
111:
112: private static int toString(String d, int idx, StringBuffer sb) {
113: int dimensions = 0;
114: while (idx < d.length() && d.charAt(idx) == '[') {
115: ++dimensions;
116: ++idx;
117: }
118: if (idx >= d.length())
119: throw new RuntimeException("Invalid descriptor \"" + d
120: + "\"");
121: switch (d.charAt(idx)) {
122: case 'L': {
123: int idx2 = d.indexOf(';', idx);
124: if (idx2 == -1)
125: throw new RuntimeException("Invalid descriptor \"" + d
126: + "\"");
127: sb.append(d.substring(idx + 1, idx2).replace('/', '.'));
128: idx = idx2;
129: }
130: break;
131: case 'V':
132: sb.append("void");
133: break;
134: case 'B':
135: sb.append("byte");
136: break;
137: case 'C':
138: sb.append("char");
139: break;
140: case 'D':
141: sb.append("double");
142: break;
143: case 'F':
144: sb.append("float");
145: break;
146: case 'I':
147: sb.append("int");
148: break;
149: case 'J':
150: sb.append("long");
151: break;
152: case 'S':
153: sb.append("short");
154: break;
155: case 'Z':
156: sb.append("boolean");
157: break;
158: default:
159: throw new RuntimeException("Invalid descriptor \"" + d
160: + "\"");
161: }
162: for (; dimensions > 0; --dimensions)
163: sb.append("[]");
164: return idx + 1;
165: }
166:
167: /**
168: * Convert a class name as defined by "Class.getName()" into a
169: * descriptor.
170: */
171: public static String fromClassName(String className) {
172: if (className.equals("void"))
173: return Descriptor.VOID_;
174: if (className.equals("byte"))
175: return Descriptor.BYTE_;
176: if (className.equals("char"))
177: return Descriptor.CHAR_;
178: if (className.equals("double"))
179: return Descriptor.DOUBLE_;
180: if (className.equals("float"))
181: return Descriptor.FLOAT_;
182: if (className.equals("int"))
183: return Descriptor.INT_;
184: if (className.equals("long"))
185: return Descriptor.LONG_;
186: if (className.equals("short"))
187: return Descriptor.SHORT_;
188: if (className.equals("boolean"))
189: return Descriptor.BOOLEAN_;
190: if (className.startsWith("["))
191: return className.replace('.', '/');
192: return 'L' + className.replace('.', '/') + ';';
193: }
194:
195: /**
196: * Convert a class name in the "internal form" as described in JVMS 4.2 into a descriptor.
197: * <p>
198: * Also implement the encoding of array types as described in JVMS 4.4.1.
199: */
200: public static String fromInternalForm(String internalForm) {
201: if (internalForm.charAt(0) == '[')
202: return internalForm;
203: return 'L' + internalForm + ';';
204: }
205:
206: /**
207: * Convert a field descriptor into a class name as defined by {@link
208: * Class#getName()}.
209: */
210: public static String toClassName(String d) {
211: if (d.length() == 1) {
212: if (d.equals(Descriptor.VOID_))
213: return "void";
214: if (d.equals(Descriptor.BYTE_))
215: return "byte";
216: if (d.equals(Descriptor.CHAR_))
217: return "char";
218: if (d.equals(Descriptor.DOUBLE_))
219: return "double";
220: if (d.equals(Descriptor.FLOAT_))
221: return "float";
222: if (d.equals(Descriptor.INT_))
223: return "int";
224: if (d.equals(Descriptor.LONG_))
225: return "long";
226: if (d.equals(Descriptor.SHORT_))
227: return "short";
228: if (d.equals(Descriptor.BOOLEAN_))
229: return "boolean";
230: } else {
231: char firstChar = d.charAt(0);
232: if (firstChar == 'L' && d.endsWith(";")) {
233:
234: // Class or interface -- convert "Ljava/lang/String;" to "java.lang.String".
235: return d.substring(1, d.length() - 1).replace('/', '.');
236: }
237: if (firstChar == '[') {
238:
239: // Array type -- convert "[Ljava/lang/String;" to "[Ljava.lang.String;".
240: return d.replace('/', '.');
241: }
242: }
243: throw new RuntimeException("(Invalid field descriptor \"" + d
244: + "\")");
245: }
246:
247: /**
248: * Convert a descriptor into the "internal form" as defined by JVMS 4.2.
249: */
250: public static String toInternalForm(String d) {
251: if (d.charAt(0) != 'L')
252: throw new RuntimeException(
253: "Attempt to convert non-class descriptor \"" + d
254: + "\" into internal form");
255: return d.substring(1, d.length() - 1);
256: }
257:
258: public static boolean isPrimitive(String d) {
259: return d.length() == 1
260: && "VBCDFIJSZ".indexOf(d.charAt(0)) != -1;
261: }
262:
263: public static boolean isPrimitiveNumeric(String d) {
264: return d.length() == 1 && "BDFIJSC".indexOf(d.charAt(0)) != -1;
265: }
266:
267: /**
268: * Returns the package name of a class or interface reference descriptor,
269: * or <code>null</code> if the class or interface is declared in the
270: * default package.
271: */
272: public static String getPackageName(String d) {
273: if (d.charAt(0) != 'L')
274: throw new RuntimeException(
275: "Attempt to get package name of non-class descriptor \""
276: + d + "\"");
277: int idx = d.lastIndexOf('/');
278: return idx == -1 ? null : d.substring(1, idx).replace('/', '.');
279: }
280:
281: /**
282: * Check whether two reference types are declared in the same package.
283: */
284: public static boolean areInSamePackage(String d1, String d2) {
285: String packageName1 = Descriptor.getPackageName(d1);
286: String packageName2 = Descriptor.getPackageName(d2);
287: return packageName1 == null ? packageName2 == null
288: : packageName1.equals(packageName2);
289: }
290:
291: public final static String VOID_ = "V";
292: public final static String BYTE_ = "B";
293: public final static String CHAR_ = "C";
294: public final static String DOUBLE_ = "D";
295: public final static String FLOAT_ = "F";
296: public final static String INT_ = "I";
297: public final static String LONG_ = "J";
298: public final static String SHORT_ = "S";
299: public final static String BOOLEAN_ = "Z";
300: public final static String OBJECT = "Ljava/lang/Object;";
301: public final static String STRING = "Ljava/lang/String;";
302: public final static String STRING_BUFFER = "Ljava/lang/StringBuffer;";
303: public final static String STRING_BUILDER = "Ljava/lang/StringBuilder;"; // Since 1.5!
304: public final static String CLASS = "Ljava/lang/Class;";
305: public final static String THROWABLE = "Ljava/lang/Throwable;";
306: public final static String RUNTIME_EXCEPTION = "Ljava/lang/RuntimeException;";
307: public final static String ERROR = "Ljava/lang/Error;";
308: public final static String CLONEABLE = "Ljava/lang/Cloneable;";
309: public final static String SERIALIZABLE = "Ljava/io/Serializable;";
310: public final static String BOOLEAN = "Ljava/lang/Boolean;";
311: public final static String BYTE = "Ljava/lang/Byte;";
312: public final static String CHARACTER = "Ljava/lang/Character;";
313: public final static String SHORT = "Ljava/lang/Short;";
314: public final static String INTEGER = "Ljava/lang/Integer;";
315: public final static String LONG = "Ljava/lang/Long;";
316: public final static String FLOAT = "Ljava/lang/Float;";
317: public final static String DOUBLE = "Ljava/lang/Double;";
318: }
|