/*
* This file is part of JOP, the Java Optimized Processor
* see <http://www.jopdesign.com/>
*
* Copyright (C) 2010, Stefan Hepp (stefan@stefant.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.jopdesign.common.type;
import com.jopdesign.common.misc.AppInfoError;
import com.jopdesign.common.misc.Ternary;
import org.apache.bcel.Constants;
import org.apache.bcel.generic.ArrayType;
import org.apache.bcel.generic.ObjectType;
import org.apache.bcel.generic.ReferenceType;
import org.apache.bcel.generic.Type;
/**
* TypeInfo is a (mutable) wrapper of a BCEL type, and extends it with some
* custom methods, e.g. to allow further restriction of the value domain.
*
* @author Stefan Hepp (stefan@stefant.org)
*/
public class TypeInfo<T extends Type> {
public static TypeInfo getTypeInfo(Type type) {
switch (type.getType()) {
case Constants.T_UNKNOWN: return new TypeInfo<Type>(Type.UNKNOWN);
case Constants.T_VOID: return new BasicTypeInfo(Type.VOID);
case Constants.T_BOOLEAN: return new BasicTypeInfo(Type.BOOLEAN);
case Constants.T_BYTE: return new BasicTypeInfo(Type.BYTE);
case Constants.T_CHAR: return new BasicTypeInfo(Type.CHAR);
case Constants.T_SHORT: return new BasicTypeInfo(Type.SHORT);
case Constants.T_INT: return new BasicTypeInfo(Type.INT);
case Constants.T_LONG: return new BasicTypeInfo(Type.LONG);
case Constants.T_FLOAT: return new BasicTypeInfo(Type.FLOAT);
case Constants.T_DOUBLE: return new BasicTypeInfo(Type.DOUBLE);
case Constants.T_ARRAY:
return new ArrayTypeInfo((ArrayType) type);
case Constants.T_REFERENCE:
if ( type instanceof ObjectType) {
return new ObjectTypeInfo((ObjectType) type);
}
if ( "<null object>".equals(((ReferenceType)type).getSignature()) ) {
return new ReferenceTypeInfo<ReferenceType>(Type.NULL);
}
throw new AppInfoError("Unknown BCEL reference type: " + type);
default:
throw new AppInfoError("Unknown BCEL type ID: " + type.getType());
}
}
public static TypeInfo[] getTypeInfos(Type[] argumentTypes) {
if ( argumentTypes == null ) {
return null;
}
TypeInfo[] args = new TypeInfo[argumentTypes.length];
for ( int i = 0; i < argumentTypes.length; i++ ) {
args[i] = getTypeInfo(argumentTypes[i]);
}
return args;
}
public static Type[] getTypes(TypeInfo[] types) {
Type[] t = new Type[types.length];
for (int i = 0; i < types.length; i++) {
t[i] = types[i].getType();
}
return t;
}
/**
* Get the type used by the JVM for this type.
* @param type the type to check.
* @return one of {@link Constants#T_INT}, {@link Constants#T_LONG}, {@link Constants#T_FLOAT},
* {@link Constants#T_DOUBLE}, {@link Constants#T_REFERENCE}, {@link Constants#T_VOID} or
* {@link Constants#T_UNKNOWN}.
*/
public static byte getMachineType(Type type) {
switch ( type.getType() ) {
case Constants.T_LONG:
case Constants.T_FLOAT:
case Constants.T_DOUBLE:
case Constants.T_INT:
case Constants.T_VOID:
case Constants.T_UNKNOWN:
return type.getType();
case Constants.T_BYTE:
case Constants.T_BOOLEAN:
case Constants.T_CHAR:
case Constants.T_SHORT:
return Constants.T_INT;
case Constants.T_ARRAY:
case Constants.T_REFERENCE:
return Constants.T_REFERENCE;
default:
throw new AppInfoError("Unknown BCEL type ID: " + type.getType());
}
}
public static Ternary canAssign(Type to, Type src) {
// TODO implement
return Ternary.UNKNOWN;
}
private final T type;
protected TypeInfo(T type) {
this.type = type;
}
/**
* Test if this type is compatible to another type without cast.
*
* @param typeInfo the type to compare to.
* @return TRUE if a value of typeInfo can be assigned to a variable of this type, FALSE if they are
* not compatible, and UNKNOWN if it is unknown (e.g. type not known).
*/
public Ternary canAssignFrom(TypeInfo typeInfo) {
return canAssign(getType(), typeInfo.getType());
}
public String getTypeDescriptor() {
return type.getSignature();
}
public String toString() {
return getTypeDescriptor();
}
public T getType() {
return type;
}
public boolean isArray() {
return type.getType() == Constants.T_ARRAY;
}
/**
* Get the type used by the JVM for this type.
* @return one of {@link Constants#T_INT}, {@link Constants#T_LONG}, {@link Constants#T_FLOAT},
* {@link Constants#T_DOUBLE}, {@link Constants#T_REFERENCE}, {@link Constants#T_VOID} or
* {@link Constants#T_UNKNOWN}.
*/
public byte getMachineType() {
return getMachineType(type);
}
}