package javassist.compiler;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtPrimitiveType;
import javassist.NotFoundException;
import javassist.compiler.ast.ASTList;
import javassist.compiler.ast.ASTree;
import javassist.compiler.ast.CallExpr;
import javassist.compiler.ast.CastExpr;
import javassist.compiler.ast.Expr;
import javassist.compiler.ast.Member;
import javassist.compiler.ast.Symbol;
public class JvstTypeChecker extends TypeChecker {
private JvstCodeGen codeGen;
public JvstTypeChecker(CtClass cc, ClassPool cp, JvstCodeGen gen) {
super(cc, cp);
codeGen = gen;
}
public void addNullIfVoid() {
if (exprType == VOID) {
exprType = CLASS;
arrayDim = 0;
className = jvmJavaLangObject;
}
}
@Override
public void atMember(Member mem) throws CompileError {
String name = mem.get();
if (name.equals(codeGen.paramArrayName)) {
exprType = CLASS;
arrayDim = 1;
className = jvmJavaLangObject;
}
else if (name.equals(JvstCodeGen.sigName)) {
exprType = CLASS;
arrayDim = 1;
className = "java/lang/Class";
}
else if (name.equals(JvstCodeGen.dollarTypeName)
|| name.equals(JvstCodeGen.clazzName)) {
exprType = CLASS;
arrayDim = 0;
className = "java/lang/Class";
}
else
super.atMember(mem);
}
@Override
protected void atFieldAssign(Expr expr, int op, ASTree left, ASTree right)
throws CompileError
{
if (left instanceof Member
&& ((Member)left).get().equals(codeGen.paramArrayName)) {
right.accept(this);
CtClass[] params = codeGen.paramTypeList;
if (params == null)
return;
int n = params.length;
for (int i = 0; i < n; ++i)
compileUnwrapValue(params[i]);
}
else
super.atFieldAssign(expr, op, left, right);
}
@Override
public void atCastExpr(CastExpr expr) throws CompileError {
ASTList classname = expr.getClassName();
if (classname != null && expr.getArrayDim() == 0) {
ASTree p = classname.head();
if (p instanceof Symbol && classname.tail() == null) {
String typename = ((Symbol)p).get();
if (typename.equals(codeGen.returnCastName)) {
atCastToRtype(expr);
return;
}
else if (typename.equals(JvstCodeGen.wrapperCastName)) {
atCastToWrapper(expr);
return;
}
}
}
super.atCastExpr(expr);
}
protected void atCastToRtype(CastExpr expr) throws CompileError {
CtClass returnType = codeGen.returnType;
expr.getOprand().accept(this);
if (exprType == VOID || CodeGen.isRefType(exprType) || arrayDim > 0)
compileUnwrapValue(returnType);
else if (returnType instanceof CtPrimitiveType) {
CtPrimitiveType pt = (CtPrimitiveType)returnType;
int destType = MemberResolver.descToType(pt.getDescriptor());
exprType = destType;
arrayDim = 0;
className = null;
}
}
protected void atCastToWrapper(CastExpr expr) throws CompileError {
expr.getOprand().accept(this);
if (CodeGen.isRefType(exprType) || arrayDim > 0)
return;
CtClass clazz = resolver.lookupClass(exprType, arrayDim, className);
if (clazz instanceof CtPrimitiveType) {
exprType = CLASS;
arrayDim = 0;
className = jvmJavaLangObject;
}
}
@Override
public void atCallExpr(CallExpr expr) throws CompileError {
ASTree method = expr.oprand1();
if (method instanceof Member) {
String name = ((Member)method).get();
if (codeGen.procHandler != null
&& name.equals(codeGen.proceedName)) {
codeGen.procHandler.setReturnType(this,
(ASTList)expr.oprand2());
return;
}
else if (name.equals(JvstCodeGen.cflowName)) {
atCflow((ASTList)expr.oprand2());
return;
}
}
super.atCallExpr(expr);
}
protected void atCflow(ASTList cname) throws CompileError {
exprType = INT;
arrayDim = 0;
className = null;
}
public boolean isParamListName(ASTList args) {
if (codeGen.paramTypeList != null
&& args != null && args.tail() == null) {
ASTree left = args.head();
return (left instanceof Member
&& ((Member)left).get().equals(codeGen.paramListName));
}
return false;
}
@Override
public int getMethodArgsLength(ASTList args) {
String pname = codeGen.paramListName;
int n = 0;
while (args != null) {
ASTree a = args.head();
if (a instanceof Member && ((Member)a).get().equals(pname)) {
if (codeGen.paramTypeList != null)
n += codeGen.paramTypeList.length;
}
else
++n;
args = args.tail();
}
return n;
}
@Override
public void atMethodArgs(ASTList args, int[] types, int[] dims,
String[] cnames) throws CompileError {
CtClass[] params = codeGen.paramTypeList;
String pname = codeGen.paramListName;
int i = 0;
while (args != null) {
ASTree a = args.head();
if (a instanceof Member && ((Member)a).get().equals(pname)) {
if (params != null) {
int n = params.length;
for (int k = 0; k < n; ++k) {
CtClass p = params[k];
setType(p);
types[i] = exprType;
dims[i] = arrayDim;
cnames[i] = className;
++i;
}
}
}
else {
a.accept(this);
types[i] = exprType;
dims[i] = arrayDim;
cnames[i] = className;
++i;
}
args = args.tail();
}
}
void compileInvokeSpecial(ASTree target, String classname,
String methodname, String descriptor,
ASTList args)
throws CompileError
{
target.accept(this);
int nargs = getMethodArgsLength(args);
atMethodArgs(args, new int[nargs], new int[nargs],
new String[nargs]);
setReturnType(descriptor);
addNullIfVoid();
}
protected void compileUnwrapValue(CtClass type) throws CompileError
{
if (type == CtClass.voidType)
addNullIfVoid();
else
setType(type);
}
public void setType(CtClass type) throws CompileError {
setType(type, 0);
}
private void setType(CtClass type, int dim) throws CompileError {
if (type.isPrimitive()) {
CtPrimitiveType pt = (CtPrimitiveType)type;
exprType = MemberResolver.descToType(pt.getDescriptor());
arrayDim = dim;
className = null;
}
else if (type.isArray())
try {
setType(type.getComponentType(), dim + 1);
}
catch (NotFoundException e) {
throw new CompileError("undefined type: " + type.getName());
}
else {
exprType = CLASS;
arrayDim = dim;
className = MemberResolver.javaToJvmName(type.getName());
}
}
}