@@ -71,6 +71,8 @@ public abstract class CtClass { | |||
*/ | |||
public static final String version = "3.30.2-GA"; | |||
private int linesCount = 0; | |||
/** | |||
* Prints the version number and the copyright notice. | |||
* | |||
@@ -1575,6 +1577,14 @@ public abstract class CtClass { | |||
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 | |||
* method does not prune or freeze the class after writing the class |
@@ -69,6 +69,7 @@ public class CtNewConstructor { | |||
Javac compiler = new Javac(declaring); | |||
try { | |||
CtMember obj = compiler.compile(src); | |||
declaring.addLines(src.split("\n").length); | |||
if (obj instanceof CtConstructor) { | |||
// a stack map table has been already created. | |||
return (CtConstructor)obj; |
@@ -77,6 +77,7 @@ public class CtNewMethod { | |||
compiler.recordProceed(delegateObj, delegateMethod); | |||
CtMember obj = compiler.compile(src); | |||
declaring.addLines(src.split("\n").length); | |||
if (obj instanceof CtMethod) | |||
return (CtMethod)obj; | |||
} |
@@ -347,6 +347,20 @@ public class CodeAttribute extends AttributeInfo implements Opcode { | |||
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. | |||
*/ |
@@ -35,7 +35,7 @@ public class LineNumberAttribute extends AttributeInfo { | |||
super(cp, n, in); | |||
} | |||
private LineNumberAttribute(ConstPool cp, byte[] i) { | |||
LineNumberAttribute(ConstPool cp, byte[] i) { | |||
super(cp, tag, i); | |||
} | |||
@@ -0,0 +1,40 @@ | |||
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); | |||
} | |||
} | |||
} |
@@ -121,8 +121,8 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { | |||
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) { | |||
@@ -184,7 +184,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { | |||
/* Expands a simple class name to java.lang.*. | |||
* 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; | |||
/** | |||
@@ -267,13 +267,13 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { | |||
} | |||
@Override | |||
public void atASTList(ASTList n) throws CompileError { fatal(); } | |||
public void atASTList(ASTList n) throws CompileError { fatal(n.getLineNumber()); } | |||
@Override | |||
public void atPair(Pair n) throws CompileError { fatal(); } | |||
public void atPair(Pair n) throws CompileError { fatal(n.getLineNumber()); } | |||
@Override | |||
public void atSymbol(Symbol n) throws CompileError { fatal(); } | |||
public void atSymbol(Symbol n) throws CompileError { fatal(n.getLineNumber()); } | |||
@Override | |||
public void atFieldDecl(FieldDecl field) throws CompileError { | |||
@@ -325,7 +325,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { | |||
hasReturned = true; | |||
} | |||
else | |||
throw new CompileError("no return statement"); | |||
throw new CompileError("no return statement", s.getLineNumber()); | |||
} | |||
private boolean needsSuperCall(Stmnt body) throws CompileError { | |||
@@ -403,7 +403,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { | |||
// LABEL, SWITCH label stament might be null?. | |||
hasReturned = false; | |||
throw new CompileError( | |||
"sorry, not supported statement: TokenId " + op); | |||
"sorry, not supported statement: TokenId " + op, st.getLineNumber()); | |||
} | |||
} | |||
@@ -590,7 +590,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { | |||
if (op == DEFAULT) | |||
defaultPc = bytecode.currentPc(); | |||
else if (op != CASE) | |||
fatal(); | |||
fatal(st.getLineNumber()); | |||
else { | |||
int curPos = bytecode.currentPc(); | |||
long caseLabel; | |||
@@ -638,7 +638,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { | |||
expr = TypeChecker.stripPlusExpr(expr); | |||
if (expr instanceof IntConst) | |||
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) | |||
@@ -658,7 +658,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { | |||
gotoDefaults.add(pc); | |||
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) | |||
@@ -666,7 +666,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { | |||
{ | |||
if (st.head() != null) | |||
throw new CompileError( | |||
"sorry, not support labeled break or continue"); | |||
"sorry, not support labeled break or continue", st.getLineNumber()); | |||
bytecode.addOpcode(Opcode.GOTO); | |||
Integer pc = Integer.valueOf(bytecode.currentPc()); | |||
@@ -718,7 +718,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { | |||
ASTree e = st.getLeft(); | |||
compileExpr(e); | |||
if (exprType != CLASS || arrayDim > 0) | |||
throw new CompileError("bad throw statement"); | |||
throw new CompileError("bad throw statement", st.getLineNumber()); | |||
bytecode.addOpcode(ATHROW); | |||
hasReturned = true; | |||
@@ -736,7 +736,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { | |||
compileExpr(st.head()); | |||
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; | |||
final int var = bc.getMaxLocals(); | |||
@@ -783,7 +783,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { | |||
if (getListSize(breakList) != nbreaks | |||
|| getListSize(continueList) != ncontinues) | |||
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) { | |||
@@ -802,7 +802,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { | |||
@Override | |||
public void atDeclarator(Declarator d) throws CompileError { | |||
d.setLocalVar(getMaxLocals()); | |||
d.setClassName(resolveClassName(d.getClassName())); | |||
d.setClassName(resolveClassName(d.getClassName(), d.getLineNumber())); | |||
int size; | |||
if (is2word(d.getType(), d.getArrayDim())) | |||
@@ -863,7 +863,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { | |||
else | |||
msg = "incompatible type for " + expr.getName(); | |||
throw new CompileError(msg); | |||
throw new CompileError(msg, expr.getLineNumber()); | |||
} | |||
/* op is either =, %=, &=, *=, /=, +=, -=, ^=, |=, <<=, >>=, or >>>=. | |||
@@ -962,7 +962,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { | |||
int token = assignOps[op - MOD_E]; | |||
int k = lookupBinOp(token); | |||
if (k < 0) | |||
fatal(); | |||
fatal(right.getLineNumber()); | |||
atArithBinExpr(expr, token, k, type); | |||
} | |||
@@ -981,9 +981,9 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { | |||
if (!jvmJavaLangString.equals(cname)) | |||
badAssign(expr); | |||
convToString(type, dim); // the value might be null. | |||
convToString(type, dim, expr.getLineNumber()); // the value might be null. | |||
right.accept(this); | |||
convToString(exprType, arrayDim); | |||
convToString(exprType, arrayDim, expr.getLineNumber()); | |||
bytecode.addInvokevirtual(javaLangString, "concat", | |||
"(Ljava/lang/String;)Ljava/lang/String;"); | |||
exprType = CLASS; | |||
@@ -1025,7 +1025,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { | |||
bytecode.write16bit(pc, bytecode.currentPc() - pc + 1); | |||
expr.elseExpr().accept(this); | |||
if (dim1 != arrayDim) | |||
throw new CompileError("type mismatch in ?:"); | |||
throw new CompileError("type mismatch in ?:", expr.getLineNumber()); | |||
bytecode.write16bit(pc2, bytecode.currentPc() - pc2 + 1); | |||
} | |||
@@ -1072,7 +1072,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { | |||
String cname1 = className; | |||
right.accept(this); | |||
if (dim1 != arrayDim) | |||
throw new CompileError("incompatible array types"); | |||
throw new CompileError("incompatible array types", expr.getLineNumber()); | |||
if (token == '+' && dim1 == 0 | |||
&& (type1 == CLASS || exprType == CLASS)) | |||
@@ -1139,7 +1139,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { | |||
= (type2 == CLASS && jvmJavaLangString.equals(className)); | |||
if (type2Is2) | |||
convToString(type2, dim2); | |||
convToString(type2, dim2, expr.getLineNumber()); | |||
if (is2word(type1, dim1)) { | |||
bytecode.addOpcode(DUP_X2); | |||
@@ -1149,11 +1149,11 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { | |||
bytecode.addOpcode(SWAP); | |||
// even if type1 is String, the left operand might be null. | |||
convToString(type1, dim1); | |||
convToString(type1, dim1, expr.getLineNumber()); | |||
bytecode.addOpcode(SWAP); | |||
if (!type2Is2 && !type2IsString) | |||
convToString(type2, dim2); | |||
convToString(type2, dim2, expr.getLineNumber()); | |||
bytecode.addInvokevirtual(javaLangString, "concat", | |||
"(Ljava/lang/String;)Ljava/lang/String;"); | |||
@@ -1162,7 +1162,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { | |||
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"; | |||
if (isRefType(type) || dim > 0) | |||
@@ -1184,7 +1184,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { | |||
bytecode.addInvokestatic(javaLangString, method, | |||
"(C)Ljava/lang/String;"); | |||
else if (type == VOID) | |||
throw new CompileError("void type expression"); | |||
throw new CompileError("void type expression", lineNumber); | |||
else /* INT, BYTE, SHORT */ | |||
bytecode.addInvokestatic(javaLangString, method, | |||
"(I)Ljava/lang/String;"); | |||
@@ -1237,7 +1237,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { | |||
else { // others | |||
expr.accept(this); | |||
if (exprType != BOOLEAN || arrayDim != 0) | |||
throw new CompileError("boolean expr is required"); | |||
throw new CompileError("boolean expr is required", expr.getLineNumber()); | |||
bytecode.addOpcode(branchIf ? IFNE : IFEQ); | |||
} | |||
@@ -1280,7 +1280,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { | |||
expr.oprand2().accept(this); | |||
if (dim1 != arrayDim) | |||
if (type1 != NULL && exprType != NULL) | |||
throw new CompileError("incompatible array types"); | |||
throw new CompileError("incompatible array types", expr.getLineNumber()); | |||
else if (exprType == NULL) | |||
arrayDim = dim1; | |||
@@ -1348,7 +1348,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { | |||
else if (p == P_LONG) | |||
bytecode.addOpcode(LCMP); // 1: >, 0: =, -1: < | |||
else | |||
fatal(); | |||
fatal(expr.getLineNumber()); | |||
int[] op = ifOp2; | |||
for (int i = 0; i < op.length; i += 3) | |||
@@ -1362,7 +1362,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { | |||
} | |||
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; | |||
@@ -1462,7 +1462,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { | |||
bytecode.addOpcode(SWAP); | |||
} | |||
else | |||
fatal(); | |||
fatal(expr.getLineNumber()); | |||
} | |||
else if (op != NOP) | |||
bytecode.addOpcode(op); | |||
@@ -1503,11 +1503,11 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { | |||
int srcDim = arrayDim; | |||
if (invalidDim(srcType, arrayDim, className, type, dim, name, true) | |||
|| srcType == VOID || type == VOID) | |||
throw new CompileError(msg); | |||
throw new CompileError(msg, expr.getLineNumber()); | |||
if (type == CLASS) { | |||
if (!isRefType(srcType) && srcDim == 0) | |||
throw new CompileError(msg); | |||
throw new CompileError(msg, expr.getLineNumber()); | |||
return toJvmArrayName(name, dim); | |||
} | |||
@@ -1591,7 +1591,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { | |||
bytecode.addIconst(0); | |||
} | |||
else if (token == CALL) // method call | |||
fatal(); | |||
fatal(expr.getLineNumber()); | |||
else { | |||
expr.oprand1().accept(this); | |||
int type = typePrecedence(exprType); | |||
@@ -1633,12 +1633,12 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { | |||
// do nothing. ignore. | |||
} | |||
else | |||
fatal(); | |||
fatal(expr.getLineNumber()); | |||
} | |||
} | |||
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 | |||
@@ -1649,14 +1649,14 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { | |||
public void atClassObject(Expr expr) throws CompileError { | |||
ASTree op1 = expr.oprand1(); | |||
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(); | |||
if (cname.startsWith("[")) { | |||
int i = cname.indexOf("[L"); | |||
if (i >= 0) { | |||
String name = cname.substring(i + 2, cname.length() - 1); | |||
String name2 = resolveClassName(name); | |||
String name2 = resolveClassName(name, expr.getLineNumber()); | |||
if (!name.equals(name2)) { | |||
/* For example, to obtain String[].class, | |||
* "[Ljava.lang.String;" (not "[Ljava/lang/String"!) | |||
@@ -1673,7 +1673,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { | |||
} | |||
} | |||
else { | |||
cname = resolveClassName(MemberResolver.javaToJvmName(cname)); | |||
cname = resolveClassName(MemberResolver.javaToJvmName(cname), expr.getLineNumber()); | |||
cname = MemberResolver.jvmToJavaName(cname); | |||
} | |||
@@ -1736,13 +1736,13 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { | |||
int type = exprType; | |||
int dim = arrayDim; | |||
if (dim == 0) | |||
throw new CompileError("bad array access"); | |||
throw new CompileError("bad array access", array.getLineNumber()); | |||
String cname = className; | |||
index.accept(this); | |||
if (typePrecedence(exprType) != P_INT || arrayDim > 0) | |||
throw new CompileError("bad array index"); | |||
throw new CompileError("bad array index", array.getLineNumber()); | |||
exprType = type; | |||
arrayDim = dim - 1; | |||
@@ -1992,7 +1992,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { | |||
case SUPER : | |||
if (inStaticMethod) | |||
throw new CompileError("not-available: " | |||
+ (token == THIS ? "this" : "super")); | |||
+ (token == THIS ? "this" : "super"), k.getLineNumber()); | |||
bytecode.addAload(0); | |||
exprType = CLASS; | |||
@@ -2002,7 +2002,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { | |||
className = getSuperName(); | |||
break; | |||
default : | |||
fatal(); | |||
fatal(k.getLineNumber()); | |||
} | |||
} | |||
@@ -25,12 +25,19 @@ public class CompileError extends Exception { | |||
private Lex lex; | |||
private String reason; | |||
private int lineNumber = -1; | |||
public CompileError(String s, Lex l) { | |||
reason = s; | |||
this(s, l.getLineNumber()); | |||
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; | |||
lex = null; | |||
} | |||
@@ -45,6 +52,10 @@ public class CompileError extends Exception { | |||
public Lex getLex() { return lex; } | |||
public int getLineNumber() { | |||
return lineNumber; | |||
} | |||
@Override | |||
public String getMessage() { | |||
return reason; |
@@ -43,7 +43,7 @@ import javassist.compiler.ast.Stmnt; | |||
import javassist.compiler.ast.Symbol; | |||
public class Javac { | |||
JvstCodeGen gen; | |||
JvstCodeGenWitlLineNumber gen; | |||
SymbolTable stable; | |||
private Bytecode bytecode; | |||
@@ -71,7 +71,7 @@ public class Javac { | |||
* belongs to. | |||
*/ | |||
public Javac(Bytecode b, CtClass thisClass) { | |||
gen = new JvstCodeGen(b, thisClass, thisClass.getClassPool()); | |||
gen = new JvstCodeGenWitlLineNumber(b, thisClass, thisClass.getClassPool()); | |||
stable = new SymbolTable(); | |||
bytecode = b; | |||
} | |||
@@ -94,7 +94,9 @@ public class Javac { | |||
* @see #recordProceed(String,String) | |||
*/ | |||
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); | |||
try { | |||
if (mem instanceof FieldDecl) | |||
@@ -106,11 +108,8 @@ public class Javac { | |||
decl.getClassFile2()); | |||
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()); | |||
} | |||
} | |||
@@ -160,8 +159,9 @@ public class Javac { | |||
gen.getThisClass()); | |||
cons.setModifiers(mod); | |||
md.accept(gen); | |||
cons.getMethodInfo().setCodeAttribute( | |||
bytecode.toCodeAttribute()); | |||
CodeAttribute cattr = bytecode.toCodeAttribute(); | |||
cattr.setAttribute(gen.toLineNumberAttribute()); | |||
cons.getMethodInfo().setCodeAttribute(cattr); | |||
cons.setExceptionTypes(tlist); | |||
return cons; | |||
} | |||
@@ -173,17 +173,18 @@ public class Javac { | |||
method.setModifiers(mod); | |||
gen.setThisMethod(method); | |||
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.setExceptionTypes(tlist); | |||
return method; | |||
} | |||
catch (NotFoundException e) { | |||
throw new CompileError(e.toString()); | |||
throw new CompileError(e.toString(), md.getLineNumber()); | |||
} | |||
} | |||
@@ -219,7 +220,7 @@ public class Javac { | |||
Stmnt s = p.parseStatement(stb); | |||
if (p.hasMore()) | |||
throw new CompileError( | |||
"the method/constructor body must be surrounded by {}"); | |||
"the method/constructor body must be surrounded by {}", s.getLineNumber()); | |||
boolean callSuper = false; | |||
if (method instanceof CtConstructor) | |||
@@ -231,7 +232,7 @@ public class Javac { | |||
return bytecode; | |||
} | |||
catch (NotFoundException e) { | |||
throw new CompileError(e.toString()); | |||
throw new CompileError(e.toString(), -1); | |||
} | |||
} | |||
@@ -443,27 +444,27 @@ public class Javac { | |||
ProceedHandler h = new ProceedHandler() { | |||
@Override | |||
public void doit(JvstCodeGen gen, Bytecode b, ASTList args) | |||
public void doit(JvstCodeGen gen, Bytecode b, ASTList args, int lineNumber) | |||
throws CompileError | |||
{ | |||
ASTree expr = new Member(m); | |||
ASTree expr = new Member(m, texpr.getLineNumber()); | |||
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.addNullIfVoid(); | |||
} | |||
@Override | |||
public void setReturnType(JvstTypeChecker check, ASTList args) | |||
public void setReturnType(JvstTypeChecker check, ASTList args, int lineNumber) | |||
throws CompileError | |||
{ | |||
ASTree expr = new Member(m); | |||
ASTree expr = new Member(m, texpr.getLineNumber()); | |||
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); | |||
check.addNullIfVoid(); | |||
} | |||
@@ -489,23 +490,23 @@ public class Javac { | |||
ProceedHandler h = new ProceedHandler() { | |||
@Override | |||
public void doit(JvstCodeGen gen, Bytecode b, ASTList args) | |||
public void doit(JvstCodeGen gen, Bytecode b, ASTList args, int lineNumber) | |||
throws CompileError | |||
{ | |||
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.addNullIfVoid(); | |||
} | |||
@Override | |||
public void setReturnType(JvstTypeChecker check, ASTList args) | |||
public void setReturnType(JvstTypeChecker check, ASTList args, int lineNumber) | |||
throws CompileError | |||
{ | |||
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); | |||
check.addNullIfVoid(); | |||
} | |||
@@ -535,14 +536,14 @@ public class Javac { | |||
ProceedHandler h = new ProceedHandler() { | |||
@Override | |||
public void doit(JvstCodeGen gen, Bytecode b, ASTList args) | |||
public void doit(JvstCodeGen gen, Bytecode b, ASTList args, int lineNumber) | |||
throws CompileError | |||
{ | |||
gen.compileInvokeSpecial(texpr, methodIndex, descriptor, args); | |||
} | |||
@Override | |||
public void setReturnType(JvstTypeChecker c, ASTList args) | |||
public void setReturnType(JvstTypeChecker c, ASTList args, int lineNumber) | |||
throws CompileError | |||
{ | |||
c.compileInvokeSpecial(texpr, classname, methodname, descriptor, args); |
@@ -110,14 +110,14 @@ public class JvstCodeGen extends MemberCodeGen { | |||
} | |||
else if (name.equals(dollarTypeName)) { | |||
if (dollarType == null) | |||
throw new CompileError(dollarTypeName + " is not available"); | |||
throw new CompileError(dollarTypeName + " is not available", mem.getLineNumber()); | |||
bytecode.addLdc(Descriptor.of(dollarType)); | |||
callGetType("getType"); | |||
} | |||
else if (name.equals(clazzName)) { | |||
if (param0Type == null) | |||
throw new CompileError(clazzName + " is not available"); | |||
throw new CompileError(clazzName + " is not available", mem.getLineNumber()); | |||
bytecode.addLdc(param0Type); | |||
callGetType("getClazz"); | |||
@@ -141,13 +141,13 @@ public class JvstCodeGen extends MemberCodeGen { | |||
if (left instanceof Member | |||
&& ((Member)left).get().equals(paramArrayName)) { | |||
if (op != '=') | |||
throw new CompileError("bad operator for " + paramArrayName); | |||
throw new CompileError("bad operator for " + paramArrayName, expr.getLineNumber()); | |||
right.accept(this); | |||
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) | |||
bytecode.addOpcode(POP); | |||
} | |||
@@ -155,7 +155,7 @@ public class JvstCodeGen extends MemberCodeGen { | |||
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 | |||
{ | |||
if (params == null) | |||
@@ -167,7 +167,7 @@ public class JvstCodeGen extends MemberCodeGen { | |||
code.addOpcode(DUP); | |||
code.addIconst(i); | |||
code.addOpcode(AALOAD); | |||
compileUnwrapValue(params[i], code); | |||
compileUnwrapValue(params[i], code, lineNumber); | |||
code.addStore(varNo, params[i]); | |||
varNo += is2word(exprType, arrayDim) ? 2 : 1; | |||
} | |||
@@ -201,17 +201,17 @@ public class JvstCodeGen extends MemberCodeGen { | |||
protected void atCastToRtype(CastExpr expr) throws CompileError { | |||
expr.getOprand().accept(this); | |||
if (exprType == VOID || isRefType(exprType) || arrayDim > 0) | |||
compileUnwrapValue(returnType, bytecode); | |||
compileUnwrapValue(returnType, bytecode, expr.getLineNumber()); | |||
else if (returnType instanceof CtPrimitiveType) { | |||
CtPrimitiveType pt = (CtPrimitiveType)returnType; | |||
int destType = MemberResolver.descToType(pt.getDescriptor()); | |||
int destType = MemberResolver.descToType(pt.getDescriptor(), expr.getLineNumber()); | |||
atNumCastExpr(exprType, destType); | |||
exprType = destType; | |||
arrayDim = 0; | |||
className = null; | |||
} | |||
else | |||
throw new CompileError("invalid cast"); | |||
throw new CompileError("invalid cast", expr.getLineNumber()); | |||
} | |||
protected void atCastToWrapper(CastExpr expr) throws CompileError { | |||
@@ -219,7 +219,7 @@ public class JvstCodeGen extends MemberCodeGen { | |||
if (isRefType(exprType) || arrayDim > 0) | |||
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) { | |||
CtPrimitiveType pt = (CtPrimitiveType)clazz; | |||
String wrapper = pt.getWrapperName(); | |||
@@ -249,11 +249,11 @@ public class JvstCodeGen extends MemberCodeGen { | |||
if (method instanceof Member) { | |||
String name = ((Member)method).get(); | |||
if (procHandler != null && name.equals(proceedName)) { | |||
procHandler.doit(this, bytecode, (ASTList)expr.oprand2()); | |||
procHandler.doit(this, bytecode, (ASTList)expr.oprand2(), expr.getLineNumber()); | |||
return; | |||
} | |||
else if (name.equals(cflowName)) { | |||
atCflow((ASTList)expr.oprand2()); | |||
atCflow((ASTList)expr.oprand2(), expr.getLineNumber()); | |||
return; | |||
} | |||
} | |||
@@ -263,16 +263,16 @@ public class JvstCodeGen extends MemberCodeGen { | |||
/* To support $cflow(). | |||
*/ | |||
protected void atCflow(ASTList cname) throws CompileError { | |||
protected void atCflow(ASTList cname, int lineNumber) throws CompileError { | |||
StringBuilder sbuf = new StringBuilder(); | |||
if (cname == null || cname.tail() != null) | |||
throw new CompileError("bad " + cflowName); | |||
throw new CompileError("bad " + cflowName, lineNumber); | |||
makeCflowName(sbuf, cname.head()); | |||
String name = sbuf.toString(); | |||
Object[] names = resolver.getClassPool().lookupCflow(name); | |||
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], | |||
"Ljavassist/runtime/Cflow;"); | |||
@@ -305,7 +305,7 @@ public class JvstCodeGen extends MemberCodeGen { | |||
} | |||
} | |||
throw new CompileError("bad " + cflowName); | |||
throw new CompileError("bad " + cflowName, name.getLineNumber()); | |||
} | |||
/* To support $$. ($$) is equivalent to ($1, ..., $n). | |||
@@ -364,7 +364,7 @@ public class JvstCodeGen extends MemberCodeGen { | |||
for (int k = 0; k < n; ++k) { | |||
CtClass p = params[k]; | |||
regno += bytecode.addLoad(regno, p); | |||
setType(p); | |||
setType(p, a.getLineNumber()); | |||
types[i] = exprType; | |||
dims[i] = arrayDim; | |||
cnames[i] = className; | |||
@@ -420,7 +420,7 @@ public class JvstCodeGen extends MemberCodeGen { | |||
atMethodArgs(args, new int[nargs], new int[nargs], | |||
new String[nargs]); | |||
bytecode.addInvokespecial(methodIndex, descriptor); | |||
setReturnType(descriptor, false, false); | |||
setReturnType(descriptor, false, false, target.getLineNumber()); | |||
addNullIfVoid(); | |||
} | |||
@@ -530,7 +530,7 @@ public class JvstCodeGen extends MemberCodeGen { | |||
String varName = prefix + "0"; | |||
Declarator decl | |||
= new Declarator(CLASS, MemberResolver.javaToJvmName(target), | |||
0, varNo++, new Symbol(varName)); | |||
0, varNo++, new Symbol(varName, 0), 0); | |||
tbl.append(varName, decl); | |||
} | |||
@@ -569,11 +569,11 @@ public class JvstCodeGen extends MemberCodeGen { | |||
className = jvmJavaLangObject; | |||
} | |||
else | |||
setType(cc); | |||
setType(cc, cc.getLinesCount()); | |||
Declarator decl | |||
= new Declarator(exprType, className, arrayDim, | |||
varNo, new Symbol(varName)); | |||
varNo, new Symbol(varName, 0), 0); | |||
tbl.append(varName, decl); | |||
return is2word(exprType, arrayDim) ? 2 : 1; | |||
} | |||
@@ -593,7 +593,7 @@ public class JvstCodeGen extends MemberCodeGen { | |||
while ((c = typeDesc.charAt(dim)) == '[') | |||
++dim; | |||
int type = MemberResolver.descToType(c); | |||
int type = MemberResolver.descToType(c, -1); | |||
String cname = null; | |||
if (type == CLASS) { | |||
if (dim == 0) | |||
@@ -603,7 +603,7 @@ public class JvstCodeGen extends MemberCodeGen { | |||
} | |||
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); | |||
} | |||
@@ -653,7 +653,7 @@ public class JvstCodeGen extends MemberCodeGen { | |||
return 8; | |||
} | |||
protected void compileUnwrapValue(CtClass type, Bytecode code) | |||
protected void compileUnwrapValue(CtClass type, Bytecode code, int lineNumber) | |||
throws CompileError | |||
{ | |||
if (type == CtClass.voidType) { | |||
@@ -662,7 +662,7 @@ public class JvstCodeGen extends MemberCodeGen { | |||
} | |||
if (exprType == VOID) | |||
throw new CompileError("invalid type for " + returnCastName); | |||
throw new CompileError("invalid type for " + returnCastName, lineNumber); | |||
if (type instanceof CtPrimitiveType) { | |||
CtPrimitiveType pt = (CtPrimitiveType)type; | |||
@@ -671,34 +671,34 @@ public class JvstCodeGen extends MemberCodeGen { | |||
code.addCheckcast(wrapper); | |||
code.addInvokevirtual(wrapper, pt.getGetMethodName(), | |||
pt.getGetMethodDescriptor()); | |||
setType(type); | |||
setType(type, lineNumber); | |||
} | |||
else { | |||
code.addCheckcast(type); | |||
setType(type); | |||
setType(type, lineNumber); | |||
} | |||
} | |||
/* Sets exprType, arrayDim, and className; | |||
* 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()) { | |||
CtPrimitiveType pt = (CtPrimitiveType)type; | |||
exprType = MemberResolver.descToType(pt.getDescriptor()); | |||
exprType = MemberResolver.descToType(pt.getDescriptor(), lineNumber); | |||
arrayDim = dim; | |||
className = null; | |||
} | |||
else if (type.isArray()) | |||
try { | |||
setType(type.getComponentType(), dim + 1); | |||
setType(type.getComponentType(), dim + 1, lineNumber); | |||
} | |||
catch (NotFoundException e) { | |||
throw new CompileError("undefined type: " + type.getName()); | |||
throw new CompileError("undefined type: " + type.getName(), lineNumber); | |||
} | |||
else { | |||
exprType = CLASS; | |||
@@ -714,9 +714,9 @@ public class JvstCodeGen extends MemberCodeGen { | |||
if (type instanceof CtPrimitiveType) { | |||
CtPrimitiveType pt = (CtPrimitiveType)type; | |||
atNumCastExpr(exprType, | |||
MemberResolver.descToType(pt.getDescriptor())); | |||
MemberResolver.descToType(pt.getDescriptor(), type.getLinesCount() - 1)); | |||
} | |||
else | |||
throw new CompileError("type mismatch"); | |||
throw new CompileError("type mismatch", type.getLinesCount() - 1); | |||
} | |||
} |
@@ -0,0 +1,265 @@ | |||
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); | |||
} | |||
} |
@@ -89,7 +89,7 @@ public class JvstTypeChecker extends TypeChecker { | |||
int n = params.length; | |||
for (int i = 0; i < n; ++i) | |||
compileUnwrapValue(params[i]); | |||
compileUnwrapValue(params[i], expr.getLineNumber()); | |||
} | |||
else | |||
super.atFieldAssign(expr, op, left, right); | |||
@@ -124,10 +124,10 @@ public class JvstTypeChecker extends TypeChecker { | |||
CtClass returnType = codeGen.returnType; | |||
expr.getOprand().accept(this); | |||
if (exprType == VOID || CodeGen.isRefType(exprType) || arrayDim > 0) | |||
compileUnwrapValue(returnType); | |||
compileUnwrapValue(returnType, expr.getLineNumber()); | |||
else if (returnType instanceof CtPrimitiveType) { | |||
CtPrimitiveType pt = (CtPrimitiveType)returnType; | |||
int destType = MemberResolver.descToType(pt.getDescriptor()); | |||
int destType = MemberResolver.descToType(pt.getDescriptor(), expr.getLineNumber()); | |||
exprType = destType; | |||
arrayDim = 0; | |||
className = null; | |||
@@ -139,7 +139,7 @@ public class JvstTypeChecker extends TypeChecker { | |||
if (CodeGen.isRefType(exprType) || arrayDim > 0) | |||
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) { | |||
exprType = CLASS; | |||
arrayDim = 0; | |||
@@ -158,7 +158,7 @@ public class JvstTypeChecker extends TypeChecker { | |||
if (codeGen.procHandler != null | |||
&& name.equals(codeGen.proceedName)) { | |||
codeGen.procHandler.setReturnType(this, | |||
(ASTList)expr.oprand2()); | |||
(ASTList)expr.oprand2(), expr.getLineNumber()); | |||
return; | |||
} | |||
else if (name.equals(JvstCodeGen.cflowName)) { | |||
@@ -223,7 +223,7 @@ public class JvstTypeChecker extends TypeChecker { | |||
int n = params.length; | |||
for (int k = 0; k < n; ++k) { | |||
CtClass p = params[k]; | |||
setType(p); | |||
setType(p, a.getLineNumber()); | |||
types[i] = exprType; | |||
dims[i] = arrayDim; | |||
cnames[i] = className; | |||
@@ -254,38 +254,38 @@ public class JvstTypeChecker extends TypeChecker { | |||
int nargs = getMethodArgsLength(args); | |||
atMethodArgs(args, new int[nargs], new int[nargs], | |||
new String[nargs]); | |||
setReturnType(descriptor); | |||
setReturnType(descriptor, target.getLineNumber()); | |||
addNullIfVoid(); | |||
} | |||
protected void compileUnwrapValue(CtClass type) throws CompileError | |||
protected void compileUnwrapValue(CtClass type, int lineNumber) throws CompileError | |||
{ | |||
if (type == CtClass.voidType) | |||
addNullIfVoid(); | |||
else | |||
setType(type); | |||
setType(type, lineNumber); | |||
} | |||
/* Sets exprType, arrayDim, and className; | |||
* 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()) { | |||
CtPrimitiveType pt = (CtPrimitiveType)type; | |||
exprType = MemberResolver.descToType(pt.getDescriptor()); | |||
exprType = MemberResolver.descToType(pt.getDescriptor(), lineNumber); | |||
arrayDim = dim; | |||
className = null; | |||
} | |||
else if (type.isArray()) | |||
try { | |||
setType(type.getComponentType(), dim + 1); | |||
setType(type.getComponentType(), dim + 1, lineNumber); | |||
} | |||
catch (NotFoundException e) { | |||
throw new CompileError("undefined type: " + type.getName()); | |||
throw new CompileError("undefined type: " + type.getName(), lineNumber); | |||
} | |||
else { | |||
exprType = CLASS; |
@@ -39,6 +39,10 @@ public class Lex implements TokenId { | |||
* Constructs a lexical analyzer. | |||
*/ | |||
public Lex(String s) { | |||
this(s, 0); | |||
} | |||
Lex(String s, int startLineNumber) { | |||
lastChar = -1; | |||
textBuffer = new StringBuilder(); | |||
currentToken = new Token(); | |||
@@ -47,7 +51,7 @@ public class Lex implements TokenId { | |||
input = s; | |||
position = 0; | |||
maxlen = s.length(); | |||
lineNumber = 0; | |||
lineNumber = startLineNumber; | |||
} | |||
public int get() { | |||
@@ -163,7 +167,8 @@ public class Lex implements TokenId { | |||
ungetc(c); | |||
c = '/'; | |||
} | |||
} | |||
} else if (c == '\n') | |||
++lineNumber; | |||
} while(isBlank(c)); | |||
return c; | |||
} | |||
@@ -529,4 +534,8 @@ public class Lex implements TokenId { | |||
lastChar = -1; | |||
return c; | |||
} | |||
public int getLineNumber() { | |||
return lineNumber + 1; | |||
} | |||
} |
@@ -234,7 +234,7 @@ public class MemberCodeGen extends CodeGen { | |||
body.accept(this); | |||
int end = bc.currentPc(); | |||
if (start == end) | |||
throw new CompileError("empty try block"); | |||
throw new CompileError("empty try block", st.getLineNumber()); | |||
boolean tryNotReturn = !hasReturned; | |||
if (tryNotReturn) { | |||
@@ -254,7 +254,7 @@ public class MemberCodeGen extends CodeGen { | |||
decl.setLocalVar(var); | |||
CtClass type = resolver.lookupClassByJvmName(decl.getClassName()); | |||
CtClass type = resolver.lookupClassByJvmName(decl.getClassName(), st.getLineNumber()); | |||
decl.setClassName(MemberResolver.javaToJvmName(type.getName())); | |||
bc.addExceptionHandler(start, end, bc.currentPc(), type); | |||
bc.growStack(1); | |||
@@ -346,21 +346,21 @@ public class MemberCodeGen extends CodeGen { | |||
if (init != null) | |||
throw new CompileError( | |||
"sorry, multi-dimensional array initializer " + | |||
"for new is not supported"); | |||
"for new is not supported", expr.getLineNumber()); | |||
atMultiNewArray(type, classname, size); | |||
return; | |||
} | |||
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, | |||
String jvmClassname, ArrayInit init) throws CompileError { | |||
String jvmClassname, ArrayInit init, int lineNumber) throws CompileError { | |||
if (init == null) | |||
if (sizeExpr == null) | |||
throw new CompileError("no array size"); | |||
throw new CompileError("no array size", lineNumber); | |||
else | |||
sizeExpr.accept(this); | |||
else | |||
@@ -369,11 +369,11 @@ public class MemberCodeGen extends CodeGen { | |||
bytecode.addIconst(s); | |||
} | |||
else | |||
throw new CompileError("unnecessary array size specified for new"); | |||
throw new CompileError("unnecessary array size specified for new", lineNumber); | |||
String elementClass; | |||
if (type == CLASS) { | |||
elementClass = resolveClassName(jvmClassname); | |||
elementClass = resolveClassName(jvmClassname, lineNumber); | |||
bytecode.addAnewarray(MemberResolver.jvmToJavaName(elementClass)); | |||
} | |||
else { | |||
@@ -405,7 +405,7 @@ public class MemberCodeGen extends CodeGen { | |||
atype = T_LONG; | |||
break; | |||
default : | |||
badNewExpr(); | |||
badNewExpr(lineNumber); | |||
break; | |||
} | |||
@@ -433,19 +433,19 @@ public class MemberCodeGen extends CodeGen { | |||
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 | |||
protected void atArrayVariableAssign(ArrayInit init, int varType, | |||
int varArray, String varClass) throws CompileError { | |||
atNewArrayExpr2(varType, null, varClass, init); | |||
atNewArrayExpr2(varType, null, varClass, init, init.getLineNumber()); | |||
} | |||
@Override | |||
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) | |||
@@ -461,7 +461,7 @@ public class MemberCodeGen extends CodeGen { | |||
++count; | |||
s.accept(this); | |||
if (exprType != INT) | |||
throw new CompileError("bad type for array size"); | |||
throw new CompileError("bad type for array size", classname.getLineNumber()); | |||
} | |||
String desc; | |||
@@ -503,7 +503,7 @@ public class MemberCodeGen extends CodeGen { | |||
mname = MethodInfo.nameInit; // <init> | |||
targetClass = thisClass; | |||
if (inStaticMethod) | |||
throw new CompileError("a constructor cannot be static"); | |||
throw new CompileError("a constructor cannot be static", expr.getLineNumber()); | |||
bytecode.addAload(0); // this | |||
if (((Keyword)method).get() == SUPER) | |||
@@ -515,7 +515,7 @@ public class MemberCodeGen extends CodeGen { | |||
int op = e.getOperator(); | |||
if (op == MEMBER) { // static method | |||
targetClass | |||
= resolver.lookupClass(((Symbol)e.oprand1()).get(), false); | |||
= resolver.lookupClass(((Symbol)e.oprand1()).get(), false, expr.getLineNumber()); | |||
isStatic = true; | |||
} | |||
else if (op == '.') { | |||
@@ -552,25 +552,25 @@ public class MemberCodeGen extends CodeGen { | |||
} | |||
if (arrayDim > 0) | |||
targetClass = resolver.lookupClass(javaLangObject, true); | |||
targetClass = resolver.lookupClass(javaLangObject, true, expr.getLineNumber()); | |||
else if (exprType == CLASS /* && arrayDim == 0 */) | |||
targetClass = resolver.lookupClassByJvmName(className); | |||
targetClass = resolver.lookupClassByJvmName(className, expr.getLineNumber()); | |||
else | |||
badMethod(); | |||
badMethod(e.getLineNumber()); | |||
} | |||
} | |||
else | |||
badMethod(); | |||
badMethod(expr.getLineNumber()); | |||
} | |||
else | |||
fatal(); | |||
fatal(expr.getLineNumber()); | |||
atMethodCallCore(targetClass, mname, args, isStatic, isSpecial, | |||
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); | |||
} | |||
/* | |||
@@ -612,7 +612,7 @@ public class MemberCodeGen extends CodeGen { | |||
msg = "Method " + mname + " not found in " | |||
+ targetClass.getName(); | |||
throw new CompileError(msg); | |||
throw new CompileError(msg, args.getLineNumber()); | |||
} | |||
atMethodCallCore2(targetClass, mname, isStatic, isSpecial, | |||
@@ -645,7 +645,7 @@ public class MemberCodeGen extends CodeGen { | |||
if (mname.equals(MethodInfo.nameInit)) { | |||
isSpecial = true; | |||
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.getClassFile().getMajorVersion() < ClassFile.JAVA_8 | |||
@@ -701,12 +701,12 @@ public class MemberCodeGen extends CodeGen { | |||
} | |||
else | |||
if (isStatic) | |||
throw new CompileError(mname + " is not static"); | |||
throw new CompileError(mname + " is not static", targetClass.getLinesCount() - 1); | |||
else | |||
bytecode.addInvokevirtual(declClass, mname, desc); | |||
} | |||
setReturnType(desc, isStatic, popTarget); | |||
setReturnType(desc, isStatic, popTarget, targetClass.getLinesCount() - 1); | |||
} | |||
/* | |||
@@ -729,7 +729,7 @@ public class MemberCodeGen extends CodeGen { | |||
} | |||
throw new CompileError("Method " + methodName | |||
+ " is private"); | |||
+ " is private", declClass.getLinesCount() - 1); | |||
} | |||
/* | |||
@@ -752,7 +752,7 @@ public class MemberCodeGen extends CodeGen { | |||
} | |||
throw new CompileError("the called constructor is private in " | |||
+ declClass.getName()); | |||
+ declClass.getName(), declClass.getLinesCount() - 1); | |||
} | |||
private boolean isEnclosing(CtClass outer, CtClass inner) { | |||
@@ -785,12 +785,12 @@ public class MemberCodeGen extends CodeGen { | |||
} | |||
} | |||
void setReturnType(String desc, boolean isStatic, boolean popTarget) | |||
void setReturnType(String desc, boolean isStatic, boolean popTarget, int lineNumber) | |||
throws CompileError | |||
{ | |||
int i = desc.indexOf(')'); | |||
if (i < 0) | |||
badMethod(); | |||
badMethod(lineNumber); | |||
char c = desc.charAt(++i); | |||
int dim = 0; | |||
@@ -803,13 +803,13 @@ public class MemberCodeGen extends CodeGen { | |||
if (c == 'L') { | |||
int j = desc.indexOf(';', i + 1); | |||
if (j < 0) | |||
badMethod(); | |||
badMethod(lineNumber); | |||
exprType = CLASS; | |||
className = desc.substring(i + 1, j); | |||
} | |||
else { | |||
exprType = MemberResolver.descToType(c); | |||
exprType = MemberResolver.descToType(c, lineNumber); | |||
className = null; | |||
} | |||
@@ -843,15 +843,15 @@ public class MemberCodeGen extends CodeGen { | |||
int fi; | |||
if (op == '=') { | |||
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) | |||
fi = addFieldrefInfo(f, finfo); | |||
else | |||
fi = 0; | |||
} | |||
else | |||
fi = atFieldRead(f, is_static); | |||
fi = atFieldRead(f, is_static, expr.getLineNumber()); | |||
int fType = exprType; | |||
int fDim = arrayDim; | |||
@@ -921,18 +921,18 @@ public class MemberCodeGen extends CodeGen { | |||
} | |||
boolean is_static = resultStatic; | |||
ASTree cexpr = TypeChecker.getConstantFieldValue(f); | |||
ASTree cexpr = TypeChecker.getConstantFieldValue(f, expr.getLineNumber()); | |||
if (cexpr == null) | |||
atFieldRead(f, is_static); | |||
atFieldRead(f, is_static,expr.getLineNumber() ); | |||
else { | |||
cexpr.accept(this); | |||
setFieldType(f.getFieldInfo2()); | |||
setFieldType(f.getFieldInfo2(), expr.getLineNumber()); | |||
} | |||
} | |||
private void atArrayLength(ASTree expr) throws CompileError { | |||
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); | |||
exprType = INT; | |||
@@ -944,10 +944,10 @@ public class MemberCodeGen extends CodeGen { | |||
* It returns a fieldref_info index or zero if the field is a private | |||
* 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(); | |||
boolean is2byte = setFieldType(finfo); | |||
AccessorMaker maker = isAccessibleField(f, finfo); | |||
boolean is2byte = setFieldType(finfo, lineNumber); | |||
AccessorMaker maker = isAccessibleField(f, finfo, lineNumber); | |||
if (maker != null) { | |||
MethodInfo minfo = maker.getFieldGetter(finfo, isStatic); | |||
bytecode.addInvokestatic(f.getDeclaringClass(), minfo.getName(), | |||
@@ -973,7 +973,7 @@ public class MemberCodeGen extends CodeGen { | |||
* an exception or it returns AccessorMaker if the field is a private | |||
* one declared in an enclosing class. | |||
*/ | |||
private AccessorMaker isAccessibleField(CtField f, FieldInfo finfo) | |||
private AccessorMaker isAccessibleField(CtField f, FieldInfo finfo, int lineNumber) | |||
throws CompileError | |||
{ | |||
if (AccessFlag.isPrivate(finfo.getAccessFlags()) | |||
@@ -985,7 +985,7 @@ public class MemberCodeGen extends CodeGen { | |||
return maker; | |||
} | |||
throw new CompileError("Field " + f.getName() + " in " | |||
+ declClass.getName() + " is private."); | |||
+ declClass.getName() + " is private.", lineNumber); | |||
} | |||
return null; // accessible field | |||
@@ -996,7 +996,7 @@ public class MemberCodeGen extends CodeGen { | |||
* | |||
* @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(); | |||
int i = 0; | |||
@@ -1008,7 +1008,7 @@ public class MemberCodeGen extends CodeGen { | |||
} | |||
arrayDim = dim; | |||
exprType = MemberResolver.descToType(c); | |||
exprType = MemberResolver.descToType(c, lineNumber); | |||
if (c == 'L') | |||
className = type.substring(i + 1, type.indexOf(';', i + 1)); | |||
@@ -1046,7 +1046,7 @@ public class MemberCodeGen extends CodeGen { | |||
if (!is_static) | |||
bytecode.addOpcode(DUP); | |||
int fi = atFieldRead(f, is_static); | |||
int fi = atFieldRead(f, is_static, oprand.getLineNumber()); | |||
int t = exprType; | |||
boolean is2w = is2word(t, arrayDim); | |||
@@ -1082,7 +1082,7 @@ public class MemberCodeGen extends CodeGen { | |||
if (!is_static) | |||
if (inStaticMethod) | |||
throw new CompileError( | |||
"not available in a static method: " + name); | |||
"not available in a static method: " + name, expr.getLineNumber()); | |||
else | |||
bytecode.addAload(0); // this | |||
@@ -1117,7 +1117,7 @@ public class MemberCodeGen extends CodeGen { | |||
&& ((Symbol)e.oprand2()).get().equals("length")) | |||
return null; // expr is an array length. | |||
else | |||
badLvalue(); | |||
badLvalue(expr.getLineNumber()); | |||
boolean is_static = Modifier.isStatic(f.getModifiers()); | |||
if (is_static) | |||
@@ -1142,17 +1142,17 @@ public class MemberCodeGen extends CodeGen { | |||
} | |||
} | |||
else | |||
badLvalue(); | |||
badLvalue(expr.getLineNumber()); | |||
} | |||
else | |||
badLvalue(); | |||
badLvalue(expr.getLineNumber()); | |||
resultStatic = false; | |||
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 { | |||
@@ -1201,7 +1201,7 @@ public class MemberCodeGen extends CodeGen { | |||
* For example, this converts Object into java/lang/Object. | |||
*/ | |||
@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); | |||
} | |||
} |
@@ -50,8 +50,8 @@ public class MemberResolver implements TokenId { | |||
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 { | |||
@@ -85,7 +85,7 @@ public class MemberResolver implements TokenId { | |||
if (current != null && clazz == currentClass) | |||
if (current.getName().equals(methodName)) { | |||
int res = compareSignature(current.getDescriptor(), | |||
argTypes, argDims, argClassNames); | |||
argTypes, argDims, argClassNames, currentClass.getLinesCount() - 1); | |||
if (res != NO) { | |||
Method r = new Method(clazz, current, res); | |||
if (res == YES) | |||
@@ -116,7 +116,7 @@ public class MemberResolver implements TokenId { | |||
if (minfo.getName().equals(methodName) | |||
&& (minfo.getAccessFlags() & AccessFlag.BRIDGE) == 0) { | |||
int res = compareSignature(minfo.getDescriptor(), | |||
argTypes, argDims, argClassNames); | |||
argTypes, argDims, argClassNames, clazz.getLinesCount() - 1); | |||
if (res != NO) { | |||
Method r = new Method(clazz, minfo, res); | |||
if (res == YES) | |||
@@ -199,7 +199,7 @@ public class MemberResolver implements TokenId { | |||
* of parameter types that do not exactly match. | |||
*/ | |||
private int compareSignature(String desc, int[] argTypes, | |||
int[] argDims, String[] argClassNames) | |||
int[] argDims, String[] argClassNames, int lineNumber) | |||
throws CompileError | |||
{ | |||
int result = YES; | |||
@@ -247,9 +247,9 @@ public class MemberResolver implements TokenId { | |||
String cname = desc.substring(i, j); | |||
if (!cname.equals(argClassNames[n])) { | |||
CtClass clazz = lookupClassByJvmName(argClassNames[n]); | |||
CtClass clazz = lookupClassByJvmName(argClassNames[n], lineNumber); | |||
try { | |||
if (clazz.subtypeOf(lookupClassByJvmName(cname))) | |||
if (clazz.subtypeOf(lookupClassByJvmName(cname, lineNumber))) | |||
result++; | |||
else | |||
return NO; | |||
@@ -262,7 +262,7 @@ public class MemberResolver implements TokenId { | |||
i = j + 1; | |||
} | |||
else { | |||
int t = descToType(c); | |||
int t = descToType(c, lineNumber); | |||
int at = argTypes[n]; | |||
if (t != at) | |||
if (t == INT | |||
@@ -280,7 +280,7 @@ public class MemberResolver implements TokenId { | |||
* Only used by fieldAccess() in MemberCodeGen and TypeChecker. | |||
* | |||
* @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, | |||
ASTree expr) throws NoFieldException | |||
@@ -288,7 +288,7 @@ public class MemberResolver implements TokenId { | |||
String field = fieldSym.get(); | |||
CtClass cc = null; | |||
try { | |||
cc = lookupClass(jvmToJavaName(jvmClassName), true); | |||
cc = lookupClass(jvmToJavaName(jvmClassName), true, expr.getLineNumber()); | |||
} | |||
catch (CompileError e) { | |||
// EXPR might be part of a qualified class name. | |||
@@ -320,55 +320,56 @@ public class MemberResolver implements TokenId { | |||
public CtField lookupField(String className, Symbol fieldName) | |||
throws CompileError | |||
{ | |||
CtClass cc = lookupClass(className, false); | |||
CtClass cc = lookupClass(className, false, fieldName.getLineNumber()); | |||
try { | |||
return cc.getField(fieldName.get()); | |||
} | |||
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 { | |||
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 { | |||
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 | |||
{ | |||
String cname = ""; | |||
CtClass clazz; | |||
if (type == CLASS) { | |||
clazz = lookupClassByJvmName(classname); | |||
clazz = lookupClassByJvmName(classname, lineNumber); | |||
if (dim > 0) | |||
cname = clazz.getName(); | |||
else | |||
return clazz; | |||
} | |||
else | |||
cname = getTypeName(type); | |||
cname = getTypeName(type, lineNumber); | |||
while (dim-- > 0) | |||
cname += "[]"; | |||
return lookupClass(cname, false); | |||
return lookupClass(cname, false, lineNumber); | |||
} | |||
/* | |||
* type cannot be CLASS | |||
*/ | |||
static String getTypeName(int type) throws CompileError { | |||
static String getTypeName(int type, int lineNumber) throws CompileError { | |||
String cname = ""; | |||
switch (type) { | |||
case BOOLEAN : | |||
@@ -399,22 +400,23 @@ public class MemberResolver implements TokenId { | |||
cname = "void"; | |||
break; | |||
default : | |||
fatal(); | |||
fatal(lineNumber); | |||
} | |||
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 | |||
{ | |||
Map<String,String> cache = getInvalidNames(); | |||
String found = cache.get(name); | |||
if (found == INVALID) | |||
throw new CompileError("no such class: " + name); | |||
throw new CompileError("no such class: " + name, lineNumber); | |||
else if (found != null) | |||
try { | |||
return classPool.get(found); | |||
@@ -426,7 +428,7 @@ public class MemberResolver implements TokenId { | |||
cc = lookupClass0(name, notCheckInner); | |||
} | |||
catch (NotFoundException e) { | |||
cc = searchImports(name); | |||
cc = searchImports(name, lineNumber); | |||
} | |||
cache.put(name, cc.getName()); | |||
@@ -461,7 +463,7 @@ public class MemberResolver implements TokenId { | |||
return ht; | |||
} | |||
private CtClass searchImports(String orgName) | |||
private CtClass searchImports(String orgName, int lineNumber) | |||
throws CompileError | |||
{ | |||
if (orgName.indexOf('.') < 0) { | |||
@@ -483,7 +485,7 @@ public class MemberResolver implements TokenId { | |||
} | |||
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) | |||
@@ -520,10 +522,10 @@ public class MemberResolver implements TokenId { | |||
/* Expands a simple class name to java.lang.*. | |||
* 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) | |||
return null; | |||
return javaToJvmName(lookupClassByJvmName(jvmName).getName()); | |||
return javaToJvmName(lookupClassByJvmName(jvmName, lineNumber).getName()); | |||
} | |||
public static CtClass getSuperclass(CtClass c) throws CompileError { | |||
@@ -534,7 +536,7 @@ public class MemberResolver implements TokenId { | |||
} | |||
catch (NotFoundException e) {} | |||
throw new CompileError("cannot find the super class of " | |||
+ c.getName()); | |||
+ c.getName(), c.getLinesCount() - 1); | |||
} | |||
public static CtClass getSuperInterface(CtClass c, String interfaceName) | |||
@@ -547,7 +549,7 @@ public class MemberResolver implements TokenId { | |||
return intfs[i]; | |||
} catch (NotFoundException e) {} | |||
throw new CompileError("cannot find the super interface " + interfaceName | |||
+ " of " + c.getName()); | |||
+ " of " + c.getName(), c.getLinesCount() - 1); | |||
} | |||
public static String javaToJvmName(String classname) { | |||
@@ -558,7 +560,7 @@ public class MemberResolver implements TokenId { | |||
return classname.replace('/', '.'); | |||
} | |||
public static int descToType(char c) throws CompileError { | |||
public static int descToType(char c, int lineNumber) throws CompileError { | |||
switch (c) { | |||
case 'Z' : | |||
return BOOLEAN; | |||
@@ -582,7 +584,7 @@ public class MemberResolver implements TokenId { | |||
case '[' : | |||
return CLASS; | |||
default : | |||
fatal(); | |||
fatal(lineNumber); | |||
return VOID; // never reach here | |||
} | |||
} |
@@ -27,7 +27,7 @@ public class NoFieldException extends CompileError { | |||
/* NAME must be JVM-internal representation. | |||
*/ | |||
public NoFieldException(String name, ASTree e) { | |||
super("no such field: " + name); | |||
super("no such field: " + name, e.getLineNumber()); | |||
fieldName = name; | |||
expr = e; | |||
} |
@@ -66,7 +66,7 @@ public final class Parser implements TokenId { | |||
Declarator d; | |||
boolean isConstructor = false; | |||
if (lex.lookAhead() == Identifier && lex.lookAhead(1) == '(') { | |||
d = new Declarator(VOID, 0); | |||
d = new Declarator(VOID, 0, lex.getLineNumber()); | |||
isConstructor = true; | |||
} | |||
else | |||
@@ -81,7 +81,7 @@ public final class Parser implements TokenId { | |||
else | |||
name = lex.getString(); | |||
d.setVariable(new Symbol(name)); | |||
d.setVariable(new Symbol(name, lex.getLineNumber())); | |||
if (isConstructor || lex.lookAhead() == '(') | |||
return parseMethod1(tbl, isConstructor, mods, d); | |||
return parseField(tbl, mods, d); | |||
@@ -103,7 +103,7 @@ public final class Parser implements TokenId { | |||
int c = lex.get(); | |||
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 == ',') | |||
throw new CompileError( | |||
"only one field can be declared in one declaration", lex); | |||
@@ -131,7 +131,7 @@ public final class Parser implements TokenId { | |||
ASTList parms = null; | |||
if (lex.lookAhead() != ')') | |||
while (true) { | |||
parms = ASTList.append(parms, parseFormalParam(tbl)); | |||
parms = ASTList.append(parms, parseFormalParam(tbl), lex.getLineNumber()); | |||
int t = lex.lookAhead(); | |||
if (t == ',') | |||
lex.get(); | |||
@@ -148,7 +148,7 @@ public final class Parser implements TokenId { | |||
if (lex.lookAhead() == THROWS) { | |||
lex.get(); | |||
while (true) { | |||
throwsList = ASTList.append(throwsList, parseClassType(tbl)); | |||
throwsList = ASTList.append(throwsList, parseClassType(tbl), lex.getLineNumber()); | |||
if (lex.lookAhead() == ',') | |||
lex.get(); | |||
else | |||
@@ -157,7 +157,7 @@ public final class Parser implements TokenId { | |||
} | |||
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. | |||
@@ -171,7 +171,7 @@ public final class Parser implements TokenId { | |||
else { | |||
body = parseBlock(tbl); | |||
if (body == null) | |||
body = new Stmnt(BLOCK); | |||
body = new Stmnt(BLOCK, lex.getLineNumber()); | |||
} | |||
md.sublist(4).setHead(body); | |||
@@ -191,7 +191,7 @@ public final class Parser implements TokenId { | |||
if (t == ABSTRACT || t == FINAL || t == PUBLIC || t == PROTECTED | |||
|| t == PRIVATE || t == SYNCHRONIZED || t == STATIC | |||
|| 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 | |||
break; | |||
} | |||
@@ -206,11 +206,11 @@ public final class Parser implements TokenId { | |||
if (isBuiltinType(t) || t == VOID) { | |||
lex.get(); // primitive type | |||
int dim = parseArrayDimension(); | |||
return new Declarator(t, dim); | |||
return new Declarator(t, dim, lex.getLineNumber()); | |||
} | |||
ASTList name = parseClassType(tbl); | |||
int dim = parseArrayDimension(); | |||
return new Declarator(name, dim); | |||
return new Declarator(name, dim, lex.getLineNumber()); | |||
} | |||
private static boolean isBuiltinType(int t) { | |||
@@ -228,7 +228,7 @@ public final class Parser implements TokenId { | |||
throw new SyntaxError(lex); | |||
String name = lex.getString(); | |||
d.setVariable(new Symbol(name)); | |||
d.setVariable(new Symbol(name, lex.getLineNumber())); | |||
d.addArrayDim(parseArrayDimension()); | |||
tbl.append(name, d); | |||
return d; | |||
@@ -261,13 +261,13 @@ public final class Parser implements TokenId { | |||
return parseBlock(tbl); | |||
else if (t == ';') { | |||
lex.get(); | |||
return new Stmnt(BLOCK); // empty statement | |||
return new Stmnt(BLOCK, lex.getLineNumber()); // empty statement | |||
} | |||
else if (t == Identifier && lex.lookAhead(1) == ':') { | |||
lex.get(); // Identifier | |||
String label = lex.getString(); | |||
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) | |||
return parseIf(tbl); | |||
@@ -298,20 +298,22 @@ public final class Parser implements TokenId { | |||
/* block.statement : "{" statement* "}" | |||
*/ | |||
private Stmnt parseBlock(SymbolTable tbl) throws CompileError { | |||
int blockLineNumber = lex.getLineNumber(); | |||
if (lex.get() != '{') | |||
throw new SyntaxError(lex); | |||
Stmnt body = null; | |||
SymbolTable tbl2 = new SymbolTable(tbl); | |||
while (lex.lookAhead() != '}') { | |||
int lineNumber = lex.getLineNumber(); | |||
Stmnt s = parseStatement(tbl2); | |||
if (s != null) | |||
body = (Stmnt)ASTList.concat(body, new Stmnt(BLOCK, s)); | |||
body = (Stmnt)ASTList.concat(body, new Stmnt(BLOCK, s, lineNumber)); | |||
} | |||
lex.get(); // '}' | |||
if (body == null) | |||
return new Stmnt(BLOCK); // empty block | |||
return new Stmnt(BLOCK, blockLineNumber); // empty block | |||
return body; | |||
} | |||
@@ -321,7 +323,9 @@ public final class Parser implements TokenId { | |||
private Stmnt parseIf(SymbolTable tbl) throws CompileError { | |||
int t = lex.get(); // IF | |||
ASTree expr = parseParExpression(tbl); | |||
int exprLineNum = lex.getLineNumber(); | |||
Stmnt thenp = parseStatement(tbl); | |||
int thenLineNum = lex.getLineNumber(); | |||
Stmnt elsep; | |||
if (lex.lookAhead() == ELSE) { | |||
lex.get(); | |||
@@ -330,7 +334,7 @@ public final class Parser implements TokenId { | |||
else | |||
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 | |||
@@ -340,8 +344,9 @@ public final class Parser implements TokenId { | |||
{ | |||
int t = lex.get(); // WHILE | |||
ASTree expr = parseParExpression(tbl); | |||
int lineNumber = lex.getLineNumber(); | |||
Stmnt body = parseStatement(tbl); | |||
return new Stmnt(t, expr, body); | |||
return new Stmnt(t, expr, body, lineNumber); | |||
} | |||
/* do.statement : DO statement WHILE "(" expression ")" ";" | |||
@@ -356,7 +361,7 @@ public final class Parser implements TokenId { | |||
if (lex.get() != ')' || lex.get() != ';') | |||
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 ")" | |||
@@ -372,6 +377,7 @@ public final class Parser implements TokenId { | |||
if (lex.get() != '(') | |||
throw new SyntaxError(lex); | |||
int expr1LineNumber = lex.getLineNumber(); | |||
if (lex.lookAhead() == ';') { | |||
lex.get(); | |||
expr1 = null; | |||
@@ -379,6 +385,7 @@ public final class Parser implements TokenId { | |||
else | |||
expr1 = parseDeclarationOrExpression(tbl2, true); | |||
int expr2LineNumber = lex.getLineNumber(); | |||
if (lex.lookAhead() == ';') | |||
expr2 = null; | |||
else | |||
@@ -387,6 +394,7 @@ public final class Parser implements TokenId { | |||
if (lex.get() != ';') | |||
throw new CompileError("; is missing", lex); | |||
int expr3LineNumber = lex.getLineNumber(); | |||
if (lex.lookAhead() == ')') | |||
expr3 = null; | |||
else | |||
@@ -397,7 +405,7 @@ public final class Parser implements TokenId { | |||
Stmnt body = parseStatement(tbl2); | |||
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 "}" | |||
@@ -411,7 +419,7 @@ public final class Parser implements TokenId { | |||
int t = lex.get(); // SWITCH | |||
ASTree expr = parseParExpression(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 { | |||
@@ -428,17 +436,17 @@ public final class Parser implements TokenId { | |||
throw new CompileError("no case or default in a switch block", | |||
lex); | |||
Stmnt body = new Stmnt(BLOCK, s); | |||
Stmnt body = new Stmnt(BLOCK, s, lex.getLineNumber()); | |||
while (lex.lookAhead() != '}') { | |||
Stmnt s2 = parseStmntOrCase(tbl2); | |||
if (s2 != null) { | |||
int op2 = s2.getOperator(); | |||
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; | |||
} | |||
else | |||
s = (Stmnt)ASTList.concat(s, new Stmnt(BLOCK, s2)); | |||
s = (Stmnt)ASTList.concat(s, new Stmnt(BLOCK, s2, lex.getLineNumber())); | |||
} | |||
} | |||
@@ -454,9 +462,9 @@ public final class Parser implements TokenId { | |||
lex.get(); | |||
Stmnt s; | |||
if (t == CASE) | |||
s = new Stmnt(t, parseExpression(tbl)); | |||
s = new Stmnt(t, parseExpression(tbl), lex.getLineNumber()); | |||
else | |||
s = new Stmnt(DEFAULT); | |||
s = new Stmnt(DEFAULT, lex.getLineNumber()); | |||
if (lex.get() != ':') | |||
throw new CompileError(": is missing", lex); | |||
@@ -477,7 +485,7 @@ public final class Parser implements TokenId { | |||
throw new SyntaxError(lex); | |||
Stmnt body = parseBlock(tbl); | |||
return new Stmnt(t, expr, body); | |||
return new Stmnt(t, expr, body, lex.getLineNumber()); | |||
} | |||
/* try.statement | |||
@@ -503,7 +511,7 @@ public final class Parser implements TokenId { | |||
throw new SyntaxError(lex); | |||
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; | |||
@@ -512,14 +520,14 @@ public final class Parser implements TokenId { | |||
finallyBlock = parseBlock(tbl); | |||
} | |||
return Stmnt.make(TRY, block, catchList, finallyBlock); | |||
return Stmnt.make(TRY, block, catchList, finallyBlock, lex.getLineNumber()); | |||
} | |||
/* return.statement : RETURN [ expression ] ";" | |||
*/ | |||
private Stmnt parseReturn(SymbolTable tbl) throws CompileError { | |||
int t = lex.get(); // RETURN | |||
Stmnt s = new Stmnt(t); | |||
Stmnt s = new Stmnt(t, lex.getLineNumber()); | |||
if (lex.lookAhead() != ';') | |||
s.setLeft(parseExpression(tbl)); | |||
@@ -537,7 +545,7 @@ public final class Parser implements TokenId { | |||
if (lex.get() != ';') | |||
throw new CompileError("; is missing", lex); | |||
return new Stmnt(t, expr); | |||
return new Stmnt(t, expr, lex.getLineNumber()); | |||
} | |||
/* break.statement : BREAK [ Identifier ] ";" | |||
@@ -554,10 +562,10 @@ public final class Parser implements TokenId { | |||
throws CompileError | |||
{ | |||
int t = lex.get(); // CONTINUE | |||
Stmnt s = new Stmnt(t); | |||
Stmnt s = new Stmnt(t, lex.getLineNumber()); | |||
int t2 = lex.get(); | |||
if (t2 == Identifier) { | |||
s.setLeft(new Symbol(lex.getString())); | |||
s.setLeft(new Symbol(lex.getString(), lex.getLineNumber())); | |||
t2 = lex.get(); | |||
} | |||
@@ -589,7 +597,7 @@ public final class Parser implements TokenId { | |||
if (isBuiltinType(t)) { | |||
t = lex.get(); | |||
int dim = parseArrayDimension(); | |||
return parseDeclarators(tbl, new Declarator(t, dim)); | |||
return parseDeclarators(tbl, new Declarator(t, dim, lex.getLineNumber())); | |||
} | |||
else if (t == Identifier) { | |||
int i = nextIsClassType(0); | |||
@@ -597,7 +605,7 @@ public final class Parser implements TokenId { | |||
if (lex.lookAhead(i) == Identifier) { | |||
ASTList name = parseClassType(tbl); | |||
int dim = parseArrayDimension(); | |||
return parseDeclarators(tbl, new Declarator(name, dim)); | |||
return parseDeclarators(tbl, new Declarator(name, dim, lex.getLineNumber())); | |||
} | |||
} | |||
@@ -605,7 +613,7 @@ public final class Parser implements TokenId { | |||
if (exprList) | |||
expr = parseExprList(tbl); | |||
else | |||
expr = new Stmnt(EXPR, parseExpression(tbl)); | |||
expr = new Stmnt(EXPR, parseExpression(tbl), lex.getLineNumber()); | |||
if (lex.get() != ';') | |||
throw new CompileError("; is missing", lex); | |||
@@ -618,8 +626,8 @@ public final class Parser implements TokenId { | |||
private Stmnt parseExprList(SymbolTable tbl) throws CompileError { | |||
Stmnt expr = null; | |||
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() == ',') | |||
lex.get(); | |||
else | |||
@@ -635,7 +643,7 @@ public final class Parser implements TokenId { | |||
Stmnt decl = null; | |||
for (;;) { | |||
decl = (Stmnt)ASTList.concat(decl, | |||
new Stmnt(DECL, parseDeclarator(tbl, d))); | |||
new Stmnt(DECL, parseDeclarator(tbl, d), lex.getLineNumber())); | |||
int t = lex.get(); | |||
if (t == ';') | |||
return decl; | |||
@@ -653,7 +661,7 @@ public final class Parser implements TokenId { | |||
throw new SyntaxError(lex); | |||
String name = lex.getString(); | |||
Symbol symbol = new Symbol(name); | |||
Symbol symbol = new Symbol(name, lex.getLineNumber()); | |||
int dim = parseArrayDimension(); | |||
ASTree init = null; | |||
if (lex.lookAhead() == '=') { | |||
@@ -661,7 +669,7 @@ public final class Parser implements TokenId { | |||
init = parseInitializer(tbl); | |||
} | |||
Declarator decl = d.make(symbol, dim, init); | |||
Declarator decl = d.make(symbol, dim, init, lex.getLineNumber()); | |||
tbl.append(name, decl); | |||
return decl; | |||
} | |||
@@ -683,14 +691,14 @@ public final class Parser implements TokenId { | |||
lex.get(); // '{' | |||
if(lex.lookAhead() == '}'){ | |||
lex.get(); | |||
return new ArrayInit(null); | |||
return new ArrayInit(null, lex.getLineNumber()); | |||
} | |||
ASTree expr = parseExpression(tbl); | |||
ArrayInit init = new ArrayInit(expr); | |||
ArrayInit init = new ArrayInit(expr, lex.getLineNumber()); | |||
while (lex.lookAhead() == ',') { | |||
lex.get(); | |||
expr = parseExpression(tbl); | |||
ASTList.append(init, expr); | |||
ASTList.append(init, expr, lex.getLineNumber()); | |||
} | |||
if (lex.get() != '}') | |||
@@ -722,7 +730,7 @@ public final class Parser implements TokenId { | |||
int t = lex.get(); | |||
ASTree right = parseExpression(tbl); | |||
return AssignExpr.makeAssign(t, left, right); | |||
return AssignExpr.makeAssign(t, left, right, lex.getLineNumber()); | |||
} | |||
private static boolean isAssignOp(int t) { | |||
@@ -744,7 +752,7 @@ public final class Parser implements TokenId { | |||
throw new CompileError(": is missing", lex); | |||
ASTree elseExpr = parseExpression(tbl); | |||
return new CondExpr(cond, thenExpr, elseExpr); | |||
return new CondExpr(cond, thenExpr, elseExpr, lex.getLineNumber()); | |||
} | |||
return cond; | |||
} | |||
@@ -808,11 +816,11 @@ public final class Parser implements TokenId { | |||
if (isBuiltinType(t)) { | |||
lex.get(); // primitive type | |||
int dim = parseArrayDimension(); | |||
return new InstanceOfExpr(t, dim, expr); | |||
return new InstanceOfExpr(t, dim, expr, lex.getLineNumber()); | |||
} | |||
ASTList name = parseClassType(tbl); | |||
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) | |||
@@ -829,7 +837,7 @@ public final class Parser implements TokenId { | |||
if (p2 != 0 && prec > p2) | |||
expr2 = binaryExpr2(tbl, expr2, p2); | |||
else | |||
return BinExpr.makeBin(t, expr, expr2); | |||
return BinExpr.makeBin(t, expr, expr2, lex.getLineNumber()); | |||
} | |||
} | |||
@@ -887,17 +895,17 @@ public final class Parser implements TokenId { | |||
case IntConstant : | |||
case CharConstant : | |||
lex.get(); | |||
return new IntConst(-lex.getLong(), t2); | |||
return new IntConst(-lex.getLong(), t2, lex.getLineNumber()); | |||
case DoubleConstant : | |||
case FloatConstant : | |||
lex.get(); | |||
return new DoubleConst(-lex.getDouble(), t2); | |||
return new DoubleConst(-lex.getDouble(), t2, lex.getLineNumber()); | |||
default : | |||
break; | |||
} | |||
} | |||
return Expr.make(t, parseUnaryExpr(tbl)); | |||
return Expr.make(t, parseUnaryExpr(tbl), lex.getLineNumber()); | |||
case '(' : | |||
return parseCast(tbl); | |||
default : | |||
@@ -922,7 +930,7 @@ public final class Parser implements TokenId { | |||
if (lex.get() != ')') | |||
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()) { | |||
lex.get(); // '(' | |||
@@ -931,7 +939,7 @@ public final class Parser implements TokenId { | |||
if (lex.get() != ')') | |||
throw new CompileError(") is missing", lex); | |||
return new CastExpr(name, dim, parseUnaryExpr(tbl)); | |||
return new CastExpr(name, dim, parseUnaryExpr(tbl), lex.getLineNumber()); | |||
} | |||
else | |||
return parsePostfix(tbl); | |||
@@ -1001,7 +1009,7 @@ public final class Parser implements TokenId { | |||
if (lex.get() != Identifier) | |||
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() == '.') | |||
lex.get(); | |||
else | |||
@@ -1035,11 +1043,11 @@ public final class Parser implements TokenId { | |||
case IntConstant : | |||
case CharConstant : | |||
lex.get(); | |||
return new IntConst(lex.getLong(), token); | |||
return new IntConst(lex.getLong(), token, lex.getLineNumber()); | |||
case DoubleConstant : | |||
case FloatConstant : | |||
lex.get(); | |||
return new DoubleConst(lex.getDouble(), token); | |||
return new DoubleConst(lex.getDouble(), token, lex.getLineNumber()); | |||
default : | |||
break; | |||
} | |||
@@ -1066,13 +1074,13 @@ public final class Parser implements TokenId { | |||
if (index == null) | |||
throw new SyntaxError(lex); | |||
expr = Expr.make(ARRAY, expr, index); | |||
expr = Expr.make(ARRAY, expr, index, lex.getLineNumber()); | |||
} | |||
break; | |||
case PLUSPLUS : | |||
case MINUSMINUS : | |||
t = lex.get(); | |||
expr = Expr.make(t, null, expr); | |||
expr = Expr.make(t, null, expr, lex.getLineNumber()); | |||
break; | |||
case '.' : | |||
lex.get(); | |||
@@ -1080,10 +1088,10 @@ public final class Parser implements TokenId { | |||
if (t == CLASS) | |||
expr = parseDotClass(expr, 0); | |||
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) { | |||
str = lex.getString(); | |||
expr = Expr.make('.', expr, new Member(str)); | |||
expr = Expr.make('.', expr, new Member(str, lex.getLineNumber()), lex.getLineNumber()); | |||
} | |||
else | |||
throw new CompileError("missing member name", lex); | |||
@@ -1095,8 +1103,8 @@ public final class Parser implements TokenId { | |||
throw new CompileError("missing static member name", lex); | |||
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; | |||
default : | |||
return expr; | |||
@@ -1121,7 +1129,7 @@ public final class Parser implements TokenId { | |||
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, | |||
@@ -1133,7 +1141,7 @@ public final class Parser implements TokenId { | |||
{ | |||
if (dim > 0) { | |||
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; | |||
switch(builtinType) { | |||
@@ -1166,10 +1174,10 @@ public final class Parser implements TokenId { | |||
break; | |||
default : | |||
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 ")" | |||
@@ -1193,7 +1201,7 @@ public final class Parser implements TokenId { | |||
throw new SyntaxError(lex); | |||
} | |||
return CallExpr.makeCall(expr, parseArgumentList(tbl)); | |||
return CallExpr.makeCall(expr, parseArgumentList(tbl), lex.getLineNumber()); | |||
} | |||
private String toClassName(ASTree name) | |||
@@ -1246,15 +1254,15 @@ public final class Parser implements TokenId { | |||
case TRUE : | |||
case FALSE : | |||
case NULL : | |||
return new Keyword(t); | |||
return new Keyword(t, lex.getLineNumber()); | |||
case Identifier : | |||
name = lex.getString(); | |||
decl = tbl.lookup(name); | |||
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 : | |||
return new StringL(lex.getString()); | |||
return new StringL(lex.getString(), lex.getLineNumber()); | |||
case NEW : | |||
return parseNew(tbl); | |||
case '(' : | |||
@@ -1286,21 +1294,21 @@ public final class Parser implements TokenId { | |||
if (lex.lookAhead() == '{') | |||
init = parseArrayInitializer(tbl); | |||
return new NewExpr(t, size, init); | |||
return new NewExpr(t, size, init, lex.getLineNumber()); | |||
} | |||
else if (t == Identifier) { | |||
ASTList name = parseClassType(tbl); | |||
t = lex.lookAhead(); | |||
if (t == '(') { | |||
ASTList args = parseArgumentList(tbl); | |||
return new NewExpr(name, args); | |||
return new NewExpr(name, args, lex.getLineNumber()); | |||
} | |||
else if (t == '[') { | |||
ASTList size = parseArraySize(tbl); | |||
if (lex.lookAhead() == '{') | |||
init = parseArrayInitializer(tbl); | |||
return NewExpr.makeObjectArray(name, size, init); | |||
return NewExpr.makeObjectArray(name, size, init, lex.getLineNumber()); | |||
} | |||
} | |||
@@ -1312,7 +1320,7 @@ public final class Parser implements TokenId { | |||
private ASTList parseArraySize(SymbolTable tbl) throws CompileError { | |||
ASTList list = null; | |||
while (lex.lookAhead() == '[') | |||
list = ASTList.append(list, parseArrayIndex(tbl)); | |||
list = ASTList.append(list, parseArrayIndex(tbl), lex.getLineNumber()); | |||
return list; | |||
} | |||
@@ -1341,7 +1349,7 @@ public final class Parser implements TokenId { | |||
ASTList list = null; | |||
if (lex.lookAhead() != ')') | |||
for (;;) { | |||
list = ASTList.append(list, parseExpression(tbl)); | |||
list = ASTList.append(list, parseExpression(tbl), lex.getLineNumber()); | |||
if (lex.lookAhead() == ',') | |||
lex.get(); | |||
else |
@@ -25,6 +25,6 @@ import javassist.compiler.ast.ASTList; | |||
* @see javassist.compiler.JvstCodeGen#setProceedHandler(ProceedHandler, String) | |||
*/ | |||
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; | |||
} |
@@ -73,14 +73,14 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { | |||
* into a String object. | |||
*/ | |||
protected static String argTypesToString(int[] types, int[] dims, | |||
String[] cnames) { | |||
String[] cnames, int lineNumber) { | |||
StringBuilder sbuf = new StringBuilder(); | |||
sbuf.append('('); | |||
int n = types.length; | |||
if (n > 0) { | |||
int i = 0; | |||
while (true) { | |||
typeToString(sbuf, types[i], dims[i], cnames[i]); | |||
typeToString(sbuf, types[i], dims[i], cnames[i], lineNumber); | |||
if (++i < n) | |||
sbuf.append(','); | |||
else | |||
@@ -97,7 +97,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { | |||
* into a String object. | |||
*/ | |||
protected static StringBuilder typeToString(StringBuilder sbuf, | |||
int type, int dim, String cname) { | |||
int type, int dim, String cname, int lineNumber) { | |||
String s; | |||
if (type == CLASS) | |||
s = MemberResolver.jvmToJavaName(cname); | |||
@@ -105,7 +105,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { | |||
s = "Object"; | |||
else | |||
try { | |||
s = MemberResolver.getTypeName(type); | |||
s = MemberResolver.getTypeName(type, lineNumber); | |||
} | |||
catch (CompileError e) { | |||
s = "?"; | |||
@@ -125,8 +125,8 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { | |||
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); | |||
} | |||
/** | |||
@@ -156,8 +156,8 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { | |||
/* Expands a simple class name to java.lang.*. | |||
* For example, this converts Object into java/lang/Object. | |||
*/ | |||
protected String resolveClassName(String jvmName) throws CompileError { | |||
return resolver.resolveJvmClassName(jvmName); | |||
protected String resolveClassName(String jvmName, int lineNumber) throws CompileError { | |||
return resolver.resolveJvmClassName(jvmName, lineNumber); | |||
} | |||
@Override | |||
@@ -168,7 +168,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { | |||
CtClass clazz = resolver.lookupClassByName(expr.getClassName()); | |||
String cname = clazz.getName(); | |||
ASTList args = expr.getArguments(); | |||
atMethodCallCore(clazz, MethodInfo.nameInit, args); | |||
atMethodCallCore(clazz, MethodInfo.nameInit, args, expr.getLineNumber()); | |||
exprType = CLASS; | |||
arrayDim = 0; | |||
className = MemberResolver.javaToJvmName(cname); | |||
@@ -294,7 +294,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { | |||
throws CompileError | |||
{ | |||
CtField f = fieldAccess(left); | |||
atFieldRead(f); | |||
atFieldRead(f, expr.getLineNumber()); | |||
int fType = exprType; | |||
int fDim = arrayDim; | |||
String cname = className; | |||
@@ -316,9 +316,9 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { | |||
if (dim1 == 0 && dim1 == arrayDim) | |||
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)) { | |||
expr.setElse(new CastExpr(type1, 0, expr.elseExpr())); | |||
expr.setElse(new CastExpr(type1, 0, expr.elseExpr(), expr.getLineNumber())); | |||
exprType = type1; | |||
} | |||
} | |||
@@ -343,7 +343,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { | |||
* an expression using StringBuffer. | |||
*/ | |||
e = CallExpr.makeCall(Expr.make('.', e, | |||
new Member("toString")), null); | |||
new Member("toString", expr.getLineNumber()), expr.getLineNumber()), null, expr.getLineNumber()); | |||
expr.setOprand1(e); | |||
expr.setOprand2(null); // <---- look at this! | |||
className = jvmJavaLangString; | |||
@@ -404,9 +404,10 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { | |||
if ((type1 == CLASS && dim1 == 0 && jvmJavaLangString.equals(cname)) | |||
|| (exprType == CLASS && arrayDim == 0 | |||
&& jvmJavaLangString.equals(className))) { | |||
ASTList sbufClass = ASTList.make(new Symbol("java"), | |||
new Symbol("lang"), new Symbol("StringBuffer")); | |||
ASTree e = new NewExpr(sbufClass, null); | |||
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; | |||
arrayDim = 0; | |||
className = "java/lang/StringBuffer"; | |||
@@ -424,7 +425,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { | |||
ASTree newExpr = null; | |||
if (left instanceof StringL && right instanceof StringL && op == '+') | |||
newExpr = new StringL(((StringL)left).get() | |||
+ ((StringL)right).get()); | |||
+ ((StringL)right).get(), left.getLineNumber()); | |||
else if (left instanceof IntConst) | |||
newExpr = ((IntConst)left).compute(op, right); | |||
else if (left instanceof DoubleConst) | |||
@@ -451,7 +452,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { | |||
Expr e = (Expr)expr; | |||
int op = e.getOperator(); | |||
if (op == MEMBER) { | |||
ASTree cexpr = getConstantFieldValue((Member)e.oprand2()); | |||
ASTree cexpr = getConstantFieldValue((Member)e.oprand2(), expr.getLineNumber()); | |||
if (cexpr != null) | |||
return cexpr; | |||
} | |||
@@ -459,7 +460,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { | |||
return e.getLeft(); | |||
} | |||
else if (expr instanceof Member) { | |||
ASTree cexpr = getConstantFieldValue((Member)expr); | |||
ASTree cexpr = getConstantFieldValue((Member)expr, expr.getLineNumber()); | |||
if (cexpr != null) | |||
return cexpr; | |||
} | |||
@@ -471,11 +472,11 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { | |||
* If MEM is a static final field, this method returns a constant | |||
* 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) | |||
return null; | |||
@@ -484,19 +485,19 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { | |||
return null; | |||
if (value instanceof String) | |||
return new StringL((String)value); | |||
return new StringL((String)value, lineNumber); | |||
else if (value instanceof Double || value instanceof Float) { | |||
int token = (value instanceof Double) | |||
? DoubleConstant : FloatConstant; | |||
return new DoubleConst(((Number)value).doubleValue(), token); | |||
return new DoubleConst(((Number)value).doubleValue(), token, lineNumber); | |||
} | |||
else if (value instanceof Number) { | |||
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) | |||
return new Keyword(((Boolean)value).booleanValue() | |||
? TokenId.TRUE : TokenId.FALSE); | |||
? TokenId.TRUE : TokenId.FALSE, lineNumber); | |||
else | |||
return null; | |||
} | |||
@@ -512,8 +513,8 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { | |||
} | |||
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) | |||
@@ -561,7 +562,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { | |||
throws CompileError | |||
{ | |||
if (CodeGen.rightIsStrong(type1, type2)) | |||
expr.setLeft(new CastExpr(type2, 0, expr.oprand1())); | |||
expr.setLeft(new CastExpr(type2, 0, expr.oprand1(), expr.getLineNumber())); | |||
else | |||
exprType = type1; | |||
} | |||
@@ -618,7 +619,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { | |||
else if (token == '!') | |||
booleanExpr(expr); | |||
else if (token == CALL) // method call | |||
fatal(); | |||
fatal(expr.getLineNumber()); | |||
else { | |||
oprand.accept(this); | |||
if (!isConstant(expr, token, oprand)) | |||
@@ -681,7 +682,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { | |||
if (op == MEMBER) // static method | |||
targetClass | |||
= resolver.lookupClass(((Symbol)e.oprand1()).get(), | |||
false); | |||
false, e.getLineNumber()); | |||
else if (op == '.') { | |||
ASTree target = e.oprand1(); | |||
String classFollowedByDotSuper = isDotSuper(target); | |||
@@ -702,30 +703,30 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { | |||
className = nfe.getField(); // JVM-internal | |||
e.setOperator(MEMBER); | |||
e.setOprand1(new Symbol(MemberResolver.jvmToJavaName( | |||
className))); | |||
className), e.getLineNumber())); | |||
} | |||
if (arrayDim > 0) | |||
targetClass = resolver.lookupClass(javaLangObject, true); | |||
targetClass = resolver.lookupClass(javaLangObject, true, e.getLineNumber()); | |||
else if (exprType == CLASS /* && arrayDim == 0 */) | |||
targetClass = resolver.lookupClassByJvmName(className); | |||
targetClass = resolver.lookupClassByJvmName(className, e.getLineNumber()); | |||
else | |||
badMethod(); | |||
badMethod(e.getLineNumber()); | |||
} | |||
} | |||
else | |||
badMethod(); | |||
badMethod(expr.getLineNumber()); | |||
} | |||
else | |||
fatal(); | |||
fatal(expr.getLineNumber()); | |||
MemberResolver.Method minfo | |||
= atMethodCallCore(targetClass, mname, args); | |||
= atMethodCallCore(targetClass, mname, args, expr.getLineNumber()); | |||
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); | |||
} | |||
/** | |||
@@ -753,7 +754,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { | |||
* and the MethodInfo of that method. Never null. | |||
*/ | |||
public MemberResolver.Method atMethodCallCore(CtClass targetClass, | |||
String mname, ASTList args) | |||
String mname, ASTList args, int lineNumber) | |||
throws CompileError | |||
{ | |||
int nargs = getMethodArgsLength(args); | |||
@@ -767,18 +768,18 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { | |||
mname, types, dims, cnames); | |||
if (found == null) { | |||
String clazz = targetClass.getName(); | |||
String signature = argTypesToString(types, dims, cnames); | |||
String signature = argTypesToString(types, dims, cnames, lineNumber); | |||
String msg; | |||
if (mname.equals(MethodInfo.nameInit)) | |||
msg = "cannot find constructor " + clazz + signature; | |||
else | |||
msg = mname + signature + " not found in " + clazz; | |||
throw new CompileError(msg); | |||
throw new CompileError(msg, lineNumber); | |||
} | |||
String desc = found.info.getDescriptor(); | |||
setReturnType(desc); | |||
setReturnType(desc, lineNumber); | |||
return found; | |||
} | |||
@@ -800,10 +801,10 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { | |||
} | |||
} | |||
void setReturnType(String desc) throws CompileError { | |||
void setReturnType(String desc, int lineNumber) throws CompileError { | |||
int i = desc.indexOf(')'); | |||
if (i < 0) | |||
badMethod(); | |||
badMethod(lineNumber); | |||
char c = desc.charAt(++i); | |||
int dim = 0; | |||
@@ -816,22 +817,22 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { | |||
if (c == 'L') { | |||
int j = desc.indexOf(';', i + 1); | |||
if (j < 0) | |||
badMethod(); | |||
badMethod(lineNumber); | |||
exprType = CLASS; | |||
className = desc.substring(i + 1, j); | |||
} | |||
else { | |||
exprType = MemberResolver.descToType(c); | |||
exprType = MemberResolver.descToType(c, lineNumber); | |||
className = null; | |||
} | |||
} | |||
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(); | |||
String type = finfo.getDescriptor(); | |||
@@ -844,7 +845,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { | |||
} | |||
arrayDim = dim; | |||
exprType = MemberResolver.descToType(c); | |||
exprType = MemberResolver.descToType(c, lineNumber); | |||
if (c == 'L') | |||
className = type.substring(i + 1, type.indexOf(';', i + 1)); | |||
@@ -933,14 +934,14 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { | |||
} | |||
} | |||
throw new CompileError("bad field access"); | |||
throw new CompileError("bad field access", expr.getLineNumber()); | |||
} | |||
private CtField fieldAccess2(Expr e, String jvmClassName) throws CompileError { | |||
Member fname = (Member)e.oprand2(); | |||
CtField f = resolver.lookupFieldByJvmName2(jvmClassName, fname, e); | |||
e.setOperator(MEMBER); | |||
e.setOprand1(new Symbol(MemberResolver.jvmToJavaName(jvmClassName))); | |||
e.setOprand1(new Symbol(MemberResolver.jvmToJavaName(jvmClassName), e.getLineNumber())); | |||
fname.setField(f); | |||
return f; | |||
} | |||
@@ -1006,7 +1007,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { | |||
protected void atFieldPlusPlus(ASTree oprand) throws CompileError | |||
{ | |||
CtField f = fieldAccess(oprand); | |||
atFieldRead(f); | |||
atFieldRead(f, oprand.getLineNumber()); | |||
int t = exprType; | |||
if (t == INT || t == BYTE || t == CHAR || t == SHORT) | |||
exprType = INT; | |||
@@ -1046,7 +1047,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { | |||
className = getSuperName(); | |||
break; | |||
default : | |||
fatal(); | |||
fatal(k.getLineNumber()); | |||
} | |||
} | |||
@@ -28,18 +28,18 @@ public class ASTList extends ASTree { | |||
private ASTree left; | |||
private ASTList right; | |||
public ASTList(ASTree _head, ASTList _tail) { | |||
public ASTList(ASTree _head, ASTList _tail, int lineNumber) { | |||
super(lineNumber); | |||
left = _head; | |||
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 | |||
@@ -146,8 +146,8 @@ public class ASTList extends ASTree { | |||
/** | |||
* 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)); | |||
} | |||
/** |
@@ -29,6 +29,12 @@ public abstract class ASTree implements Serializable { | |||
/** default serialVersionUID */ | |||
private static final long serialVersionUID = 1L; | |||
private final int lineNumber; | |||
public ASTree(int lineNumber) { | |||
this.lineNumber = lineNumber; | |||
} | |||
public ASTree getLeft() { return null; } | |||
public ASTree getRight() { return null; } | |||
@@ -61,4 +67,8 @@ public abstract class ASTree implements Serializable { | |||
String name = getClass().getName(); | |||
return name.substring(name.lastIndexOf('.') + 1); | |||
} | |||
public int getLineNumber() { | |||
return lineNumber; | |||
} | |||
} |
@@ -27,10 +27,12 @@ public class ArrayInit extends ASTList { | |||
/** | |||
* 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); | |||
} | |||
/** |
@@ -29,13 +29,13 @@ public class AssignExpr extends Expr { | |||
/** default serialVersionUID */ | |||
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, | |||
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 |
@@ -33,12 +33,12 @@ public class BinExpr extends Expr { | |||
/** default serialVersionUID */ | |||
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 |
@@ -28,8 +28,8 @@ public class CallExpr extends Expr { | |||
private static final long serialVersionUID = 1L; | |||
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; | |||
} | |||
@@ -41,8 +41,8 @@ public class CallExpr extends Expr { | |||
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 |
@@ -28,14 +28,14 @@ public class CastExpr extends ASTList implements TokenId { | |||
protected int castType; | |||
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; | |||
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; | |||
arrayDim = dim; | |||
} |
@@ -25,8 +25,8 @@ public class CondExpr extends ASTList { | |||
/** default serialVersionUID */ | |||
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(); } |
@@ -30,16 +30,16 @@ public class Declarator extends ASTList implements TokenId { | |||
protected int localVar; | |||
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; | |||
arrayDim = dim; | |||
localVar = -1; | |||
qualifiedClass = null; | |||
} | |||
public Declarator(ASTList className, int dim) { | |||
super(null); | |||
public Declarator(ASTList className, int dim, int lineNumber) { | |||
super(null, lineNumber); | |||
varType = CLASS; | |||
arrayDim = dim; | |||
localVar = -1; | |||
@@ -49,21 +49,21 @@ public class Declarator extends ASTList implements TokenId { | |||
/* For declaring a pre-defined? local variable. | |||
*/ | |||
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; | |||
arrayDim = dim; | |||
localVar = var; | |||
qualifiedClass = jvmClassName; | |||
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.setLeft(sym); | |||
append(d, init); | |||
append(d, init, lineNumber); | |||
return d; | |||
} | |||
@@ -28,7 +28,11 @@ public class DoubleConst extends ASTree { | |||
protected double value; | |||
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; } | |||
@@ -63,15 +67,15 @@ public class DoubleConst extends ASTree { | |||
else | |||
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) { | |||
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, | |||
int newType) | |||
int newType, int lineNumber) | |||
{ | |||
double newValue; | |||
switch (op) { | |||
@@ -94,6 +98,6 @@ public class DoubleConst extends ASTree { | |||
return null; | |||
} | |||
return new DoubleConst(newValue, newType); | |||
return new DoubleConst(newValue, newType, lineNumber); | |||
} | |||
} |
@@ -33,22 +33,22 @@ public class Expr extends ASTList implements TokenId { | |||
private static final long serialVersionUID = 1L; | |||
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; | |||
} | |||
Expr(int op, ASTree _head) { | |||
super(_head); | |||
Expr(int op, ASTree _head, int lineNumber) { | |||
super(_head, lineNumber); | |||
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; } |
@@ -22,8 +22,8 @@ public class FieldDecl extends ASTList { | |||
/** default serialVersionUID */ | |||
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(); } |
@@ -25,12 +25,12 @@ public class InstanceOfExpr extends CastExpr { | |||
/** default serialVersionUID */ | |||
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 |
@@ -28,7 +28,11 @@ public class IntConst extends ASTree { | |||
protected long value; | |||
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; } | |||
@@ -111,7 +115,7 @@ public class IntConst extends ASTree { | |||
return null; | |||
} | |||
return new IntConst(newValue, newType); | |||
return new IntConst(newValue, newType, right.getLineNumber()); | |||
} | |||
private DoubleConst compute0(int op, DoubleConst right) { | |||
@@ -138,6 +142,6 @@ public class IntConst extends ASTree { | |||
return null; | |||
} | |||
return new DoubleConst(newValue, right.type); | |||
return new DoubleConst(newValue, right.type, right.getLineNumber()); | |||
} | |||
} |
@@ -26,7 +26,8 @@ public class Keyword extends ASTree { | |||
private static final long serialVersionUID = 1L; | |||
protected int tokenId; | |||
public Keyword(int token) { | |||
public Keyword(int token, int lineNumber) { | |||
super(lineNumber); | |||
tokenId = token; | |||
} | |||
@@ -29,8 +29,8 @@ public class Member extends Symbol { | |||
// this is used to obtain the value of a static final field. | |||
private CtField field; | |||
public Member(String name) { | |||
super(name); | |||
public Member(String name, int lineNumber) { | |||
super(name, lineNumber); | |||
field = null; | |||
} | |||
@@ -23,8 +23,8 @@ public class MethodDecl extends ASTList { | |||
private static final long serialVersionUID = 1L; | |||
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() { |
@@ -28,26 +28,26 @@ public class NewExpr extends ASTList implements TokenId { | |||
protected boolean newArray; | |||
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; | |||
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; | |||
arrayType = type; | |||
if (init != null) | |||
append(this, init); | |||
append(this, init, lineNumber); | |||
} | |||
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; | |||
if (init != null) | |||
append(e, init); | |||
append(e, init, lineNumber); | |||
return e; | |||
} |
@@ -28,6 +28,7 @@ public class Pair extends ASTree { | |||
protected ASTree left, right; | |||
public Pair(ASTree _left, ASTree _right) { | |||
super(_left.getLineNumber()); | |||
left = _left; | |||
right = _right; | |||
} |
@@ -27,26 +27,26 @@ public class Stmnt extends ASTList implements TokenId { | |||
private static final long serialVersionUID = 1L; | |||
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; | |||
} | |||
public Stmnt(int op, ASTree _head) { | |||
super(_head); | |||
public Stmnt(int op, ASTree _head, int lineNumber) { | |||
super(_head, lineNumber); | |||
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 |
@@ -26,7 +26,8 @@ public class StringL extends ASTree { | |||
private static final long serialVersionUID = 1L; | |||
protected String text; | |||
public StringL(String t) { | |||
public StringL(String t, int lineNumber) { | |||
super(lineNumber); | |||
text = t; | |||
} | |||
@@ -26,7 +26,8 @@ public class Symbol extends ASTree { | |||
private static final long serialVersionUID = 1L; | |||
protected String identifier; | |||
public Symbol(String sym) { | |||
public Symbol(String sym, int lineNumber) { | |||
super(lineNumber); | |||
identifier = sym; | |||
} | |||
@@ -26,8 +26,8 @@ public class Variable extends Symbol { | |||
private static final long serialVersionUID = 1L; | |||
protected Declarator declarator; | |||
public Variable(String sym, Declarator d) { | |||
super(sym); | |||
public Variable(String sym, Declarator d, int lineNumber) { | |||
super(sym, lineNumber); | |||
declarator = d; | |||
} | |||
@@ -163,26 +163,26 @@ public class Cast extends Expr { | |||
} | |||
@Override | |||
public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args) | |||
public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args, int lineNumber) | |||
throws CompileError | |||
{ | |||
if (gen.getMethodArgsLength(args) != 1) | |||
throw new CompileError(Javac.proceedName | |||
+ "() cannot take more than one parameter " | |||
+ "for cast"); | |||
+ "for cast", lineNumber); | |||
gen.atMethodArgs(args, new int[1], new int[1], new String[1]); | |||
bytecode.addOpcode(Opcode.CHECKCAST); | |||
bytecode.addIndex(index); | |||
gen.setType(retType); | |||
gen.setType(retType, lineNumber); | |||
} | |||
@Override | |||
public void setReturnType(JvstTypeChecker c, ASTList args) | |||
public void setReturnType(JvstTypeChecker c, ASTList args, int lineNumber) | |||
throws CompileError | |||
{ | |||
c.atMethodArgs(args, new int[1], new int[1], new String[1]); | |||
c.setType(retType); | |||
c.setType(retType, lineNumber); | |||
} | |||
} | |||
} |
@@ -259,12 +259,12 @@ public class FieldAccess extends Expr { | |||
} | |||
@Override | |||
public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args) | |||
public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args, int lineNumber) | |||
throws CompileError | |||
{ | |||
if (args != null && !gen.isParamListName(args)) | |||
throw new CompileError(Javac.proceedName | |||
+ "() cannot take a parameter for field reading"); | |||
+ "() cannot take a parameter for field reading", lineNumber); | |||
int stack; | |||
if (isStatic(opcode)) | |||
@@ -282,14 +282,14 @@ public class FieldAccess extends Expr { | |||
bytecode.add(opcode); | |||
bytecode.addIndex(index); | |||
bytecode.growStack(stack); | |||
gen.setType(fieldType); | |||
gen.setType(fieldType, lineNumber); | |||
} | |||
@Override | |||
public void setReturnType(JvstTypeChecker c, ASTList args) | |||
public void setReturnType(JvstTypeChecker c, ASTList args, int lineNumber) | |||
throws CompileError | |||
{ | |||
c.setType(fieldType); | |||
c.setType(fieldType, lineNumber); | |||
} | |||
} | |||
@@ -309,13 +309,13 @@ public class FieldAccess extends Expr { | |||
} | |||
@Override | |||
public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args) | |||
public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args, int lineNumber) | |||
throws CompileError | |||
{ | |||
if (gen.getMethodArgsLength(args) != 1) | |||
throw new CompileError(Javac.proceedName | |||
+ "() cannot take more than one parameter " | |||
+ "for field writing"); | |||
+ "for field writing", lineNumber); | |||
int stack; | |||
if (isStatic(opcode)) | |||
@@ -335,16 +335,16 @@ public class FieldAccess extends Expr { | |||
bytecode.add(opcode); | |||
bytecode.addIndex(index); | |||
bytecode.growStack(stack); | |||
gen.setType(CtClass.voidType); | |||
gen.setType(CtClass.voidType, lineNumber); | |||
gen.addNullIfVoid(); | |||
} | |||
@Override | |||
public void setReturnType(JvstTypeChecker c, ASTList args) | |||
public void setReturnType(JvstTypeChecker c, ASTList args, int lineNumber) | |||
throws CompileError | |||
{ | |||
c.atMethodArgs(args, new int[1], new int[1], new String[1]); | |||
c.setType(CtClass.voidType); | |||
c.setType(CtClass.voidType, lineNumber); | |||
c.addNullIfVoid(); | |||
} | |||
} |
@@ -167,26 +167,26 @@ public class Instanceof extends Expr { | |||
} | |||
@Override | |||
public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args) | |||
public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args, int lineNumber) | |||
throws CompileError | |||
{ | |||
if (gen.getMethodArgsLength(args) != 1) | |||
throw new CompileError(Javac.proceedName | |||
+ "() cannot take more than one parameter " | |||
+ "for instanceof"); | |||
+ "for instanceof", lineNumber); | |||
gen.atMethodArgs(args, new int[1], new int[1], new String[1]); | |||
bytecode.addOpcode(Opcode.INSTANCEOF); | |||
bytecode.addIndex(index); | |||
gen.setType(CtClass.booleanType); | |||
gen.setType(CtClass.booleanType, lineNumber); | |||
} | |||
@Override | |||
public void setReturnType(JvstTypeChecker c, ASTList args) | |||
public void setReturnType(JvstTypeChecker c, ASTList args, int lineNumber) | |||
throws CompileError | |||
{ | |||
c.atMethodArgs(args, new int[1], new int[1], new String[1]); | |||
c.setType(CtClass.booleanType); | |||
c.setType(CtClass.booleanType, lineNumber); | |||
} | |||
} | |||
} |
@@ -270,13 +270,13 @@ public class NewArray extends Expr { | |||
} | |||
@Override | |||
public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args) | |||
public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args, int lineNumber) | |||
throws CompileError | |||
{ | |||
int num = gen.getMethodArgsLength(args); | |||
if (num != dimension) | |||
throw new CompileError(Javac.proceedName | |||
+ "() with a wrong number of parameters"); | |||
+ "() with a wrong number of parameters", lineNumber); | |||
gen.atMethodArgs(args, new int[num], | |||
new int[num], new String[num]); | |||
@@ -291,14 +291,14 @@ public class NewArray extends Expr { | |||
bytecode.growStack(1 - dimension); | |||
} | |||
gen.setType(arrayType); | |||
gen.setType(arrayType, lineNumber); | |||
} | |||
@Override | |||
public void setReturnType(JvstTypeChecker c, ASTList args) | |||
public void setReturnType(JvstTypeChecker c, ASTList args, int lineNumber) | |||
throws CompileError | |||
{ | |||
c.setType(arrayType); | |||
c.setType(arrayType, lineNumber); | |||
} | |||
} | |||
} |
@@ -263,7 +263,7 @@ public class NewExpr extends Expr { | |||
} | |||
@Override | |||
public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args) | |||
public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args, int lineNumber) | |||
throws CompileError | |||
{ | |||
bytecode.addOpcode(NEW); | |||
@@ -271,15 +271,15 @@ public class NewExpr extends Expr { | |||
bytecode.addOpcode(DUP); | |||
gen.atMethodCallCore(newType, MethodInfo.nameInit, args, | |||
false, true, -1, null); | |||
gen.setType(newType); | |||
gen.setType(newType, lineNumber); | |||
} | |||
@Override | |||
public void setReturnType(JvstTypeChecker c, ASTList args) | |||
public void setReturnType(JvstTypeChecker c, ASTList args, int lineNumber) | |||
throws CompileError | |||
{ | |||
c.atMethodCallCore(newType, MethodInfo.nameInit, args); | |||
c.setType(newType); | |||
c.atMethodCallCore(newType, MethodInfo.nameInit, args, lineNumber); | |||
c.setType(newType, lineNumber); | |||
} | |||
} | |||
} |
@@ -0,0 +1,93 @@ | |||
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"); | |||
} | |||
} |
@@ -105,11 +105,11 @@ public class CompTest extends TestCase { | |||
public void testArgTypesToString() { | |||
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); | |||
s = TypeChecker.argTypesToString(new int[] { TokenId.INT, TokenId.CHAR, TokenId.CLASS }, | |||
new int[] { 0, 1, 0 }, | |||
new String[] { null, null, "String" }); | |||
new String[] { null, null, "String" }, 0); | |||
assertEquals("(int,char[],String)", s); | |||
} | |||