Browse Source

Merge pull request #484 from kuznet1/master

Line numbers support
master
Shigeru Chiba 1 month ago
parent
commit
bb261b4438
No account linked to committer's email address
49 changed files with 958 additions and 478 deletions
  1. 10
    0
      src/main/javassist/CtClass.java
  2. 1
    0
      src/main/javassist/CtNewConstructor.java
  3. 1
    0
      src/main/javassist/CtNewMethod.java
  4. 14
    0
      src/main/javassist/bytecode/CodeAttribute.java
  5. 1
    1
      src/main/javassist/bytecode/LineNumberAttribute.java
  6. 40
    0
      src/main/javassist/bytecode/LineNumberAttributeBuilder.java
  7. 44
    44
      src/main/javassist/compiler/CodeGen.java
  8. 13
    2
      src/main/javassist/compiler/CompileError.java
  9. 34
    33
      src/main/javassist/compiler/Javac.java
  10. 36
    36
      src/main/javassist/compiler/JvstCodeGen.java
  11. 265
    0
      src/main/javassist/compiler/JvstCodeGenWitlLineNumber.java
  12. 15
    15
      src/main/javassist/compiler/JvstTypeChecker.java
  13. 11
    2
      src/main/javassist/compiler/Lex.java
  14. 56
    56
      src/main/javassist/compiler/MemberCodeGen.java
  15. 37
    35
      src/main/javassist/compiler/MemberResolver.java
  16. 1
    1
      src/main/javassist/compiler/NoFieldException.java
  17. 84
    76
      src/main/javassist/compiler/Parser.java
  18. 2
    2
      src/main/javassist/compiler/ProceedHandler.java
  19. 56
    55
      src/main/javassist/compiler/TypeChecker.java
  20. 8
    8
      src/main/javassist/compiler/ast/ASTList.java
  21. 10
    0
      src/main/javassist/compiler/ast/ASTree.java
  22. 5
    3
      src/main/javassist/compiler/ast/ArrayInit.java
  23. 4
    4
      src/main/javassist/compiler/ast/AssignExpr.java
  24. 4
    4
      src/main/javassist/compiler/ast/BinExpr.java
  25. 4
    4
      src/main/javassist/compiler/ast/CallExpr.java
  26. 4
    4
      src/main/javassist/compiler/ast/CastExpr.java
  27. 2
    2
      src/main/javassist/compiler/ast/CondExpr.java
  28. 10
    10
      src/main/javassist/compiler/ast/Declarator.java
  29. 9
    5
      src/main/javassist/compiler/ast/DoubleConst.java
  30. 8
    8
      src/main/javassist/compiler/ast/Expr.java
  31. 2
    2
      src/main/javassist/compiler/ast/FieldDecl.java
  32. 4
    4
      src/main/javassist/compiler/ast/InstanceOfExpr.java
  33. 7
    3
      src/main/javassist/compiler/ast/IntConst.java
  34. 2
    1
      src/main/javassist/compiler/ast/Keyword.java
  35. 2
    2
      src/main/javassist/compiler/ast/Member.java
  36. 2
    2
      src/main/javassist/compiler/ast/MethodDecl.java
  37. 8
    8
      src/main/javassist/compiler/ast/NewExpr.java
  38. 1
    0
      src/main/javassist/compiler/ast/Pair.java
  39. 10
    10
      src/main/javassist/compiler/ast/Stmnt.java
  40. 2
    1
      src/main/javassist/compiler/ast/StringL.java
  41. 2
    1
      src/main/javassist/compiler/ast/Symbol.java
  42. 2
    2
      src/main/javassist/compiler/ast/Variable.java
  43. 5
    5
      src/main/javassist/expr/Cast.java
  44. 10
    10
      src/main/javassist/expr/FieldAccess.java
  45. 5
    5
      src/main/javassist/expr/Instanceof.java
  46. 5
    5
      src/main/javassist/expr/NewArray.java
  47. 5
    5
      src/main/javassist/expr/NewExpr.java
  48. 93
    0
      src/test/javassist/LineNumberTest.java
  49. 2
    2
      src/test/javassist/compiler/CompTest.java

+ 10
- 0
src/main/javassist/CtClass.java View File

*/ */
public static final String version = "3.30.2-GA"; public static final String version = "3.30.2-GA";


private int linesCount = 0;

/** /**
* Prints the version number and the copyright notice. * Prints the version number and the copyright notice.
* *
new DelayedFileOutputStream(filename))); new DelayedFileOutputStream(filename)));
} }


public int getLinesCount() {
return linesCount;
}

void addLines(int count) {
this.linesCount += count;
}

/** /**
* Writes a class file as <code>writeFile()</code> does although this * Writes a class file as <code>writeFile()</code> does although this
* method does not prune or freeze the class after writing the class * method does not prune or freeze the class after writing the class

+ 1
- 0
src/main/javassist/CtNewConstructor.java View File

Javac compiler = new Javac(declaring); Javac compiler = new Javac(declaring);
try { try {
CtMember obj = compiler.compile(src); CtMember obj = compiler.compile(src);
declaring.addLines(src.split("\n").length);
if (obj instanceof CtConstructor) { if (obj instanceof CtConstructor) {
// a stack map table has been already created. // a stack map table has been already created.
return (CtConstructor)obj; return (CtConstructor)obj;

+ 1
- 0
src/main/javassist/CtNewMethod.java View File

compiler.recordProceed(delegateObj, delegateMethod); compiler.recordProceed(delegateObj, delegateMethod);


CtMember obj = compiler.compile(src); CtMember obj = compiler.compile(src);
declaring.addLines(src.split("\n").length);
if (obj instanceof CtMethod) if (obj instanceof CtMethod)
return (CtMethod)obj; return (CtMethod)obj;
} }

+ 14
- 0
src/main/javassist/bytecode/CodeAttribute.java View File

attributes.add(sm); attributes.add(sm);
} }


/**
* Adds a line number table. If another copy of line number table
* is already contained, the old one is removed.
*
* @param lnt the line number table added to this code attribute.
* If it is null, a new line number is not added.
* Only the old line number is removed.
*/
public void setAttribute(LineNumberAttribute lnt) {
AttributeInfo.remove(attributes, LineNumberAttribute.tag);
if (lnt != null)
attributes.add(lnt);
}

/** /**
* Copies code. * Copies code.
*/ */

+ 1
- 1
src/main/javassist/bytecode/LineNumberAttribute.java View File

super(cp, n, in); super(cp, n, in);
} }


private LineNumberAttribute(ConstPool cp, byte[] i) {
LineNumberAttribute(ConstPool cp, byte[] i) {
super(cp, tag, i); super(cp, tag, i);
} }



+ 40
- 0
src/main/javassist/bytecode/LineNumberAttributeBuilder.java View File

package javassist.bytecode;

import javassist.compiler.ast.ASTree;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class LineNumberAttributeBuilder {
private final HashMap<Integer, Integer> map = new HashMap<>();

public void put(int newPc, ASTree tree) {
if (tree != null)
put(newPc, tree.getLineNumber());
}

private void put(int newPc, int lineNum) {
Integer pc = map.get(lineNum);
if (pc == null || newPc < pc) {
map.put(lineNum, newPc);
}
}

public LineNumberAttribute build(ConstPool cp) {
int size = map.size();
try (ByteArrayOutputStream bos = new ByteArrayOutputStream(size * 4 + 2);
DataOutputStream dos = new DataOutputStream(bos)) {
dos.writeShort(size);
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
dos.writeShort(entry.getValue());
dos.writeShort(entry.getKey());
}
return new LineNumberAttribute(cp, bos.toByteArray());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

+ 44
- 44
src/main/javassist/compiler/CodeGen.java View File

typeChecker = checker; typeChecker = checker;
} }


protected static void fatal() throws CompileError {
throw new CompileError("fatal");
protected static void fatal(int lineNumber) throws CompileError {
throw new CompileError("fatal", lineNumber);
} }


public static boolean is2word(int type, int dim) { public static boolean is2word(int type, int dim) {
/* Expands a simple class name to java.lang.*. /* Expands a simple class name to java.lang.*.
* For example, this converts Object into java/lang/Object. * For example, this converts Object into java/lang/Object.
*/ */
protected abstract String resolveClassName(String jvmClassName)
protected abstract String resolveClassName(String jvmClassName, int lineNumber)
throws CompileError; throws CompileError;


/** /**
} }


@Override @Override
public void atASTList(ASTList n) throws CompileError { fatal(); }
public void atASTList(ASTList n) throws CompileError { fatal(n.getLineNumber()); }


@Override @Override
public void atPair(Pair n) throws CompileError { fatal(); }
public void atPair(Pair n) throws CompileError { fatal(n.getLineNumber()); }


@Override @Override
public void atSymbol(Symbol n) throws CompileError { fatal(); }
public void atSymbol(Symbol n) throws CompileError { fatal(n.getLineNumber()); }


@Override @Override
public void atFieldDecl(FieldDecl field) throws CompileError { public void atFieldDecl(FieldDecl field) throws CompileError {
hasReturned = true; hasReturned = true;
} }
else else
throw new CompileError("no return statement");
throw new CompileError("no return statement", s.getLineNumber());
} }


private boolean needsSuperCall(Stmnt body) throws CompileError { private boolean needsSuperCall(Stmnt body) throws CompileError {
// LABEL, SWITCH label stament might be null?. // LABEL, SWITCH label stament might be null?.
hasReturned = false; hasReturned = false;
throw new CompileError( throw new CompileError(
"sorry, not supported statement: TokenId " + op);
"sorry, not supported statement: TokenId " + op, st.getLineNumber());
} }
} }


if (op == DEFAULT) if (op == DEFAULT)
defaultPc = bytecode.currentPc(); defaultPc = bytecode.currentPc();
else if (op != CASE) else if (op != CASE)
fatal();
fatal(st.getLineNumber());
else { else {
int curPos = bytecode.currentPc(); int curPos = bytecode.currentPc();
long caseLabel; long caseLabel;
expr = TypeChecker.stripPlusExpr(expr); expr = TypeChecker.stripPlusExpr(expr);
if (expr instanceof IntConst) if (expr instanceof IntConst)
return (int)((IntConst)expr).get(); return (int)((IntConst)expr).get();
throw new CompileError("bad case label");
throw new CompileError("bad case label", expr.getLineNumber());
} }


private int computeStringLabel(ASTree expr, int tmpVar, List<Integer> gotoDefaults) private int computeStringLabel(ASTree expr, int tmpVar, List<Integer> gotoDefaults)
gotoDefaults.add(pc); gotoDefaults.add(pc);
return (int)label.hashCode(); return (int)label.hashCode();
} }
throw new CompileError("bad case label");
throw new CompileError("bad case label", expr.getLineNumber());
} }


private void atBreakStmnt(Stmnt st, boolean notCont) private void atBreakStmnt(Stmnt st, boolean notCont)
{ {
if (st.head() != null) if (st.head() != null)
throw new CompileError( throw new CompileError(
"sorry, not support labeled break or continue");
"sorry, not support labeled break or continue", st.getLineNumber());


bytecode.addOpcode(Opcode.GOTO); bytecode.addOpcode(Opcode.GOTO);
Integer pc = Integer.valueOf(bytecode.currentPc()); Integer pc = Integer.valueOf(bytecode.currentPc());
ASTree e = st.getLeft(); ASTree e = st.getLeft();
compileExpr(e); compileExpr(e);
if (exprType != CLASS || arrayDim > 0) if (exprType != CLASS || arrayDim > 0)
throw new CompileError("bad throw statement");
throw new CompileError("bad throw statement", st.getLineNumber());


bytecode.addOpcode(ATHROW); bytecode.addOpcode(ATHROW);
hasReturned = true; hasReturned = true;


compileExpr(st.head()); compileExpr(st.head());
if (exprType != CLASS && arrayDim == 0) if (exprType != CLASS && arrayDim == 0)
throw new CompileError("bad type expr for synchronized block");
throw new CompileError("bad type expr for synchronized block", st.getLineNumber());


Bytecode bc = bytecode; Bytecode bc = bytecode;
final int var = bc.getMaxLocals(); final int var = bc.getMaxLocals();
if (getListSize(breakList) != nbreaks if (getListSize(breakList) != nbreaks
|| getListSize(continueList) != ncontinues) || getListSize(continueList) != ncontinues)
throw new CompileError( throw new CompileError(
"sorry, cannot break/continue in synchronized block");
"sorry, cannot break/continue in synchronized block", st.getLineNumber());
} }


private static int getListSize(List<Integer> list) { private static int getListSize(List<Integer> list) {
@Override @Override
public void atDeclarator(Declarator d) throws CompileError { public void atDeclarator(Declarator d) throws CompileError {
d.setLocalVar(getMaxLocals()); d.setLocalVar(getMaxLocals());
d.setClassName(resolveClassName(d.getClassName()));
d.setClassName(resolveClassName(d.getClassName(), d.getLineNumber()));


int size; int size;
if (is2word(d.getType(), d.getArrayDim())) if (is2word(d.getType(), d.getArrayDim()))
else else
msg = "incompatible type for " + expr.getName(); msg = "incompatible type for " + expr.getName();


throw new CompileError(msg);
throw new CompileError(msg, expr.getLineNumber());
} }


/* op is either =, %=, &=, *=, /=, +=, -=, ^=, |=, <<=, >>=, or >>>=. /* op is either =, %=, &=, *=, /=, +=, -=, ^=, |=, <<=, >>=, or >>>=.
int token = assignOps[op - MOD_E]; int token = assignOps[op - MOD_E];
int k = lookupBinOp(token); int k = lookupBinOp(token);
if (k < 0) if (k < 0)
fatal();
fatal(right.getLineNumber());


atArithBinExpr(expr, token, k, type); atArithBinExpr(expr, token, k, type);
} }
if (!jvmJavaLangString.equals(cname)) if (!jvmJavaLangString.equals(cname))
badAssign(expr); badAssign(expr);


convToString(type, dim); // the value might be null.
convToString(type, dim, expr.getLineNumber()); // the value might be null.
right.accept(this); right.accept(this);
convToString(exprType, arrayDim);
convToString(exprType, arrayDim, expr.getLineNumber());
bytecode.addInvokevirtual(javaLangString, "concat", bytecode.addInvokevirtual(javaLangString, "concat",
"(Ljava/lang/String;)Ljava/lang/String;"); "(Ljava/lang/String;)Ljava/lang/String;");
exprType = CLASS; exprType = CLASS;
bytecode.write16bit(pc, bytecode.currentPc() - pc + 1); bytecode.write16bit(pc, bytecode.currentPc() - pc + 1);
expr.elseExpr().accept(this); expr.elseExpr().accept(this);
if (dim1 != arrayDim) if (dim1 != arrayDim)
throw new CompileError("type mismatch in ?:");
throw new CompileError("type mismatch in ?:", expr.getLineNumber());


bytecode.write16bit(pc2, bytecode.currentPc() - pc2 + 1); bytecode.write16bit(pc2, bytecode.currentPc() - pc2 + 1);
} }
String cname1 = className; String cname1 = className;
right.accept(this); right.accept(this);
if (dim1 != arrayDim) if (dim1 != arrayDim)
throw new CompileError("incompatible array types");
throw new CompileError("incompatible array types", expr.getLineNumber());


if (token == '+' && dim1 == 0 if (token == '+' && dim1 == 0
&& (type1 == CLASS || exprType == CLASS)) && (type1 == CLASS || exprType == CLASS))
= (type2 == CLASS && jvmJavaLangString.equals(className)); = (type2 == CLASS && jvmJavaLangString.equals(className));


if (type2Is2) if (type2Is2)
convToString(type2, dim2);
convToString(type2, dim2, expr.getLineNumber());


if (is2word(type1, dim1)) { if (is2word(type1, dim1)) {
bytecode.addOpcode(DUP_X2); bytecode.addOpcode(DUP_X2);
bytecode.addOpcode(SWAP); bytecode.addOpcode(SWAP);


// even if type1 is String, the left operand might be null. // even if type1 is String, the left operand might be null.
convToString(type1, dim1);
convToString(type1, dim1, expr.getLineNumber());
bytecode.addOpcode(SWAP); bytecode.addOpcode(SWAP);


if (!type2Is2 && !type2IsString) if (!type2Is2 && !type2IsString)
convToString(type2, dim2);
convToString(type2, dim2, expr.getLineNumber());


bytecode.addInvokevirtual(javaLangString, "concat", bytecode.addInvokevirtual(javaLangString, "concat",
"(Ljava/lang/String;)Ljava/lang/String;"); "(Ljava/lang/String;)Ljava/lang/String;");
className = jvmJavaLangString; className = jvmJavaLangString;
} }


private void convToString(int type, int dim) throws CompileError {
private void convToString(int type, int dim, int lineNumber) throws CompileError {
final String method = "valueOf"; final String method = "valueOf";


if (isRefType(type) || dim > 0) if (isRefType(type) || dim > 0)
bytecode.addInvokestatic(javaLangString, method, bytecode.addInvokestatic(javaLangString, method,
"(C)Ljava/lang/String;"); "(C)Ljava/lang/String;");
else if (type == VOID) else if (type == VOID)
throw new CompileError("void type expression");
throw new CompileError("void type expression", lineNumber);
else /* INT, BYTE, SHORT */ else /* INT, BYTE, SHORT */
bytecode.addInvokestatic(javaLangString, method, bytecode.addInvokestatic(javaLangString, method,
"(I)Ljava/lang/String;"); "(I)Ljava/lang/String;");
else { // others else { // others
expr.accept(this); expr.accept(this);
if (exprType != BOOLEAN || arrayDim != 0) if (exprType != BOOLEAN || arrayDim != 0)
throw new CompileError("boolean expr is required");
throw new CompileError("boolean expr is required", expr.getLineNumber());


bytecode.addOpcode(branchIf ? IFNE : IFEQ); bytecode.addOpcode(branchIf ? IFNE : IFEQ);
} }
expr.oprand2().accept(this); expr.oprand2().accept(this);
if (dim1 != arrayDim) if (dim1 != arrayDim)
if (type1 != NULL && exprType != NULL) if (type1 != NULL && exprType != NULL)
throw new CompileError("incompatible array types");
throw new CompileError("incompatible array types", expr.getLineNumber());
else if (exprType == NULL) else if (exprType == NULL)
arrayDim = dim1; arrayDim = dim1;


else if (p == P_LONG) else if (p == P_LONG)
bytecode.addOpcode(LCMP); // 1: >, 0: =, -1: < bytecode.addOpcode(LCMP); // 1: >, 0: =, -1: <
else else
fatal();
fatal(expr.getLineNumber());


int[] op = ifOp2; int[] op = ifOp2;
for (int i = 0; i < op.length; i += 3) for (int i = 0; i < op.length; i += 3)
} }


protected static void badTypes(Expr expr) throws CompileError { protected static void badTypes(Expr expr) throws CompileError {
throw new CompileError("invalid types for " + expr.getName());
throw new CompileError("invalid types for " + expr.getName(), expr.getLineNumber());
} }


private static final int P_DOUBLE = 0; private static final int P_DOUBLE = 0;
bytecode.addOpcode(SWAP); bytecode.addOpcode(SWAP);
} }
else else
fatal();
fatal(expr.getLineNumber());
} }
else if (op != NOP) else if (op != NOP)
bytecode.addOpcode(op); bytecode.addOpcode(op);
int srcDim = arrayDim; int srcDim = arrayDim;
if (invalidDim(srcType, arrayDim, className, type, dim, name, true) if (invalidDim(srcType, arrayDim, className, type, dim, name, true)
|| srcType == VOID || type == VOID) || srcType == VOID || type == VOID)
throw new CompileError(msg);
throw new CompileError(msg, expr.getLineNumber());


if (type == CLASS) { if (type == CLASS) {
if (!isRefType(srcType) && srcDim == 0) if (!isRefType(srcType) && srcDim == 0)
throw new CompileError(msg);
throw new CompileError(msg, expr.getLineNumber());


return toJvmArrayName(name, dim); return toJvmArrayName(name, dim);
} }
bytecode.addIconst(0); bytecode.addIconst(0);
} }
else if (token == CALL) // method call else if (token == CALL) // method call
fatal();
fatal(expr.getLineNumber());
else { else {
expr.oprand1().accept(this); expr.oprand1().accept(this);
int type = typePrecedence(exprType); int type = typePrecedence(exprType);
// do nothing. ignore. // do nothing. ignore.
} }
else else
fatal();
fatal(expr.getLineNumber());
} }
} }


protected static void badType(Expr expr) throws CompileError { protected static void badType(Expr expr) throws CompileError {
throw new CompileError("invalid type for " + expr.getName());
throw new CompileError("invalid type for " + expr.getName(), expr.getLineNumber());
} }


@Override @Override
public void atClassObject(Expr expr) throws CompileError { public void atClassObject(Expr expr) throws CompileError {
ASTree op1 = expr.oprand1(); ASTree op1 = expr.oprand1();
if (!(op1 instanceof Symbol)) if (!(op1 instanceof Symbol))
throw new CompileError("fatal error: badly parsed .class expr");
throw new CompileError("fatal error: badly parsed .class expr", expr.getLineNumber());


String cname = ((Symbol)op1).get(); String cname = ((Symbol)op1).get();
if (cname.startsWith("[")) { if (cname.startsWith("[")) {
int i = cname.indexOf("[L"); int i = cname.indexOf("[L");
if (i >= 0) { if (i >= 0) {
String name = cname.substring(i + 2, cname.length() - 1); String name = cname.substring(i + 2, cname.length() - 1);
String name2 = resolveClassName(name);
String name2 = resolveClassName(name, expr.getLineNumber());
if (!name.equals(name2)) { if (!name.equals(name2)) {
/* For example, to obtain String[].class, /* For example, to obtain String[].class,
* "[Ljava.lang.String;" (not "[Ljava/lang/String"!) * "[Ljava.lang.String;" (not "[Ljava/lang/String"!)
} }
} }
else { else {
cname = resolveClassName(MemberResolver.javaToJvmName(cname));
cname = resolveClassName(MemberResolver.javaToJvmName(cname), expr.getLineNumber());
cname = MemberResolver.jvmToJavaName(cname); cname = MemberResolver.jvmToJavaName(cname);
} }


int type = exprType; int type = exprType;
int dim = arrayDim; int dim = arrayDim;
if (dim == 0) if (dim == 0)
throw new CompileError("bad array access");
throw new CompileError("bad array access", array.getLineNumber());


String cname = className; String cname = className;


index.accept(this); index.accept(this);
if (typePrecedence(exprType) != P_INT || arrayDim > 0) if (typePrecedence(exprType) != P_INT || arrayDim > 0)
throw new CompileError("bad array index");
throw new CompileError("bad array index", array.getLineNumber());


exprType = type; exprType = type;
arrayDim = dim - 1; arrayDim = dim - 1;
case SUPER : case SUPER :
if (inStaticMethod) if (inStaticMethod)
throw new CompileError("not-available: " throw new CompileError("not-available: "
+ (token == THIS ? "this" : "super"));
+ (token == THIS ? "this" : "super"), k.getLineNumber());


bytecode.addAload(0); bytecode.addAload(0);
exprType = CLASS; exprType = CLASS;
className = getSuperName(); className = getSuperName();
break; break;
default : default :
fatal();
fatal(k.getLineNumber());
} }
} }



+ 13
- 2
src/main/javassist/compiler/CompileError.java View File

private Lex lex; private Lex lex;
private String reason; private String reason;


private int lineNumber = -1;

public CompileError(String s, Lex l) { public CompileError(String s, Lex l) {
reason = s;
this(s, l.getLineNumber());
lex = l; lex = l;
} }


public CompileError(String s) {
public CompileError(String s, int lineNumber) {
this.lineNumber = lineNumber;
reason = String.format("line %d: %s", lineNumber, s);
}

private CompileError(String s) {
reason = s; reason = s;
lex = null; lex = null;
} }


public Lex getLex() { return lex; } public Lex getLex() { return lex; }


public int getLineNumber() {
return lineNumber;
}

@Override @Override
public String getMessage() { public String getMessage() {
return reason; return reason;

+ 34
- 33
src/main/javassist/compiler/Javac.java View File

import javassist.compiler.ast.Symbol; import javassist.compiler.ast.Symbol;


public class Javac { public class Javac {
JvstCodeGen gen;
JvstCodeGenWitlLineNumber gen;
SymbolTable stable; SymbolTable stable;
private Bytecode bytecode; private Bytecode bytecode;


* belongs to. * belongs to.
*/ */
public Javac(Bytecode b, CtClass thisClass) { public Javac(Bytecode b, CtClass thisClass) {
gen = new JvstCodeGen(b, thisClass, thisClass.getClassPool());
gen = new JvstCodeGenWitlLineNumber(b, thisClass, thisClass.getClassPool());
stable = new SymbolTable(); stable = new SymbolTable();
bytecode = b; bytecode = b;
} }
* @see #recordProceed(String,String) * @see #recordProceed(String,String)
*/ */
public CtMember compile(String src) throws CompileError { public CtMember compile(String src) throws CompileError {
Parser p = new Parser(new Lex(src));
int startLine = gen.thisClass.getLinesCount();
Lex lex = new Lex(src, startLine);
Parser p = new Parser(lex);
ASTList mem = p.parseMember1(stable); ASTList mem = p.parseMember1(stable);
try { try {
if (mem instanceof FieldDecl) if (mem instanceof FieldDecl)
decl.getClassFile2()); decl.getClassFile2());
return cb; return cb;
} }
catch (BadBytecode bb) {
throw new CompileError(bb.getMessage());
}
catch (CannotCompileException e) {
throw new CompileError(e.getMessage());
catch (BadBytecode | CannotCompileException bb) {
throw new CompileError(bb.getMessage(), lex.getLineNumber());
} }
} }


gen.getThisClass()); gen.getThisClass());
cons.setModifiers(mod); cons.setModifiers(mod);
md.accept(gen); md.accept(gen);
cons.getMethodInfo().setCodeAttribute(
bytecode.toCodeAttribute());
CodeAttribute cattr = bytecode.toCodeAttribute();
cattr.setAttribute(gen.toLineNumberAttribute());
cons.getMethodInfo().setCodeAttribute(cattr);
cons.setExceptionTypes(tlist); cons.setExceptionTypes(tlist);
return cons; return cons;
} }
method.setModifiers(mod); method.setModifiers(mod);
gen.setThisMethod(method); gen.setThisMethod(method);
md.accept(gen); md.accept(gen);
if (md.getBody() != null)
method.getMethodInfo().setCodeAttribute(
bytecode.toCodeAttribute());
else
if (md.getBody() != null) {
CodeAttribute cattr = bytecode.toCodeAttribute();
cattr.setAttribute(gen.toLineNumberAttribute());
method.getMethodInfo().setCodeAttribute(cattr);
} else
method.setModifiers(mod | Modifier.ABSTRACT); method.setModifiers(mod | Modifier.ABSTRACT);


method.setExceptionTypes(tlist); method.setExceptionTypes(tlist);
return method; return method;
} }
catch (NotFoundException e) { catch (NotFoundException e) {
throw new CompileError(e.toString());
throw new CompileError(e.toString(), md.getLineNumber());
} }
} }


Stmnt s = p.parseStatement(stb); Stmnt s = p.parseStatement(stb);
if (p.hasMore()) if (p.hasMore())
throw new CompileError( throw new CompileError(
"the method/constructor body must be surrounded by {}");
"the method/constructor body must be surrounded by {}", s.getLineNumber());


boolean callSuper = false; boolean callSuper = false;
if (method instanceof CtConstructor) if (method instanceof CtConstructor)
return bytecode; return bytecode;
} }
catch (NotFoundException e) { catch (NotFoundException e) {
throw new CompileError(e.toString());
throw new CompileError(e.toString(), -1);
} }
} }




ProceedHandler h = new ProceedHandler() { ProceedHandler h = new ProceedHandler() {
@Override @Override
public void doit(JvstCodeGen gen, Bytecode b, ASTList args)
public void doit(JvstCodeGen gen, Bytecode b, ASTList args, int lineNumber)
throws CompileError throws CompileError
{ {
ASTree expr = new Member(m);
ASTree expr = new Member(m, texpr.getLineNumber());
if (texpr != null) if (texpr != null)
expr = Expr.make('.', texpr, expr);
expr = Expr.make('.', texpr, expr, texpr.getLineNumber());


expr = CallExpr.makeCall(expr, args);
expr = CallExpr.makeCall(expr, args, texpr.getLineNumber());
gen.compileExpr(expr); gen.compileExpr(expr);
gen.addNullIfVoid(); gen.addNullIfVoid();
} }


@Override @Override
public void setReturnType(JvstTypeChecker check, ASTList args)
public void setReturnType(JvstTypeChecker check, ASTList args, int lineNumber)
throws CompileError throws CompileError
{ {
ASTree expr = new Member(m);
ASTree expr = new Member(m, texpr.getLineNumber());
if (texpr != null) if (texpr != null)
expr = Expr.make('.', texpr, expr);
expr = Expr.make('.', texpr, expr, texpr.getLineNumber());


expr = CallExpr.makeCall(expr, args);
expr = CallExpr.makeCall(expr, args, texpr.getLineNumber());
expr.accept(check); expr.accept(check);
check.addNullIfVoid(); check.addNullIfVoid();
} }


ProceedHandler h = new ProceedHandler() { ProceedHandler h = new ProceedHandler() {
@Override @Override
public void doit(JvstCodeGen gen, Bytecode b, ASTList args)
public void doit(JvstCodeGen gen, Bytecode b, ASTList args, int lineNumber)
throws CompileError throws CompileError
{ {
Expr expr = Expr.make(TokenId.MEMBER, Expr expr = Expr.make(TokenId.MEMBER,
new Symbol(c), new Member(m));
expr = CallExpr.makeCall(expr, args);
new Symbol(c, args.getLineNumber()), new Member(m, args.getLineNumber()), args.getLineNumber());
expr = CallExpr.makeCall(expr, args, args.getLineNumber());
gen.compileExpr(expr); gen.compileExpr(expr);
gen.addNullIfVoid(); gen.addNullIfVoid();
} }


@Override @Override
public void setReturnType(JvstTypeChecker check, ASTList args)
public void setReturnType(JvstTypeChecker check, ASTList args, int lineNumber)
throws CompileError throws CompileError
{ {
Expr expr = Expr.make(TokenId.MEMBER, Expr expr = Expr.make(TokenId.MEMBER,
new Symbol(c), new Member(m));
expr = CallExpr.makeCall(expr, args);
new Symbol(c, args.getLineNumber()), new Member(m, args.getLineNumber()), args.getLineNumber());
expr = CallExpr.makeCall(expr, args, args.getLineNumber());
expr.accept(check); expr.accept(check);
check.addNullIfVoid(); check.addNullIfVoid();
} }


ProceedHandler h = new ProceedHandler() { ProceedHandler h = new ProceedHandler() {
@Override @Override
public void doit(JvstCodeGen gen, Bytecode b, ASTList args)
public void doit(JvstCodeGen gen, Bytecode b, ASTList args, int lineNumber)
throws CompileError throws CompileError
{ {
gen.compileInvokeSpecial(texpr, methodIndex, descriptor, args); gen.compileInvokeSpecial(texpr, methodIndex, descriptor, args);
} }


@Override @Override
public void setReturnType(JvstTypeChecker c, ASTList args)
public void setReturnType(JvstTypeChecker c, ASTList args, int lineNumber)
throws CompileError throws CompileError
{ {
c.compileInvokeSpecial(texpr, classname, methodname, descriptor, args); c.compileInvokeSpecial(texpr, classname, methodname, descriptor, args);

+ 36
- 36
src/main/javassist/compiler/JvstCodeGen.java View File

} }
else if (name.equals(dollarTypeName)) { else if (name.equals(dollarTypeName)) {
if (dollarType == null) if (dollarType == null)
throw new CompileError(dollarTypeName + " is not available");
throw new CompileError(dollarTypeName + " is not available", mem.getLineNumber());


bytecode.addLdc(Descriptor.of(dollarType)); bytecode.addLdc(Descriptor.of(dollarType));
callGetType("getType"); callGetType("getType");
} }
else if (name.equals(clazzName)) { else if (name.equals(clazzName)) {
if (param0Type == null) if (param0Type == null)
throw new CompileError(clazzName + " is not available");
throw new CompileError(clazzName + " is not available", mem.getLineNumber());


bytecode.addLdc(param0Type); bytecode.addLdc(param0Type);
callGetType("getClazz"); callGetType("getClazz");
if (left instanceof Member if (left instanceof Member
&& ((Member)left).get().equals(paramArrayName)) { && ((Member)left).get().equals(paramArrayName)) {
if (op != '=') if (op != '=')
throw new CompileError("bad operator for " + paramArrayName);
throw new CompileError("bad operator for " + paramArrayName, expr.getLineNumber());


right.accept(this); right.accept(this);
if (arrayDim != 1 || exprType != CLASS) if (arrayDim != 1 || exprType != CLASS)
throw new CompileError("invalid type for " + paramArrayName);
throw new CompileError("invalid type for " + paramArrayName, expr.getLineNumber());


atAssignParamList(paramTypeList, bytecode);
atAssignParamList(paramTypeList, bytecode, expr.getLineNumber());
if (!doDup) if (!doDup)
bytecode.addOpcode(POP); bytecode.addOpcode(POP);
} }
super.atFieldAssign(expr, op, left, right, doDup); super.atFieldAssign(expr, op, left, right, doDup);
} }


protected void atAssignParamList(CtClass[] params, Bytecode code)
protected void atAssignParamList(CtClass[] params, Bytecode code, int lineNumber)
throws CompileError throws CompileError
{ {
if (params == null) if (params == null)
code.addOpcode(DUP); code.addOpcode(DUP);
code.addIconst(i); code.addIconst(i);
code.addOpcode(AALOAD); code.addOpcode(AALOAD);
compileUnwrapValue(params[i], code);
compileUnwrapValue(params[i], code, lineNumber);
code.addStore(varNo, params[i]); code.addStore(varNo, params[i]);
varNo += is2word(exprType, arrayDim) ? 2 : 1; varNo += is2word(exprType, arrayDim) ? 2 : 1;
} }
protected void atCastToRtype(CastExpr expr) throws CompileError { protected void atCastToRtype(CastExpr expr) throws CompileError {
expr.getOprand().accept(this); expr.getOprand().accept(this);
if (exprType == VOID || isRefType(exprType) || arrayDim > 0) if (exprType == VOID || isRefType(exprType) || arrayDim > 0)
compileUnwrapValue(returnType, bytecode);
compileUnwrapValue(returnType, bytecode, expr.getLineNumber());
else if (returnType instanceof CtPrimitiveType) { else if (returnType instanceof CtPrimitiveType) {
CtPrimitiveType pt = (CtPrimitiveType)returnType; CtPrimitiveType pt = (CtPrimitiveType)returnType;
int destType = MemberResolver.descToType(pt.getDescriptor());
int destType = MemberResolver.descToType(pt.getDescriptor(), expr.getLineNumber());
atNumCastExpr(exprType, destType); atNumCastExpr(exprType, destType);
exprType = destType; exprType = destType;
arrayDim = 0; arrayDim = 0;
className = null; className = null;
} }
else else
throw new CompileError("invalid cast");
throw new CompileError("invalid cast", expr.getLineNumber());
} }


protected void atCastToWrapper(CastExpr expr) throws CompileError { protected void atCastToWrapper(CastExpr expr) throws CompileError {
if (isRefType(exprType) || arrayDim > 0) if (isRefType(exprType) || arrayDim > 0)
return; // Object type. do nothing. return; // Object type. do nothing.


CtClass clazz = resolver.lookupClass(exprType, arrayDim, className);
CtClass clazz = resolver.lookupClass(exprType, arrayDim, className, expr.getLineNumber());
if (clazz instanceof CtPrimitiveType) { if (clazz instanceof CtPrimitiveType) {
CtPrimitiveType pt = (CtPrimitiveType)clazz; CtPrimitiveType pt = (CtPrimitiveType)clazz;
String wrapper = pt.getWrapperName(); String wrapper = pt.getWrapperName();
if (method instanceof Member) { if (method instanceof Member) {
String name = ((Member)method).get(); String name = ((Member)method).get();
if (procHandler != null && name.equals(proceedName)) { if (procHandler != null && name.equals(proceedName)) {
procHandler.doit(this, bytecode, (ASTList)expr.oprand2());
procHandler.doit(this, bytecode, (ASTList)expr.oprand2(), expr.getLineNumber());
return; return;
} }
else if (name.equals(cflowName)) { else if (name.equals(cflowName)) {
atCflow((ASTList)expr.oprand2());
atCflow((ASTList)expr.oprand2(), expr.getLineNumber());
return; return;
} }
} }


/* To support $cflow(). /* To support $cflow().
*/ */
protected void atCflow(ASTList cname) throws CompileError {
protected void atCflow(ASTList cname, int lineNumber) throws CompileError {
StringBuilder sbuf = new StringBuilder(); StringBuilder sbuf = new StringBuilder();
if (cname == null || cname.tail() != null) if (cname == null || cname.tail() != null)
throw new CompileError("bad " + cflowName);
throw new CompileError("bad " + cflowName, lineNumber);


makeCflowName(sbuf, cname.head()); makeCflowName(sbuf, cname.head());
String name = sbuf.toString(); String name = sbuf.toString();
Object[] names = resolver.getClassPool().lookupCflow(name); Object[] names = resolver.getClassPool().lookupCflow(name);
if (names == null) if (names == null)
throw new CompileError("no such " + cflowName + ": " + name);
throw new CompileError("no such " + cflowName + ": " + name, lineNumber);


bytecode.addGetstatic((String)names[0], (String)names[1], bytecode.addGetstatic((String)names[0], (String)names[1],
"Ljavassist/runtime/Cflow;"); "Ljavassist/runtime/Cflow;");
} }
} }


throw new CompileError("bad " + cflowName);
throw new CompileError("bad " + cflowName, name.getLineNumber());
} }


/* To support $$. ($$) is equivalent to ($1, ..., $n). /* To support $$. ($$) is equivalent to ($1, ..., $n).
for (int k = 0; k < n; ++k) { for (int k = 0; k < n; ++k) {
CtClass p = params[k]; CtClass p = params[k];
regno += bytecode.addLoad(regno, p); regno += bytecode.addLoad(regno, p);
setType(p);
setType(p, a.getLineNumber());
types[i] = exprType; types[i] = exprType;
dims[i] = arrayDim; dims[i] = arrayDim;
cnames[i] = className; cnames[i] = className;
atMethodArgs(args, new int[nargs], new int[nargs], atMethodArgs(args, new int[nargs], new int[nargs],
new String[nargs]); new String[nargs]);
bytecode.addInvokespecial(methodIndex, descriptor); bytecode.addInvokespecial(methodIndex, descriptor);
setReturnType(descriptor, false, false);
setReturnType(descriptor, false, false, target.getLineNumber());
addNullIfVoid(); addNullIfVoid();
} }


String varName = prefix + "0"; String varName = prefix + "0";
Declarator decl Declarator decl
= new Declarator(CLASS, MemberResolver.javaToJvmName(target), = new Declarator(CLASS, MemberResolver.javaToJvmName(target),
0, varNo++, new Symbol(varName));
0, varNo++, new Symbol(varName, 0), 0);
tbl.append(varName, decl); tbl.append(varName, decl);
} }


className = jvmJavaLangObject; className = jvmJavaLangObject;
} }
else else
setType(cc);
setType(cc, cc.getLinesCount());


Declarator decl Declarator decl
= new Declarator(exprType, className, arrayDim, = new Declarator(exprType, className, arrayDim,
varNo, new Symbol(varName));
varNo, new Symbol(varName, 0), 0);
tbl.append(varName, decl); tbl.append(varName, decl);
return is2word(exprType, arrayDim) ? 2 : 1; return is2word(exprType, arrayDim) ? 2 : 1;
} }
while ((c = typeDesc.charAt(dim)) == '[') while ((c = typeDesc.charAt(dim)) == '[')
++dim; ++dim;


int type = MemberResolver.descToType(c);
int type = MemberResolver.descToType(c, -1);
String cname = null; String cname = null;
if (type == CLASS) { if (type == CLASS) {
if (dim == 0) if (dim == 0)
} }


Declarator decl Declarator decl
= new Declarator(type, cname, dim, varNo, new Symbol(varName));
= new Declarator(type, cname, dim, varNo, new Symbol(varName, 0), 0);
tbl.append(varName, decl); tbl.append(varName, decl);
} }


return 8; return 8;
} }


protected void compileUnwrapValue(CtClass type, Bytecode code)
protected void compileUnwrapValue(CtClass type, Bytecode code, int lineNumber)
throws CompileError throws CompileError
{ {
if (type == CtClass.voidType) { if (type == CtClass.voidType) {
} }


if (exprType == VOID) if (exprType == VOID)
throw new CompileError("invalid type for " + returnCastName);
throw new CompileError("invalid type for " + returnCastName, lineNumber);


if (type instanceof CtPrimitiveType) { if (type instanceof CtPrimitiveType) {
CtPrimitiveType pt = (CtPrimitiveType)type; CtPrimitiveType pt = (CtPrimitiveType)type;
code.addCheckcast(wrapper); code.addCheckcast(wrapper);
code.addInvokevirtual(wrapper, pt.getGetMethodName(), code.addInvokevirtual(wrapper, pt.getGetMethodName(),
pt.getGetMethodDescriptor()); pt.getGetMethodDescriptor());
setType(type);
setType(type, lineNumber);
} }
else { else {
code.addCheckcast(type); code.addCheckcast(type);
setType(type);
setType(type, lineNumber);
} }
} }


/* Sets exprType, arrayDim, and className; /* Sets exprType, arrayDim, and className;
* If type is void, then this method does nothing. * If type is void, then this method does nothing.
*/ */
public void setType(CtClass type) throws CompileError {
setType(type, 0);
public void setType(CtClass type, int lineNumber) throws CompileError {
setType(type, 0, lineNumber);
} }


private void setType(CtClass type, int dim) throws CompileError {
private void setType(CtClass type, int dim, int lineNumber) throws CompileError {
if (type.isPrimitive()) { if (type.isPrimitive()) {
CtPrimitiveType pt = (CtPrimitiveType)type; CtPrimitiveType pt = (CtPrimitiveType)type;
exprType = MemberResolver.descToType(pt.getDescriptor());
exprType = MemberResolver.descToType(pt.getDescriptor(), lineNumber);
arrayDim = dim; arrayDim = dim;
className = null; className = null;
} }
else if (type.isArray()) else if (type.isArray())
try { try {
setType(type.getComponentType(), dim + 1);
setType(type.getComponentType(), dim + 1, lineNumber);
} }
catch (NotFoundException e) { catch (NotFoundException e) {
throw new CompileError("undefined type: " + type.getName());
throw new CompileError("undefined type: " + type.getName(), lineNumber);
} }
else { else {
exprType = CLASS; exprType = CLASS;
if (type instanceof CtPrimitiveType) { if (type instanceof CtPrimitiveType) {
CtPrimitiveType pt = (CtPrimitiveType)type; CtPrimitiveType pt = (CtPrimitiveType)type;
atNumCastExpr(exprType, atNumCastExpr(exprType,
MemberResolver.descToType(pt.getDescriptor()));
MemberResolver.descToType(pt.getDescriptor(), type.getLinesCount() - 1));
} }
else else
throw new CompileError("type mismatch");
throw new CompileError("type mismatch", type.getLinesCount() - 1);
} }
} }

+ 265
- 0
src/main/javassist/compiler/JvstCodeGenWitlLineNumber.java View File

package javassist.compiler;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.bytecode.Bytecode;
import javassist.bytecode.LineNumberAttribute;
import javassist.bytecode.LineNumberAttributeBuilder;
import javassist.compiler.ast.*;

public class JvstCodeGenWitlLineNumber extends JvstCodeGen {
private final LineNumberAttributeBuilder lineNumberAttributeBuilder = new LineNumberAttributeBuilder();
public JvstCodeGenWitlLineNumber(Bytecode b, CtClass cc, ClassPool cp) {
super(b, cc, cp);
}

public LineNumberAttribute toLineNumberAttribute() {
return lineNumberAttributeBuilder.build(bytecode.getConstPool());
}

@Override
public void atASTList(ASTList n) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), n);
super.atASTList(n);
}

@Override
public void atPair(Pair n) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), n);
super.atPair(n);
}

@Override
public void atSymbol(Symbol n) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), n);
super.atSymbol(n);
}

@Override
public void atFieldDecl(FieldDecl field) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), field);
super.atFieldDecl(field);
}

@Override
public void atMethodDecl(MethodDecl method) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), method);
super.atMethodDecl(method);
}

@Override
public void atMethodBody(Stmnt s, boolean isCons, boolean isVoid) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), s);
super.atMethodBody(s, isCons, isVoid);
}

@Override
public void atStmnt(Stmnt st) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), st);
super.atStmnt(st);
}

@Override
public void atDeclarator(Declarator d) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), d);
super.atDeclarator(d);
}

@Override
public void atAssignExpr(AssignExpr expr) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), expr);
super.atAssignExpr(expr);
}

@Override
protected void atAssignExpr(AssignExpr expr, boolean doDup) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), expr);
super.atAssignExpr(expr, doDup);
}

@Override
protected void atAssignCore(Expr expr, int op, ASTree right, int type, int dim, String cname) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), expr);
super.atAssignCore(expr, op, right, type, dim, cname);
}

@Override
public void atCondExpr(CondExpr expr) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), expr);
super.atCondExpr(expr);
}

@Override
public void atBinExpr(BinExpr expr) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), expr);
super.atBinExpr(expr);
}

@Override
public void atInstanceOfExpr(InstanceOfExpr expr) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), expr);
super.atInstanceOfExpr(expr);
}

@Override
public void atExpr(Expr expr) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), expr);
super.atExpr(expr);
}

@Override
public void atClassObject(Expr expr) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), expr);
super.atClassObject(expr);
}

@Override
public void atArrayRead(ASTree array, ASTree index) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), array);
super.atArrayRead(array, index);
}

@Override
protected void arrayAccess(ASTree array, ASTree index) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), array);
super.arrayAccess(array, index);
}

@Override
public void atArrayPlusPlus(int token, boolean isPost, Expr expr, boolean doDup) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), expr);
super.atArrayPlusPlus(token, isPost, expr, doDup);
}

@Override
protected void atPlusPlusCore(int dup_code, boolean doDup, int token, boolean isPost, Expr expr) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), expr);
super.atPlusPlusCore(dup_code, doDup, token, isPost, expr);
}

@Override
public void atVariable(Variable v) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), v);
super.atVariable(v);
}

@Override
public void atKeyword(Keyword k) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), k);
super.atKeyword(k);
}

@Override
public void atStringL(javassist.compiler.ast.StringL s) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), s);
super.atStringL(s);
}

@Override
public void atIntConst(IntConst i) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), i);
super.atIntConst(i);
}

@Override
public void atDoubleConst(DoubleConst d) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), d);
super.atDoubleConst(d);
}

@Override
public void atMember(Member mem) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), mem);
super.atMember(mem);
}

@Override
protected void atFieldAssign(Expr expr, int op, ASTree left, ASTree right, boolean doDup) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), expr);
super.atFieldAssign(expr, op, left, right, doDup);
}

@Override
public void atCastExpr(CastExpr expr) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), expr);
super.atCastExpr(expr);
}

@Override
protected void atCastToRtype(CastExpr expr) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), expr);
super.atCastToRtype(expr);
}

@Override
protected void atCastToWrapper(CastExpr expr) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), expr);
super.atCastToWrapper(expr);
}

@Override
public void atCallExpr(CallExpr expr) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), expr);
super.atCallExpr(expr);
}

@Override
protected void atCflow(ASTList cname, int lineNumber) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), cname);
super.atCflow(cname, lineNumber);
}

@Override
protected void atTryStmnt(Stmnt st) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), st);
super.atTryStmnt(st);
}

@Override
public void atNewExpr(NewExpr expr) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), expr);
super.atNewExpr(expr);
}

@Override
public void atNewArrayExpr(NewExpr expr) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), expr);
super.atNewArrayExpr(expr);
}

@Override
protected void atArrayVariableAssign(ArrayInit init, int varType, int varArray, String varClass) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), init);
super.atArrayVariableAssign(init, varType, varArray, varClass);
}

@Override
public void atArrayInit(ArrayInit init) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), init);
super.atArrayInit(init);
}

@Override
protected void atMultiNewArray(int type, ASTList classname, ASTList size) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), classname);
super.atMultiNewArray(type, classname, size);
}

@Override
public void atMethodCallCore(CtClass targetClass, String mname, ASTList args, boolean isStatic, boolean isSpecial, int aload0pos, MemberResolver.Method found) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), args);
super.atMethodCallCore(targetClass, mname, args, isStatic, isSpecial, aload0pos, found);
}

@Override
protected void atFieldRead(ASTree expr) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), expr);
super.atFieldRead(expr);
}

@Override
protected void atFieldPlusPlus(int token, boolean isPost, ASTree oprand, Expr expr, boolean doDup) throws CompileError {
lineNumberAttributeBuilder.put(bytecode.currentPc(), expr);
super.atFieldPlusPlus(token, isPost, oprand, expr, doDup);
}
}

+ 15
- 15
src/main/javassist/compiler/JvstTypeChecker.java View File



int n = params.length; int n = params.length;
for (int i = 0; i < n; ++i) for (int i = 0; i < n; ++i)
compileUnwrapValue(params[i]);
compileUnwrapValue(params[i], expr.getLineNumber());
} }
else else
super.atFieldAssign(expr, op, left, right); super.atFieldAssign(expr, op, left, right);
CtClass returnType = codeGen.returnType; CtClass returnType = codeGen.returnType;
expr.getOprand().accept(this); expr.getOprand().accept(this);
if (exprType == VOID || CodeGen.isRefType(exprType) || arrayDim > 0) if (exprType == VOID || CodeGen.isRefType(exprType) || arrayDim > 0)
compileUnwrapValue(returnType);
compileUnwrapValue(returnType, expr.getLineNumber());
else if (returnType instanceof CtPrimitiveType) { else if (returnType instanceof CtPrimitiveType) {
CtPrimitiveType pt = (CtPrimitiveType)returnType; CtPrimitiveType pt = (CtPrimitiveType)returnType;
int destType = MemberResolver.descToType(pt.getDescriptor());
int destType = MemberResolver.descToType(pt.getDescriptor(), expr.getLineNumber());
exprType = destType; exprType = destType;
arrayDim = 0; arrayDim = 0;
className = null; className = null;
if (CodeGen.isRefType(exprType) || arrayDim > 0) if (CodeGen.isRefType(exprType) || arrayDim > 0)
return; // Object type. do nothing. return; // Object type. do nothing.


CtClass clazz = resolver.lookupClass(exprType, arrayDim, className);
CtClass clazz = resolver.lookupClass(exprType, arrayDim, className, expr.getLineNumber());
if (clazz instanceof CtPrimitiveType) { if (clazz instanceof CtPrimitiveType) {
exprType = CLASS; exprType = CLASS;
arrayDim = 0; arrayDim = 0;
if (codeGen.procHandler != null if (codeGen.procHandler != null
&& name.equals(codeGen.proceedName)) { && name.equals(codeGen.proceedName)) {
codeGen.procHandler.setReturnType(this, codeGen.procHandler.setReturnType(this,
(ASTList)expr.oprand2());
(ASTList)expr.oprand2(), expr.getLineNumber());
return; return;
} }
else if (name.equals(JvstCodeGen.cflowName)) { else if (name.equals(JvstCodeGen.cflowName)) {
int n = params.length; int n = params.length;
for (int k = 0; k < n; ++k) { for (int k = 0; k < n; ++k) {
CtClass p = params[k]; CtClass p = params[k];
setType(p);
setType(p, a.getLineNumber());
types[i] = exprType; types[i] = exprType;
dims[i] = arrayDim; dims[i] = arrayDim;
cnames[i] = className; cnames[i] = className;
int nargs = getMethodArgsLength(args); int nargs = getMethodArgsLength(args);
atMethodArgs(args, new int[nargs], new int[nargs], atMethodArgs(args, new int[nargs], new int[nargs],
new String[nargs]); new String[nargs]);
setReturnType(descriptor);
setReturnType(descriptor, target.getLineNumber());
addNullIfVoid(); addNullIfVoid();
} }


protected void compileUnwrapValue(CtClass type) throws CompileError
protected void compileUnwrapValue(CtClass type, int lineNumber) throws CompileError
{ {
if (type == CtClass.voidType) if (type == CtClass.voidType)
addNullIfVoid(); addNullIfVoid();
else else
setType(type);
setType(type, lineNumber);
} }


/* Sets exprType, arrayDim, and className; /* Sets exprType, arrayDim, and className;
* If type is void, then this method does nothing. * If type is void, then this method does nothing.
*/ */
public void setType(CtClass type) throws CompileError {
setType(type, 0);
public void setType(CtClass type, int lineNumber) throws CompileError {
setType(type, 0, lineNumber);
} }


private void setType(CtClass type, int dim) throws CompileError {
private void setType(CtClass type, int dim, int lineNumber) throws CompileError {
if (type.isPrimitive()) { if (type.isPrimitive()) {
CtPrimitiveType pt = (CtPrimitiveType)type; CtPrimitiveType pt = (CtPrimitiveType)type;
exprType = MemberResolver.descToType(pt.getDescriptor());
exprType = MemberResolver.descToType(pt.getDescriptor(), lineNumber);
arrayDim = dim; arrayDim = dim;
className = null; className = null;
} }
else if (type.isArray()) else if (type.isArray())
try { try {
setType(type.getComponentType(), dim + 1);
setType(type.getComponentType(), dim + 1, lineNumber);
} }
catch (NotFoundException e) { catch (NotFoundException e) {
throw new CompileError("undefined type: " + type.getName());
throw new CompileError("undefined type: " + type.getName(), lineNumber);
} }
else { else {
exprType = CLASS; exprType = CLASS;

+ 11
- 2
src/main/javassist/compiler/Lex.java View File

* Constructs a lexical analyzer. * Constructs a lexical analyzer.
*/ */
public Lex(String s) { public Lex(String s) {
this(s, 0);
}

Lex(String s, int startLineNumber) {
lastChar = -1; lastChar = -1;
textBuffer = new StringBuilder(); textBuffer = new StringBuilder();
currentToken = new Token(); currentToken = new Token();
input = s; input = s;
position = 0; position = 0;
maxlen = s.length(); maxlen = s.length();
lineNumber = 0;
lineNumber = startLineNumber;
} }


public int get() { public int get() {
ungetc(c); ungetc(c);
c = '/'; c = '/';
} }
}
} else if (c == '\n')
++lineNumber;
} while(isBlank(c)); } while(isBlank(c));
return c; return c;
} }
lastChar = -1; lastChar = -1;
return c; return c;
} }

public int getLineNumber() {
return lineNumber + 1;
}
} }

+ 56
- 56
src/main/javassist/compiler/MemberCodeGen.java View File

body.accept(this); body.accept(this);
int end = bc.currentPc(); int end = bc.currentPc();
if (start == end) if (start == end)
throw new CompileError("empty try block");
throw new CompileError("empty try block", st.getLineNumber());


boolean tryNotReturn = !hasReturned; boolean tryNotReturn = !hasReturned;
if (tryNotReturn) { if (tryNotReturn) {


decl.setLocalVar(var); decl.setLocalVar(var);


CtClass type = resolver.lookupClassByJvmName(decl.getClassName());
CtClass type = resolver.lookupClassByJvmName(decl.getClassName(), st.getLineNumber());
decl.setClassName(MemberResolver.javaToJvmName(type.getName())); decl.setClassName(MemberResolver.javaToJvmName(type.getName()));
bc.addExceptionHandler(start, end, bc.currentPc(), type); bc.addExceptionHandler(start, end, bc.currentPc(), type);
bc.growStack(1); bc.growStack(1);
if (init != null) if (init != null)
throw new CompileError( throw new CompileError(
"sorry, multi-dimensional array initializer " + "sorry, multi-dimensional array initializer " +
"for new is not supported");
"for new is not supported", expr.getLineNumber());


atMultiNewArray(type, classname, size); atMultiNewArray(type, classname, size);
return; return;
} }


ASTree sizeExpr = size.head(); ASTree sizeExpr = size.head();
atNewArrayExpr2(type, sizeExpr, Declarator.astToClassName(classname, '/'), init);
atNewArrayExpr2(type, sizeExpr, Declarator.astToClassName(classname, '/'), init, expr.getLineNumber());
} }


private void atNewArrayExpr2(int type, ASTree sizeExpr, private void atNewArrayExpr2(int type, ASTree sizeExpr,
String jvmClassname, ArrayInit init) throws CompileError {
String jvmClassname, ArrayInit init, int lineNumber) throws CompileError {
if (init == null) if (init == null)
if (sizeExpr == null) if (sizeExpr == null)
throw new CompileError("no array size");
throw new CompileError("no array size", lineNumber);
else else
sizeExpr.accept(this); sizeExpr.accept(this);
else else
bytecode.addIconst(s); bytecode.addIconst(s);
} }
else else
throw new CompileError("unnecessary array size specified for new");
throw new CompileError("unnecessary array size specified for new", lineNumber);


String elementClass; String elementClass;
if (type == CLASS) { if (type == CLASS) {
elementClass = resolveClassName(jvmClassname);
elementClass = resolveClassName(jvmClassname, lineNumber);
bytecode.addAnewarray(MemberResolver.jvmToJavaName(elementClass)); bytecode.addAnewarray(MemberResolver.jvmToJavaName(elementClass));
} }
else { else {
atype = T_LONG; atype = T_LONG;
break; break;
default : default :
badNewExpr();
badNewExpr(lineNumber);
break; break;
} }


className = elementClass; className = elementClass;
} }


private static void badNewExpr() throws CompileError {
throw new CompileError("bad new expression");
private static void badNewExpr(int lineNumber) throws CompileError {
throw new CompileError("bad new expression", lineNumber);
} }


@Override @Override
protected void atArrayVariableAssign(ArrayInit init, int varType, protected void atArrayVariableAssign(ArrayInit init, int varType,
int varArray, String varClass) throws CompileError { int varArray, String varClass) throws CompileError {
atNewArrayExpr2(varType, null, varClass, init);
atNewArrayExpr2(varType, null, varClass, init, init.getLineNumber());
} }


@Override @Override
public void atArrayInit(ArrayInit init) throws CompileError { public void atArrayInit(ArrayInit init) throws CompileError {
throw new CompileError("array initializer is not supported");
throw new CompileError("array initializer is not supported", init.getLineNumber());
} }


protected void atMultiNewArray(int type, ASTList classname, ASTList size) protected void atMultiNewArray(int type, ASTList classname, ASTList size)
++count; ++count;
s.accept(this); s.accept(this);
if (exprType != INT) if (exprType != INT)
throw new CompileError("bad type for array size");
throw new CompileError("bad type for array size", classname.getLineNumber());
} }


String desc; String desc;
mname = MethodInfo.nameInit; // <init> mname = MethodInfo.nameInit; // <init>
targetClass = thisClass; targetClass = thisClass;
if (inStaticMethod) if (inStaticMethod)
throw new CompileError("a constructor cannot be static");
throw new CompileError("a constructor cannot be static", expr.getLineNumber());
bytecode.addAload(0); // this bytecode.addAload(0); // this


if (((Keyword)method).get() == SUPER) if (((Keyword)method).get() == SUPER)
int op = e.getOperator(); int op = e.getOperator();
if (op == MEMBER) { // static method if (op == MEMBER) { // static method
targetClass targetClass
= resolver.lookupClass(((Symbol)e.oprand1()).get(), false);
= resolver.lookupClass(((Symbol)e.oprand1()).get(), false, expr.getLineNumber());
isStatic = true; isStatic = true;
} }
else if (op == '.') { else if (op == '.') {
} }


if (arrayDim > 0) if (arrayDim > 0)
targetClass = resolver.lookupClass(javaLangObject, true);
targetClass = resolver.lookupClass(javaLangObject, true, expr.getLineNumber());
else if (exprType == CLASS /* && arrayDim == 0 */) else if (exprType == CLASS /* && arrayDim == 0 */)
targetClass = resolver.lookupClassByJvmName(className);
targetClass = resolver.lookupClassByJvmName(className, expr.getLineNumber());
else else
badMethod();
badMethod(e.getLineNumber());
} }
} }
else else
badMethod();
badMethod(expr.getLineNumber());
} }
else else
fatal();
fatal(expr.getLineNumber());


atMethodCallCore(targetClass, mname, args, isStatic, isSpecial, atMethodCallCore(targetClass, mname, args, isStatic, isSpecial,
aload0pos, cached); aload0pos, cached);
} }


private static void badMethod() throws CompileError {
throw new CompileError("bad method");
private static void badMethod(int lineNumber) throws CompileError {
throw new CompileError("bad method", lineNumber);
} }


/* /*
msg = "Method " + mname + " not found in " msg = "Method " + mname + " not found in "
+ targetClass.getName(); + targetClass.getName();


throw new CompileError(msg);
throw new CompileError(msg, args.getLineNumber());
} }


atMethodCallCore2(targetClass, mname, isStatic, isSpecial, atMethodCallCore2(targetClass, mname, isStatic, isSpecial,
if (mname.equals(MethodInfo.nameInit)) { if (mname.equals(MethodInfo.nameInit)) {
isSpecial = true; isSpecial = true;
if (declClass != targetClass) if (declClass != targetClass)
throw new CompileError("no such constructor: " + targetClass.getName());
throw new CompileError("no such constructor: " + targetClass.getName(), targetClass.getLinesCount() - 1);


if (declClass != thisClass && AccessFlag.isPrivate(acc)) { if (declClass != thisClass && AccessFlag.isPrivate(acc)) {
if (declClass.getClassFile().getMajorVersion() < ClassFile.JAVA_8 if (declClass.getClassFile().getMajorVersion() < ClassFile.JAVA_8
} }
else else
if (isStatic) if (isStatic)
throw new CompileError(mname + " is not static");
throw new CompileError(mname + " is not static", targetClass.getLinesCount() - 1);
else else
bytecode.addInvokevirtual(declClass, mname, desc); bytecode.addInvokevirtual(declClass, mname, desc);
} }


setReturnType(desc, isStatic, popTarget);
setReturnType(desc, isStatic, popTarget, targetClass.getLinesCount() - 1);
} }


/* /*
} }


throw new CompileError("Method " + methodName throw new CompileError("Method " + methodName
+ " is private");
+ " is private", declClass.getLinesCount() - 1);
} }


/* /*
} }


throw new CompileError("the called constructor is private in " throw new CompileError("the called constructor is private in "
+ declClass.getName());
+ declClass.getName(), declClass.getLinesCount() - 1);
} }


private boolean isEnclosing(CtClass outer, CtClass inner) { private boolean isEnclosing(CtClass outer, CtClass inner) {
} }
} }


void setReturnType(String desc, boolean isStatic, boolean popTarget)
void setReturnType(String desc, boolean isStatic, boolean popTarget, int lineNumber)
throws CompileError throws CompileError
{ {
int i = desc.indexOf(')'); int i = desc.indexOf(')');
if (i < 0) if (i < 0)
badMethod();
badMethod(lineNumber);


char c = desc.charAt(++i); char c = desc.charAt(++i);
int dim = 0; int dim = 0;
if (c == 'L') { if (c == 'L') {
int j = desc.indexOf(';', i + 1); int j = desc.indexOf(';', i + 1);
if (j < 0) if (j < 0)
badMethod();
badMethod(lineNumber);


exprType = CLASS; exprType = CLASS;
className = desc.substring(i + 1, j); className = desc.substring(i + 1, j);
} }
else { else {
exprType = MemberResolver.descToType(c);
exprType = MemberResolver.descToType(c, lineNumber);
className = null; className = null;
} }


int fi; int fi;
if (op == '=') { if (op == '=') {
FieldInfo finfo = f.getFieldInfo2(); FieldInfo finfo = f.getFieldInfo2();
setFieldType(finfo);
AccessorMaker maker = isAccessibleField(f, finfo);
setFieldType(finfo, expr.getLineNumber());
AccessorMaker maker = isAccessibleField(f, finfo, expr.getLineNumber());
if (maker == null) if (maker == null)
fi = addFieldrefInfo(f, finfo); fi = addFieldrefInfo(f, finfo);
else else
fi = 0; fi = 0;
} }
else else
fi = atFieldRead(f, is_static);
fi = atFieldRead(f, is_static, expr.getLineNumber());


int fType = exprType; int fType = exprType;
int fDim = arrayDim; int fDim = arrayDim;
} }


boolean is_static = resultStatic; boolean is_static = resultStatic;
ASTree cexpr = TypeChecker.getConstantFieldValue(f);
ASTree cexpr = TypeChecker.getConstantFieldValue(f, expr.getLineNumber());
if (cexpr == null) if (cexpr == null)
atFieldRead(f, is_static);
atFieldRead(f, is_static,expr.getLineNumber() );
else { else {
cexpr.accept(this); cexpr.accept(this);
setFieldType(f.getFieldInfo2());
setFieldType(f.getFieldInfo2(), expr.getLineNumber());
} }
} }


private void atArrayLength(ASTree expr) throws CompileError { private void atArrayLength(ASTree expr) throws CompileError {
if (arrayDim == 0) if (arrayDim == 0)
throw new CompileError(".length applied to a non array");
throw new CompileError(".length applied to a non array", expr.getLineNumber());


bytecode.addOpcode(ARRAYLENGTH); bytecode.addOpcode(ARRAYLENGTH);
exprType = INT; exprType = INT;
* It returns a fieldref_info index or zero if the field is a private * It returns a fieldref_info index or zero if the field is a private
* one declared in an enclosing class. * one declared in an enclosing class.
*/ */
private int atFieldRead(CtField f, boolean isStatic) throws CompileError {
private int atFieldRead(CtField f, boolean isStatic, int lineNumber) throws CompileError {
FieldInfo finfo = f.getFieldInfo2(); FieldInfo finfo = f.getFieldInfo2();
boolean is2byte = setFieldType(finfo);
AccessorMaker maker = isAccessibleField(f, finfo);
boolean is2byte = setFieldType(finfo, lineNumber);
AccessorMaker maker = isAccessibleField(f, finfo, lineNumber);
if (maker != null) { if (maker != null) {
MethodInfo minfo = maker.getFieldGetter(finfo, isStatic); MethodInfo minfo = maker.getFieldGetter(finfo, isStatic);
bytecode.addInvokestatic(f.getDeclaringClass(), minfo.getName(), bytecode.addInvokestatic(f.getDeclaringClass(), minfo.getName(),
* an exception or it returns AccessorMaker if the field is a private * an exception or it returns AccessorMaker if the field is a private
* one declared in an enclosing class. * one declared in an enclosing class.
*/ */
private AccessorMaker isAccessibleField(CtField f, FieldInfo finfo)
private AccessorMaker isAccessibleField(CtField f, FieldInfo finfo, int lineNumber)
throws CompileError throws CompileError
{ {
if (AccessFlag.isPrivate(finfo.getAccessFlags()) if (AccessFlag.isPrivate(finfo.getAccessFlags())
return maker; return maker;
} }
throw new CompileError("Field " + f.getName() + " in " throw new CompileError("Field " + f.getName() + " in "
+ declClass.getName() + " is private.");
+ declClass.getName() + " is private.", lineNumber);
} }


return null; // accessible field return null; // accessible field
* *
* @return true if the field type is long or double. * @return true if the field type is long or double.
*/ */
private boolean setFieldType(FieldInfo finfo) throws CompileError {
private boolean setFieldType(FieldInfo finfo, int lineNumber) throws CompileError {
String type = finfo.getDescriptor(); String type = finfo.getDescriptor();


int i = 0; int i = 0;
} }


arrayDim = dim; arrayDim = dim;
exprType = MemberResolver.descToType(c);
exprType = MemberResolver.descToType(c, lineNumber);


if (c == 'L') if (c == 'L')
className = type.substring(i + 1, type.indexOf(';', i + 1)); className = type.substring(i + 1, type.indexOf(';', i + 1));
if (!is_static) if (!is_static)
bytecode.addOpcode(DUP); bytecode.addOpcode(DUP);


int fi = atFieldRead(f, is_static);
int fi = atFieldRead(f, is_static, oprand.getLineNumber());
int t = exprType; int t = exprType;
boolean is2w = is2word(t, arrayDim); boolean is2w = is2word(t, arrayDim);


if (!is_static) if (!is_static)
if (inStaticMethod) if (inStaticMethod)
throw new CompileError( throw new CompileError(
"not available in a static method: " + name);
"not available in a static method: " + name, expr.getLineNumber());
else else
bytecode.addAload(0); // this bytecode.addAload(0); // this


&& ((Symbol)e.oprand2()).get().equals("length")) && ((Symbol)e.oprand2()).get().equals("length"))
return null; // expr is an array length. return null; // expr is an array length.
else else
badLvalue();
badLvalue(expr.getLineNumber());


boolean is_static = Modifier.isStatic(f.getModifiers()); boolean is_static = Modifier.isStatic(f.getModifiers());
if (is_static) if (is_static)
} }
} }
else else
badLvalue();
badLvalue(expr.getLineNumber());
} }
else else
badLvalue();
badLvalue(expr.getLineNumber());


resultStatic = false; resultStatic = false;
return null; // never reach return null; // never reach
} }


private static void badLvalue() throws CompileError {
throw new CompileError("bad l-value");
private static void badLvalue(int lineNumber) throws CompileError {
throw new CompileError("bad l-value", lineNumber);
} }


public CtClass[] makeParamList(MethodDecl md) throws CompileError { public CtClass[] makeParamList(MethodDecl md) throws CompileError {
* For example, this converts Object into java/lang/Object. * For example, this converts Object into java/lang/Object.
*/ */
@Override @Override
protected String resolveClassName(String jvmName) throws CompileError {
return resolver.resolveJvmClassName(jvmName);
protected String resolveClassName(String jvmName, int lineNumber) throws CompileError {
return resolver.resolveJvmClassName(jvmName, lineNumber);
} }
} }

+ 37
- 35
src/main/javassist/compiler/MemberResolver.java View File



public ClassPool getClassPool() { return classPool; } public ClassPool getClassPool() { return classPool; }


private static void fatal() throws CompileError {
throw new CompileError("fatal");
private static void fatal(int lineNumber) throws CompileError {
throw new CompileError("fatal", lineNumber);
} }


public static class Method { public static class Method {
if (current != null && clazz == currentClass) if (current != null && clazz == currentClass)
if (current.getName().equals(methodName)) { if (current.getName().equals(methodName)) {
int res = compareSignature(current.getDescriptor(), int res = compareSignature(current.getDescriptor(),
argTypes, argDims, argClassNames);
argTypes, argDims, argClassNames, currentClass.getLinesCount() - 1);
if (res != NO) { if (res != NO) {
Method r = new Method(clazz, current, res); Method r = new Method(clazz, current, res);
if (res == YES) if (res == YES)
if (minfo.getName().equals(methodName) if (minfo.getName().equals(methodName)
&& (minfo.getAccessFlags() & AccessFlag.BRIDGE) == 0) { && (minfo.getAccessFlags() & AccessFlag.BRIDGE) == 0) {
int res = compareSignature(minfo.getDescriptor(), int res = compareSignature(minfo.getDescriptor(),
argTypes, argDims, argClassNames);
argTypes, argDims, argClassNames, clazz.getLinesCount() - 1);
if (res != NO) { if (res != NO) {
Method r = new Method(clazz, minfo, res); Method r = new Method(clazz, minfo, res);
if (res == YES) if (res == YES)
* of parameter types that do not exactly match. * of parameter types that do not exactly match.
*/ */
private int compareSignature(String desc, int[] argTypes, private int compareSignature(String desc, int[] argTypes,
int[] argDims, String[] argClassNames)
int[] argDims, String[] argClassNames, int lineNumber)
throws CompileError throws CompileError
{ {
int result = YES; int result = YES;


String cname = desc.substring(i, j); String cname = desc.substring(i, j);
if (!cname.equals(argClassNames[n])) { if (!cname.equals(argClassNames[n])) {
CtClass clazz = lookupClassByJvmName(argClassNames[n]);
CtClass clazz = lookupClassByJvmName(argClassNames[n], lineNumber);
try { try {
if (clazz.subtypeOf(lookupClassByJvmName(cname)))
if (clazz.subtypeOf(lookupClassByJvmName(cname, lineNumber)))
result++; result++;
else else
return NO; return NO;
i = j + 1; i = j + 1;
} }
else { else {
int t = descToType(c);
int t = descToType(c, lineNumber);
int at = argTypes[n]; int at = argTypes[n];
if (t != at) if (t != at)
if (t == INT if (t == INT
* Only used by fieldAccess() in MemberCodeGen and TypeChecker. * Only used by fieldAccess() in MemberCodeGen and TypeChecker.
* *
* @param jvmClassName a JVM class name. e.g. java/lang/String * @param jvmClassName a JVM class name. e.g. java/lang/String
* @see #lookupClass(String, boolean)
* @see #lookupClass(String, boolean, int)
*/ */
public CtField lookupFieldByJvmName2(String jvmClassName, Symbol fieldSym, public CtField lookupFieldByJvmName2(String jvmClassName, Symbol fieldSym,
ASTree expr) throws NoFieldException ASTree expr) throws NoFieldException
String field = fieldSym.get(); String field = fieldSym.get();
CtClass cc = null; CtClass cc = null;
try { try {
cc = lookupClass(jvmToJavaName(jvmClassName), true);
cc = lookupClass(jvmToJavaName(jvmClassName), true, expr.getLineNumber());
} }
catch (CompileError e) { catch (CompileError e) {
// EXPR might be part of a qualified class name. // EXPR might be part of a qualified class name.
public CtField lookupField(String className, Symbol fieldName) public CtField lookupField(String className, Symbol fieldName)
throws CompileError throws CompileError
{ {
CtClass cc = lookupClass(className, false);
CtClass cc = lookupClass(className, false, fieldName.getLineNumber());
try { try {
return cc.getField(fieldName.get()); return cc.getField(fieldName.get());
} }
catch (NotFoundException e) {} catch (NotFoundException e) {}
throw new CompileError("no such field: " + fieldName.get());
throw new CompileError("no such field: " + fieldName.get(), fieldName.getLineNumber());
} }


public CtClass lookupClassByName(ASTList name) throws CompileError { public CtClass lookupClassByName(ASTList name) throws CompileError {
return lookupClass(Declarator.astToClassName(name, '.'), false);
return lookupClass(Declarator.astToClassName(name, '.'), false, name.getLineNumber());
} }


public CtClass lookupClassByJvmName(String jvmName) throws CompileError {
return lookupClass(jvmToJavaName(jvmName), false);
public CtClass lookupClassByJvmName(String jvmName, int lineNumber) throws CompileError {
return lookupClass(jvmToJavaName(jvmName), false, lineNumber);
} }


public CtClass lookupClass(Declarator decl) throws CompileError { public CtClass lookupClass(Declarator decl) throws CompileError {
return lookupClass(decl.getType(), decl.getArrayDim(), return lookupClass(decl.getType(), decl.getArrayDim(),
decl.getClassName());
decl.getClassName(), decl.getLineNumber());
} }


/** /**
* @param classname jvm class name.
* @param classname jvm class name.
* @param lineNumber
*/ */
public CtClass lookupClass(int type, int dim, String classname)
public CtClass lookupClass(int type, int dim, String classname, int lineNumber)
throws CompileError throws CompileError
{ {
String cname = ""; String cname = "";
CtClass clazz; CtClass clazz;
if (type == CLASS) { if (type == CLASS) {
clazz = lookupClassByJvmName(classname);
clazz = lookupClassByJvmName(classname, lineNumber);
if (dim > 0) if (dim > 0)
cname = clazz.getName(); cname = clazz.getName();
else else
return clazz; return clazz;
} }
else else
cname = getTypeName(type);
cname = getTypeName(type, lineNumber);


while (dim-- > 0) while (dim-- > 0)
cname += "[]"; cname += "[]";


return lookupClass(cname, false);
return lookupClass(cname, false, lineNumber);
} }


/* /*
* type cannot be CLASS * type cannot be CLASS
*/ */
static String getTypeName(int type) throws CompileError {
static String getTypeName(int type, int lineNumber) throws CompileError {
String cname = ""; String cname = "";
switch (type) { switch (type) {
case BOOLEAN : case BOOLEAN :
cname = "void"; cname = "void";
break; break;
default : default :
fatal();
fatal(lineNumber);
} }


return cname; return cname;
} }


/** /**
* @param name a qualified class name. e.g. java.lang.String
* @param name a qualified class name. e.g. java.lang.String
* @param lineNumber
*/ */
public CtClass lookupClass(String name, boolean notCheckInner)
public CtClass lookupClass(String name, boolean notCheckInner, int lineNumber)
throws CompileError throws CompileError
{ {
Map<String,String> cache = getInvalidNames(); Map<String,String> cache = getInvalidNames();
String found = cache.get(name); String found = cache.get(name);
if (found == INVALID) if (found == INVALID)
throw new CompileError("no such class: " + name);
throw new CompileError("no such class: " + name, lineNumber);
else if (found != null) else if (found != null)
try { try {
return classPool.get(found); return classPool.get(found);
cc = lookupClass0(name, notCheckInner); cc = lookupClass0(name, notCheckInner);
} }
catch (NotFoundException e) { catch (NotFoundException e) {
cc = searchImports(name);
cc = searchImports(name, lineNumber);
} }


cache.put(name, cc.getName()); cache.put(name, cc.getName());
return ht; return ht;
} }


private CtClass searchImports(String orgName)
private CtClass searchImports(String orgName, int lineNumber)
throws CompileError throws CompileError
{ {
if (orgName.indexOf('.') < 0) { if (orgName.indexOf('.') < 0) {
} }


getInvalidNames().put(orgName, INVALID); getInvalidNames().put(orgName, INVALID);
throw new CompileError("no such class: " + orgName);
throw new CompileError("no such class: " + orgName, lineNumber);
} }


private CtClass lookupClass0(String classname, boolean notCheckInner) private CtClass lookupClass0(String classname, boolean notCheckInner)
/* Expands a simple class name to java.lang.*. /* Expands a simple class name to java.lang.*.
* For example, this converts Object into java/lang/Object. * For example, this converts Object into java/lang/Object.
*/ */
public String resolveJvmClassName(String jvmName) throws CompileError {
public String resolveJvmClassName(String jvmName, int lineNumber) throws CompileError {
if (jvmName == null) if (jvmName == null)
return null; return null;
return javaToJvmName(lookupClassByJvmName(jvmName).getName());
return javaToJvmName(lookupClassByJvmName(jvmName, lineNumber).getName());
} }


public static CtClass getSuperclass(CtClass c) throws CompileError { public static CtClass getSuperclass(CtClass c) throws CompileError {
} }
catch (NotFoundException e) {} catch (NotFoundException e) {}
throw new CompileError("cannot find the super class of " throw new CompileError("cannot find the super class of "
+ c.getName());
+ c.getName(), c.getLinesCount() - 1);
} }


public static CtClass getSuperInterface(CtClass c, String interfaceName) public static CtClass getSuperInterface(CtClass c, String interfaceName)
return intfs[i]; return intfs[i];
} catch (NotFoundException e) {} } catch (NotFoundException e) {}
throw new CompileError("cannot find the super interface " + interfaceName throw new CompileError("cannot find the super interface " + interfaceName
+ " of " + c.getName());
+ " of " + c.getName(), c.getLinesCount() - 1);
} }


public static String javaToJvmName(String classname) { public static String javaToJvmName(String classname) {
return classname.replace('/', '.'); return classname.replace('/', '.');
} }


public static int descToType(char c) throws CompileError {
public static int descToType(char c, int lineNumber) throws CompileError {
switch (c) { switch (c) {
case 'Z' : case 'Z' :
return BOOLEAN; return BOOLEAN;
case '[' : case '[' :
return CLASS; return CLASS;
default : default :
fatal();
fatal(lineNumber);
return VOID; // never reach here return VOID; // never reach here
} }
} }

+ 1
- 1
src/main/javassist/compiler/NoFieldException.java View File

/* NAME must be JVM-internal representation. /* NAME must be JVM-internal representation.
*/ */
public NoFieldException(String name, ASTree e) { public NoFieldException(String name, ASTree e) {
super("no such field: " + name);
super("no such field: " + name, e.getLineNumber());
fieldName = name; fieldName = name;
expr = e; expr = e;
} }

+ 84
- 76
src/main/javassist/compiler/Parser.java View File

Declarator d; Declarator d;
boolean isConstructor = false; boolean isConstructor = false;
if (lex.lookAhead() == Identifier && lex.lookAhead(1) == '(') { if (lex.lookAhead() == Identifier && lex.lookAhead(1) == '(') {
d = new Declarator(VOID, 0);
d = new Declarator(VOID, 0, lex.getLineNumber());
isConstructor = true; isConstructor = true;
} }
else else
else else
name = lex.getString(); name = lex.getString();


d.setVariable(new Symbol(name));
d.setVariable(new Symbol(name, lex.getLineNumber()));
if (isConstructor || lex.lookAhead() == '(') if (isConstructor || lex.lookAhead() == '(')
return parseMethod1(tbl, isConstructor, mods, d); return parseMethod1(tbl, isConstructor, mods, d);
return parseField(tbl, mods, d); return parseField(tbl, mods, d);


int c = lex.get(); int c = lex.get();
if (c == ';') if (c == ';')
return new FieldDecl(mods, new ASTList(d, new ASTList(expr)));
return new FieldDecl(mods, new ASTList(d, new ASTList(expr, lex.getLineNumber()), lex.getLineNumber()), lex.getLineNumber());
else if (c == ',') else if (c == ',')
throw new CompileError( throw new CompileError(
"only one field can be declared in one declaration", lex); "only one field can be declared in one declaration", lex);
ASTList parms = null; ASTList parms = null;
if (lex.lookAhead() != ')') if (lex.lookAhead() != ')')
while (true) { while (true) {
parms = ASTList.append(parms, parseFormalParam(tbl));
parms = ASTList.append(parms, parseFormalParam(tbl), lex.getLineNumber());
int t = lex.lookAhead(); int t = lex.lookAhead();
if (t == ',') if (t == ',')
lex.get(); lex.get();
if (lex.lookAhead() == THROWS) { if (lex.lookAhead() == THROWS) {
lex.get(); lex.get();
while (true) { while (true) {
throwsList = ASTList.append(throwsList, parseClassType(tbl));
throwsList = ASTList.append(throwsList, parseClassType(tbl), lex.getLineNumber());
if (lex.lookAhead() == ',') if (lex.lookAhead() == ',')
lex.get(); lex.get();
else else
} }


return new MethodDecl(mods, new ASTList(d, return new MethodDecl(mods, new ASTList(d,
ASTList.make(parms, throwsList, null)));
ASTList.make(parms, throwsList, null, lex.getLineNumber()), lex.getLineNumber()), lex.getLineNumber());
} }


/* Parses a method body. /* Parses a method body.
else { else {
body = parseBlock(tbl); body = parseBlock(tbl);
if (body == null) if (body == null)
body = new Stmnt(BLOCK);
body = new Stmnt(BLOCK, lex.getLineNumber());
} }


md.sublist(4).setHead(body); md.sublist(4).setHead(body);
if (t == ABSTRACT || t == FINAL || t == PUBLIC || t == PROTECTED if (t == ABSTRACT || t == FINAL || t == PUBLIC || t == PROTECTED
|| t == PRIVATE || t == SYNCHRONIZED || t == STATIC || t == PRIVATE || t == SYNCHRONIZED || t == STATIC
|| t == VOLATILE || t == TRANSIENT || t == STRICT) || t == VOLATILE || t == TRANSIENT || t == STRICT)
list = new ASTList(new Keyword(lex.get()), list);
list = new ASTList(new Keyword(lex.get(), lex.getLineNumber()), list, lex.getLineNumber());
else else
break; break;
} }
if (isBuiltinType(t) || t == VOID) { if (isBuiltinType(t) || t == VOID) {
lex.get(); // primitive type lex.get(); // primitive type
int dim = parseArrayDimension(); int dim = parseArrayDimension();
return new Declarator(t, dim);
return new Declarator(t, dim, lex.getLineNumber());
} }
ASTList name = parseClassType(tbl); ASTList name = parseClassType(tbl);
int dim = parseArrayDimension(); int dim = parseArrayDimension();
return new Declarator(name, dim);
return new Declarator(name, dim, lex.getLineNumber());
} }


private static boolean isBuiltinType(int t) { private static boolean isBuiltinType(int t) {
throw new SyntaxError(lex); throw new SyntaxError(lex);


String name = lex.getString(); String name = lex.getString();
d.setVariable(new Symbol(name));
d.setVariable(new Symbol(name, lex.getLineNumber()));
d.addArrayDim(parseArrayDimension()); d.addArrayDim(parseArrayDimension());
tbl.append(name, d); tbl.append(name, d);
return d; return d;
return parseBlock(tbl); return parseBlock(tbl);
else if (t == ';') { else if (t == ';') {
lex.get(); lex.get();
return new Stmnt(BLOCK); // empty statement
return new Stmnt(BLOCK, lex.getLineNumber()); // empty statement
} }
else if (t == Identifier && lex.lookAhead(1) == ':') { else if (t == Identifier && lex.lookAhead(1) == ':') {
lex.get(); // Identifier lex.get(); // Identifier
String label = lex.getString(); String label = lex.getString();
lex.get(); // ':' lex.get(); // ':'
return Stmnt.make(LABEL, new Symbol(label), parseStatement(tbl));
return Stmnt.make(LABEL, new Symbol(label, lex.getLineNumber()), parseStatement(tbl), lex.getLineNumber());
} }
else if (t == IF) else if (t == IF)
return parseIf(tbl); return parseIf(tbl);
/* block.statement : "{" statement* "}" /* block.statement : "{" statement* "}"
*/ */
private Stmnt parseBlock(SymbolTable tbl) throws CompileError { private Stmnt parseBlock(SymbolTable tbl) throws CompileError {
int blockLineNumber = lex.getLineNumber();
if (lex.get() != '{') if (lex.get() != '{')
throw new SyntaxError(lex); throw new SyntaxError(lex);


Stmnt body = null; Stmnt body = null;
SymbolTable tbl2 = new SymbolTable(tbl); SymbolTable tbl2 = new SymbolTable(tbl);
while (lex.lookAhead() != '}') { while (lex.lookAhead() != '}') {
int lineNumber = lex.getLineNumber();
Stmnt s = parseStatement(tbl2); Stmnt s = parseStatement(tbl2);
if (s != null) if (s != null)
body = (Stmnt)ASTList.concat(body, new Stmnt(BLOCK, s));
body = (Stmnt)ASTList.concat(body, new Stmnt(BLOCK, s, lineNumber));
} }


lex.get(); // '}' lex.get(); // '}'
if (body == null) if (body == null)
return new Stmnt(BLOCK); // empty block
return new Stmnt(BLOCK, blockLineNumber); // empty block
return body; return body;
} }


private Stmnt parseIf(SymbolTable tbl) throws CompileError { private Stmnt parseIf(SymbolTable tbl) throws CompileError {
int t = lex.get(); // IF int t = lex.get(); // IF
ASTree expr = parseParExpression(tbl); ASTree expr = parseParExpression(tbl);
int exprLineNum = lex.getLineNumber();
Stmnt thenp = parseStatement(tbl); Stmnt thenp = parseStatement(tbl);
int thenLineNum = lex.getLineNumber();
Stmnt elsep; Stmnt elsep;
if (lex.lookAhead() == ELSE) { if (lex.lookAhead() == ELSE) {
lex.get(); lex.get();
else else
elsep = null; elsep = null;


return new Stmnt(t, expr, new ASTList(thenp, new ASTList(elsep)));
return new Stmnt(t, expr, new ASTList(thenp, new ASTList(elsep, lex.getLineNumber()), thenLineNum), exprLineNum);
} }


/* while.statement : WHILE "(" expression ")" statement /* while.statement : WHILE "(" expression ")" statement
{ {
int t = lex.get(); // WHILE int t = lex.get(); // WHILE
ASTree expr = parseParExpression(tbl); ASTree expr = parseParExpression(tbl);
int lineNumber = lex.getLineNumber();
Stmnt body = parseStatement(tbl); Stmnt body = parseStatement(tbl);
return new Stmnt(t, expr, body);
return new Stmnt(t, expr, body, lineNumber);
} }


/* do.statement : DO statement WHILE "(" expression ")" ";" /* do.statement : DO statement WHILE "(" expression ")" ";"
if (lex.get() != ')' || lex.get() != ';') if (lex.get() != ')' || lex.get() != ';')
throw new SyntaxError(lex); throw new SyntaxError(lex);


return new Stmnt(t, expr, body);
return new Stmnt(t, expr, body, lex.getLineNumber());
} }


/* for.statement : FOR "(" decl.or.expr expression ";" expression ")" /* for.statement : FOR "(" decl.or.expr expression ";" expression ")"
if (lex.get() != '(') if (lex.get() != '(')
throw new SyntaxError(lex); throw new SyntaxError(lex);


int expr1LineNumber = lex.getLineNumber();
if (lex.lookAhead() == ';') { if (lex.lookAhead() == ';') {
lex.get(); lex.get();
expr1 = null; expr1 = null;
else else
expr1 = parseDeclarationOrExpression(tbl2, true); expr1 = parseDeclarationOrExpression(tbl2, true);


int expr2LineNumber = lex.getLineNumber();
if (lex.lookAhead() == ';') if (lex.lookAhead() == ';')
expr2 = null; expr2 = null;
else else
if (lex.get() != ';') if (lex.get() != ';')
throw new CompileError("; is missing", lex); throw new CompileError("; is missing", lex);


int expr3LineNumber = lex.getLineNumber();
if (lex.lookAhead() == ')') if (lex.lookAhead() == ')')
expr3 = null; expr3 = null;
else else


Stmnt body = parseStatement(tbl2); Stmnt body = parseStatement(tbl2);
return new Stmnt(t, expr1, new ASTList(expr2, return new Stmnt(t, expr1, new ASTList(expr2,
new ASTList(expr3, body)));
new ASTList(expr3, body, expr3LineNumber), expr2LineNumber), expr1LineNumber);
} }


/* switch.statement : SWITCH "(" expression ")" "{" switch.block "}" /* switch.statement : SWITCH "(" expression ")" "{" switch.block "}"
int t = lex.get(); // SWITCH int t = lex.get(); // SWITCH
ASTree expr = parseParExpression(tbl); ASTree expr = parseParExpression(tbl);
Stmnt body = parseSwitchBlock(tbl); Stmnt body = parseSwitchBlock(tbl);
return new Stmnt(t, expr, body);
return new Stmnt(t, expr, body, lex.getLineNumber());
} }


private Stmnt parseSwitchBlock(SymbolTable tbl) throws CompileError { private Stmnt parseSwitchBlock(SymbolTable tbl) throws CompileError {
throw new CompileError("no case or default in a switch block", throw new CompileError("no case or default in a switch block",
lex); lex);


Stmnt body = new Stmnt(BLOCK, s);
Stmnt body = new Stmnt(BLOCK, s, lex.getLineNumber());
while (lex.lookAhead() != '}') { while (lex.lookAhead() != '}') {
Stmnt s2 = parseStmntOrCase(tbl2); Stmnt s2 = parseStmntOrCase(tbl2);
if (s2 != null) { if (s2 != null) {
int op2 = s2.getOperator(); int op2 = s2.getOperator();
if (op2 == CASE || op2 == DEFAULT) { if (op2 == CASE || op2 == DEFAULT) {
body = (Stmnt)ASTList.concat(body, new Stmnt(BLOCK, s2));
body = (Stmnt)ASTList.concat(body, new Stmnt(BLOCK, s2, lex.getLineNumber()));
s = s2; s = s2;
} }
else else
s = (Stmnt)ASTList.concat(s, new Stmnt(BLOCK, s2));
s = (Stmnt)ASTList.concat(s, new Stmnt(BLOCK, s2, lex.getLineNumber()));
} }
} }


lex.get(); lex.get();
Stmnt s; Stmnt s;
if (t == CASE) if (t == CASE)
s = new Stmnt(t, parseExpression(tbl));
s = new Stmnt(t, parseExpression(tbl), lex.getLineNumber());
else else
s = new Stmnt(DEFAULT);
s = new Stmnt(DEFAULT, lex.getLineNumber());


if (lex.get() != ':') if (lex.get() != ':')
throw new CompileError(": is missing", lex); throw new CompileError(": is missing", lex);
throw new SyntaxError(lex); throw new SyntaxError(lex);


Stmnt body = parseBlock(tbl); Stmnt body = parseBlock(tbl);
return new Stmnt(t, expr, body);
return new Stmnt(t, expr, body, lex.getLineNumber());
} }


/* try.statement /* try.statement
throw new SyntaxError(lex); throw new SyntaxError(lex);


Stmnt b = parseBlock(tbl2); Stmnt b = parseBlock(tbl2);
catchList = ASTList.append(catchList, new Pair(d, b));
catchList = ASTList.append(catchList, new Pair(d, b), lex.getLineNumber());
} }


Stmnt finallyBlock = null; Stmnt finallyBlock = null;
finallyBlock = parseBlock(tbl); finallyBlock = parseBlock(tbl);
} }


return Stmnt.make(TRY, block, catchList, finallyBlock);
return Stmnt.make(TRY, block, catchList, finallyBlock, lex.getLineNumber());
} }


/* return.statement : RETURN [ expression ] ";" /* return.statement : RETURN [ expression ] ";"
*/ */
private Stmnt parseReturn(SymbolTable tbl) throws CompileError { private Stmnt parseReturn(SymbolTable tbl) throws CompileError {
int t = lex.get(); // RETURN int t = lex.get(); // RETURN
Stmnt s = new Stmnt(t);
Stmnt s = new Stmnt(t, lex.getLineNumber());
if (lex.lookAhead() != ';') if (lex.lookAhead() != ';')
s.setLeft(parseExpression(tbl)); s.setLeft(parseExpression(tbl));


if (lex.get() != ';') if (lex.get() != ';')
throw new CompileError("; is missing", lex); throw new CompileError("; is missing", lex);


return new Stmnt(t, expr);
return new Stmnt(t, expr, lex.getLineNumber());
} }


/* break.statement : BREAK [ Identifier ] ";" /* break.statement : BREAK [ Identifier ] ";"
throws CompileError throws CompileError
{ {
int t = lex.get(); // CONTINUE int t = lex.get(); // CONTINUE
Stmnt s = new Stmnt(t);
Stmnt s = new Stmnt(t, lex.getLineNumber());
int t2 = lex.get(); int t2 = lex.get();
if (t2 == Identifier) { if (t2 == Identifier) {
s.setLeft(new Symbol(lex.getString()));
s.setLeft(new Symbol(lex.getString(), lex.getLineNumber()));
t2 = lex.get(); t2 = lex.get();
} }


if (isBuiltinType(t)) { if (isBuiltinType(t)) {
t = lex.get(); t = lex.get();
int dim = parseArrayDimension(); int dim = parseArrayDimension();
return parseDeclarators(tbl, new Declarator(t, dim));
return parseDeclarators(tbl, new Declarator(t, dim, lex.getLineNumber()));
} }
else if (t == Identifier) { else if (t == Identifier) {
int i = nextIsClassType(0); int i = nextIsClassType(0);
if (lex.lookAhead(i) == Identifier) { if (lex.lookAhead(i) == Identifier) {
ASTList name = parseClassType(tbl); ASTList name = parseClassType(tbl);
int dim = parseArrayDimension(); int dim = parseArrayDimension();
return parseDeclarators(tbl, new Declarator(name, dim));
return parseDeclarators(tbl, new Declarator(name, dim, lex.getLineNumber()));
} }
} }


if (exprList) if (exprList)
expr = parseExprList(tbl); expr = parseExprList(tbl);
else else
expr = new Stmnt(EXPR, parseExpression(tbl));
expr = new Stmnt(EXPR, parseExpression(tbl), lex.getLineNumber());


if (lex.get() != ';') if (lex.get() != ';')
throw new CompileError("; is missing", lex); throw new CompileError("; is missing", lex);
private Stmnt parseExprList(SymbolTable tbl) throws CompileError { private Stmnt parseExprList(SymbolTable tbl) throws CompileError {
Stmnt expr = null; Stmnt expr = null;
for (;;) { for (;;) {
Stmnt e = new Stmnt(EXPR, parseExpression(tbl));
expr = (Stmnt)ASTList.concat(expr, new Stmnt(BLOCK, e));
Stmnt e = new Stmnt(EXPR, parseExpression(tbl), lex.getLineNumber());
expr = (Stmnt)ASTList.concat(expr, new Stmnt(BLOCK, e, lex.getLineNumber()));
if (lex.lookAhead() == ',') if (lex.lookAhead() == ',')
lex.get(); lex.get();
else else
Stmnt decl = null; Stmnt decl = null;
for (;;) { for (;;) {
decl = (Stmnt)ASTList.concat(decl, decl = (Stmnt)ASTList.concat(decl,
new Stmnt(DECL, parseDeclarator(tbl, d)));
new Stmnt(DECL, parseDeclarator(tbl, d), lex.getLineNumber()));
int t = lex.get(); int t = lex.get();
if (t == ';') if (t == ';')
return decl; return decl;
throw new SyntaxError(lex); throw new SyntaxError(lex);


String name = lex.getString(); String name = lex.getString();
Symbol symbol = new Symbol(name);
Symbol symbol = new Symbol(name, lex.getLineNumber());
int dim = parseArrayDimension(); int dim = parseArrayDimension();
ASTree init = null; ASTree init = null;
if (lex.lookAhead() == '=') { if (lex.lookAhead() == '=') {
init = parseInitializer(tbl); init = parseInitializer(tbl);
} }


Declarator decl = d.make(symbol, dim, init);
Declarator decl = d.make(symbol, dim, init, lex.getLineNumber());
tbl.append(name, decl); tbl.append(name, decl);
return decl; return decl;
} }
lex.get(); // '{' lex.get(); // '{'
if(lex.lookAhead() == '}'){ if(lex.lookAhead() == '}'){
lex.get(); lex.get();
return new ArrayInit(null);
return new ArrayInit(null, lex.getLineNumber());
} }
ASTree expr = parseExpression(tbl); ASTree expr = parseExpression(tbl);
ArrayInit init = new ArrayInit(expr);
ArrayInit init = new ArrayInit(expr, lex.getLineNumber());
while (lex.lookAhead() == ',') { while (lex.lookAhead() == ',') {
lex.get(); lex.get();
expr = parseExpression(tbl); expr = parseExpression(tbl);
ASTList.append(init, expr);
ASTList.append(init, expr, lex.getLineNumber());
} }


if (lex.get() != '}') if (lex.get() != '}')


int t = lex.get(); int t = lex.get();
ASTree right = parseExpression(tbl); ASTree right = parseExpression(tbl);
return AssignExpr.makeAssign(t, left, right);
return AssignExpr.makeAssign(t, left, right, lex.getLineNumber());
} }


private static boolean isAssignOp(int t) { private static boolean isAssignOp(int t) {
throw new CompileError(": is missing", lex); throw new CompileError(": is missing", lex);


ASTree elseExpr = parseExpression(tbl); ASTree elseExpr = parseExpression(tbl);
return new CondExpr(cond, thenExpr, elseExpr);
return new CondExpr(cond, thenExpr, elseExpr, lex.getLineNumber());
} }
return cond; return cond;
} }
if (isBuiltinType(t)) { if (isBuiltinType(t)) {
lex.get(); // primitive type lex.get(); // primitive type
int dim = parseArrayDimension(); int dim = parseArrayDimension();
return new InstanceOfExpr(t, dim, expr);
return new InstanceOfExpr(t, dim, expr, lex.getLineNumber());
} }
ASTList name = parseClassType(tbl); ASTList name = parseClassType(tbl);
int dim = parseArrayDimension(); int dim = parseArrayDimension();
return new InstanceOfExpr(name, dim, expr);
return new InstanceOfExpr(name, dim, expr, lex.getLineNumber());
} }


private ASTree binaryExpr2(SymbolTable tbl, ASTree expr, int prec) private ASTree binaryExpr2(SymbolTable tbl, ASTree expr, int prec)
if (p2 != 0 && prec > p2) if (p2 != 0 && prec > p2)
expr2 = binaryExpr2(tbl, expr2, p2); expr2 = binaryExpr2(tbl, expr2, p2);
else else
return BinExpr.makeBin(t, expr, expr2);
return BinExpr.makeBin(t, expr, expr2, lex.getLineNumber());
} }
} }


case IntConstant : case IntConstant :
case CharConstant : case CharConstant :
lex.get(); lex.get();
return new IntConst(-lex.getLong(), t2);
return new IntConst(-lex.getLong(), t2, lex.getLineNumber());
case DoubleConstant : case DoubleConstant :
case FloatConstant : case FloatConstant :
lex.get(); lex.get();
return new DoubleConst(-lex.getDouble(), t2);
return new DoubleConst(-lex.getDouble(), t2, lex.getLineNumber());
default : default :
break; break;
} }
} }


return Expr.make(t, parseUnaryExpr(tbl));
return Expr.make(t, parseUnaryExpr(tbl), lex.getLineNumber());
case '(' : case '(' :
return parseCast(tbl); return parseCast(tbl);
default : default :
if (lex.get() != ')') if (lex.get() != ')')
throw new CompileError(") is missing", lex); throw new CompileError(") is missing", lex);


return new CastExpr(t, dim, parseUnaryExpr(tbl));
return new CastExpr(t, dim, parseUnaryExpr(tbl), lex.getLineNumber());
} }
else if (t == Identifier && nextIsClassCast()) { else if (t == Identifier && nextIsClassCast()) {
lex.get(); // '(' lex.get(); // '('
if (lex.get() != ')') if (lex.get() != ')')
throw new CompileError(") is missing", lex); throw new CompileError(") is missing", lex);


return new CastExpr(name, dim, parseUnaryExpr(tbl));
return new CastExpr(name, dim, parseUnaryExpr(tbl), lex.getLineNumber());
} }
else else
return parsePostfix(tbl); return parsePostfix(tbl);
if (lex.get() != Identifier) if (lex.get() != Identifier)
throw new SyntaxError(lex); throw new SyntaxError(lex);


list = ASTList.append(list, new Symbol(lex.getString()));
list = ASTList.append(list, new Symbol(lex.getString(), lex.getLineNumber()), lex.getLineNumber());
if (lex.lookAhead() == '.') if (lex.lookAhead() == '.')
lex.get(); lex.get();
else else
case IntConstant : case IntConstant :
case CharConstant : case CharConstant :
lex.get(); lex.get();
return new IntConst(lex.getLong(), token);
return new IntConst(lex.getLong(), token, lex.getLineNumber());
case DoubleConstant : case DoubleConstant :
case FloatConstant : case FloatConstant :
lex.get(); lex.get();
return new DoubleConst(lex.getDouble(), token);
return new DoubleConst(lex.getDouble(), token, lex.getLineNumber());
default : default :
break; break;
} }
if (index == null) if (index == null)
throw new SyntaxError(lex); throw new SyntaxError(lex);


expr = Expr.make(ARRAY, expr, index);
expr = Expr.make(ARRAY, expr, index, lex.getLineNumber());
} }
break; break;
case PLUSPLUS : case PLUSPLUS :
case MINUSMINUS : case MINUSMINUS :
t = lex.get(); t = lex.get();
expr = Expr.make(t, null, expr);
expr = Expr.make(t, null, expr, lex.getLineNumber());
break; break;
case '.' : case '.' :
lex.get(); lex.get();
if (t == CLASS) if (t == CLASS)
expr = parseDotClass(expr, 0); expr = parseDotClass(expr, 0);
else if (t == SUPER) else if (t == SUPER)
expr = Expr.make('.', new Symbol(toClassName(expr)), new Keyword(t));
expr = Expr.make('.', new Symbol(toClassName(expr), lex.getLineNumber()), new Keyword(t, lex.getLineNumber()), lex.getLineNumber());
else if (t == Identifier) { else if (t == Identifier) {
str = lex.getString(); str = lex.getString();
expr = Expr.make('.', expr, new Member(str));
expr = Expr.make('.', expr, new Member(str, lex.getLineNumber()), lex.getLineNumber());
} }
else else
throw new CompileError("missing member name", lex); throw new CompileError("missing member name", lex);
throw new CompileError("missing static member name", lex); throw new CompileError("missing static member name", lex);


str = lex.getString(); str = lex.getString();
expr = Expr.make(MEMBER, new Symbol(toClassName(expr)),
new Member(str));
expr = Expr.make(MEMBER, new Symbol(toClassName(expr), lex.getLineNumber()),
new Member(str, lex.getLineNumber()), lex.getLineNumber());
break; break;
default : default :
return expr; return expr;
cname = sbuf.toString(); cname = sbuf.toString();
} }


return Expr.make('.', new Symbol(cname), new Member("class"));
return Expr.make('.', new Symbol(cname, className.getLineNumber()), new Member("class", className.getLineNumber()), lex.getLineNumber());
} }


/* Parses a .class expression on a built-in type. For example, /* Parses a .class expression on a built-in type. For example,
{ {
if (dim > 0) { if (dim > 0) {
String cname = CodeGen.toJvmTypeName(builtinType, dim); String cname = CodeGen.toJvmTypeName(builtinType, dim);
return Expr.make('.', new Symbol(cname), new Member("class"));
return Expr.make('.', new Symbol(cname, lex.getLineNumber()), new Member("class", lex.getLineNumber()), lex.getLineNumber());
} }
String cname; String cname;
switch(builtinType) { switch(builtinType) {
break; break;
default : default :
throw new CompileError("invalid builtin type: " throw new CompileError("invalid builtin type: "
+ builtinType);
+ builtinType, lex);
} }


return Expr.make(MEMBER, new Symbol(cname), new Member("TYPE"));
return Expr.make(MEMBER, new Symbol(cname, lex.getLineNumber()), new Member("TYPE", lex.getLineNumber()), lex.getLineNumber());
} }


/* method.call : method.expr "(" argument.list ")" /* method.call : method.expr "(" argument.list ")"
throw new SyntaxError(lex); throw new SyntaxError(lex);
} }


return CallExpr.makeCall(expr, parseArgumentList(tbl));
return CallExpr.makeCall(expr, parseArgumentList(tbl), lex.getLineNumber());
} }


private String toClassName(ASTree name) private String toClassName(ASTree name)
case TRUE : case TRUE :
case FALSE : case FALSE :
case NULL : case NULL :
return new Keyword(t);
return new Keyword(t, lex.getLineNumber());
case Identifier : case Identifier :
name = lex.getString(); name = lex.getString();
decl = tbl.lookup(name); decl = tbl.lookup(name);
if (decl == null) if (decl == null)
return new Member(name); // this or static member
return new Variable(name, decl); // local variable
return new Member(name, lex.getLineNumber()); // this or static member
return new Variable(name, decl, lex.getLineNumber()); // local variable
case StringL : case StringL :
return new StringL(lex.getString());
return new StringL(lex.getString(), lex.getLineNumber());
case NEW : case NEW :
return parseNew(tbl); return parseNew(tbl);
case '(' : case '(' :
if (lex.lookAhead() == '{') if (lex.lookAhead() == '{')
init = parseArrayInitializer(tbl); init = parseArrayInitializer(tbl);


return new NewExpr(t, size, init);
return new NewExpr(t, size, init, lex.getLineNumber());
} }
else if (t == Identifier) { else if (t == Identifier) {
ASTList name = parseClassType(tbl); ASTList name = parseClassType(tbl);
t = lex.lookAhead(); t = lex.lookAhead();
if (t == '(') { if (t == '(') {
ASTList args = parseArgumentList(tbl); ASTList args = parseArgumentList(tbl);
return new NewExpr(name, args);
return new NewExpr(name, args, lex.getLineNumber());
} }
else if (t == '[') { else if (t == '[') {
ASTList size = parseArraySize(tbl); ASTList size = parseArraySize(tbl);
if (lex.lookAhead() == '{') if (lex.lookAhead() == '{')
init = parseArrayInitializer(tbl); init = parseArrayInitializer(tbl);


return NewExpr.makeObjectArray(name, size, init);
return NewExpr.makeObjectArray(name, size, init, lex.getLineNumber());
} }
} }


private ASTList parseArraySize(SymbolTable tbl) throws CompileError { private ASTList parseArraySize(SymbolTable tbl) throws CompileError {
ASTList list = null; ASTList list = null;
while (lex.lookAhead() == '[') while (lex.lookAhead() == '[')
list = ASTList.append(list, parseArrayIndex(tbl));
list = ASTList.append(list, parseArrayIndex(tbl), lex.getLineNumber());


return list; return list;
} }
ASTList list = null; ASTList list = null;
if (lex.lookAhead() != ')') if (lex.lookAhead() != ')')
for (;;) { for (;;) {
list = ASTList.append(list, parseExpression(tbl));
list = ASTList.append(list, parseExpression(tbl), lex.getLineNumber());
if (lex.lookAhead() == ',') if (lex.lookAhead() == ',')
lex.get(); lex.get();
else else

+ 2
- 2
src/main/javassist/compiler/ProceedHandler.java View File

* @see javassist.compiler.JvstCodeGen#setProceedHandler(ProceedHandler, String) * @see javassist.compiler.JvstCodeGen#setProceedHandler(ProceedHandler, String)
*/ */
public interface ProceedHandler { public interface ProceedHandler {
void doit(JvstCodeGen gen, Bytecode b, ASTList args) throws CompileError;
void setReturnType(JvstTypeChecker c, ASTList args) throws CompileError;
void doit(JvstCodeGen gen, Bytecode b, ASTList args, int lineNumber) throws CompileError;
void setReturnType(JvstTypeChecker c, ASTList args, int lineNumber) throws CompileError;
} }

+ 56
- 55
src/main/javassist/compiler/TypeChecker.java View File

* into a String object. * into a String object.
*/ */
protected static String argTypesToString(int[] types, int[] dims, protected static String argTypesToString(int[] types, int[] dims,
String[] cnames) {
String[] cnames, int lineNumber) {
StringBuilder sbuf = new StringBuilder(); StringBuilder sbuf = new StringBuilder();
sbuf.append('('); sbuf.append('(');
int n = types.length; int n = types.length;
if (n > 0) { if (n > 0) {
int i = 0; int i = 0;
while (true) { while (true) {
typeToString(sbuf, types[i], dims[i], cnames[i]);
typeToString(sbuf, types[i], dims[i], cnames[i], lineNumber);
if (++i < n) if (++i < n)
sbuf.append(','); sbuf.append(',');
else else
* into a String object. * into a String object.
*/ */
protected static StringBuilder typeToString(StringBuilder sbuf, protected static StringBuilder typeToString(StringBuilder sbuf,
int type, int dim, String cname) {
int type, int dim, String cname, int lineNumber) {
String s; String s;
if (type == CLASS) if (type == CLASS)
s = MemberResolver.jvmToJavaName(cname); s = MemberResolver.jvmToJavaName(cname);
s = "Object"; s = "Object";
else else
try { try {
s = MemberResolver.getTypeName(type);
s = MemberResolver.getTypeName(type, lineNumber);
} }
catch (CompileError e) { catch (CompileError e) {
s = "?"; s = "?";
thisMethod = m; thisMethod = m;
} }


protected static void fatal() throws CompileError {
throw new CompileError("fatal");
protected static void fatal(int lineLum) throws CompileError {
throw new CompileError("fatal", lineLum);
} }


/** /**
/* Expands a simple class name to java.lang.*. /* Expands a simple class name to java.lang.*.
* For example, this converts Object into java/lang/Object. * For example, this converts Object into java/lang/Object.
*/ */
protected String resolveClassName(String jvmName) throws CompileError {
return resolver.resolveJvmClassName(jvmName);
protected String resolveClassName(String jvmName, int lineNumber) throws CompileError {
return resolver.resolveJvmClassName(jvmName, lineNumber);
} }


@Override @Override
CtClass clazz = resolver.lookupClassByName(expr.getClassName()); CtClass clazz = resolver.lookupClassByName(expr.getClassName());
String cname = clazz.getName(); String cname = clazz.getName();
ASTList args = expr.getArguments(); ASTList args = expr.getArguments();
atMethodCallCore(clazz, MethodInfo.nameInit, args);
atMethodCallCore(clazz, MethodInfo.nameInit, args, expr.getLineNumber());
exprType = CLASS; exprType = CLASS;
arrayDim = 0; arrayDim = 0;
className = MemberResolver.javaToJvmName(cname); className = MemberResolver.javaToJvmName(cname);
throws CompileError throws CompileError
{ {
CtField f = fieldAccess(left); CtField f = fieldAccess(left);
atFieldRead(f);
atFieldRead(f, expr.getLineNumber());
int fType = exprType; int fType = exprType;
int fDim = arrayDim; int fDim = arrayDim;
String cname = className; String cname = className;


if (dim1 == 0 && dim1 == arrayDim) if (dim1 == 0 && dim1 == arrayDim)
if (CodeGen.rightIsStrong(type1, exprType)) if (CodeGen.rightIsStrong(type1, exprType))
expr.setThen(new CastExpr(exprType, 0, expr.thenExpr()));
expr.setThen(new CastExpr(exprType, 0, expr.thenExpr(), expr.getLineNumber()));
else if (CodeGen.rightIsStrong(exprType, type1)) { else if (CodeGen.rightIsStrong(exprType, type1)) {
expr.setElse(new CastExpr(type1, 0, expr.elseExpr()));
expr.setElse(new CastExpr(type1, 0, expr.elseExpr(), expr.getLineNumber()));
exprType = type1; exprType = type1;
} }
} }
* an expression using StringBuffer. * an expression using StringBuffer.
*/ */
e = CallExpr.makeCall(Expr.make('.', e, e = CallExpr.makeCall(Expr.make('.', e,
new Member("toString")), null);
new Member("toString", expr.getLineNumber()), expr.getLineNumber()), null, expr.getLineNumber());
expr.setOprand1(e); expr.setOprand1(e);
expr.setOprand2(null); // <---- look at this! expr.setOprand2(null); // <---- look at this!
className = jvmJavaLangString; className = jvmJavaLangString;
if ((type1 == CLASS && dim1 == 0 && jvmJavaLangString.equals(cname)) if ((type1 == CLASS && dim1 == 0 && jvmJavaLangString.equals(cname))
|| (exprType == CLASS && arrayDim == 0 || (exprType == CLASS && arrayDim == 0
&& jvmJavaLangString.equals(className))) { && jvmJavaLangString.equals(className))) {
ASTList sbufClass = ASTList.make(new Symbol("java"),
new Symbol("lang"), new Symbol("StringBuffer"));
ASTree e = new NewExpr(sbufClass, null);
int lineNum = expr.getLineNumber();
ASTList sbufClass = ASTList.make(new Symbol("java", lineNum),
new Symbol("lang", lineNum), new Symbol("StringBuffer", lineNum), lineNum);
ASTree e = new NewExpr(sbufClass, null, lineNum);
exprType = CLASS; exprType = CLASS;
arrayDim = 0; arrayDim = 0;
className = "java/lang/StringBuffer"; className = "java/lang/StringBuffer";
ASTree newExpr = null; ASTree newExpr = null;
if (left instanceof StringL && right instanceof StringL && op == '+') if (left instanceof StringL && right instanceof StringL && op == '+')
newExpr = new StringL(((StringL)left).get() newExpr = new StringL(((StringL)left).get()
+ ((StringL)right).get());
+ ((StringL)right).get(), left.getLineNumber());
else if (left instanceof IntConst) else if (left instanceof IntConst)
newExpr = ((IntConst)left).compute(op, right); newExpr = ((IntConst)left).compute(op, right);
else if (left instanceof DoubleConst) else if (left instanceof DoubleConst)
Expr e = (Expr)expr; Expr e = (Expr)expr;
int op = e.getOperator(); int op = e.getOperator();
if (op == MEMBER) { if (op == MEMBER) {
ASTree cexpr = getConstantFieldValue((Member)e.oprand2());
ASTree cexpr = getConstantFieldValue((Member)e.oprand2(), expr.getLineNumber());
if (cexpr != null) if (cexpr != null)
return cexpr; return cexpr;
} }
return e.getLeft(); return e.getLeft();
} }
else if (expr instanceof Member) { else if (expr instanceof Member) {
ASTree cexpr = getConstantFieldValue((Member)expr);
ASTree cexpr = getConstantFieldValue((Member)expr, expr.getLineNumber());
if (cexpr != null) if (cexpr != null)
return cexpr; return cexpr;
} }
* If MEM is a static final field, this method returns a constant * If MEM is a static final field, this method returns a constant
* expression representing the value of that field. * expression representing the value of that field.
*/ */
private static ASTree getConstantFieldValue(Member mem) {
return getConstantFieldValue(mem.getField());
private static ASTree getConstantFieldValue(Member mem, int lineNumber) {
return getConstantFieldValue(mem.getField(), lineNumber);
} }


public static ASTree getConstantFieldValue(CtField f) {
public static ASTree getConstantFieldValue(CtField f, int lineNumber) {
if (f == null) if (f == null)
return null; return null;


return null; return null;


if (value instanceof String) if (value instanceof String)
return new StringL((String)value);
return new StringL((String)value, lineNumber);
else if (value instanceof Double || value instanceof Float) { else if (value instanceof Double || value instanceof Float) {
int token = (value instanceof Double) int token = (value instanceof Double)
? DoubleConstant : FloatConstant; ? DoubleConstant : FloatConstant;
return new DoubleConst(((Number)value).doubleValue(), token);
return new DoubleConst(((Number)value).doubleValue(), token, lineNumber);
} }
else if (value instanceof Number) { else if (value instanceof Number) {
int token = (value instanceof Long) ? LongConstant : IntConstant; int token = (value instanceof Long) ? LongConstant : IntConstant;
return new IntConst(((Number)value).longValue(), token);
return new IntConst(((Number)value).longValue(), token, lineNumber);
} }
else if (value instanceof Boolean) else if (value instanceof Boolean)
return new Keyword(((Boolean)value).booleanValue() return new Keyword(((Boolean)value).booleanValue()
? TokenId.TRUE : TokenId.FALSE);
? TokenId.TRUE : TokenId.FALSE, lineNumber);
else else
return null; return null;
} }
} }


private static Expr makeAppendCall(ASTree target, ASTree arg) { private static Expr makeAppendCall(ASTree target, ASTree arg) {
return CallExpr.makeCall(Expr.make('.', target, new Member("append")),
new ASTList(arg));
return CallExpr.makeCall(Expr.make('.', target, new Member("append", target.getLineNumber()), target.getLineNumber()),
new ASTList(arg, target.getLineNumber()), target.getLineNumber());
} }


private void computeBinExprType(BinExpr expr, int token, int type1) private void computeBinExprType(BinExpr expr, int token, int type1)
throws CompileError throws CompileError
{ {
if (CodeGen.rightIsStrong(type1, type2)) if (CodeGen.rightIsStrong(type1, type2))
expr.setLeft(new CastExpr(type2, 0, expr.oprand1()));
expr.setLeft(new CastExpr(type2, 0, expr.oprand1(), expr.getLineNumber()));
else else
exprType = type1; exprType = type1;
} }
else if (token == '!') else if (token == '!')
booleanExpr(expr); booleanExpr(expr);
else if (token == CALL) // method call else if (token == CALL) // method call
fatal();
fatal(expr.getLineNumber());
else { else {
oprand.accept(this); oprand.accept(this);
if (!isConstant(expr, token, oprand)) if (!isConstant(expr, token, oprand))
if (op == MEMBER) // static method if (op == MEMBER) // static method
targetClass targetClass
= resolver.lookupClass(((Symbol)e.oprand1()).get(), = resolver.lookupClass(((Symbol)e.oprand1()).get(),
false);
false, e.getLineNumber());
else if (op == '.') { else if (op == '.') {
ASTree target = e.oprand1(); ASTree target = e.oprand1();
String classFollowedByDotSuper = isDotSuper(target); String classFollowedByDotSuper = isDotSuper(target);
className = nfe.getField(); // JVM-internal className = nfe.getField(); // JVM-internal
e.setOperator(MEMBER); e.setOperator(MEMBER);
e.setOprand1(new Symbol(MemberResolver.jvmToJavaName( e.setOprand1(new Symbol(MemberResolver.jvmToJavaName(
className)));
className), e.getLineNumber()));
} }


if (arrayDim > 0) if (arrayDim > 0)
targetClass = resolver.lookupClass(javaLangObject, true);
targetClass = resolver.lookupClass(javaLangObject, true, e.getLineNumber());
else if (exprType == CLASS /* && arrayDim == 0 */) else if (exprType == CLASS /* && arrayDim == 0 */)
targetClass = resolver.lookupClassByJvmName(className);
targetClass = resolver.lookupClassByJvmName(className, e.getLineNumber());
else else
badMethod();
badMethod(e.getLineNumber());
} }
} }
else else
badMethod();
badMethod(expr.getLineNumber());
} }
else else
fatal();
fatal(expr.getLineNumber());


MemberResolver.Method minfo MemberResolver.Method minfo
= atMethodCallCore(targetClass, mname, args);
= atMethodCallCore(targetClass, mname, args, expr.getLineNumber());
expr.setMethod(minfo); expr.setMethod(minfo);
} }


private static void badMethod() throws CompileError {
throw new CompileError("bad method");
private static void badMethod(int lineNumber) throws CompileError {
throw new CompileError("bad method", lineNumber);
} }


/** /**
* and the MethodInfo of that method. Never null. * and the MethodInfo of that method. Never null.
*/ */
public MemberResolver.Method atMethodCallCore(CtClass targetClass, public MemberResolver.Method atMethodCallCore(CtClass targetClass,
String mname, ASTList args)
String mname, ASTList args, int lineNumber)
throws CompileError throws CompileError
{ {
int nargs = getMethodArgsLength(args); int nargs = getMethodArgsLength(args);
mname, types, dims, cnames); mname, types, dims, cnames);
if (found == null) { if (found == null) {
String clazz = targetClass.getName(); String clazz = targetClass.getName();
String signature = argTypesToString(types, dims, cnames);
String signature = argTypesToString(types, dims, cnames, lineNumber);
String msg; String msg;
if (mname.equals(MethodInfo.nameInit)) if (mname.equals(MethodInfo.nameInit))
msg = "cannot find constructor " + clazz + signature; msg = "cannot find constructor " + clazz + signature;
else else
msg = mname + signature + " not found in " + clazz; msg = mname + signature + " not found in " + clazz;


throw new CompileError(msg);
throw new CompileError(msg, lineNumber);
} }


String desc = found.info.getDescriptor(); String desc = found.info.getDescriptor();
setReturnType(desc);
setReturnType(desc, lineNumber);
return found; return found;
} }


} }
} }


void setReturnType(String desc) throws CompileError {
void setReturnType(String desc, int lineNumber) throws CompileError {
int i = desc.indexOf(')'); int i = desc.indexOf(')');
if (i < 0) if (i < 0)
badMethod();
badMethod(lineNumber);


char c = desc.charAt(++i); char c = desc.charAt(++i);
int dim = 0; int dim = 0;
if (c == 'L') { if (c == 'L') {
int j = desc.indexOf(';', i + 1); int j = desc.indexOf(';', i + 1);
if (j < 0) if (j < 0)
badMethod();
badMethod(lineNumber);


exprType = CLASS; exprType = CLASS;
className = desc.substring(i + 1, j); className = desc.substring(i + 1, j);
} }
else { else {
exprType = MemberResolver.descToType(c);
exprType = MemberResolver.descToType(c, lineNumber);
className = null; className = null;
} }
} }


private void atFieldRead(ASTree expr) throws CompileError { private void atFieldRead(ASTree expr) throws CompileError {
atFieldRead(fieldAccess(expr));
atFieldRead(fieldAccess(expr), expr.getLineNumber());
} }


private void atFieldRead(CtField f) throws CompileError {
private void atFieldRead(CtField f, int lineNumber) throws CompileError {
FieldInfo finfo = f.getFieldInfo2(); FieldInfo finfo = f.getFieldInfo2();
String type = finfo.getDescriptor(); String type = finfo.getDescriptor();


} }


arrayDim = dim; arrayDim = dim;
exprType = MemberResolver.descToType(c);
exprType = MemberResolver.descToType(c, lineNumber);


if (c == 'L') if (c == 'L')
className = type.substring(i + 1, type.indexOf(';', i + 1)); className = type.substring(i + 1, type.indexOf(';', i + 1));
} }
} }


throw new CompileError("bad field access");
throw new CompileError("bad field access", expr.getLineNumber());
} }


private CtField fieldAccess2(Expr e, String jvmClassName) throws CompileError { private CtField fieldAccess2(Expr e, String jvmClassName) throws CompileError {
Member fname = (Member)e.oprand2(); Member fname = (Member)e.oprand2();
CtField f = resolver.lookupFieldByJvmName2(jvmClassName, fname, e); CtField f = resolver.lookupFieldByJvmName2(jvmClassName, fname, e);
e.setOperator(MEMBER); e.setOperator(MEMBER);
e.setOprand1(new Symbol(MemberResolver.jvmToJavaName(jvmClassName)));
e.setOprand1(new Symbol(MemberResolver.jvmToJavaName(jvmClassName), e.getLineNumber()));
fname.setField(f); fname.setField(f);
return f; return f;
} }
protected void atFieldPlusPlus(ASTree oprand) throws CompileError protected void atFieldPlusPlus(ASTree oprand) throws CompileError
{ {
CtField f = fieldAccess(oprand); CtField f = fieldAccess(oprand);
atFieldRead(f);
atFieldRead(f, oprand.getLineNumber());
int t = exprType; int t = exprType;
if (t == INT || t == BYTE || t == CHAR || t == SHORT) if (t == INT || t == BYTE || t == CHAR || t == SHORT)
exprType = INT; exprType = INT;
className = getSuperName(); className = getSuperName();
break; break;
default : default :
fatal();
fatal(k.getLineNumber());
} }
} }



+ 8
- 8
src/main/javassist/compiler/ast/ASTList.java View File

private ASTree left; private ASTree left;
private ASTList right; private ASTList right;


public ASTList(ASTree _head, ASTList _tail) {
public ASTList(ASTree _head, ASTList _tail, int lineNumber) {
super(lineNumber);
left = _head; left = _head;
right = _tail; right = _tail;
} }


public ASTList(ASTree _head) {
left = _head;
right = null;
public ASTList(ASTree _head, int lineNumber) {
this(_head, null, lineNumber);
} }


public static ASTList make(ASTree e1, ASTree e2, ASTree e3) {
return new ASTList(e1, new ASTList(e2, new ASTList(e3)));
public static ASTList make(ASTree e1, ASTree e2, ASTree e3 , int lineNumber) {
return new ASTList(e1, new ASTList(e2, new ASTList(e3, lineNumber), lineNumber), lineNumber);
} }


@Override @Override
/** /**
* Appends an object to a list. * Appends an object to a list.
*/ */
public static ASTList append(ASTList a, ASTree b) {
return concat(a, new ASTList(b));
public static ASTList append(ASTList a, ASTree b, int lineNumber) {
return concat(a, new ASTList(b, lineNumber));
} }


/** /**

+ 10
- 0
src/main/javassist/compiler/ast/ASTree.java View File

/** default serialVersionUID */ /** default serialVersionUID */
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;


private final int lineNumber;

public ASTree(int lineNumber) {
this.lineNumber = lineNumber;
}

public ASTree getLeft() { return null; } public ASTree getLeft() { return null; }


public ASTree getRight() { return null; } public ASTree getRight() { return null; }
String name = getClass().getName(); String name = getClass().getName();
return name.substring(name.lastIndexOf('.') + 1); return name.substring(name.lastIndexOf('.') + 1);
} }

public int getLineNumber() {
return lineNumber;
}
} }

+ 5
- 3
src/main/javassist/compiler/ast/ArrayInit.java View File



/** /**
* Constructs an object. * Constructs an object.
* @param firstElement maybe null when the initializer is <code>{}</code> (empty).
*
* @param firstElement maybe null when the initializer is <code>{}</code> (empty).
* @param lineNumber
*/ */
public ArrayInit(ASTree firstElement) {
super(firstElement);
public ArrayInit(ASTree firstElement, int lineNumber) {
super(firstElement, lineNumber);
} }


/** /**

+ 4
- 4
src/main/javassist/compiler/ast/AssignExpr.java View File

/** default serialVersionUID */ /** default serialVersionUID */
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;


private AssignExpr(int op, ASTree _head, ASTList _tail) {
super(op, _head, _tail);
private AssignExpr(int op, ASTree _head, ASTList _tail, int lineNumber) {
super(op, _head, _tail, lineNumber);
} }


public static AssignExpr makeAssign(int op, ASTree oprand1, public static AssignExpr makeAssign(int op, ASTree oprand1,
ASTree oprand2) {
return new AssignExpr(op, oprand1, new ASTList(oprand2));
ASTree oprand2, int lineNumber) {
return new AssignExpr(op, oprand1, new ASTList(oprand2, lineNumber), lineNumber);
} }


@Override @Override

+ 4
- 4
src/main/javassist/compiler/ast/BinExpr.java View File

/** default serialVersionUID */ /** default serialVersionUID */
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;


private BinExpr(int op, ASTree _head, ASTList _tail) {
super(op, _head, _tail);
private BinExpr(int op, ASTree _head, ASTList _tail, int lineNumber) {
super(op, _head, _tail, lineNumber);
} }


public static BinExpr makeBin(int op, ASTree oprand1, ASTree oprand2) {
return new BinExpr(op, oprand1, new ASTList(oprand2));
public static BinExpr makeBin(int op, ASTree oprand1, ASTree oprand2, int lineNumber) {
return new BinExpr(op, oprand1, new ASTList(oprand2, lineNumber), lineNumber);
} }


@Override @Override

+ 4
- 4
src/main/javassist/compiler/ast/CallExpr.java View File

private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private MemberResolver.Method method; // cached result of lookupMethod() private MemberResolver.Method method; // cached result of lookupMethod()


private CallExpr(ASTree _head, ASTList _tail) {
super(TokenId.CALL, _head, _tail);
private CallExpr(ASTree _head, ASTList _tail, int lineNumber) {
super(TokenId.CALL, _head, _tail, lineNumber);
method = null; method = null;
} }


return method; return method;
} }


public static CallExpr makeCall(ASTree target, ASTree args) {
return new CallExpr(target, new ASTList(args));
public static CallExpr makeCall(ASTree target, ASTree args, int lineNumber) {
return new CallExpr(target, new ASTList(args, lineNumber), lineNumber);
} }


@Override @Override

+ 4
- 4
src/main/javassist/compiler/ast/CastExpr.java View File

protected int castType; protected int castType;
protected int arrayDim; protected int arrayDim;


public CastExpr(ASTList className, int dim, ASTree expr) {
super(className, new ASTList(expr));
public CastExpr(ASTList className, int dim, ASTree expr, int lineNumber) {
super(className, new ASTList(expr, lineNumber), lineNumber);
castType = CLASS; castType = CLASS;
arrayDim = dim; arrayDim = dim;
} }


public CastExpr(int type, int dim, ASTree expr) {
super(null, new ASTList(expr));
public CastExpr(int type, int dim, ASTree expr, int lineNumber) {
super(null, new ASTList(expr, lineNumber), lineNumber);
castType = type; castType = type;
arrayDim = dim; arrayDim = dim;
} }

+ 2
- 2
src/main/javassist/compiler/ast/CondExpr.java View File

/** default serialVersionUID */ /** default serialVersionUID */
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;


public CondExpr(ASTree cond, ASTree thenp, ASTree elsep) {
super(cond, new ASTList(thenp, new ASTList(elsep)));
public CondExpr(ASTree cond, ASTree thenp, ASTree elsep, int lineNumber) {
super(cond, new ASTList(thenp, new ASTList(elsep, lineNumber), lineNumber), lineNumber);
} }


public ASTree condExpr() { return head(); } public ASTree condExpr() { return head(); }

+ 10
- 10
src/main/javassist/compiler/ast/Declarator.java View File

protected int localVar; protected int localVar;
protected String qualifiedClass; // JVM-internal representation protected String qualifiedClass; // JVM-internal representation


public Declarator(int type, int dim) {
super(null);
public Declarator(int type, int dim, int lineNumber) {
super(null, lineNumber);
varType = type; varType = type;
arrayDim = dim; arrayDim = dim;
localVar = -1; localVar = -1;
qualifiedClass = null; qualifiedClass = null;
} }


public Declarator(ASTList className, int dim) {
super(null);
public Declarator(ASTList className, int dim, int lineNumber) {
super(null, lineNumber);
varType = CLASS; varType = CLASS;
arrayDim = dim; arrayDim = dim;
localVar = -1; localVar = -1;
/* For declaring a pre-defined? local variable. /* For declaring a pre-defined? local variable.
*/ */
public Declarator(int type, String jvmClassName, int dim, public Declarator(int type, String jvmClassName, int dim,
int var, Symbol sym) {
super(null);
int var, Symbol sym, int lineNumber) {
super(null, lineNumber);
varType = type; varType = type;
arrayDim = dim; arrayDim = dim;
localVar = var; localVar = var;
qualifiedClass = jvmClassName; qualifiedClass = jvmClassName;
setLeft(sym); setLeft(sym);
append(this, null); // initializer
append(this, null, lineNumber); // initializer
} }


public Declarator make(Symbol sym, int dim, ASTree init) {
Declarator d = new Declarator(this.varType, this.arrayDim + dim);
public Declarator make(Symbol sym, int dim, ASTree init, int lineNumber) {
Declarator d = new Declarator(this.varType, this.arrayDim + dim, lineNumber);
d.qualifiedClass = this.qualifiedClass; d.qualifiedClass = this.qualifiedClass;
d.setLeft(sym); d.setLeft(sym);
append(d, init);
append(d, init, lineNumber);
return d; return d;
} }



+ 9
- 5
src/main/javassist/compiler/ast/DoubleConst.java View File

protected double value; protected double value;
protected int type; protected int type;


public DoubleConst(double v, int tokenId) { value = v; type = tokenId; }
public DoubleConst(double v, int tokenId, int lineNumber) {
super(lineNumber);
value = v;
type = tokenId;
}


public double get() { return value; } public double get() { return value; }


else else
newType = TokenId.FloatConstant; newType = TokenId.FloatConstant;


return compute(op, this.value, right.value, newType);
return compute(op, this.value, right.value, newType, getLineNumber());
} }


private DoubleConst compute0(int op, IntConst right) { private DoubleConst compute0(int op, IntConst right) {
return compute(op, this.value, right.value, this.type);
return compute(op, this.value, right.value, this.type, getLineNumber());
} }


private static DoubleConst compute(int op, double value1, double value2, private static DoubleConst compute(int op, double value1, double value2,
int newType)
int newType, int lineNumber)
{ {
double newValue; double newValue;
switch (op) { switch (op) {
return null; return null;
} }


return new DoubleConst(newValue, newType);
return new DoubleConst(newValue, newType, lineNumber);
} }
} }

+ 8
- 8
src/main/javassist/compiler/ast/Expr.java View File

private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
protected int operatorId; protected int operatorId;


Expr(int op, ASTree _head, ASTList _tail) {
super(_head, _tail);
Expr(int op, ASTree _head, ASTList _tail, int lineNumber) {
super(_head, _tail, lineNumber);
operatorId = op; operatorId = op;
} }


Expr(int op, ASTree _head) {
super(_head);
Expr(int op, ASTree _head, int lineNumber) {
super(_head, lineNumber);
operatorId = op; operatorId = op;
} }


public static Expr make(int op, ASTree oprand1, ASTree oprand2) {
return new Expr(op, oprand1, new ASTList(oprand2));
public static Expr make(int op, ASTree oprand1, ASTree oprand2, int lineNumber) {
return new Expr(op, oprand1, new ASTList(oprand2, lineNumber), lineNumber);
} }


public static Expr make(int op, ASTree oprand1) {
return new Expr(op, oprand1);
public static Expr make(int op, ASTree oprand1, int lineNumber) {
return new Expr(op, oprand1, lineNumber);
} }


public int getOperator() { return operatorId; } public int getOperator() { return operatorId; }

+ 2
- 2
src/main/javassist/compiler/ast/FieldDecl.java View File

/** default serialVersionUID */ /** default serialVersionUID */
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;


public FieldDecl(ASTree _head, ASTList _tail) {
super(_head, _tail);
public FieldDecl(ASTree _head, ASTList _tail, int lineNumber) {
super(_head, _tail, lineNumber);
} }


public ASTList getModifiers() { return (ASTList)getLeft(); } public ASTList getModifiers() { return (ASTList)getLeft(); }

+ 4
- 4
src/main/javassist/compiler/ast/InstanceOfExpr.java View File

/** default serialVersionUID */ /** default serialVersionUID */
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;


public InstanceOfExpr(ASTList className, int dim, ASTree expr) {
super(className, dim, expr);
public InstanceOfExpr(ASTList className, int dim, ASTree expr, int lineNumber) {
super(className, dim, expr, lineNumber);
} }


public InstanceOfExpr(int type, int dim, ASTree expr) {
super(type, dim, expr);
public InstanceOfExpr(int type, int dim, ASTree expr, int lineNumber) {
super(type, dim, expr, lineNumber);
} }


@Override @Override

+ 7
- 3
src/main/javassist/compiler/ast/IntConst.java View File

protected long value; protected long value;
protected int type; protected int type;


public IntConst(long v, int tokenId) { value = v; type = tokenId; }
public IntConst(long v, int tokenId, int lineNumber) {
super(lineNumber);
value = v;
type = tokenId;
}


public long get() { return value; } public long get() { return value; }


return null; return null;
} }


return new IntConst(newValue, newType);
return new IntConst(newValue, newType, right.getLineNumber());
} }


private DoubleConst compute0(int op, DoubleConst right) { private DoubleConst compute0(int op, DoubleConst right) {
return null; return null;
} }


return new DoubleConst(newValue, right.type);
return new DoubleConst(newValue, right.type, right.getLineNumber());
} }
} }

+ 2
- 1
src/main/javassist/compiler/ast/Keyword.java View File

private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
protected int tokenId; protected int tokenId;


public Keyword(int token) {
public Keyword(int token, int lineNumber) {
super(lineNumber);
tokenId = token; tokenId = token;
} }



+ 2
- 2
src/main/javassist/compiler/ast/Member.java View File

// this is used to obtain the value of a static final field. // this is used to obtain the value of a static final field.
private CtField field; private CtField field;


public Member(String name) {
super(name);
public Member(String name, int lineNumber) {
super(name, lineNumber);
field = null; field = null;
} }



+ 2
- 2
src/main/javassist/compiler/ast/MethodDecl.java View File

private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public static final String initName = "<init>"; public static final String initName = "<init>";


public MethodDecl(ASTree _head, ASTList _tail) {
super(_head, _tail);
public MethodDecl(ASTree _head, ASTList _tail, int lineNumber) {
super(_head, _tail, lineNumber);
} }


public boolean isConstructor() { public boolean isConstructor() {

+ 8
- 8
src/main/javassist/compiler/ast/NewExpr.java View File

protected boolean newArray; protected boolean newArray;
protected int arrayType; protected int arrayType;


public NewExpr(ASTList className, ASTList args) {
super(className, new ASTList(args));
public NewExpr(ASTList className, ASTList args, int lineNumber) {
super(className, new ASTList(args, lineNumber), lineNumber);
newArray = false; newArray = false;
arrayType = CLASS; arrayType = CLASS;
} }


public NewExpr(int type, ASTList arraySize, ArrayInit init) {
super(null, new ASTList(arraySize));
public NewExpr(int type, ASTList arraySize, ArrayInit init, int lineNumber) {
super(null, new ASTList(arraySize, lineNumber), lineNumber);
newArray = true; newArray = true;
arrayType = type; arrayType = type;
if (init != null) if (init != null)
append(this, init);
append(this, init, lineNumber);
} }


public static NewExpr makeObjectArray(ASTList className, public static NewExpr makeObjectArray(ASTList className,
ASTList arraySize, ArrayInit init) {
NewExpr e = new NewExpr(className, arraySize);
ASTList arraySize, ArrayInit init, int lineNumber) {
NewExpr e = new NewExpr(className, arraySize, lineNumber);
e.newArray = true; e.newArray = true;
if (init != null) if (init != null)
append(e, init);
append(e, init, lineNumber);


return e; return e;
} }

+ 1
- 0
src/main/javassist/compiler/ast/Pair.java View File

protected ASTree left, right; protected ASTree left, right;


public Pair(ASTree _left, ASTree _right) { public Pair(ASTree _left, ASTree _right) {
super(_left.getLineNumber());
left = _left; left = _left;
right = _right; right = _right;
} }

+ 10
- 10
src/main/javassist/compiler/ast/Stmnt.java View File

private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
protected int operatorId; protected int operatorId;


public Stmnt(int op, ASTree _head, ASTList _tail) {
super(_head, _tail);
public Stmnt(int op, ASTree _head, ASTList _tail, int lineNumber) {
super(_head, _tail, lineNumber);
operatorId = op; operatorId = op;
} }


public Stmnt(int op, ASTree _head) {
super(_head);
public Stmnt(int op, ASTree _head, int lineNumber) {
super(_head, lineNumber);
operatorId = op; operatorId = op;
} }


public Stmnt(int op) {
this(op, null);
public Stmnt(int op, int lineNumber) {
this(op, null, lineNumber);
} }


public static Stmnt make(int op, ASTree oprand1, ASTree oprand2) {
return new Stmnt(op, oprand1, new ASTList(oprand2));
public static Stmnt make(int op, ASTree oprand1, ASTree oprand2, int lineNumber) {
return new Stmnt(op, oprand1, new ASTList(oprand2, lineNumber), lineNumber);
} }


public static Stmnt make(int op, ASTree op1, ASTree op2, ASTree op3) {
return new Stmnt(op, op1, new ASTList(op2, new ASTList(op3)));
public static Stmnt make(int op, ASTree op1, ASTree op2, ASTree op3, int lineNumber) {
return new Stmnt(op, op1, new ASTList(op2, new ASTList(op3, lineNumber), lineNumber), lineNumber);
} }


@Override @Override

+ 2
- 1
src/main/javassist/compiler/ast/StringL.java View File

private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
protected String text; protected String text;


public StringL(String t) {
public StringL(String t, int lineNumber) {
super(lineNumber);
text = t; text = t;
} }



+ 2
- 1
src/main/javassist/compiler/ast/Symbol.java View File

private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
protected String identifier; protected String identifier;


public Symbol(String sym) {
public Symbol(String sym, int lineNumber) {
super(lineNumber);
identifier = sym; identifier = sym;
} }



+ 2
- 2
src/main/javassist/compiler/ast/Variable.java View File

private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
protected Declarator declarator; protected Declarator declarator;


public Variable(String sym, Declarator d) {
super(sym);
public Variable(String sym, Declarator d, int lineNumber) {
super(sym, lineNumber);
declarator = d; declarator = d;
} }



+ 5
- 5
src/main/javassist/expr/Cast.java View File

} }


@Override @Override
public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args)
public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args, int lineNumber)
throws CompileError throws CompileError
{ {
if (gen.getMethodArgsLength(args) != 1) if (gen.getMethodArgsLength(args) != 1)
throw new CompileError(Javac.proceedName throw new CompileError(Javac.proceedName
+ "() cannot take more than one parameter " + "() cannot take more than one parameter "
+ "for cast");
+ "for cast", lineNumber);


gen.atMethodArgs(args, new int[1], new int[1], new String[1]); gen.atMethodArgs(args, new int[1], new int[1], new String[1]);
bytecode.addOpcode(Opcode.CHECKCAST); bytecode.addOpcode(Opcode.CHECKCAST);
bytecode.addIndex(index); bytecode.addIndex(index);
gen.setType(retType);
gen.setType(retType, lineNumber);
} }


@Override @Override
public void setReturnType(JvstTypeChecker c, ASTList args)
public void setReturnType(JvstTypeChecker c, ASTList args, int lineNumber)
throws CompileError throws CompileError
{ {
c.atMethodArgs(args, new int[1], new int[1], new String[1]); c.atMethodArgs(args, new int[1], new int[1], new String[1]);
c.setType(retType);
c.setType(retType, lineNumber);
} }
} }
} }

+ 10
- 10
src/main/javassist/expr/FieldAccess.java View File

} }


@Override @Override
public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args)
public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args, int lineNumber)
throws CompileError throws CompileError
{ {
if (args != null && !gen.isParamListName(args)) if (args != null && !gen.isParamListName(args))
throw new CompileError(Javac.proceedName throw new CompileError(Javac.proceedName
+ "() cannot take a parameter for field reading");
+ "() cannot take a parameter for field reading", lineNumber);


int stack; int stack;
if (isStatic(opcode)) if (isStatic(opcode))
bytecode.add(opcode); bytecode.add(opcode);
bytecode.addIndex(index); bytecode.addIndex(index);
bytecode.growStack(stack); bytecode.growStack(stack);
gen.setType(fieldType);
gen.setType(fieldType, lineNumber);
} }


@Override @Override
public void setReturnType(JvstTypeChecker c, ASTList args)
public void setReturnType(JvstTypeChecker c, ASTList args, int lineNumber)
throws CompileError throws CompileError
{ {
c.setType(fieldType);
c.setType(fieldType, lineNumber);
} }
} }


} }


@Override @Override
public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args)
public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args, int lineNumber)
throws CompileError throws CompileError
{ {
if (gen.getMethodArgsLength(args) != 1) if (gen.getMethodArgsLength(args) != 1)
throw new CompileError(Javac.proceedName throw new CompileError(Javac.proceedName
+ "() cannot take more than one parameter " + "() cannot take more than one parameter "
+ "for field writing");
+ "for field writing", lineNumber);


int stack; int stack;
if (isStatic(opcode)) if (isStatic(opcode))
bytecode.add(opcode); bytecode.add(opcode);
bytecode.addIndex(index); bytecode.addIndex(index);
bytecode.growStack(stack); bytecode.growStack(stack);
gen.setType(CtClass.voidType);
gen.setType(CtClass.voidType, lineNumber);
gen.addNullIfVoid(); gen.addNullIfVoid();
} }


@Override @Override
public void setReturnType(JvstTypeChecker c, ASTList args)
public void setReturnType(JvstTypeChecker c, ASTList args, int lineNumber)
throws CompileError throws CompileError
{ {
c.atMethodArgs(args, new int[1], new int[1], new String[1]); c.atMethodArgs(args, new int[1], new int[1], new String[1]);
c.setType(CtClass.voidType);
c.setType(CtClass.voidType, lineNumber);
c.addNullIfVoid(); c.addNullIfVoid();
} }
} }

+ 5
- 5
src/main/javassist/expr/Instanceof.java View File

} }


@Override @Override
public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args)
public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args, int lineNumber)
throws CompileError throws CompileError
{ {
if (gen.getMethodArgsLength(args) != 1) if (gen.getMethodArgsLength(args) != 1)
throw new CompileError(Javac.proceedName throw new CompileError(Javac.proceedName
+ "() cannot take more than one parameter " + "() cannot take more than one parameter "
+ "for instanceof");
+ "for instanceof", lineNumber);


gen.atMethodArgs(args, new int[1], new int[1], new String[1]); gen.atMethodArgs(args, new int[1], new int[1], new String[1]);
bytecode.addOpcode(Opcode.INSTANCEOF); bytecode.addOpcode(Opcode.INSTANCEOF);
bytecode.addIndex(index); bytecode.addIndex(index);
gen.setType(CtClass.booleanType);
gen.setType(CtClass.booleanType, lineNumber);
} }


@Override @Override
public void setReturnType(JvstTypeChecker c, ASTList args)
public void setReturnType(JvstTypeChecker c, ASTList args, int lineNumber)
throws CompileError throws CompileError
{ {
c.atMethodArgs(args, new int[1], new int[1], new String[1]); c.atMethodArgs(args, new int[1], new int[1], new String[1]);
c.setType(CtClass.booleanType);
c.setType(CtClass.booleanType, lineNumber);
} }
} }
} }

+ 5
- 5
src/main/javassist/expr/NewArray.java View File

} }


@Override @Override
public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args)
public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args, int lineNumber)
throws CompileError throws CompileError
{ {
int num = gen.getMethodArgsLength(args); int num = gen.getMethodArgsLength(args);
if (num != dimension) if (num != dimension)
throw new CompileError(Javac.proceedName throw new CompileError(Javac.proceedName
+ "() with a wrong number of parameters");
+ "() with a wrong number of parameters", lineNumber);


gen.atMethodArgs(args, new int[num], gen.atMethodArgs(args, new int[num],
new int[num], new String[num]); new int[num], new String[num]);
bytecode.growStack(1 - dimension); bytecode.growStack(1 - dimension);
} }


gen.setType(arrayType);
gen.setType(arrayType, lineNumber);
} }


@Override @Override
public void setReturnType(JvstTypeChecker c, ASTList args)
public void setReturnType(JvstTypeChecker c, ASTList args, int lineNumber)
throws CompileError throws CompileError
{ {
c.setType(arrayType);
c.setType(arrayType, lineNumber);
} }
} }
} }

+ 5
- 5
src/main/javassist/expr/NewExpr.java View File

} }


@Override @Override
public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args)
public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args, int lineNumber)
throws CompileError throws CompileError
{ {
bytecode.addOpcode(NEW); bytecode.addOpcode(NEW);
bytecode.addOpcode(DUP); bytecode.addOpcode(DUP);
gen.atMethodCallCore(newType, MethodInfo.nameInit, args, gen.atMethodCallCore(newType, MethodInfo.nameInit, args,
false, true, -1, null); false, true, -1, null);
gen.setType(newType);
gen.setType(newType, lineNumber);
} }


@Override @Override
public void setReturnType(JvstTypeChecker c, ASTList args)
public void setReturnType(JvstTypeChecker c, ASTList args, int lineNumber)
throws CompileError throws CompileError
{ {
c.atMethodCallCore(newType, MethodInfo.nameInit, args);
c.setType(newType);
c.atMethodCallCore(newType, MethodInfo.nameInit, args, lineNumber);
c.setType(newType, lineNumber);
} }
} }
} }

+ 93
- 0
src/test/javassist/LineNumberTest.java View File

package javassist;

import junit.framework.TestCase;

public class LineNumberTest extends TestCase {
private final ClassPool loader = ClassPool.getDefault();
private static int classNumber = 0;

public void testComma() {
doTestCompile(String.join("\n",
"public void run() {",
" return",
"}"), "line 3: syntax error near \" return\n}\"");
}

public void testUndevField() {
doTestCompile(String.join("\n",
"public void run() {",
" foo = 5;",
"}"), "line 2: no such field: foo");
}

public void testUndevMethod() {
doTestCompile(String.join("\n",
"public void run() {",
" foo();",
"}"), "line 2: foo() not found in javassist.LineNumberCompileTest2");
}

public void testException() {
doTestRuntime(String.join("\n",
"public void run() {",
" throw new java.lang.RuntimeException();",
"}"), 0, 5);
}

public void testIf() {
doTestRuntime(String.join("\n",
"public void run() {",
" if (throwException()) {",
" }",
"}"), 1, 5);
}

public void testWhile() {
doTestRuntime(String.join("\n",
"public void run() {",
" while (throwException()) {",
" }",
"}"), 1, 5);
}

public void testFor() {
doTestRuntime(String.join("\n",
"public void run() {",
" for (; throwException(); ) {",
" ",
" }",
"}"), 1, 5);
}

private void doTestCompile(String src, String msg) {
CtClass testClass = loader.makeClass("javassist.LineNumberCompileTest" + classNumber++);
try {
testClass.addMethod(CtMethod.make(src, testClass));
} catch (CannotCompileException e) {
assertEquals(msg, e.getCause().getMessage());
return;
}
fail("should not happen");
}

private void doTestRuntime(String src, int stackOffset, int lineNumber) {
CtClass testClass = loader.makeClass("javassist.LineNumberRuntimeTest" + classNumber++);
String test = String.join("\n",
"private boolean throwException() {",
" throw new java.lang.RuntimeException();",
"}");
try {
testClass.addInterface(loader.get("java.lang.Runnable"));
testClass.addMethod(CtMethod.make(test, testClass));
testClass.addMethod(CtMethod.make(src, testClass));
Class cls = testClass.toClass(LineNumberTest.class);
var runnable = (Runnable) cls.getConstructor().newInstance();
runnable.run();
} catch (Exception e) {
var lineNum = e.getStackTrace()[stackOffset].getLineNumber();
assertEquals("Line number should be right", lineNumber, lineNum);
return;
}
fail("should not happen");
}
}

+ 2
- 2
src/test/javassist/compiler/CompTest.java View File



public void testArgTypesToString() { public void testArgTypesToString() {
String s; String s;
s = TypeChecker.argTypesToString(new int[0], new int[0], new String[0]);
s = TypeChecker.argTypesToString(new int[0], new int[0], new String[0], 0);
assertEquals("()", s); assertEquals("()", s);
s = TypeChecker.argTypesToString(new int[] { TokenId.INT, TokenId.CHAR, TokenId.CLASS }, s = TypeChecker.argTypesToString(new int[] { TokenId.INT, TokenId.CHAR, TokenId.CLASS },
new int[] { 0, 1, 0 }, new int[] { 0, 1, 0 },
new String[] { null, null, "String" });
new String[] { null, null, "String" }, 0);
assertEquals("(int,char[],String)", s); assertEquals("(int,char[],String)", s);
} }



Loading…
Cancel
Save