001: /*
002: $Id: ClassHelper.java 4215 2006-11-13 11:18:35Z blackdrag $ created on 25.10.2005
003:
004: Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
005:
006: Redistribution and use of this software and associated documentation
007: ("Software"), with or without modification, are permitted provided
008: that the following conditions are met:
009:
010: 1. Redistributions of source code must retain copyright
011: statements and notices. Redistributions must also contain a
012: copy of this document.
013:
014: 2. Redistributions in binary form must reproduce the
015: above copyright notice, this list of conditions and the
016: following disclaimer in the documentation and/or other
017: materials provided with the distribution.
018:
019: 3. The name "groovy" must not be used to endorse or promote
020: products derived from this Software without prior written
021: permission of The Codehaus. For written permission,
022: please contact info@codehaus.org.
023:
024: 4. Products derived from this Software may not be called "groovy"
025: nor may "groovy" appear in their names without prior written
026: permission of The Codehaus. "groovy" is a registered
027: trademark of The Codehaus.
028:
029: 5. Due credit should be given to The Codehaus -
030: http://groovy.codehaus.org/
031:
032: THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
033: ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
034: NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
035: FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
036: THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
037: INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
038: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
039: SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
040: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
041: STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
042: ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
043: OF THE POSSIBILITY OF SUCH DAMAGE.
044: */
045:
046: package org.codehaus.groovy.ast;
047:
048: import groovy.lang.Closure;
049: import groovy.lang.GString;
050: import groovy.lang.MetaClass;
051: import groovy.lang.Range;
052: import groovy.lang.Reference;
053: import groovy.lang.Script;
054:
055: import java.math.BigDecimal;
056: import java.math.BigInteger;
057: import java.util.List;
058: import java.util.Map;
059: import java.util.regex.Pattern;
060:
061: import org.objectweb.asm.Opcodes;
062:
063: /**
064: * This class is a Helper for ClassNode and classes handling ClassNodes.
065: * It does contain a set of predefined ClassNodes for the most used
066: * types and some code for cached ClassNode creation and basic
067: * ClassNode handling
068: *
069: * @author Jochen Theodorou
070: */
071: public class ClassHelper {
072:
073: private static String[] names = new String[] {
074: boolean.class.getName(), char.class.getName(),
075: byte.class.getName(), short.class.getName(),
076: int.class.getName(), long.class.getName(),
077: double.class.getName(), float.class.getName(),
078: Object.class.getName(), Void.TYPE.getName(),
079: Closure.class.getName(), GString.class.getName(),
080: List.class.getName(), Map.class.getName(),
081: Range.class.getName(), Pattern.class.getName(),
082: Script.class.getName(), String.class.getName(),
083: Boolean.class.getName(), Character.class.getName(),
084: Byte.class.getName(), Short.class.getName(),
085: Integer.class.getName(), Long.class.getName(),
086: Double.class.getName(), Float.class.getName(),
087: BigDecimal.class.getName(), BigInteger.class.getName(),
088: Void.class.getName(), Reference.class.getName(),
089: Class.class.getName(), MetaClass.class.getName() };
090:
091: private static Class[] classes = new Class[] { Object.class,
092: Boolean.TYPE, Character.TYPE, Byte.TYPE, Short.TYPE,
093: Integer.TYPE, Long.TYPE, Double.TYPE, Float.TYPE,
094: Void.TYPE, Closure.class, GString.class, List.class,
095: Map.class, Range.class, Pattern.class, Script.class,
096: String.class, Boolean.class, Character.class, Byte.class,
097: Short.class, Integer.class, Long.class, Double.class,
098: Float.class, BigDecimal.class, BigInteger.class,
099: Void.class, Reference.class, Class.class, MetaClass.class };
100:
101: public static final ClassNode DYNAMIC_TYPE = new ClassNode(
102: Object.class),
103: OBJECT_TYPE = DYNAMIC_TYPE,
104: VOID_TYPE = new ClassNode(Void.TYPE),
105: CLOSURE_TYPE = new ClassNode(Closure.class),
106: GSTRING_TYPE = new ClassNode(GString.class),
107: LIST_TYPE = new ClassNode(List.class),
108: MAP_TYPE = new ClassNode(Map.class),
109: RANGE_TYPE = new ClassNode(Range.class),
110: PATTERN_TYPE = new ClassNode(Pattern.class),
111: STRING_TYPE = new ClassNode(String.class),
112: SCRIPT_TYPE = new ClassNode(Script.class),
113: REFERENCE_TYPE = new ClassNode(Reference.class),
114:
115: boolean_TYPE = new ClassNode(boolean.class),
116: char_TYPE = new ClassNode(char.class),
117: byte_TYPE = new ClassNode(byte.class),
118: int_TYPE = new ClassNode(int.class),
119: long_TYPE = new ClassNode(long.class),
120: short_TYPE = new ClassNode(short.class),
121: double_TYPE = new ClassNode(double.class),
122: float_TYPE = new ClassNode(float.class),
123: Byte_TYPE = new ClassNode(Byte.class),
124: Short_TYPE = new ClassNode(Short.class),
125: Integer_TYPE = new ClassNode(Integer.class),
126: Long_TYPE = new ClassNode(Long.class),
127: Character_TYPE = new ClassNode(Character.class),
128: Float_TYPE = new ClassNode(Float.class),
129: Double_TYPE = new ClassNode(Double.class),
130: Boolean_TYPE = new ClassNode(Boolean.class),
131: BigInteger_TYPE = new ClassNode(java.math.BigInteger.class),
132: BigDecimal_TYPE = new ClassNode(java.math.BigDecimal.class),
133: void_WRAPPER_TYPE = new ClassNode(Void.class),
134:
135: CLASS_Type = new ClassNode(Class.class),
136: METACLASS_TYPE = new ClassNode(MetaClass.class);
137:
138: private static ClassNode[] types = new ClassNode[] { OBJECT_TYPE,
139: boolean_TYPE, char_TYPE, byte_TYPE, short_TYPE, int_TYPE,
140: long_TYPE, double_TYPE, float_TYPE, VOID_TYPE,
141: CLOSURE_TYPE, GSTRING_TYPE, LIST_TYPE, MAP_TYPE,
142: RANGE_TYPE, PATTERN_TYPE, SCRIPT_TYPE, STRING_TYPE,
143: Boolean_TYPE, Character_TYPE, Byte_TYPE, Short_TYPE,
144: Integer_TYPE, Long_TYPE, Double_TYPE, Float_TYPE,
145: BigDecimal_TYPE, BigInteger_TYPE, void_WRAPPER_TYPE,
146: REFERENCE_TYPE, CLASS_Type, METACLASS_TYPE };
147:
148: private static ClassNode[] numbers = new ClassNode[] { char_TYPE,
149: byte_TYPE, short_TYPE, int_TYPE, long_TYPE, double_TYPE,
150: float_TYPE, Short_TYPE, Byte_TYPE, Character_TYPE,
151: Integer_TYPE, Float_TYPE, Long_TYPE, Double_TYPE,
152: BigInteger_TYPE, BigDecimal_TYPE };
153:
154: protected static final ClassNode[] EMPTY_TYPE_ARRAY = {};
155:
156: public static final String OBJECT = "java.lang.Object";
157:
158: /**
159: * Creates an array of ClassNodes using an array of classes.
160: * For each of the given classes a new ClassNode will be
161: * created
162: * @see #make(Class)
163: * @param classes an array of classes used to create the ClassNodes
164: * @return an array of ClassNodes
165: */
166: public static ClassNode[] make(Class[] classes) {
167: ClassNode[] cns = new ClassNode[classes.length];
168: for (int i = 0; i < cns.length; i++) {
169: cns[i] = make(classes[i]);
170: }
171:
172: return cns;
173: }
174:
175: /**
176: * Creates a ClassNode using a given class.
177: * A new ClassNode object is only created if the class
178: * is not one of the predefined ones
179: *
180: * @param c class used to created the ClassNode
181: * @return ClassNode instance created from the given class
182: */
183: public static ClassNode make(Class c) {
184: for (int i = 0; i < classes.length; i++) {
185: if (c == classes[i])
186: return types[i];
187: }
188: if (c.isArray()) {
189: ClassNode cn = make(c.getComponentType());
190: return cn.makeArray();
191: }
192: ClassNode t = new ClassNode(c);
193: return t;
194: }
195:
196: /**
197: * Creates a ClassNode using a given class.
198: * Unlike make(String) this method will not use the cache
199: * to create the ClassNode. This means the ClassNode created
200: * from this method using the same name will have a different
201: * references
202: *
203: * @see #make(String)
204: * @param name of the class the ClassNode is representing
205: */
206: public static ClassNode makeWithoutCaching(String name) {
207: ClassNode cn = new ClassNode(name, Opcodes.ACC_PUBLIC,
208: OBJECT_TYPE);
209: cn.isPrimaryNode = false;
210: return cn;
211: }
212:
213: /**
214: * Creates a ClassNode using a given class.
215: * If the name is one of the predefined ClassNodes then the
216: * corresponding ClassNode instance will be returned. If the
217: * is null of of length 0 the dynamic type is returned
218: *
219: * @param name of the class the ClassNode is representing
220: */
221: public static ClassNode make(String name) {
222: if (name == null || name.length() == 0)
223: return DYNAMIC_TYPE;
224:
225: for (int i = 0; i < classes.length; i++) {
226: String cname = classes[i].getName();
227: if (name.equals(cname))
228: return types[i];
229: }
230: return makeWithoutCaching(name);
231: }
232:
233: /**
234: * Creates a ClassNode containing the wrapper of a ClassNode
235: * of primitive type. Any ClassNode representing a primitive
236: * type should be created using the predefined types used in
237: * class. The method will check the parameter for known
238: * references of ClassNode representing a primitive type. If
239: * Reference is found, then a ClassNode will be contained that
240: * represents the wrapper class. For exmaple for boolean, the
241: * wrapper class is java.lang.Boolean.
242: *
243: * If the parameter is no primitve type, the redirected
244: * ClassNode will be returned
245: *
246: * @see #make(Class)
247: * @see #make(String)
248: * @param cn the ClassNode containing a possible primitive type
249: */
250: public static ClassNode getWrapper(ClassNode cn) {
251: cn = cn.redirect();
252: if (!isPrimitiveType(cn))
253: return cn;
254: if (cn == boolean_TYPE) {
255: return Boolean_TYPE;
256: } else if (cn == byte_TYPE) {
257: return Byte_TYPE;
258: } else if (cn == char_TYPE) {
259: return Character_TYPE;
260: } else if (cn == short_TYPE) {
261: return Short_TYPE;
262: } else if (cn == int_TYPE) {
263: return Integer_TYPE;
264: } else if (cn == long_TYPE) {
265: return Long_TYPE;
266: } else if (cn == float_TYPE) {
267: return Float_TYPE;
268: } else if (cn == double_TYPE) {
269: return Double_TYPE;
270: } else if (cn == VOID_TYPE) {
271: return void_WRAPPER_TYPE;
272: } else {
273: return cn;
274: }
275: }
276:
277: /**
278: * Test to determine if a ClasNode is a primitve type.
279: * Note: this only works for ClassNodes created using a
280: * predefined ClassNode
281: *
282: * @see #make(Class)
283: * @see #make(String)
284: * @param cn the ClassNode containing a possible primitive type
285: * @return true if the ClassNode is a primitve type
286: */
287: public static boolean isPrimitiveType(ClassNode cn) {
288: return cn == boolean_TYPE || cn == char_TYPE || cn == byte_TYPE
289: || cn == short_TYPE || cn == int_TYPE
290: || cn == long_TYPE || cn == float_TYPE
291: || cn == double_TYPE || cn == VOID_TYPE;
292: }
293:
294: public static ClassNode makeReference() {
295: return make(Reference.class);
296: }
297:
298: }
|