aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/javassist
diff options
context:
space:
mode:
authorchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>2003-11-27 05:33:16 +0000
committerchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>2003-11-27 05:33:16 +0000
commitcdca9771599b4c3337aaf42cf7460a27dc1719d5 (patch)
tree9617dfa2aa53d78c6bd2d3cf4428137d355faa76 /src/main/javassist
parentced4ae1f0e2130b36cb51faf6345d5b8e036585e (diff)
downloadjavassist-cdca9771599b4c3337aaf42cf7460a27dc1719d5.tar.gz
javassist-cdca9771599b4c3337aaf42cf7460a27dc1719d5.zip
I implemented a type checker for better code generation.
git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@55 30ef5769-5b8d-40dd-aea6-55b5d6557bb3
Diffstat (limited to 'src/main/javassist')
-rw-r--r--src/main/javassist/URLClassPath.java2
-rw-r--r--src/main/javassist/compiler/CodeGen.java191
-rw-r--r--src/main/javassist/compiler/Javac.java50
-rw-r--r--src/main/javassist/compiler/JvstCodeGen.java57
-rw-r--r--src/main/javassist/compiler/JvstTypeChecker.java282
-rw-r--r--src/main/javassist/compiler/MemberCodeGen.java448
-rw-r--r--src/main/javassist/compiler/MemberResolver.java461
-rw-r--r--src/main/javassist/compiler/Parser.java4
-rw-r--r--src/main/javassist/compiler/ProceedHandler.java4
-rw-r--r--src/main/javassist/compiler/TypeChecker.java755
-rw-r--r--src/main/javassist/compiler/ast/AssignExpr.java2
-rw-r--r--src/main/javassist/compiler/ast/BinExpr.java5
-rw-r--r--src/main/javassist/compiler/ast/CallExpr.java46
-rw-r--r--src/main/javassist/compiler/ast/CondExpr.java4
-rw-r--r--src/main/javassist/compiler/ast/Expr.java14
-rw-r--r--src/main/javassist/compiler/ast/Visitor.java1
-rw-r--r--src/main/javassist/expr/Cast.java7
-rw-r--r--src/main/javassist/expr/FieldAccess.java14
-rw-r--r--src/main/javassist/expr/Instanceof.java7
-rw-r--r--src/main/javassist/expr/NewExpr.java11
20 files changed, 1847 insertions, 518 deletions
diff --git a/src/main/javassist/URLClassPath.java b/src/main/javassist/URLClassPath.java
index 279b20f1..b455f381 100644
--- a/src/main/javassist/URLClassPath.java
+++ b/src/main/javassist/URLClassPath.java
@@ -61,6 +61,8 @@ public class URLClassPath implements ClassPath {
/**
* Opens a class file with http.
+ *
+ * @return null if the class file is not found.
*/
public InputStream openClassfile(String classname) {
try {
diff --git a/src/main/javassist/compiler/CodeGen.java b/src/main/javassist/compiler/CodeGen.java
index 6a0bd3dc..194c3fdb 100644
--- a/src/main/javassist/compiler/CodeGen.java
+++ b/src/main/javassist/compiler/CodeGen.java
@@ -33,6 +33,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
protected Bytecode bytecode;
private int tempVar;
+ TypeChecker typeChecker;
/**
* true if the last visited node is a return statement.
@@ -56,12 +57,17 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
public CodeGen(Bytecode b) {
bytecode = b;
tempVar = -1;
+ typeChecker = null;
hasReturned = false;
inStaticMethod = false;
breakList = null;
continueList = null;
}
+ public void setTypeChecker(TypeChecker checker) {
+ typeChecker = checker;
+ }
+
protected static void fatal() throws CompileError {
throw new CompileError("fatal");
}
@@ -192,29 +198,21 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
return sbuf.toString();
}
- protected static int jvmTypeNameToExprType(char type) {
- switch(type) {
- case 'Z' :
- return BOOLEAN;
- case 'B' :
- return BYTE;
- case 'C' :
- return CHAR;
- case 'S' :
- return SHORT;
- case 'I' :
- return INT;
- case 'J' :
- return LONG;
- case 'F' :
- return FLOAT;
- case 'D' :
- return DOUBLE;
- case 'V' :
- return VOID;
- default :
- return CLASS;
- }
+ public void compileExpr(ASTree expr) throws CompileError {
+ doTypeCheck(expr);
+ expr.accept(this);
+ }
+
+ public boolean compileBooleanExpr(boolean branchIf, ASTree expr)
+ throws CompileError
+ {
+ doTypeCheck(expr);
+ return booleanExpr(branchIf, expr);
+ }
+
+ public void doTypeCheck(ASTree expr) throws CompileError {
+ if (typeChecker != null)
+ expr.accept(typeChecker);
}
public void atASTList(ASTList n) throws CompileError { fatal(); }
@@ -302,6 +300,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
int op = st.getOperator();
if (op == EXPR) {
ASTree expr = st.getLeft();
+ doTypeCheck(expr);
if (expr instanceof AssignExpr)
atAssignExpr((AssignExpr)expr, false);
else if (isPlusPlusExpr(expr)) {
@@ -359,7 +358,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
ASTree expr = st.head();
Stmnt thenp = (Stmnt)st.tail().head();
Stmnt elsep = (Stmnt)st.tail().tail().head();
- booleanExpr(false, expr);
+ compileBooleanExpr(false, expr);
int pc = bytecode.currentPc();
int pc2 = 0;
bytecode.addIndex(0); // correct later
@@ -412,7 +411,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
if (notDo)
bytecode.write16bit(pc, pc3 - pc + 1);
- boolean alwaysBranch = booleanExpr(true, expr);
+ boolean alwaysBranch = compileBooleanExpr(true, expr);
bytecode.addIndex(pc2 - bytecode.currentPc() + 1);
patchGoto(breakList, bytecode.currentPc());
@@ -449,7 +448,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
int pc = bytecode.currentPc();
int pc2 = 0;
if (expr != null) {
- booleanExpr(false, expr);
+ compileBooleanExpr(false, expr);
pc2 = bytecode.currentPc();
bytecode.addIndex(0);
}
@@ -500,7 +499,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
if (result == null)
op = Opcode.RETURN;
else {
- result.accept(this);
+ compileExpr(result);
if (arrayDim > 0)
op = ARETURN;
else {
@@ -524,7 +523,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
private void atThrowStmnt(Stmnt st) throws CompileError {
ASTree e = st.getLeft();
- e.accept(this);
+ compileExpr(e);
if (exprType != CLASS || arrayDim > 0)
throw new CompileError("bad throw statement");
@@ -560,8 +559,10 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
/* NOTE: Array initializers has not been supported.
*/
ASTree init = d.getInitializer();
- if (init != null)
+ if (init != null) {
+ doTypeCheck(init);
atVariableAssign(null, '=', null, d, init, false);
+ }
}
public abstract void atNewExpr(NewExpr n) throws CompileError;
@@ -681,20 +682,22 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
int type, int dim, String cname)
throws CompileError
{
- right.accept(this);
- if (invalidDim(exprType, arrayDim, className, type, dim, cname, false)
- || (op != '=' && dim > 0))
- badAssign(expr);
-
if (op == PLUS_E && dim == 0 && type == CLASS)
- atStringConcatExpr(expr, type, dim, cname);
- else if (op != '=') {
- int token = assignOps[op - MOD_E];
- int k = lookupBinOp(token);
- if (k < 0)
- fatal();
+ atStringPlusEq(expr, type, dim, cname, right);
+ else {
+ right.accept(this);
+ if (invalidDim(exprType, arrayDim, className, type, dim, cname,
+ false) || (op != '=' && dim > 0))
+ badAssign(expr);
+
+ if (op != '=') {
+ int token = assignOps[op - MOD_E];
+ int k = lookupBinOp(token);
+ if (k < 0)
+ fatal();
- atArithBinExpr(expr, token, k, type);
+ atArithBinExpr(expr, token, k, type);
+ }
}
if (op != '=' || (dim == 0 && !isRefType(type)))
@@ -703,6 +706,23 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
// type check should be done here.
}
+ private void atStringPlusEq(Expr expr, int type, int dim, String cname,
+ ASTree right)
+ throws CompileError
+ {
+ if (!jvmJavaLangString.equals(cname))
+ badAssign(expr);
+
+ convToString(type, dim); // the value might be null.
+ right.accept(this);
+ convToString(exprType, arrayDim);
+ bytecode.addInvokevirtual(javaLangString, "concat",
+ "(Ljava/lang/String;)Ljava/lang/String;");
+ exprType = CLASS;
+ arrayDim = 0;
+ className = jvmJavaLangString;
+ }
+
private boolean invalidDim(int srcType, int srcDim, String srcClass,
int destType, int destDim, String destClass,
boolean isCast)
@@ -727,15 +747,19 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
int pc = bytecode.currentPc();
bytecode.addIndex(0); // correct later
expr.thenExpr().accept(this);
+ int dim1 = arrayDim;
bytecode.addOpcode(Opcode.GOTO);
int pc2 = bytecode.currentPc();
bytecode.addIndex(0);
bytecode.write16bit(pc, bytecode.currentPc() - pc + 1);
expr.elseExpr().accept(this);
+ if (dim1 != arrayDim)
+ throw new CompileError("type mismatch in ?:");
+
bytecode.write16bit(pc2, bytecode.currentPc() - pc2 + 1);
}
- private final int[] binOp = {
+ static final int[] binOp = {
'+', DADD, FADD, LADD, IADD,
'-', DSUB, FSUB, LSUB, ISUB,
'*', DMUL, FMUL, LMUL, IMUL,
@@ -748,7 +772,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
RSHIFT, NOP, NOP, LSHR, ISHR,
ARSHIFT, NOP, NOP, LUSHR, IUSHR };
- private int lookupBinOp(int token) {
+ static int lookupBinOp(int token) {
int[] code = binOp;
int s = code.length;
for (int k = 0; k < s; k = k + 5)
@@ -766,10 +790,14 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
int k = lookupBinOp(token);
if (k >= 0) {
expr.oprand1().accept(this);
+ ASTree right = expr.oprand2();
+ if (right == null)
+ return; // see TypeChecker.atBinExpr().
+
int type1 = exprType;
int dim1 = arrayDim;
String cname1 = className;
- expr.oprand2().accept(this);
+ right.accept(this);
if (dim1 != arrayDim)
throw new CompileError("incompatible array types");
@@ -778,18 +806,17 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
atStringConcatExpr(expr, type1, dim1, cname1);
else
atArithBinExpr(expr, token, k, type1);
-
- return;
}
-
- /* equation: &&, ||, ==, !=, <=, >=, <, >
- */
- booleanExpr(true, expr);
- bytecode.addIndex(7);
- bytecode.addIconst(0); // false
- bytecode.addOpcode(Opcode.GOTO);
- bytecode.addIndex(4);
- bytecode.addIconst(1); // true
+ else {
+ /* equation: &&, ||, ==, !=, <=, >=, <, >
+ */
+ booleanExpr(true, expr);
+ bytecode.addIndex(7);
+ bytecode.addIconst(0); // false
+ bytecode.addOpcode(Opcode.GOTO);
+ bytecode.addIndex(4);
+ bytecode.addIconst(1); // true
+ }
}
/* arrayDim values of the two oprands must be equal.
@@ -846,6 +873,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
else
bytecode.addOpcode(SWAP);
+ // even if type1 is String, the left operand might be null.
convToString(type1, dim1);
bytecode.addOpcode(SWAP);
@@ -923,6 +951,9 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
}
else { // others
expr.accept(this);
+ if (exprType != BOOLEAN || arrayDim != 0)
+ throw new CompileError("boolean expr is required");
+
bytecode.addOpcode(branchIf ? IFNE : IFEQ);
}
@@ -941,7 +972,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
return false;
}
- private static int getCompOperator(ASTree expr) throws CompileError {
+ static int getCompOperator(ASTree expr) throws CompileError {
if (expr instanceof Expr) {
Expr bexpr = (Expr)expr;
int token = bexpr.getOperator();
@@ -969,19 +1000,19 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
return type1;
}
- private final int ifOp[] = { EQ, IF_ICMPEQ, IF_ICMPNE,
- NEQ, IF_ICMPNE, IF_ICMPEQ,
- LE, IF_ICMPLE, IF_ICMPGT,
- GE, IF_ICMPGE, IF_ICMPLT,
- '<', IF_ICMPLT, IF_ICMPGE,
- '>', IF_ICMPGT, IF_ICMPLE };
+ private static final int ifOp[] = { EQ, IF_ICMPEQ, IF_ICMPNE,
+ NEQ, IF_ICMPNE, IF_ICMPEQ,
+ LE, IF_ICMPLE, IF_ICMPGT,
+ GE, IF_ICMPGE, IF_ICMPLT,
+ '<', IF_ICMPLT, IF_ICMPGE,
+ '>', IF_ICMPGT, IF_ICMPLE };
- private final int ifOp2[] = { EQ, IFEQ, IFNE,
- NEQ, IFNE, IFEQ,
- LE, IFLE, IFGT,
- GE, IFGE, IFLT,
- '<', IFLT, IFGE,
- '>', IFGT, IFLE };
+ private static final int ifOp2[] = { EQ, IFEQ, IFNE,
+ NEQ, IFNE, IFEQ,
+ LE, IFLE, IFGT,
+ GE, IFGE, IFLT,
+ '<', IFLT, IFGE,
+ '>', IFGT, IFLE };
/* Produces the opcode to branch if the condition is true.
* The oprands are not produced.
@@ -1070,6 +1101,18 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
return P_INT; // BOOLEAN, BYTE, CHAR, SHORT, INT
}
+ // used in TypeChecker.
+ static boolean isP_INT(int type) {
+ return typePrecedence(type) == P_INT;
+ }
+
+ // used in TypeChecker.
+ static boolean rightIsStrong(int type1, int type2) {
+ int type1_p = typePrecedence(type1);
+ int type2_p = typePrecedence(type2);
+ return type1_p >= 0 && type2_p >= 0 && type1_p > type2_p;
+ }
+
private static final int[] castOp = {
/* D F L I */
/* double */ NOP, D2F, D2L, D2I,
@@ -1221,14 +1264,12 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
}
public void atExpr(Expr expr) throws CompileError {
- // method call, array access, member access,
+ // array access, member access,
// (unary) +, (unary) -, ++, --, !, ~
int token = expr.getOperator();
ASTree oprand = expr.oprand1();
- if (token == CALL) // method call
- atMethodCall(expr);
- else if (token == '.')
+ if (token == '.')
if (((Symbol)expr.oprand2()).get().equals("length"))
atArrayLength(expr);
else
@@ -1249,6 +1290,8 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
bytecode.addIndex(4);
bytecode.addIconst(0);
}
+ else if (token == CALL) // method call
+ fatal();
else {
expr.oprand1().accept(this);
int type = typePrecedence(exprType);
@@ -1298,7 +1341,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
throw new CompileError("invalid type for " + expr.getName());
}
- protected abstract void atMethodCall(Expr expr) throws CompileError;
+ public abstract void atCallExpr(CallExpr expr) throws CompileError;
protected abstract void atFieldRead(ASTree expr) throws CompileError;
@@ -1598,7 +1641,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
public void atStringL(StringL s) throws CompileError {
exprType = CLASS;
arrayDim = 0;
- className = "java/lang/String";
+ className = jvmJavaLangString;
bytecode.addLdc(s.get());
}
diff --git a/src/main/javassist/compiler/Javac.java b/src/main/javassist/compiler/Javac.java
index 44c3ff11..2436b4bf 100644
--- a/src/main/javassist/compiler/Javac.java
+++ b/src/main/javassist/compiler/Javac.java
@@ -117,9 +117,9 @@ public class Javac {
{
CtFieldWithInit f;
Declarator d = fd.getDeclarator();
- f = new CtFieldWithInit(gen.lookupClass(d), d.getVariable().get(),
- gen.getThisClass());
- f.setModifiers(MemberCodeGen.getModifiers(fd.getModifiers()));
+ f = new CtFieldWithInit(gen.resolver.lookupClass(d),
+ d.getVariable().get(), gen.getThisClass());
+ f.setModifiers(MemberResolver.getModifiers(fd.getModifiers()));
if (fd.getInit() != null)
f.setInit(fd.getInit());
@@ -129,7 +129,7 @@ public class Javac {
private CtMember compileMethod(Parser p, MethodDecl md)
throws CompileError
{
- int mod = MemberCodeGen.getModifiers(md.getModifiers());
+ int mod = MemberResolver.getModifiers(md.getModifiers());
CtClass[] plist = gen.makeParamList(md);
CtClass[] tlist = gen.makeThrowsList(md);
recordParams(plist, Modifier.isStatic(mod));
@@ -147,7 +147,7 @@ public class Javac {
}
else {
Declarator r = md.getReturn();
- CtClass rtype = gen.lookupClass(r);
+ CtClass rtype = gen.resolver.lookupClass(r);
recordReturnType(rtype, false);
CtMethod method = new CtMethod(rtype, r.getVariable().get(),
plist, gen.getThisClass());
@@ -344,10 +344,22 @@ public class Javac {
if (texpr != null)
expr = Expr.make('.', texpr, expr);
- expr = Expr.make(TokenId.CALL, expr, args);
- expr.accept(gen);
+ expr = CallExpr.makeCall(expr, args);
+ gen.compileExpr(expr);
gen.addNullIfVoid();
}
+
+ public void setReturnType(JvstTypeChecker check, ASTList args)
+ throws CompileError
+ {
+ ASTree expr = new Member(m);
+ if (texpr != null)
+ expr = Expr.make('.', texpr, expr);
+
+ expr = CallExpr.makeCall(expr, args);
+ expr.accept(check);
+ check.addNullIfVoid();
+ }
};
gen.setProceedHandler(h, proceedName);
@@ -374,10 +386,20 @@ public class Javac {
{
Expr expr = Expr.make(TokenId.MEMBER,
new Symbol(c), new Member(m));
- expr = Expr.make(TokenId.CALL, expr, args);
- expr.accept(gen);
+ expr = CallExpr.makeCall(expr, args);
+ gen.compileExpr(expr);
gen.addNullIfVoid();
}
+
+ public void setReturnType(JvstTypeChecker check, ASTList args)
+ throws CompileError
+ {
+ Expr expr = Expr.make(TokenId.MEMBER,
+ new Symbol(c), new Member(m));
+ expr = CallExpr.makeCall(expr, args);
+ expr.accept(check);
+ check.addNullIfVoid();
+ }
};
gen.setProceedHandler(h, proceedName);
@@ -408,9 +430,15 @@ public class Javac {
public void doit(JvstCodeGen gen, Bytecode b, ASTList args)
throws CompileError
{
- gen.compileInvokeSpecial(texpr,
- cname, method, desc, args);
+ gen.compileInvokeSpecial(texpr, cname, method, desc, args);
}
+
+ public void setReturnType(JvstTypeChecker c, ASTList args)
+ throws CompileError
+ {
+ c.compileInvokeSpecial(texpr, cname, method, desc, args);
+ }
+
};
gen.setProceedHandler(h, proceedName);
diff --git a/src/main/javassist/compiler/JvstCodeGen.java b/src/main/javassist/compiler/JvstCodeGen.java
index 5081ea1e..54e95a0a 100644
--- a/src/main/javassist/compiler/JvstCodeGen.java
+++ b/src/main/javassist/compiler/JvstCodeGen.java
@@ -19,29 +19,31 @@ import javassist.*;
import javassist.bytecode.*;
import javassist.compiler.ast.*;
-/* Code generator methods for extensions by Javassist.
+/* Code generator accepting extended Java syntax for Javassist.
*/
+
public class JvstCodeGen extends MemberCodeGen {
- private String paramArrayName = null;
- private String paramListName = null;
- private CtClass[] paramTypeList = null;
+ String paramArrayName = null;
+ String paramListName = null;
+ CtClass[] paramTypeList = null;
private int paramVarBase = 0; // variable index for $0 or $1.
private boolean useParam0 = false; // true if $0 is used.
private String param0Type = null; // JVM name
- private static final String sigName = "$sig";
- private static final String dollarTypeName = "$type";
- private static final String clazzName = "$class";
+ public static final String sigName = "$sig";
+ public static final String dollarTypeName = "$type";
+ public static final String clazzName = "$class";
private CtClass dollarType = null;
- private CtClass returnType = null;
- private String returnCastName = null;
+ CtClass returnType = null;
+ String returnCastName = null;
private String returnVarName = null; // null if $_ is not used.
- private static final String wrapperCastName = "$w";
- private String proceedName = null;
- private static final String cflowName = "$cflow";
- private ProceedHandler procHandler = null; // null if not used.
+ public static final String wrapperCastName = "$w";
+ String proceedName = null;
+ public static final String cflowName = "$cflow";
+ ProceedHandler procHandler = null; // null if not used.
public JvstCodeGen(Bytecode b, CtClass cc, ClassPool cp) {
super(b, cc, cp);
+ setTypeChecker(new JvstTypeChecker(cc, cp, this));
}
/* Index of $1.
@@ -117,9 +119,6 @@ public class JvstCodeGen extends MemberCodeGen {
className = "java/lang/Class";
}
- private void atSigOrType(String sig) throws CompileError {
- }
-
protected void atFieldAssign(Expr expr, int op, ASTree left,
ASTree right, boolean doDup) throws CompileError
{
@@ -188,7 +187,8 @@ public class JvstCodeGen extends MemberCodeGen {
compileUnwrapValue(returnType, bytecode);
else if (returnType instanceof CtPrimitiveType) {
CtPrimitiveType pt = (CtPrimitiveType)returnType;
- int destType = jvmTypeNameToExprType(pt.getDescriptor());
+ int destType = MemberResolver.jvmTypeNameToExprType(
+ pt.getDescriptor());
atNumCastExpr(exprType, destType);
exprType = destType;
arrayDim = 0;
@@ -203,7 +203,7 @@ public class JvstCodeGen extends MemberCodeGen {
if (isRefType(exprType) || arrayDim > 0)
return; // Object type. do nothing.
- CtClass clazz = lookupClass(exprType, arrayDim, className);
+ CtClass clazz = resolver.lookupClass(exprType, arrayDim, className);
if (clazz instanceof CtPrimitiveType) {
CtPrimitiveType pt = (CtPrimitiveType)clazz;
String wrapper = pt.getWrapperName();
@@ -227,7 +227,7 @@ public class JvstCodeGen extends MemberCodeGen {
/* Delegates to a ProcHandler object if the method call is
* $proceed(). It may process $cflow().
*/
- protected void atMethodCall(Expr expr) throws CompileError {
+ public void atCallExpr(CallExpr expr) throws CompileError {
ASTree method = expr.oprand1();
if (method instanceof Member) {
String name = ((Member)method).get();
@@ -241,7 +241,7 @@ public class JvstCodeGen extends MemberCodeGen {
}
}
- super.atMethodCall(expr);
+ super.atCallExpr(expr);
}
/* To support $cflow().
@@ -253,7 +253,7 @@ public class JvstCodeGen extends MemberCodeGen {
makeCflowName(sbuf, cname.head());
String name = sbuf.toString();
- Object[] names = classPool.lookupCflow(name);
+ Object[] names = resolver.getClassPool().lookupCflow(name);
if (names == null)
throw new CompileError("no such a " + cflowName + ": " + name);
@@ -413,7 +413,7 @@ public class JvstCodeGen extends MemberCodeGen {
protected void atReturnStmnt(Stmnt st) throws CompileError {
ASTree result = st.getLeft();
if (result != null && returnType == CtClass.voidType) {
- result.accept(this);
+ compileExpr(result);
if (is2word(exprType, arrayDim))
bytecode.addOpcode(POP2);
else if (exprType != VOID)
@@ -500,15 +500,15 @@ public class JvstCodeGen extends MemberCodeGen {
paramVarBase = paramBase;
useParam0 = use0;
- param0Type = jvmToJavaName(target);
+ param0Type = MemberResolver.jvmToJavaName(target);
inStaticMethod = isStatic;
varNo = paramBase;
if (use0) {
String varName = prefix + "0";
Declarator decl
- = new Declarator(CLASS, javaToJvmName(target), 0, varNo++,
- new Symbol(varName));
+ = new Declarator(CLASS, MemberResolver.javaToJvmName(target),
+ 0, varNo++, new Symbol(varName));
tbl.append(varName, decl);
}
@@ -640,7 +640,7 @@ public class JvstCodeGen extends MemberCodeGen {
private void setType(CtClass type, int dim) throws CompileError {
if (type.isPrimitive()) {
CtPrimitiveType pt = (CtPrimitiveType)type;
- exprType = descToType(pt.getDescriptor());
+ exprType = MemberResolver.descToType(pt.getDescriptor());
arrayDim = dim;
className = null;
}
@@ -654,7 +654,7 @@ public class JvstCodeGen extends MemberCodeGen {
else {
exprType = CLASS;
arrayDim = dim;
- className = javaToJvmName(type.getName());
+ className = MemberResolver.javaToJvmName(type.getName());
}
}
@@ -664,7 +664,8 @@ public class JvstCodeGen extends MemberCodeGen {
if (arrayDim == 0 && !isRefType(exprType))
if (type instanceof CtPrimitiveType) {
CtPrimitiveType pt = (CtPrimitiveType)type;
- atNumCastExpr(exprType, descToType(pt.getDescriptor()));
+ atNumCastExpr(exprType,
+ MemberResolver.descToType(pt.getDescriptor()));
}
else
throw new CompileError("type mismatch");
diff --git a/src/main/javassist/compiler/JvstTypeChecker.java b/src/main/javassist/compiler/JvstTypeChecker.java
new file mode 100644
index 00000000..3b63180e
--- /dev/null
+++ b/src/main/javassist/compiler/JvstTypeChecker.java
@@ -0,0 +1,282 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2003 Shigeru Chiba. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. Alternatively, the contents of this file may be used under
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ */
+
+package javassist.compiler;
+
+import javassist.*;
+import javassist.compiler.ast.*;
+
+/* Type checker accepting extended Java syntax for Javassist.
+ */
+
+public class JvstTypeChecker extends TypeChecker {
+ private JvstCodeGen codeGen;
+
+ public JvstTypeChecker(CtClass cc, ClassPool cp, JvstCodeGen gen) {
+ super(cc, cp);
+ codeGen = gen;
+ }
+
+ /* If the type of the expression compiled last is void,
+ * add ACONST_NULL and change exprType, arrayDim, className.
+ */
+ public void addNullIfVoid() {
+ if (exprType == VOID) {
+ exprType = CLASS;
+ arrayDim = 0;
+ className = jvmJavaLangObject;
+ }
+ }
+
+ /* To support $args, $sig, and $type.
+ * $args is an array of parameter list.
+ */
+ 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);
+ }
+
+ 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);
+ }
+
+ 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);
+ }
+
+ /**
+ * Inserts a cast operator to the return type.
+ * If the return type is void, this does nothing.
+ */
+ 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.jvmTypeNameToExprType(
+ 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; // Object type. do nothing.
+
+ CtClass clazz = resolver.lookupClass(exprType, arrayDim, className);
+ if (clazz instanceof CtPrimitiveType) {
+ exprType = CLASS;
+ arrayDim = 0;
+ className = jvmJavaLangObject;
+ }
+ }
+
+ /* Delegates to a ProcHandler object if the method call is
+ * $proceed(). It may process $cflow().
+ */
+ 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);
+ }
+
+ /* To support $cflow().
+ */
+ protected void atCflow(ASTList cname) throws CompileError {
+ exprType = INT;
+ arrayDim = 0;
+ className = null;
+ }
+
+ /* To support $$. ($$) is equivalent to ($1, ..., $n).
+ * It can be used only as a parameter list of method call.
+ */
+ 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));
+ }
+ else
+ return false;
+ }
+
+ 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;
+ }
+
+ 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();
+ }
+ }
+
+ /* called by Javac#recordSpecialProceed().
+ */
+ 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);
+ }
+
+ /* Sets exprType, arrayDim, and className;
+ * If type is void, then this method does nothing.
+ */
+ 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());
+ }
+ }
+}
diff --git a/src/main/javassist/compiler/MemberCodeGen.java b/src/main/javassist/compiler/MemberCodeGen.java
index 92e299f0..e6983d21 100644
--- a/src/main/javassist/compiler/MemberCodeGen.java
+++ b/src/main/javassist/compiler/MemberCodeGen.java
@@ -15,7 +15,6 @@
package javassist.compiler;
-import java.util.List;
import javassist.*;
import javassist.bytecode.*;
import javassist.compiler.ast.*;
@@ -23,15 +22,16 @@ import javassist.compiler.ast.*;
/* Code generator methods depending on javassist.* classes.
*/
public class MemberCodeGen extends CodeGen {
- protected ClassPool classPool;
+ protected MemberResolver resolver;
protected CtClass thisClass;
protected MethodInfo thisMethod;
protected boolean resultStatic;
- public MemberCodeGen(Bytecode b, CtClass cc, ClassPool cp) {
+ public MemberCodeGen(Bytecode b, CtClass cc, ClassPool cp)
+ {
super(b);
- classPool = cp;
+ resolver = new MemberResolver(cp);
thisClass = cc;
thisMethod = null;
}
@@ -41,6 +41,8 @@ public class MemberCodeGen extends CodeGen {
*/
public void setThisMethod(CtMethod m) {
thisMethod = m.getMethodInfo2();
+ if (typeChecker != null)
+ typeChecker.setThisMethod(thisMethod);
}
public CtClass getThisClass() { return thisClass; }
@@ -49,19 +51,21 @@ public class MemberCodeGen extends CodeGen {
* Returns the JVM-internal representation of this class name.
*/
protected String getThisName() {
- return javaToJvmName(thisClass.getName());
+ return MemberResolver.javaToJvmName(thisClass.getName());
}
/**
* Returns the JVM-internal representation of this super class name.
*/
protected String getSuperName() throws CompileError {
- return javaToJvmName(getSuperclass(thisClass).getName());
+ return MemberResolver.javaToJvmName(
+ MemberResolver.getSuperclass(thisClass).getName());
}
protected void insertDefaultSuperCall() throws CompileError {
bytecode.addAload(0);
- bytecode.addInvokespecial(getSuperclass(thisClass), "<init>", "()V");
+ bytecode.addInvokespecial(MemberResolver.getSuperclass(thisClass),
+ "<init>", "()V");
}
protected void atTryStmnt(Stmnt st) throws CompileError {
@@ -90,8 +94,8 @@ public class MemberCodeGen extends CodeGen {
decl.setLocalVar(var);
- CtClass type = lookupJvmClass(decl.getClassName());
- decl.setClassName(javaToJvmName(type.getName()));
+ CtClass type = resolver.lookupClassByJvmName(decl.getClassName());
+ decl.setClassName(MemberResolver.javaToJvmName(type.getName()));
bytecode.addExceptionHandler(start, end, bytecode.currentPc(),
type);
bytecode.growStack(1);
@@ -116,17 +120,18 @@ public class MemberCodeGen extends CodeGen {
if (expr.isArray())
atNewArrayExpr(expr);
else {
- CtClass clazz = lookupClass(expr.getClassName());
+ CtClass clazz = resolver.lookupClassByName(expr.getClassName());
String cname = clazz.getName();
ASTList args = expr.getArguments();
bytecode.addNew(cname);
bytecode.addOpcode(DUP);
- atMethodCall2(clazz, MethodInfo.nameInit, args, false, true, -1);
+ atMethodCallCore(clazz, MethodInfo.nameInit, args,
+ false, true, -1, null);
exprType = CLASS;
arrayDim = 0;
- className = javaToJvmName(cname);
+ className = MemberResolver.javaToJvmName(cname);
}
}
@@ -147,7 +152,7 @@ public class MemberCodeGen extends CodeGen {
arrayDim = 1;
if (type == CLASS) {
className = resolveClassName(classname);
- bytecode.addAnewarray(jvmToJavaName(className));
+ bytecode.addAnewarray(MemberResolver.jvmToJavaName(className));
}
else {
className = null;
@@ -220,7 +225,7 @@ public class MemberCodeGen extends CodeGen {
bytecode.addMultiNewarray(desc, count);
}
- protected void atMethodCall(Expr expr) throws CompileError {
+ public void atCallExpr(CallExpr expr) throws CompileError {
String mname = null;
CtClass targetClass = null;
ASTree method = expr.oprand1();
@@ -229,10 +234,11 @@ public class MemberCodeGen extends CodeGen {
boolean isSpecial = false;
int aload0pos = -1;
+ MemberResolver.Method cached = expr.getMethod();
if (method instanceof Member) {
mname = ((Member)method).get();
targetClass = thisClass;
- if (inStaticMethod)
+ if (inStaticMethod || (cached != null && cached.isStatic()))
isStatic = true; // should be static
else {
aload0pos = bytecode.currentPc();
@@ -249,14 +255,15 @@ public class MemberCodeGen extends CodeGen {
bytecode.addAload(0); // this
if (((Keyword)method).get() == SUPER)
- targetClass = getSuperclass(targetClass);
+ targetClass = MemberResolver.getSuperclass(targetClass);
}
else if (method instanceof Expr) {
Expr e = (Expr)method;
mname = ((Symbol)e.oprand2()).get();
int op = e.getOperator();
if (op == MEMBER) { // static method
- targetClass = lookupJavaClass(((Symbol)e.oprand1()).get());
+ targetClass
+ = resolver.lookupClass(((Symbol)e.oprand1()).get());
isStatic = true;
}
else if (op == '.') {
@@ -280,9 +287,9 @@ public class MemberCodeGen extends CodeGen {
}
if (arrayDim > 0)
- targetClass = lookupJavaClass(javaLangObject);
+ targetClass = resolver.lookupClass(javaLangObject);
else if (exprType == CLASS /* && arrayDim == 0 */)
- targetClass = lookupJvmClass(className);
+ targetClass = resolver.lookupClassByJvmName(className);
else
badMethod();
}
@@ -292,27 +299,18 @@ public class MemberCodeGen extends CodeGen {
else
fatal();
- atMethodCall2(targetClass, mname, args, isStatic, isSpecial,
- aload0pos);
+ atMethodCallCore(targetClass, mname, args, isStatic, isSpecial,
+ aload0pos, cached);
}
private static void badMethod() throws CompileError {
throw new CompileError("bad method");
}
- private static CtClass getSuperclass(CtClass c) throws CompileError {
- try {
- return c.getSuperclass();
- }
- catch (NotFoundException e) {
- throw new CompileError("cannot find the super class of "
- + c.getName());
- }
- }
-
- public void atMethodCall2(CtClass targetClass, String mname,
+ // atMethodCallCore() is also called by doit() in NewExpr.ProceedForNew
+ public void atMethodCallCore(CtClass targetClass, String mname,
ASTList args, boolean isStatic, boolean isSpecial,
- int aload0pos)
+ int aload0pos, MemberResolver.Method found)
throws CompileError
{
int nargs = getMethodArgsLength(args);
@@ -320,6 +318,11 @@ public class MemberCodeGen extends CodeGen {
int[] dims = new int[nargs];
String[] cnames = new String[nargs];
+ if (!isStatic && found != null && found.isStatic()) {
+ bytecode.addOpcode(POP);
+ isStatic = true;
+ }
+
int stack = bytecode.getStackDepth();
atMethodArgs(args, types, dims, cnames);
@@ -327,8 +330,10 @@ public class MemberCodeGen extends CodeGen {
// used by invokeinterface
int count = bytecode.getStackDepth() - stack + 1;
- Object[] found = lookupMethod(targetClass, thisMethod, mname,
- types, dims, cnames, false);
+ if (found == null)
+ found = resolver.lookupMethod(targetClass, thisMethod, mname,
+ types, dims, cnames, false);
+
if (found == null) {
String msg;
if (mname.equals(MethodInfo.nameInit))
@@ -340,8 +345,8 @@ public class MemberCodeGen extends CodeGen {
throw new CompileError(msg);
}
- CtClass declClass = (CtClass)found[0];
- MethodInfo minfo = (MethodInfo)found[1];
+ CtClass declClass = found.declaring;
+ MethodInfo minfo = found.info;
String desc = minfo.getDescriptor();
int acc = minfo.getAccessFlags();
@@ -428,7 +433,7 @@ public class MemberCodeGen extends CodeGen {
className = desc.substring(i + 1, j);
}
else {
- exprType = descToType(c);
+ exprType = MemberResolver.descToType(c);
className = null;
}
@@ -450,188 +455,6 @@ public class MemberCodeGen extends CodeGen {
}
}
- private Object[] lookupMethod(CtClass clazz, MethodInfo current,
- String methodName,
- int[] argTypes, int[] argDims,
- String[] argClassNames, boolean onlyExact)
- throws CompileError
- {
- Object[] maybe = null;
-
- if (current != null)
- if (current.getName().equals(methodName)) {
- int res = compareSignature(current.getDescriptor(),
- argTypes, argDims, argClassNames);
- Object[] r = new Object[] { clazz, current };
- if (res == YES)
- return r;
- else if (res == MAYBE && maybe == null)
- maybe = r;
- }
-
- List list = clazz.getClassFile2().getMethods();
- int n = list.size();
- for (int i = 0; i < n; ++i) {
- MethodInfo minfo = (MethodInfo)list.get(i);
- if (minfo.getName().equals(methodName)) {
- int res = compareSignature(minfo.getDescriptor(),
- argTypes, argDims, argClassNames);
- Object[] r = new Object[] { clazz, minfo };
- if (res == YES)
- return r;
- else if (res == MAYBE && maybe == null)
- maybe = r;
- }
- }
-
- try {
- CtClass pclazz = clazz.getSuperclass();
- if (pclazz != null) {
- Object[] r = lookupMethod(pclazz, null, methodName, argTypes,
- argDims, argClassNames,
- (onlyExact || maybe != null));
- if (r != null)
- return r;
- }
- }
- catch (NotFoundException e) {}
-
- /* -- not necessary to search implemented interfaces.
- try {
- CtClass[] ifs = clazz.getInterfaces();
- int size = ifs.length;
- for (int i = 0; i < size; ++i) {
- Object[] r = lookupMethod(ifs[i], methodName, argTypes,
- argDims, argClassNames);
- if (r != null)
- return r;
- }
- }
- catch (NotFoundException e) {}
- */
-
- if (onlyExact)
- return null;
- else
- return maybe;
- }
-
- private static final int YES = 2;
- private static final int MAYBE = 1;
- private static final int NO = 0;
-
- /*
- * Returns YES if actual parameter types matches the given signature.
- *
- * argTypes, argDims, and argClassNames represent actual parameters.
- *
- * This method does not correctly implement the Java method dispatch
- * algorithm.
- */
- private int compareSignature(String desc, int[] argTypes,
- int[] argDims, String[] argClassNames)
- throws CompileError
- {
- int result = YES;
- int i = 1;
- int nArgs = argTypes.length;
- if (nArgs != Descriptor.numOfParameters(desc))
- return NO;
-
- int len = desc.length();
- for (int n = 0; i < len; ++n) {
- char c = desc.charAt(i++);
- if (c == ')')
- return (n == nArgs ? result : NO);
- else if (n >= nArgs)
- return NO;
-
- int dim = 0;
- while (c == '[') {
- ++dim;
- c = desc.charAt(i++);
- }
-
- if (argTypes[n] == NULL) {
- if (dim == 0 && c != 'L')
- return NO;
- }
- else if (argDims[n] != dim) {
- if (!(dim == 0 && c == 'L'
- && desc.startsWith("java/lang/Object;", i)))
- return NO;
-
- // if the thread reaches here, c must be 'L'.
- i = desc.indexOf(';', i) + 1;
- result = MAYBE;
- if (i <= 0)
- return NO; // invalid descriptor?
- }
- else if (c == 'L') { // not compare
- int j = desc.indexOf(';', i);
- if (j < 0 || argTypes[n] != CLASS)
- return NO;
-
- String cname = desc.substring(i, j);
- if (!cname.equals(argClassNames[n])) {
- CtClass clazz = lookupJvmClass(argClassNames[n]);
- try {
- if (clazz.subtypeOf(lookupJvmClass(cname)))
- result = MAYBE;
- else
- return NO;
- }
- catch (NotFoundException e) {
- result = MAYBE; // should be NO?
- }
- }
-
- i = j + 1;
- }
- else {
- int t = descToType(c);
- int at = argTypes[n];
- if (t != at)
- if (t == INT
- && (at == SHORT || at == BYTE || at == CHAR))
- result = MAYBE;
- else
- return NO;
- }
- }
-
- return NO;
- }
-
- protected static int descToType(char c) throws CompileError {
- switch (c) {
- case 'Z' :
- return BOOLEAN;
- case 'C' :
- return CHAR;
- case 'B' :
- return BYTE;
- case 'S' :
- return SHORT;
- case 'I' :
- return INT;
- case 'J' :
- return LONG;
- case 'F' :
- return FLOAT;
- case 'D' :
- return DOUBLE;
- case 'V' :
- return VOID;
- case 'L' :
- case '[' :
- return CLASS;
- default :
- fatal();
- return VOID;
- }
- }
-
protected void atFieldAssign(Expr expr, int op, ASTree left,
ASTree right, boolean doDup) throws CompileError
{
@@ -704,7 +527,7 @@ public class MemberCodeGen extends CodeGen {
arrayDim = dim;
boolean is2byte = (c == 'J' || c == 'D');
- exprType = descToType(c);
+ exprType = MemberResolver.descToType(c);
if (c == 'L')
className = type.substring(i + 1, type.indexOf(';', i + 1));
@@ -795,15 +618,16 @@ public class MemberCodeGen extends CodeGen {
Expr e = (Expr)expr;
int op = e.getOperator();
if (op == MEMBER) {
- f = lookupJavaField(((Symbol)e.oprand1()).get(),
- (Symbol)e.oprand2());
+ f = resolver.lookupField(((Symbol)e.oprand1()).get(),
+ (Symbol)e.oprand2());
is_static = true;
}
else if (op == '.') {
try {
e.oprand1().accept(this);
if (exprType == CLASS && arrayDim == 0)
- f = lookupJvmField(className, (Symbol)e.oprand2());
+ f = resolver.lookupFieldByJvmName(className,
+ (Symbol)e.oprand2());
else
badLvalue();
@@ -818,7 +642,8 @@ public class MemberCodeGen extends CodeGen {
Symbol fname = (Symbol)e.oprand2();
// it should be a static field.
try {
- f = lookupJvmField(nfe.getField(), fname);
+ f = resolver.lookupFieldByJvmName(nfe.getField(),
+ fname);
is_static = true;
}
catch (CompileError ce) {
@@ -851,7 +676,7 @@ public class MemberCodeGen extends CodeGen {
int i = 0;
params = new CtClass[plist.length()];
while (plist != null) {
- params[i++] = lookupClass((Declarator)plist.head());
+ params[i++] = resolver.lookupClass((Declarator)plist.head());
plist = plist.tail();
}
}
@@ -868,7 +693,7 @@ public class MemberCodeGen extends CodeGen {
int i = 0;
clist = new CtClass[list.length()];
while (list != null) {
- clist[i++] = lookupClass((ASTList)list.head());
+ clist[i++] = resolver.lookupClassByName((ASTList)list.head());
list = list.tail();
}
@@ -876,184 +701,19 @@ public class MemberCodeGen extends CodeGen {
}
}
- public static int getModifiers(ASTList mods) {
- int m = 0;
- while (mods != null) {
- Keyword k = (Keyword)mods.head();
- mods = mods.tail();
- switch (k.get()) {
- case STATIC :
- m |= Modifier.STATIC;
- break;
- case FINAL :
- m |= Modifier.FINAL;
- break;
- case SYNCHRONIZED :
- m |= Modifier.SYNCHRONIZED;
- break;
- case ABSTRACT :
- m |= Modifier.ABSTRACT;
- break;
- case PUBLIC :
- m |= Modifier.PUBLIC;
- break;
- case PROTECTED :
- m |= Modifier.PROTECTED;
- break;
- case PRIVATE :
- m |= Modifier.PRIVATE;
- break;
- case VOLATILE :
- m |= Modifier.VOLATILE;
- break;
- case TRANSIENT :
- m |= Modifier.TRANSIENT;
- break;
- case STRICT :
- m |= Modifier.STRICT;
- break;
- }
- }
-
- return m;
- }
-
/* Converts a class name into a JVM-internal representation.
*
* It may also expand a simple class name to java.lang.*.
* For example, this converts Object into java/lang/Object.
*/
protected String resolveClassName(ASTList name) throws CompileError {
- if (name == null)
- return null;
- else
- return javaToJvmName(lookupClass(name).getName());
+ return resolver.resolveClassName(name);
}
/* Expands a simple class name to java.lang.*.
* For example, this converts Object into java/lang/Object.
*/
protected String resolveClassName(String jvmName) throws CompileError {
- if (jvmName == null)
- return null;
- else
- return javaToJvmName(lookupJvmClass(jvmName).getName());
- }
-
- protected CtClass lookupClass(Declarator decl) throws CompileError {
- return lookupClass(decl.getType(), decl.getArrayDim(),
- decl.getClassName());
- }
-
- protected CtClass lookupClass(int type, int dim, String classname)
- throws CompileError
- {
- String cname = "";
- CtClass clazz;
- switch (type) {
- case CLASS :
- clazz = lookupJvmClass(classname);
- if (dim > 0)
- cname = clazz.getName();
- else
- return clazz;
-
- break;
- case BOOLEAN :
- cname = "boolean";
- break;
- case CHAR :
- cname = "char";
- break;
- case BYTE :
- cname = "byte";
- break;
- case SHORT :
- cname = "short";
- break;
- case INT :
- cname = "int";
- break;
- case LONG :
- cname = "long";
- break;
- case FLOAT :
- cname = "float";
- break;
- case DOUBLE :
- cname = "double";
- break;
- case VOID :
- cname = "void";
- break;
- default :
- fatal();
- }
-
- while (dim-- > 0)
- cname += "[]";
-
- return lookupJavaClass(cname);
- }
-
- protected CtClass lookupClass(ASTList name) throws CompileError {
- return lookupJavaClass(Declarator.astToClassName(name, '.'));
- }
-
- protected CtClass lookupJvmClass(String jvmName) throws CompileError {
- return lookupJavaClass(jvmToJavaName(jvmName));
- }
-
- /**
- * @param name a qualified class name. e.g. java.lang.String
- */
- private CtClass lookupJavaClass(String name) throws CompileError {
- try {
- return classPool.get(name);
- }
- catch (NotFoundException e) {}
-
- try {
- if (name.indexOf('.') < 0)
- return classPool.get("java.lang." + name);
- }
- catch (NotFoundException e) {}
-
- throw new CompileError("no such class: " + name);
- }
-
- public CtField lookupField(ASTList className, Symbol fieldName)
- throws CompileError
- {
- return lookupJavaField(Declarator.astToClassName(className, '.'),
- fieldName);
- }
-
- public CtField lookupJvmField(String className, Symbol fieldName)
- throws CompileError
- {
- return lookupJavaField(jvmToJavaName(className), fieldName);
- }
-
- /**
- * @param name a qualified class name. e.g. java.lang.String
- */
- private CtField lookupJavaField(String className, Symbol fieldName)
- throws CompileError
- {
- CtClass cc = lookupJavaClass(className);
- try {
- return cc.getField(fieldName.get());
- }
- catch (NotFoundException e) {}
- throw new CompileError("no such field: " + fieldName.get());
- }
-
- protected static String javaToJvmName(String classname) {
- return classname.replace('.', '/');
- }
-
- protected static String jvmToJavaName(String classname) {
- return classname.replace('/', '.');
+ return resolver.resolveJvmClassName(jvmName);
}
}
diff --git a/src/main/javassist/compiler/MemberResolver.java b/src/main/javassist/compiler/MemberResolver.java
new file mode 100644
index 00000000..a716fa92
--- /dev/null
+++ b/src/main/javassist/compiler/MemberResolver.java
@@ -0,0 +1,461 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2003 Shigeru Chiba. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. Alternatively, the contents of this file may be used under
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ */
+
+package javassist.compiler;
+
+import java.util.List;
+import javassist.*;
+import javassist.bytecode.*;
+import javassist.compiler.ast.*;
+
+/* Code generator methods depending on javassist.* classes.
+ */
+public class MemberResolver implements TokenId {
+ private ClassPool classPool;
+
+ public MemberResolver(ClassPool cp) {
+ classPool = cp;
+ }
+
+ public ClassPool getClassPool() { return classPool; }
+
+ private static void fatal() throws CompileError {
+ throw new CompileError("fatal");
+ }
+
+ public static class Method {
+ public CtClass declaring;
+ public MethodInfo info;
+
+ public Method(CtClass c, MethodInfo i) {
+ declaring = c;
+ info = i;
+ }
+
+ /**
+ * Returns true if the invoked method is static.
+ */
+ public boolean isStatic() {
+ int acc = info.getAccessFlags();
+ return (acc & AccessFlag.STATIC) != 0;
+ }
+ }
+
+ public Method lookupMethod(CtClass clazz, MethodInfo current,
+ String methodName,
+ int[] argTypes, int[] argDims,
+ String[] argClassNames, boolean onlyExact)
+ throws CompileError
+ {
+ Method maybe = null;
+
+ // to enable the creation of a recursively called method
+ if (current != null)
+ if (current.getName().equals(methodName)) {
+ int res = compareSignature(current.getDescriptor(),
+ argTypes, argDims, argClassNames);
+ Method r = new Method(clazz, current);
+ if (res == YES)
+ return r;
+ else if (res == MAYBE && maybe == null)
+ maybe = r;
+ }
+
+ List list = clazz.getClassFile2().getMethods();
+ int n = list.size();
+ for (int i = 0; i < n; ++i) {
+ MethodInfo minfo = (MethodInfo)list.get(i);
+ if (minfo.getName().equals(methodName)) {
+ int res = compareSignature(minfo.getDescriptor(),
+ argTypes, argDims, argClassNames);
+ Method r = new Method(clazz, minfo);
+ if (res == YES)
+ return r;
+ else if (res == MAYBE && maybe == null)
+ maybe = r;
+ }
+ }
+
+ try {
+ CtClass pclazz = clazz.getSuperclass();
+ if (pclazz != null) {
+ Method r = lookupMethod(pclazz, null, methodName, argTypes,
+ argDims, argClassNames,
+ (onlyExact || maybe != null));
+ if (r != null)
+ return r;
+ }
+ }
+ catch (NotFoundException e) {}
+
+ /* -- not necessary to search implemented interfaces.
+ try {
+ CtClass[] ifs = clazz.getInterfaces();
+ int size = ifs.length;
+ for (int i = 0; i < size; ++i) {
+ Object[] r = lookupMethod(ifs[i], methodName, argTypes,
+ argDims, argClassNames);
+ if (r != null)
+ return r;
+ }
+ }
+ catch (NotFoundException e) {}
+ */
+
+ if (onlyExact)
+ return null;
+ else
+ return maybe;
+ }
+
+ private static final int YES = 2;
+ private static final int MAYBE = 1;
+ private static final int NO = 0;
+
+ /*
+ * Returns YES if actual parameter types matches the given signature.
+ *
+ * argTypes, argDims, and argClassNames represent actual parameters.
+ *
+ * This method does not correctly implement the Java method dispatch
+ * algorithm.
+ */
+ private int compareSignature(String desc, int[] argTypes,
+ int[] argDims, String[] argClassNames)
+ throws CompileError
+ {
+ int result = YES;
+ int i = 1;
+ int nArgs = argTypes.length;
+ if (nArgs != Descriptor.numOfParameters(desc))
+ return NO;
+
+ int len = desc.length();
+ for (int n = 0; i < len; ++n) {
+ char c = desc.charAt(i++);
+ if (c == ')')
+ return (n == nArgs ? result : NO);
+ else if (n >= nArgs)
+ return NO;
+
+ int dim = 0;
+ while (c == '[') {
+ ++dim;
+ c = desc.charAt(i++);
+ }
+
+ if (argTypes[n] == NULL) {
+ if (dim == 0 && c != 'L')
+ return NO;
+ }
+ else if (argDims[n] != dim) {
+ if (!(dim == 0 && c == 'L'
+ && desc.startsWith("java/lang/Object;", i)))
+ return NO;
+
+ // if the thread reaches here, c must be 'L'.
+ i = desc.indexOf(';', i) + 1;
+ result = MAYBE;
+ if (i <= 0)
+ return NO; // invalid descriptor?
+ }
+ else if (c == 'L') { // not compare
+ int j = desc.indexOf(';', i);
+ if (j < 0 || argTypes[n] != CLASS)
+ return NO;
+
+ String cname = desc.substring(i, j);
+ if (!cname.equals(argClassNames[n])) {
+ CtClass clazz = lookupClassByJvmName(argClassNames[n]);
+ try {
+ if (clazz.subtypeOf(lookupClassByJvmName(cname)))
+ result = MAYBE;
+ else
+ return NO;
+ }
+ catch (NotFoundException e) {
+ result = MAYBE; // should be NO?
+ }
+ }
+
+ i = j + 1;
+ }
+ else {
+ int t = descToType(c);
+ int at = argTypes[n];
+ if (t != at)
+ if (t == INT
+ && (at == SHORT || at == BYTE || at == CHAR))
+ result = MAYBE;
+ else
+ return NO;
+ }
+ }
+
+ return NO;
+ }
+
+ /**
+ * @param jvmClassName a JVM class name. e.g. java/lang/String
+ */
+ public CtField lookupFieldByJvmName(String jvmClassName, Symbol fieldName)
+ throws CompileError
+ {
+ return lookupField(jvmToJavaName(jvmClassName), fieldName);
+ }
+
+ // never used??
+ private CtField lookupField2(ASTList className, Symbol fieldName)
+ throws CompileError
+ {
+ return lookupField(Declarator.astToClassName(className, '.'),
+ fieldName);
+ }
+
+ /**
+ * @param name a qualified class name. e.g. java.lang.String
+ */
+ public CtField lookupField(String className, Symbol fieldName)
+ throws CompileError
+ {
+ CtClass cc = lookupClass(className);
+ try {
+ return cc.getField(fieldName.get());
+ }
+ catch (NotFoundException e) {}
+ throw new CompileError("no such field: " + fieldName.get());
+ }
+
+ public CtClass lookupClassByName(ASTList name) throws CompileError {
+ return lookupClass(Declarator.astToClassName(name, '.'));
+ }
+
+ public CtClass lookupClassByJvmName(String jvmName) throws CompileError {
+ return lookupClass(jvmToJavaName(jvmName));
+ }
+
+ public CtClass lookupClass(Declarator decl) throws CompileError {
+ return lookupClass(decl.getType(), decl.getArrayDim(),
+ decl.getClassName());
+ }
+
+ /**
+ * @parma classname jvm class name.
+ */
+ public CtClass lookupClass(int type, int dim, String classname)
+ throws CompileError
+ {
+ String cname = "";
+ CtClass clazz;
+ switch (type) {
+ case CLASS :
+ clazz = lookupClassByJvmName(classname);
+ if (dim > 0)
+ cname = clazz.getName();
+ else
+ return clazz;
+
+ break;
+ case BOOLEAN :
+ cname = "boolean";
+ break;
+ case CHAR :
+ cname = "char";
+ break;
+ case BYTE :
+ cname = "byte";
+ break;
+ case SHORT :
+ cname = "short";
+ break;
+ case INT :
+ cname = "int";
+ break;
+ case LONG :
+ cname = "long";
+ break;
+ case FLOAT :
+ cname = "float";
+ break;
+ case DOUBLE :
+ cname = "double";
+ break;
+ case VOID :
+ cname = "void";
+ break;
+ default :
+ fatal();
+ }
+
+ while (dim-- > 0)
+ cname += "[]";
+
+ return lookupClass(cname);
+ }
+
+ /**
+ * @param name a qualified class name. e.g. java.lang.String
+ */
+ public CtClass lookupClass(String name) throws CompileError {
+ try {
+ return classPool.get(name);
+ }
+ catch (NotFoundException e) {}
+
+ try {
+ if (name.indexOf('.') < 0)
+ return classPool.get("java.lang." + name);
+ }
+ catch (NotFoundException e) {}
+
+ throw new CompileError("no such class: " + name);
+ }
+
+ /* Converts a class name into a JVM-internal representation.
+ *
+ * It may also expand a simple class name to java.lang.*.
+ * For example, this converts Object into java/lang/Object.
+ */
+ public String resolveClassName(ASTList name) throws CompileError {
+ if (name == null)
+ return null;
+ else
+ return javaToJvmName(lookupClassByName(name).getName());
+ }
+
+ /* Expands a simple class name to java.lang.*.
+ * For example, this converts Object into java/lang/Object.
+ */
+ public String resolveJvmClassName(String jvmName) throws CompileError {
+ if (jvmName == null)
+ return null;
+ else
+ return javaToJvmName(lookupClassByJvmName(jvmName).getName());
+ }
+
+ public static CtClass getSuperclass(CtClass c) throws CompileError {
+ try {
+ return c.getSuperclass();
+ }
+ catch (NotFoundException e) {
+ throw new CompileError("cannot find the super class of "
+ + c.getName());
+ }
+ }
+
+ public static String javaToJvmName(String classname) {
+ return classname.replace('.', '/');
+ }
+
+ public static String jvmToJavaName(String classname) {
+ return classname.replace('/', '.');
+ }
+
+ public static int jvmTypeNameToExprType(char type) {
+ switch(type) {
+ case 'Z' :
+ return BOOLEAN;
+ case 'B' :
+ return BYTE;
+ case 'C' :
+ return CHAR;
+ case 'S' :
+ return SHORT;
+ case 'I' :
+ return INT;
+ case 'J' :
+ return LONG;
+ case 'F' :
+ return FLOAT;
+ case 'D' :
+ return DOUBLE;
+ case 'V' :
+ return VOID;
+ default :
+ return CLASS;
+ }
+ }
+
+ public static int descToType(char c) throws CompileError {
+ switch (c) {
+ case 'Z' :
+ return BOOLEAN;
+ case 'C' :
+ return CHAR;
+ case 'B' :
+ return BYTE;
+ case 'S' :
+ return SHORT;
+ case 'I' :
+ return INT;
+ case 'J' :
+ return LONG;
+ case 'F' :
+ return FLOAT;
+ case 'D' :
+ return DOUBLE;
+ case 'V' :
+ return VOID;
+ case 'L' :
+ case '[' :
+ return CLASS;
+ default :
+ fatal();
+ return VOID;
+ }
+ }
+
+ public static int getModifiers(ASTList mods) {
+ int m = 0;
+ while (mods != null) {
+ Keyword k = (Keyword)mods.head();
+ mods = mods.tail();
+ switch (k.get()) {
+ case STATIC :
+ m |= Modifier.STATIC;
+ break;
+ case FINAL :
+ m |= Modifier.FINAL;
+ break;
+ case SYNCHRONIZED :
+ m |= Modifier.SYNCHRONIZED;
+ break;
+ case ABSTRACT :
+ m |= Modifier.ABSTRACT;
+ break;
+ case PUBLIC :
+ m |= Modifier.PUBLIC;
+ break;
+ case PROTECTED :
+ m |= Modifier.PROTECTED;
+ break;
+ case PRIVATE :
+ m |= Modifier.PRIVATE;
+ break;
+ case VOLATILE :
+ m |= Modifier.VOLATILE;
+ break;
+ case TRANSIENT :
+ m |= Modifier.TRANSIENT;
+ break;
+ case STRICT :
+ m |= Modifier.STRICT;
+ break;
+ }
+ }
+
+ return m;
+ }
+}
diff --git a/src/main/javassist/compiler/Parser.java b/src/main/javassist/compiler/Parser.java
index dcc14a24..46d17151 100644
--- a/src/main/javassist/compiler/Parser.java
+++ b/src/main/javassist/compiler/Parser.java
@@ -852,7 +852,7 @@ public final class Parser implements TokenId {
case '!' :
case '~' :
t = lex.get();
- return new Expr(t, parseUnaryExpr(tbl));
+ return Expr.make(t, parseUnaryExpr(tbl));
case '(' :
return parseCast(tbl);
default :
@@ -1051,7 +1051,7 @@ public final class Parser implements TokenId {
throw new SyntaxError(lex);
}
- return Expr.make(CALL, expr, parseArgumentList(tbl));
+ return CallExpr.makeCall(expr, parseArgumentList(tbl));
}
private String toClassName(ASTree name)
diff --git a/src/main/javassist/compiler/ProceedHandler.java b/src/main/javassist/compiler/ProceedHandler.java
index 848e4525..765109a1 100644
--- a/src/main/javassist/compiler/ProceedHandler.java
+++ b/src/main/javassist/compiler/ProceedHandler.java
@@ -25,6 +25,6 @@ import javassist.compiler.ast.ASTList;
* @see javassist.compiler.JvstCodeGen#atMethodCall(Expr)
*/
public interface ProceedHandler {
- void doit(JvstCodeGen gen, Bytecode b, ASTList args)
- throws CompileError;
+ void doit(JvstCodeGen gen, Bytecode b, ASTList args) throws CompileError;
+ void setReturnType(JvstTypeChecker c, ASTList args) throws CompileError;
}
diff --git a/src/main/javassist/compiler/TypeChecker.java b/src/main/javassist/compiler/TypeChecker.java
new file mode 100644
index 00000000..c8024b90
--- /dev/null
+++ b/src/main/javassist/compiler/TypeChecker.java
@@ -0,0 +1,755 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2003 Shigeru Chiba. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. Alternatively, the contents of this file may be used under
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ */
+
+package javassist.compiler;
+
+import javassist.CtClass;
+import javassist.CtField;
+import javassist.ClassPool;
+import javassist.NotFoundException;
+import javassist.compiler.ast.*;
+import javassist.bytecode.*;
+
+public class TypeChecker extends Visitor implements Opcode, TokenId {
+ static final String javaLangObject = "java.lang.Object";
+ static final String jvmJavaLangObject = "java/lang/Object";
+ static final String jvmJavaLangString = "java/lang/String";
+
+ /* The following fields are used by atXXX() methods
+ * for returning the type of the compiled expression.
+ */
+ protected int exprType; // VOID, NULL, CLASS, BOOLEAN, INT, ...
+ protected int arrayDim;
+ protected String className; // JVM-internal representation
+
+ protected MemberResolver resolver;
+ protected CtClass thisClass;
+ protected MethodInfo thisMethod;
+
+ public TypeChecker(CtClass cc, ClassPool cp) {
+ resolver = new MemberResolver(cp);
+ thisClass = cc;
+ thisMethod = null;
+ }
+
+ /**
+ * Records the currently compiled method.
+ */
+ public void setThisMethod(MethodInfo m) {
+ thisMethod = m;
+ }
+
+ protected static void fatal() throws CompileError {
+ throw new CompileError("fatal");
+ }
+
+ /**
+ * Returns the JVM-internal representation of this class name.
+ */
+ protected String getThisName() {
+ return MemberResolver.javaToJvmName(thisClass.getName());
+ }
+
+ /**
+ * Returns the JVM-internal representation of this super class name.
+ */
+ protected String getSuperName() throws CompileError {
+ return MemberResolver.javaToJvmName(
+ MemberResolver.getSuperclass(thisClass).getName());
+ }
+
+ /* Converts a class name into a JVM-internal representation.
+ *
+ * It may also expand a simple class name to java.lang.*.
+ * For example, this converts Object into java/lang/Object.
+ */
+ protected String resolveClassName(ASTList name) throws CompileError {
+ return resolver.resolveClassName(name);
+ }
+
+ /* Expands a simple class name to java.lang.*.
+ * For example, this converts Object into java/lang/Object.
+ */
+ protected String resolveClassName(String jvmName) throws CompileError {
+ return resolver.resolveJvmClassName(jvmName);
+ }
+
+ public void atNewExpr(NewExpr expr) throws CompileError {
+ if (expr.isArray())
+ atNewArrayExpr(expr);
+ else {
+ CtClass clazz = resolver.lookupClassByName(expr.getClassName());
+ String cname = clazz.getName();
+ ASTList args = expr.getArguments();
+ atMethodCallCore(clazz, MethodInfo.nameInit, args);
+ exprType = CLASS;
+ arrayDim = 0;
+ className = MemberResolver.javaToJvmName(cname);
+ }
+ }
+
+ public void atNewArrayExpr(NewExpr expr) throws CompileError {
+ int type = expr.getArrayType();
+ ASTList size = expr.getArraySize();
+ ASTList classname = expr.getClassName();
+ if (size.length() > 1)
+ atMultiNewArray(type, classname, size);
+ else {
+ size.head().accept(this);
+ exprType = type;
+ arrayDim = 1;
+ if (type == CLASS)
+ className = resolveClassName(classname);
+ else
+ className = null;
+ }
+ }
+
+ protected void atMultiNewArray(int type, ASTList classname, ASTList size)
+ throws CompileError
+ {
+ int count, dim;
+ dim = size.length();
+ for (count = 0; size != null; size = size.tail()) {
+ ASTree s = size.head();
+ if (s == null)
+ break; // int[][][] a = new int[3][4][];
+
+ ++count;
+ s.accept(this);
+ }
+
+ exprType = type;
+ arrayDim = dim;
+ if (type == CLASS)
+ className = resolveClassName(classname);
+ else
+ className = null;
+ }
+
+ public void atAssignExpr(AssignExpr expr) throws CompileError {
+ // =, %=, &=, *=, /=, +=, -=, ^=, |=, <<=, >>=, >>>=
+ int op = expr.getOperator();
+ ASTree left = expr.oprand1();
+ ASTree right = expr.oprand2();
+ if (left instanceof Variable)
+ atVariableAssign(expr, op, (Variable)left,
+ ((Variable)left).getDeclarator(),
+ right);
+ else {
+ if (left instanceof Expr) {
+ Expr e = (Expr)left;
+ if (e.getOperator() == ARRAY) {
+ atArrayAssign(expr, op, (Expr)left, right);
+ return;
+ }
+ }
+
+ atFieldAssign(expr, op, left, right);
+ }
+ }
+
+ /* op is either =, %=, &=, *=, /=, +=, -=, ^=, |=, <<=, >>=, or >>>=.
+ *
+ * expr and var can be null.
+ */
+ private void atVariableAssign(Expr expr, int op, Variable var,
+ Declarator d, ASTree right)
+ throws CompileError
+ {
+ int varType = d.getType();
+ int varArray = d.getArrayDim();
+ String varClass = d.getClassName();
+
+ if (op != '=')
+ atVariable(var);
+
+ right.accept(this);
+ exprType = varType;
+ arrayDim = varArray;
+ className = varClass;
+ }
+
+ private void atArrayAssign(Expr expr, int op, Expr array,
+ ASTree right) throws CompileError
+ {
+ atArrayRead(array.oprand1(), array.oprand2());
+ int aType = exprType;
+ int aDim = arrayDim;
+ String cname = className;
+ right.accept(this);
+ exprType = aType;
+ arrayDim = aDim;
+ className = cname;
+ }
+
+ protected void atFieldAssign(Expr expr, int op, ASTree left, ASTree right)
+ throws CompileError
+ {
+ CtField f = fieldAccess(left);
+ atFieldRead(f);
+ int fType = exprType;
+ int fDim = arrayDim;
+ String cname = className;
+ right.accept(this);
+ exprType = fType;
+ arrayDim = fDim;
+ className = cname;
+ }
+
+ public void atCondExpr(CondExpr expr) throws CompileError {
+ booleanExpr(expr.condExpr());
+ expr.thenExpr().accept(this);
+ int type1 = exprType;
+ int dim1 = arrayDim;
+ String cname1 = className;
+ expr.elseExpr().accept(this);
+
+ if (dim1 == 0 && dim1 == arrayDim)
+ if (CodeGen.rightIsStrong(type1, exprType))
+ expr.setThen(new CastExpr(exprType, 0, expr.thenExpr()));
+ else if (CodeGen.rightIsStrong(exprType, type1)) {
+ expr.setElse(new CastExpr(type1, 0, expr.elseExpr()));
+ exprType = type1;
+ }
+ }
+
+ public void atBinExpr(BinExpr expr) throws CompileError {
+ int token = expr.getOperator();
+ int k = CodeGen.lookupBinOp(token);
+ if (k >= 0) {
+ /* arithmetic operators: +, -, *, /, %, |, ^, &, <<, >>, >>>
+ */
+ if (token == '+') {
+ Expr e = atPlusExpr(expr);
+ if (e != null) {
+ /* String concatenation has been translated into
+ * an expression using StringBuffer.
+ */
+ e = CallExpr.makeCall(Expr.make('.', e,
+ new Member("toString")), null);
+ expr.setLeft(e);
+ expr.setOprand2(null); // <---- look at this!
+ className = jvmJavaLangString;
+ }
+ }
+ else {
+ expr.oprand1().accept(this);
+ int type1 = exprType;
+ expr.oprand2().accept(this);
+ computeBinExprType(expr, token, type1);
+ }
+ }
+ else {
+ /* equation: &&, ||, ==, !=, <=, >=, <, >
+ */
+ booleanExpr(expr);
+ }
+ }
+
+ // expr must be a + expression.
+ private Expr atPlusExpr(BinExpr expr) throws CompileError {
+ ASTree left = expr.oprand1();
+ ASTree right = expr.oprand2();
+ if (right == null) {
+ /* this expression has been already type-checked since it is
+ string concatenation.
+ see atBinExpr() above.
+ */
+ exprType = CLASS;
+ arrayDim = 0;
+ className = jvmJavaLangString;
+ return null;
+ }
+
+ if (isPlusExpr(left)) {
+ Expr newExpr = atPlusExpr((BinExpr)left);
+ if (newExpr != null) {
+ right.accept(this);
+ exprType = CLASS;
+ arrayDim = 0;
+ className = "java/lang/StringBuffer";
+ return makeAppendCall(newExpr, right);
+ }
+ }
+ else
+ left.accept(this);
+
+ int type1 = exprType;
+ int dim1 = arrayDim;
+ String cname = className;
+ right.accept(this);
+ if ((type1 == CLASS && dim1 == 0 && jvmJavaLangString.equals(cname))
+ || (exprType == CLASS && arrayDim == 0
+ && jvmJavaLangString.equals(className))) {
+ ASTList sbufClass = ASTList.make(new Symbol("java"),
+ new Symbol("lang"), new Symbol("StringBuffer"));
+ ASTree e = new NewExpr(sbufClass, null);
+ exprType = CLASS;
+ arrayDim = 0;
+ className = "java/lang/StringBuffer";
+ return makeAppendCall(makeAppendCall(e, left), right);
+ }
+ else {
+ computeBinExprType(expr, '+', type1);
+ return null;
+ }
+ }
+
+ private static boolean isPlusExpr(ASTree expr) {
+ if (expr instanceof BinExpr) {
+ BinExpr bexpr = (BinExpr)expr;
+ int token = bexpr.getOperator();
+ return token == '+';
+ }
+
+ return false;
+ }
+
+ private static Expr makeAppendCall(ASTree target, ASTree arg) {
+ return CallExpr.makeCall(Expr.make('.', target, new Member("append")),
+ new ASTList(arg));
+ }
+
+ private void computeBinExprType(BinExpr expr, int token, int type1)
+ throws CompileError
+ {
+ // arrayDim should be 0.
+ int type2 = exprType;
+ if (token == LSHIFT || token == RSHIFT || token == ARSHIFT)
+ exprType = type1;
+ else
+ insertCast(expr, type1, type2);
+
+ if (CodeGen.isP_INT(exprType))
+ exprType = INT; // type1 may be BYTE, ...
+ }
+
+ private void booleanExpr(ASTree expr)
+ throws CompileError
+ {
+ int op = CodeGen.getCompOperator(expr);
+ if (op == EQ) { // ==, !=, ...
+ BinExpr bexpr = (BinExpr)expr;
+ bexpr.oprand1().accept(this);
+ int type1 = exprType;
+ int dim1 = arrayDim;
+ bexpr.oprand2().accept(this);
+ if (dim1 == 0 && arrayDim == 0)
+ insertCast(bexpr, type1, exprType);
+ }
+ else if (op == '!')
+ ((Expr)expr).oprand1().accept(this);
+ else if (op == ANDAND || op == OROR) {
+ BinExpr bexpr = (BinExpr)expr;
+ bexpr.oprand1().accept(this);
+ bexpr.oprand2().accept(this);
+ }
+ else // others
+ expr.accept(this);
+
+ exprType = BOOLEAN;
+ arrayDim = 0;
+ }
+
+ private void insertCast(BinExpr expr, int type1, int type2)
+ throws CompileError
+ {
+ if (CodeGen.rightIsStrong(type1, type2))
+ expr.setLeft(new CastExpr(type2, 0, expr.oprand1()));
+ else
+ exprType = type1;
+ }
+
+ public void atCastExpr(CastExpr expr) throws CompileError {
+ String cname = resolveClassName(expr.getClassName());
+ expr.getOprand().accept(this);
+ exprType = expr.getType();
+ arrayDim = expr.getArrayDim();
+ className = cname;
+ }
+
+ public void atInstanceOfExpr(InstanceOfExpr expr) throws CompileError {
+ expr.getOprand().accept(this);
+ exprType = BOOLEAN;
+ arrayDim = 0;
+ }
+
+ public void atExpr(Expr expr) throws CompileError {
+ // array access, member access,
+ // (unary) +, (unary) -, ++, --, !, ~
+
+ int token = expr.getOperator();
+ ASTree oprand = expr.oprand1();
+ if (token == '.')
+ if (((Symbol)expr.oprand2()).get().equals("length"))
+ atArrayLength(expr);
+ else
+ atFieldRead(expr);
+ else if (token == MEMBER) { // field read
+ if (!atClassObject(expr)) // .class
+ atFieldRead(expr);
+ }
+ else if (token == ARRAY)
+ atArrayRead(oprand, expr.oprand2());
+ else if (token == PLUSPLUS || token == MINUSMINUS)
+ atPlusPlus(token, oprand, expr);
+ else if (token == '!')
+ booleanExpr(expr);
+ else if (token == CALL) // method call
+ fatal();
+ else {
+ expr.oprand1().accept(this);
+ if (token == '-' || token == '~')
+ if (CodeGen.isP_INT(exprType))
+ exprType = INT; // type may be BYTE, ...
+ }
+ }
+
+ public void atCallExpr(CallExpr expr) throws CompileError {
+ String mname = null;
+ CtClass targetClass = null;
+ ASTree method = expr.oprand1();
+ ASTList args = (ASTList)expr.oprand2();
+
+ if (method instanceof Member) {
+ mname = ((Member)method).get();
+ targetClass = thisClass;
+ }
+ else if (method instanceof Keyword) { // constructor
+ mname = MethodInfo.nameInit; // <init>
+ if (((Keyword)method).get() == SUPER)
+ targetClass = MemberResolver.getSuperclass(thisClass);
+ else
+ targetClass = thisClass;
+ }
+ else if (method instanceof Expr) {
+ Expr e = (Expr)method;
+ mname = ((Symbol)e.oprand2()).get();
+ int op = e.getOperator();
+ if (op == MEMBER) // static method
+ targetClass
+ = resolver.lookupClass(((Symbol)e.oprand1()).get());
+ else if (op == '.') {
+ ASTree target = e.oprand1();
+ try {
+ target.accept(this);
+ }
+ catch (NoFieldException nfe) {
+ if (nfe.getExpr() != target)
+ throw nfe;
+
+ // it should be a static method.
+ exprType = CLASS;
+ arrayDim = 0;
+ className = nfe.getField(); // JVM-internal
+ }
+
+ if (arrayDim > 0)
+ targetClass = resolver.lookupClass(javaLangObject);
+ else if (exprType == CLASS /* && arrayDim == 0 */)
+ targetClass = resolver.lookupClassByJvmName(className);
+ else
+ badMethod();
+ }
+ else
+ badMethod();
+ }
+ else
+ fatal();
+
+ MemberResolver.Method minfo
+ = atMethodCallCore(targetClass, mname, args);
+ expr.setMethod(minfo);
+ }
+
+ private static void badMethod() throws CompileError {
+ throw new CompileError("bad method");
+ }
+
+ /**
+ * @return a pair of the class declaring the invoked method
+ * and the MethodInfo of that method. Never null.
+ */
+ public MemberResolver.Method atMethodCallCore(CtClass targetClass,
+ String mname, ASTList args)
+ throws CompileError
+ {
+ int nargs = getMethodArgsLength(args);
+ int[] types = new int[nargs];
+ int[] dims = new int[nargs];
+ String[] cnames = new String[nargs];
+ atMethodArgs(args, types, dims, cnames);
+
+ MemberResolver.Method found
+ = resolver.lookupMethod(targetClass, thisMethod, mname,
+ types, dims, cnames, false);
+ if (found == null) {
+ String msg;
+ if (mname.equals(MethodInfo.nameInit))
+ msg = "constructor not found";
+ else
+ msg = "Method " + mname + " not found in "
+ + targetClass.getName();
+
+ throw new CompileError(msg);
+ }
+
+ String desc = found.info.getDescriptor();
+ setReturnType(desc);
+ return found;
+ }
+
+ public int getMethodArgsLength(ASTList args) {
+ return ASTList.length(args);
+ }
+
+ public void atMethodArgs(ASTList args, int[] types, int[] dims,
+ String[] cnames) throws CompileError {
+ int i = 0;
+ while (args != null) {
+ ASTree a = args.head();
+ a.accept(this);
+ types[i] = exprType;
+ dims[i] = arrayDim;
+ cnames[i] = className;
+ ++i;
+ args = args.tail();
+ }
+ }
+
+ void setReturnType(String desc) throws CompileError {
+ int i = desc.indexOf(')');
+ if (i < 0)
+ badMethod();
+
+ char c = desc.charAt(++i);
+ int dim = 0;
+ while (c == '[') {
+ ++dim;
+ c = desc.charAt(++i);
+ }
+
+ arrayDim = dim;
+ if (c == 'L') {
+ int j = desc.indexOf(';', i + 1);
+ if (j < 0)
+ badMethod();
+
+ exprType = CLASS;
+ className = desc.substring(i + 1, j);
+ }
+ else {
+ exprType = MemberResolver.descToType(c);
+ className = null;
+ }
+ }
+
+ private void atFieldRead(ASTree expr) throws CompileError {
+ atFieldRead(fieldAccess(expr));
+ }
+
+ private void atFieldRead(CtField f) throws CompileError {
+ FieldInfo finfo = f.getFieldInfo2();
+ String type = finfo.getDescriptor();
+
+ int i = 0;
+ int dim = 0;
+ char c = type.charAt(i);
+ while (c == '[') {
+ ++dim;
+ c = type.charAt(++i);
+ }
+
+ arrayDim = dim;
+ exprType = MemberResolver.descToType(c);
+
+ if (c == 'L')
+ className = type.substring(i + 1, type.indexOf(';', i + 1));
+ else
+ className = null;
+ }
+
+ protected CtField fieldAccess(ASTree expr) throws CompileError {
+ if (expr instanceof Member) {
+ String name = ((Member)expr).get();
+ try {
+ return thisClass.getField(name);
+ }
+ catch (NotFoundException e) {
+ // EXPR might be part of a static member access?
+ throw new NoFieldException(name, expr);
+ }
+ }
+ else if (expr instanceof Expr) {
+ Expr e = (Expr)expr;
+ int op = e.getOperator();
+ if (op == MEMBER)
+ return resolver.lookupField(((Symbol)e.oprand1()).get(),
+ (Symbol)e.oprand2());
+ else if (op == '.')
+ try {
+ e.oprand1().accept(this);
+ if (exprType == CLASS && arrayDim == 0)
+ return resolver.lookupFieldByJvmName(className,
+ (Symbol)e.oprand2());
+ }
+ catch (NoFieldException nfe) {
+ if (nfe.getExpr() != e.oprand1())
+ throw nfe;
+
+ Symbol fname = (Symbol)e.oprand2();
+ // it should be a static field.
+ try {
+ return resolver.lookupFieldByJvmName(nfe.getField(),
+ fname);
+ }
+ catch (CompileError ce) {
+ // EXPR might be part of a qualified class name.
+ throw new NoFieldException(nfe.getField() + "/"
+ + fname.get(), expr);
+ }
+ }
+ }
+
+ throw new CompileError("bad filed access");
+ }
+
+ public boolean atClassObject(Expr expr) throws CompileError {
+ if (!((Symbol)expr.oprand2()).get().equals("class"))
+ return false;
+
+ if (resolveClassName((ASTList)expr.oprand1()) == null)
+ return false;
+
+ return true;
+ }
+
+ public void atArrayLength(Expr expr) throws CompileError {
+ expr.oprand1().accept(this);
+ exprType = INT;
+ arrayDim = 0;
+ }
+
+ public void atArrayRead(ASTree array, ASTree index)
+ throws CompileError
+ {
+ array.accept(this);
+ int type = exprType;
+ int dim = arrayDim;
+ String cname = className;
+ index.accept(this);
+ exprType = type;
+ arrayDim = dim - 1;
+ className = cname;
+ }
+
+ private void atPlusPlus(int token, ASTree oprand, Expr expr)
+ throws CompileError
+ {
+ boolean isPost = oprand == null; // ++i or i++?
+ if (isPost)
+ oprand = expr.oprand2();
+
+ if (oprand instanceof Variable) {
+ Declarator d = ((Variable)oprand).getDeclarator();
+ exprType = d.getType();
+ arrayDim = d.getArrayDim();
+ }
+ else {
+ if (oprand instanceof Expr) {
+ Expr e = (Expr)oprand;
+ if (e.getOperator() == ARRAY) {
+ atArrayRead(expr.oprand1(), expr.oprand2());
+ // arrayDim should be 0.
+ int t = exprType;
+ if (t == INT || t == BYTE || t == CHAR || t == SHORT)
+ exprType = INT;
+
+ return;
+ }
+ }
+
+ atFieldPlusPlus(oprand);
+ }
+ }
+
+ protected void atFieldPlusPlus(ASTree oprand) throws CompileError
+ {
+ CtField f = fieldAccess(oprand);
+ atFieldRead(f);
+ int t = exprType;
+ if (t == INT || t == BYTE || t == CHAR || t == SHORT)
+ exprType = INT;
+ }
+
+ public void atMember(Member mem) throws CompileError {
+ atFieldRead(mem);
+ }
+
+ public void atVariable(Variable v) throws CompileError {
+ Declarator d = v.getDeclarator();
+ exprType = d.getType();
+ arrayDim = d.getArrayDim();
+ className = d.getClassName();
+ }
+
+ public void atKeyword(Keyword k) throws CompileError {
+ arrayDim = 0;
+ int token = k.get();
+ switch (token) {
+ case TRUE :
+ case FALSE :
+ exprType = BOOLEAN;
+ break;
+ case NULL :
+ exprType = NULL;
+ break;
+ case THIS :
+ case SUPER :
+ exprType = CLASS;
+ if (token == THIS)
+ className = getThisName();
+ else
+ className = getSuperName();
+ break;
+ default :
+ fatal();
+ }
+ }
+
+ public void atStringL(StringL s) throws CompileError {
+ exprType = CLASS;
+ arrayDim = 0;
+ className = jvmJavaLangString;
+ }
+
+ public void atIntConst(IntConst i) throws CompileError {
+ arrayDim = 0;
+ int type = i.getType();
+ if (type == IntConstant || type == CharConstant)
+ exprType = (type == IntConstant ? INT : CHAR);
+ else
+ exprType = LONG;
+ }
+
+ public void atDoubleConst(DoubleConst d) throws CompileError {
+ arrayDim = 0;
+ if (d.getType() == DoubleConstant)
+ exprType = DOUBLE;
+ else
+ exprType = FLOAT;
+ }
+}
diff --git a/src/main/javassist/compiler/ast/AssignExpr.java b/src/main/javassist/compiler/ast/AssignExpr.java
index 3f5b841e..77a109db 100644
--- a/src/main/javassist/compiler/ast/AssignExpr.java
+++ b/src/main/javassist/compiler/ast/AssignExpr.java
@@ -25,7 +25,7 @@ public class AssignExpr extends Expr {
* =, %=, &=, *=, +=, -=, /=, ^=, |=, <<=, >>=, >>>=
*/
- public AssignExpr(int op, ASTree _head, ASTList _tail) {
+ private AssignExpr(int op, ASTree _head, ASTList _tail) {
super(op, _head, _tail);
}
diff --git a/src/main/javassist/compiler/ast/BinExpr.java b/src/main/javassist/compiler/ast/BinExpr.java
index 3b8af793..0078d5c4 100644
--- a/src/main/javassist/compiler/ast/BinExpr.java
+++ b/src/main/javassist/compiler/ast/BinExpr.java
@@ -19,6 +19,9 @@ import javassist.compiler.CompileError;
/**
* Binary expression.
+ *
+ * <p>If the operator is +, the right node might be null.
+ * See TypeChecker.atBinExpr().
*/
public class BinExpr extends Expr {
/* operator must be either of:
@@ -26,7 +29,7 @@ public class BinExpr extends Expr {
* <<, >>, >>>, +, -, *, /, %
*/
- public BinExpr(int op, ASTree _head, ASTList _tail) {
+ private BinExpr(int op, ASTree _head, ASTList _tail) {
super(op, _head, _tail);
}
diff --git a/src/main/javassist/compiler/ast/CallExpr.java b/src/main/javassist/compiler/ast/CallExpr.java
new file mode 100644
index 00000000..7c8a63e6
--- /dev/null
+++ b/src/main/javassist/compiler/ast/CallExpr.java
@@ -0,0 +1,46 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2003 Shigeru Chiba. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. Alternatively, the contents of this file may be used under
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ */
+
+package javassist.compiler.ast;
+
+import javassist.compiler.CompileError;
+import javassist.compiler.TokenId;
+import javassist.compiler.MemberResolver;
+
+/**
+ * Method call expression.
+ */
+public class CallExpr extends Expr {
+ private MemberResolver.Method method; // cached result of lookupMethod()
+
+ private CallExpr(ASTree _head, ASTList _tail) {
+ super(TokenId.CALL, _head, _tail);
+ method = null;
+ }
+
+ public void setMethod(MemberResolver.Method m) {
+ method = m;
+ }
+
+ public MemberResolver.Method getMethod() {
+ return method;
+ }
+
+ public static CallExpr makeCall(ASTree target, ASTree args) {
+ return new CallExpr(target, new ASTList(args));
+ }
+
+ public void accept(Visitor v) throws CompileError { v.atCallExpr(this); }
+}
diff --git a/src/main/javassist/compiler/ast/CondExpr.java b/src/main/javassist/compiler/ast/CondExpr.java
index 9cb821a5..9cfde8ad 100644
--- a/src/main/javassist/compiler/ast/CondExpr.java
+++ b/src/main/javassist/compiler/ast/CondExpr.java
@@ -29,8 +29,12 @@ public class CondExpr extends ASTList {
public ASTree thenExpr() { return tail().head(); }
+ public void setThen(ASTree t) { tail().setHead(t); }
+
public ASTree elseExpr() { return tail().tail().head(); }
+ public void setElse(ASTree t) { tail().tail().setHead(t); }
+
public String getTag() { return "?:"; }
public void accept(Visitor v) throws CompileError { v.atCondExpr(this); }
diff --git a/src/main/javassist/compiler/ast/Expr.java b/src/main/javassist/compiler/ast/Expr.java
index aa7b06da..fb443448 100644
--- a/src/main/javassist/compiler/ast/Expr.java
+++ b/src/main/javassist/compiler/ast/Expr.java
@@ -24,18 +24,18 @@ import javassist.compiler.CompileError;
public class Expr extends ASTList implements TokenId {
/* operator must be either of:
* (unary) +, (unary) -, ++, --, !, ~,
- * CALL, ARRAY, . (dot), MEMBER (static member access).
+ * ARRAY, . (dot), MEMBER (static member access).
* Otherwise, the object should be an instance of a subclass.
*/
protected int operatorId;
- public Expr(int op, ASTree _head, ASTList _tail) {
+ Expr(int op, ASTree _head, ASTList _tail) {
super(_head, _tail);
operatorId = op;
}
- public Expr(int op, ASTree _head) {
+ Expr(int op, ASTree _head) {
super(_head);
operatorId = op;
}
@@ -44,12 +44,20 @@ public class Expr extends ASTList implements TokenId {
return new Expr(op, oprand1, new ASTList(oprand2));
}
+ public static Expr make(int op, ASTree oprand1) {
+ return new Expr(op, oprand1);
+ }
+
public int getOperator() { return operatorId; }
public ASTree oprand1() { return getLeft(); }
public ASTree oprand2() { return getRight().getLeft(); }
+ public void setOprand2(ASTree expr) {
+ getRight().setLeft(expr);
+ }
+
public void accept(Visitor v) throws CompileError { v.atExpr(this); }
public String getName() {
diff --git a/src/main/javassist/compiler/ast/Visitor.java b/src/main/javassist/compiler/ast/Visitor.java
index 497eb17d..389cc688 100644
--- a/src/main/javassist/compiler/ast/Visitor.java
+++ b/src/main/javassist/compiler/ast/Visitor.java
@@ -35,6 +35,7 @@ public class Visitor {
public void atCondExpr(CondExpr n) throws CompileError {}
public void atBinExpr(BinExpr n) throws CompileError {}
public void atExpr(Expr n) throws CompileError {}
+ public void atCallExpr(CallExpr n) throws CompileError {}
public void atCastExpr(CastExpr n) throws CompileError {}
public void atInstanceOfExpr(InstanceOfExpr n) throws CompileError {}
public void atNewExpr(NewExpr n) throws CompileError {}
diff --git a/src/main/javassist/expr/Cast.java b/src/main/javassist/expr/Cast.java
index 5dcbbb41..6d65af52 100644
--- a/src/main/javassist/expr/Cast.java
+++ b/src/main/javassist/expr/Cast.java
@@ -148,5 +148,12 @@ public class Cast extends Expr {
bytecode.addIndex(index);
gen.setType(retType);
}
+
+ public void setReturnType(JvstTypeChecker c, ASTList args)
+ throws CompileError
+ {
+ c.atMethodArgs(args, new int[1], new int[1], new String[1]);
+ c.setType(retType);
+ }
}
}
diff --git a/src/main/javassist/expr/FieldAccess.java b/src/main/javassist/expr/FieldAccess.java
index 0a9cfeb1..c10246c8 100644
--- a/src/main/javassist/expr/FieldAccess.java
+++ b/src/main/javassist/expr/FieldAccess.java
@@ -240,6 +240,12 @@ public class FieldAccess extends Expr {
bytecode.growStack(stack);
gen.setType(fieldType);
}
+
+ public void setReturnType(JvstTypeChecker c, ASTList args)
+ throws CompileError
+ {
+ c.setType(fieldType);
+ }
}
/* void $proceed(<field type>)
@@ -286,5 +292,13 @@ public class FieldAccess extends Expr {
gen.setType(CtClass.voidType);
gen.addNullIfVoid();
}
+
+ public void setReturnType(JvstTypeChecker c, ASTList args)
+ throws CompileError
+ {
+ c.atMethodArgs(args, new int[1], new int[1], new String[1]);
+ c.setType(CtClass.voidType);
+ c.addNullIfVoid();
+ }
}
}
diff --git a/src/main/javassist/expr/Instanceof.java b/src/main/javassist/expr/Instanceof.java
index 9743c841..4053702e 100644
--- a/src/main/javassist/expr/Instanceof.java
+++ b/src/main/javassist/expr/Instanceof.java
@@ -151,5 +151,12 @@ public class Instanceof extends Expr {
bytecode.addIndex(index);
gen.setType(CtClass.booleanType);
}
+
+ public void setReturnType(JvstTypeChecker c, ASTList args)
+ throws CompileError
+ {
+ c.atMethodArgs(args, new int[1], new int[1], new String[1]);
+ c.setType(CtClass.booleanType);
+ }
}
}
diff --git a/src/main/javassist/expr/NewExpr.java b/src/main/javassist/expr/NewExpr.java
index 423a5d72..62f25ad6 100644
--- a/src/main/javassist/expr/NewExpr.java
+++ b/src/main/javassist/expr/NewExpr.java
@@ -205,9 +205,16 @@ public class NewExpr extends Expr {
bytecode.addOpcode(NEW);
bytecode.addIndex(newIndex);
bytecode.addOpcode(DUP);
- gen.atMethodCall2(newType, MethodInfo.nameInit,
- args, false, true, -1);
+ gen.atMethodCallCore(newType, MethodInfo.nameInit, args,
+ false, true, -1, null);
gen.setType(newType);
}
+
+ public void setReturnType(JvstTypeChecker c, ASTList args)
+ throws CompileError
+ {
+ c.atMethodCallCore(newType, MethodInfo.nameInit, args);
+ c.setType(newType);
+ }
}
}