blob: b38a3ef93639cad40c333d6a9c3b2a805cc6ee81 [file] [log] [blame]
/*
$Id$ created on 25.10.2005
Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
Redistribution and use of this software and associated documentation
("Software"), with or without modification, are permitted provided
that the following conditions are met:
1. Redistributions of source code must retain copyright
statements and notices. Redistributions must also contain a
copy of this document.
2. Redistributions in binary form must reproduce the
above copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
3. The name "groovy" must not be used to endorse or promote
products derived from this Software without prior written
permission of The Codehaus. For written permission,
please contact info@codehaus.org.
4. Products derived from this Software may not be called "groovy"
nor may "groovy" appear in their names without prior written
permission of The Codehaus. "groovy" is a registered
trademark of The Codehaus.
5. Due credit should be given to The Codehaus -
http://groovy.codehaus.org/
THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.groovy.ast;
import groovy.lang.Closure;
import groovy.lang.GString;
import groovy.lang.MetaClass;
import groovy.lang.Range;
import groovy.lang.Reference;
import groovy.lang.Script;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import org.objectweb.asm.Opcodes;
/**
* This class is a Helper for ClassNode and classes handling ClassNodes.
* It does contain a set of predefined ClassNodes for the most used
* types and some code for cached ClassNode creation and basic
* ClassNode handling
*
* @author Jochen Theodorou
*/
public class ClassHelper {
private static String[] names = new String[] {
boolean.class.getName(), char.class.getName(),
byte.class.getName(), short.class.getName(),
int.class.getName(), long.class.getName(),
double.class.getName(), float.class.getName(),
Object.class.getName(), Void.TYPE.getName(),
Closure.class.getName(), GString.class.getName(),
List.class.getName(), Map.class.getName(),
Range.class.getName(), Pattern.class.getName(),
Script.class.getName(), String.class.getName(),
Boolean.class.getName(), Character.class.getName(),
Byte.class.getName(), Short.class.getName(),
Integer.class.getName(), Long.class.getName(),
Double.class.getName(), Float.class.getName(),
BigDecimal.class.getName(), BigInteger.class.getName(),
Void.class.getName(), Reference.class.getName(),
Class.class.getName(), MetaClass.class.getName()
};
private static Class[] classes = new Class[] {
Object.class, Boolean.TYPE, Character.TYPE, Byte.TYPE, Short.TYPE,
Integer.TYPE, Long.TYPE, Double.TYPE, Float.TYPE, Void.TYPE,
Closure.class, GString.class, List.class, Map.class, Range.class,
Pattern.class, Script.class, String.class, Boolean.class,
Character.class, Byte.class, Short.class, Integer.class, Long.class,
Double.class, Float.class, BigDecimal.class, BigInteger.class, Void.class,
Reference.class, Class.class, MetaClass.class
};
public static final ClassNode
DYNAMIC_TYPE = new ClassNode(Object.class), OBJECT_TYPE = DYNAMIC_TYPE,
VOID_TYPE = new ClassNode(Void.TYPE), CLOSURE_TYPE = new ClassNode(Closure.class),
GSTRING_TYPE = new ClassNode(GString.class), LIST_TYPE = new ClassNode(List.class),
MAP_TYPE = new ClassNode(Map.class), RANGE_TYPE = new ClassNode(Range.class),
PATTERN_TYPE = new ClassNode(Pattern.class), STRING_TYPE = new ClassNode(String.class),
SCRIPT_TYPE = new ClassNode(Script.class), REFERENCE_TYPE = new ClassNode(Reference.class),
boolean_TYPE = new ClassNode(boolean.class), char_TYPE = new ClassNode(char.class),
byte_TYPE = new ClassNode(byte.class), int_TYPE = new ClassNode(int.class),
long_TYPE = new ClassNode(long.class), short_TYPE = new ClassNode(short.class),
double_TYPE = new ClassNode(double.class), float_TYPE = new ClassNode(float.class),
Byte_TYPE = new ClassNode(Byte.class), Short_TYPE = new ClassNode(Short.class),
Integer_TYPE = new ClassNode(Integer.class), Long_TYPE = new ClassNode(Long.class),
Character_TYPE = new ClassNode(Character.class), Float_TYPE = new ClassNode(Float.class),
Double_TYPE = new ClassNode(Double.class), Boolean_TYPE = new ClassNode(Boolean.class),
BigInteger_TYPE = new ClassNode(java.math.BigInteger.class),
BigDecimal_TYPE = new ClassNode(java.math.BigDecimal.class),
void_WRAPPER_TYPE = new ClassNode(Void.class),
CLASS_Type = new ClassNode(Class.class), METACLASS_TYPE = new ClassNode(MetaClass.class);
private static ClassNode[] types = new ClassNode[] {
OBJECT_TYPE,
boolean_TYPE, char_TYPE, byte_TYPE, short_TYPE,
int_TYPE, long_TYPE, double_TYPE, float_TYPE,
VOID_TYPE, CLOSURE_TYPE, GSTRING_TYPE,
LIST_TYPE, MAP_TYPE, RANGE_TYPE, PATTERN_TYPE,
SCRIPT_TYPE, STRING_TYPE, Boolean_TYPE, Character_TYPE,
Byte_TYPE, Short_TYPE, Integer_TYPE, Long_TYPE,
Double_TYPE, Float_TYPE, BigDecimal_TYPE, BigInteger_TYPE,
void_WRAPPER_TYPE, REFERENCE_TYPE, CLASS_Type, METACLASS_TYPE
};
private static ClassNode[] numbers = new ClassNode[] {
char_TYPE, byte_TYPE, short_TYPE, int_TYPE, long_TYPE,
double_TYPE, float_TYPE, Short_TYPE, Byte_TYPE, Character_TYPE,
Integer_TYPE, Float_TYPE, Long_TYPE, Double_TYPE, BigInteger_TYPE,
BigDecimal_TYPE
};
protected static final ClassNode[] EMPTY_TYPE_ARRAY = {};
public static final String OBJECT = "java.lang.Object";
/**
* Creates an array of ClassNodes using an array of classes.
* For each of the given classes a new ClassNode will be
* created
* @see #make(Class)
* @param classes an array of classes used to create the ClassNodes
* @return an array of ClassNodes
*/
public static ClassNode[] make(Class[] classes) {
ClassNode[] cns = new ClassNode[classes.length];
for (int i=0; i<cns.length; i++) {
cns[i] = make(classes[i]);
}
return cns;
}
/**
* Creates a ClassNode using a given class.
* A new ClassNode object is only created if the class
* is not one of the predefined ones
*
* @param c class used to created the ClassNode
* @return ClassNode instance created from the given class
*/
public static ClassNode make(Class c) {
for (int i=0; i<classes.length; i++) {
if (c==classes[i]) return types[i];
}
if (c.isArray()) {
ClassNode cn = make(c.getComponentType());
return cn.makeArray();
}
ClassNode t = new ClassNode(c);
return t;
}
/**
* Creates a ClassNode using a given class.
* Unlike make(String) this method will not use the cache
* to create the ClassNode. This means the ClassNode created
* from this method using the same name will have a different
* references
*
* @see #make(String)
* @param name of the class the ClassNode is representing
*/
public static ClassNode makeWithoutCaching(String name) {
ClassNode cn = new ClassNode(name,Opcodes.ACC_PUBLIC,OBJECT_TYPE);
cn.isPrimaryNode = false;
return cn;
}
/**
* Creates a ClassNode using a given class.
* If the name is one of the predefined ClassNodes then the
* corresponding ClassNode instance will be returned. If the
* is null of of length 0 the dynamic type is returned
*
* @param name of the class the ClassNode is representing
*/
public static ClassNode make(String name) {
if (name == null || name.length() == 0) return DYNAMIC_TYPE;
for (int i=0; i<classes.length; i++) {
String cname = classes[i].getName();
if (name.equals(cname)) return types[i];
}
return makeWithoutCaching(name);
}
/**
* Creates a ClassNode containing the wrapper of a ClassNode
* of primitive type. Any ClassNode representing a primitive
* type should be created using the predefined types used in
* class. The method will check the parameter for known
* references of ClassNode representing a primitive type. If
* Reference is found, then a ClassNode will be contained that
* represents the wrapper class. For exmaple for boolean, the
* wrapper class is java.lang.Boolean.
*
* If the parameter is no primitve type, the redirected
* ClassNode will be returned
*
* @see #make(Class)
* @see #make(String)
* @param cn the ClassNode containing a possible primitive type
*/
public static ClassNode getWrapper(ClassNode cn) {
cn = cn.redirect();
if (!isPrimitiveType(cn)) return cn;
if (cn==boolean_TYPE) {
return Boolean_TYPE;
} else if (cn==byte_TYPE) {
return Byte_TYPE;
} else if (cn==char_TYPE) {
return Character_TYPE;
} else if (cn==short_TYPE) {
return Short_TYPE;
} else if (cn==int_TYPE) {
return Integer_TYPE;
} else if (cn==long_TYPE) {
return Long_TYPE;
} else if (cn==float_TYPE) {
return Float_TYPE;
} else if (cn==double_TYPE) {
return Double_TYPE;
} else if (cn==VOID_TYPE) {
return void_WRAPPER_TYPE;
}
else {
return cn;
}
}
/**
* Test to determine if a ClasNode is a primitve type.
* Note: this only works for ClassNodes created using a
* predefined ClassNode
*
* @see #make(Class)
* @see #make(String)
* @param cn the ClassNode containing a possible primitive type
* @return true if the ClassNode is a primitve type
*/
public static boolean isPrimitiveType(ClassNode cn) {
return cn == boolean_TYPE ||
cn == char_TYPE ||
cn == byte_TYPE ||
cn == short_TYPE ||
cn == int_TYPE ||
cn == long_TYPE ||
cn == float_TYPE ||
cn == double_TYPE ||
cn == VOID_TYPE;
}
public static ClassNode makeReference() {
return make(Reference.class);
}
}