]> source.dussan.org Git - javassist.git/commitdiff
add line numbers and test
authorakuznetsov <akuznetsov@tradingview.com>
Tue, 26 Sep 2023 11:57:53 +0000 (15:57 +0400)
committerakuznetsov <akuznetsov@tradingview.com>
Wed, 4 Oct 2023 10:06:05 +0000 (14:06 +0400)
38 files changed:
src/main/javassist/bytecode/CodeAttribute.java
src/main/javassist/bytecode/LineNumberAttribute.java
src/main/javassist/bytecode/LineNumberAttributeBuilder.java [new file with mode: 0644]
src/main/javassist/compiler/CodeGen.java
src/main/javassist/compiler/CompileError.java
src/main/javassist/compiler/Javac.java
src/main/javassist/compiler/JvstCodeGen.java
src/main/javassist/compiler/JvstCodeGenWitlLineNumber.java [new file with mode: 0644]
src/main/javassist/compiler/JvstTypeChecker.java
src/main/javassist/compiler/Lex.java
src/main/javassist/compiler/MemberCodeGen.java
src/main/javassist/compiler/NoFieldException.java
src/main/javassist/compiler/Parser.java
src/main/javassist/compiler/TypeChecker.java
src/main/javassist/compiler/ast/ASTList.java
src/main/javassist/compiler/ast/ASTree.java
src/main/javassist/compiler/ast/ArrayInit.java
src/main/javassist/compiler/ast/AssignExpr.java
src/main/javassist/compiler/ast/BinExpr.java
src/main/javassist/compiler/ast/CallExpr.java
src/main/javassist/compiler/ast/CastExpr.java
src/main/javassist/compiler/ast/CondExpr.java
src/main/javassist/compiler/ast/Declarator.java
src/main/javassist/compiler/ast/DoubleConst.java
src/main/javassist/compiler/ast/Expr.java
src/main/javassist/compiler/ast/FieldDecl.java
src/main/javassist/compiler/ast/InstanceOfExpr.java
src/main/javassist/compiler/ast/IntConst.java
src/main/javassist/compiler/ast/Keyword.java
src/main/javassist/compiler/ast/Member.java
src/main/javassist/compiler/ast/MethodDecl.java
src/main/javassist/compiler/ast/NewExpr.java
src/main/javassist/compiler/ast/Pair.java
src/main/javassist/compiler/ast/Stmnt.java
src/main/javassist/compiler/ast/StringL.java
src/main/javassist/compiler/ast/Symbol.java
src/main/javassist/compiler/ast/Variable.java
src/test/javassist/bytecode/BytecodeTest.java

index 4c8ea2f270a17b73e7d0ad62b8596d00e07e89b3..98479b21daece077c7ed10ddad1a7ab5a57dfcc2 100644 (file)
@@ -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.
      */
index cead96e06a1f15decc2cb28fd9b7bfcb10aa500b..16b37377f4255e08f35e17eecd0baf3e112b7171 100644 (file)
@@ -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);
     }
 
diff --git a/src/main/javassist/bytecode/LineNumberAttributeBuilder.java b/src/main/javassist/bytecode/LineNumberAttributeBuilder.java
new file mode 100644 (file)
index 0000000..52d9d0c
--- /dev/null
@@ -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);
+        }
+    }
+}
index e31156176aeb7f931c12e5b7deb5941b82c48633..1f028f2bde3ea90950d5e22c33ef4599b842ca71 100644 (file)
@@ -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) {
@@ -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) {
@@ -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,7 +1649,7 @@ 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("[")) {
@@ -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());
         }
     }
 
index 5b857cf2cb54ba79e92b5dff2efb5b3a3aac4134..8bb12cba70613741111332037ea1cca62c7e1413 100644 (file)
@@ -25,11 +25,18 @@ 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, int lineNumber) {
+        this.lineNumber = lineNumber;
+        reason = String.format("line %d: %s", lineNumber, s);
+    }
+
     public 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;
index 084487b41d6ccfec7481c6232b0fcc85fb4763f9..6e67ab668c5356dc9e157203f8e58fcc9127a906 100644 (file)
@@ -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;
     }
@@ -160,8 +160,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,10 +174,11 @@ 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);
@@ -446,11 +448,11 @@ public class Javac {
                 public void doit(JvstCodeGen gen, Bytecode b, ASTList args)
                     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();
                 }
@@ -459,11 +461,11 @@ public class Javac {
                 public void setReturnType(JvstTypeChecker check, ASTList args)
                     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();
                 }
@@ -493,8 +495,8 @@ public class Javac {
                     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();
                 }
@@ -504,8 +506,8 @@ public class Javac {
                     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();
                 }
index 714b96999e4c204c44b3f108487058c4b458ce85..4f25192405dd38502e6a54a839d92a81131d00f9 100644 (file)
@@ -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,11 +141,11 @@ 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);
             if (!doDup)
@@ -211,7 +211,7 @@ public class JvstCodeGen extends MemberCodeGen {
             className = null;
         }
         else
-            throw new CompileError("invalid cast");
+            throw new CompileError("invalid cast", expr.getLineNumber());
     }
 
     protected void atCastToWrapper(CastExpr expr) throws CompileError {
@@ -253,7 +253,7 @@ public class JvstCodeGen extends MemberCodeGen {
                 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).
@@ -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);
         }
 
@@ -573,7 +573,7 @@ public class JvstCodeGen extends MemberCodeGen {
 
         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;
     }
@@ -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);
     }
 
diff --git a/src/main/javassist/compiler/JvstCodeGenWitlLineNumber.java b/src/main/javassist/compiler/JvstCodeGenWitlLineNumber.java
new file mode 100644 (file)
index 0000000..969948c
--- /dev/null
@@ -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);
+    }
+}
index 13e47291f0f52de28c14bfe11079e16972a5e664..d25928a67e698aabe6c54dda40749e5328a5a178 100644 (file)
@@ -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,7 +124,7 @@ 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());
@@ -258,7 +258,7 @@ public class JvstTypeChecker extends TypeChecker {
         addNullIfVoid();
     }
 
-    protected void compileUnwrapValue(CtClass type) throws CompileError
+    protected void compileUnwrapValue(CtClass type, int lineNumber) throws CompileError
     {
         if (type == CtClass.voidType)
             addNullIfVoid();
index b7c39a9852821f22426f1a0d6604687ffeeba8b1..c2c8666c1f33f672d0fab0add3c714e29c3859cd 100644 (file)
@@ -163,7 +163,8 @@ public class Lex implements TokenId {
                     ungetc(c);
                     c = '/';
                 }
-            }
+            } else if (c == '\n')
+                ++lineNumber;
         } while(isBlank(c));
         return c;
     }
@@ -529,4 +530,8 @@ public class Lex implements TokenId {
         lastChar = -1;
         return c;
     }
+
+    public int getLineNumber() {
+        return lineNumber + 1;
+    }
 }
index e8e9912b269371acd5b7c121dec4433d0ccaeb89..52e3aaea998e8f7c2f16927c9a65f83378a23c35 100644 (file)
@@ -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) {
@@ -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,7 +369,7 @@ 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) {
@@ -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)
@@ -563,7 +563,7 @@ public class MemberCodeGen extends CodeGen {
                 badMethod();
         }
         else
-            fatal();
+            fatal(expr.getLineNumber());
 
         atMethodCallCore(targetClass, mname, args, isStatic, isSpecial,
                          aload0pos, cached);
@@ -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,
@@ -844,14 +844,14 @@ public class MemberCodeGen extends CodeGen {
         if (op == '=') {
             FieldInfo finfo = f.getFieldInfo2();
             setFieldType(finfo);
-            AccessorMaker maker = isAccessibleField(f, finfo);            
+            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,9 +921,9 @@ 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());
@@ -932,7 +932,7 @@ public class MemberCodeGen extends CodeGen {
 
     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);
+        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
@@ -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 {
index dd878590ed197d9ddaa558d700d0da2eec25aa6f..898998d1880bc2d65841fbf1049a648b56a14e0d 100644 (file)
@@ -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;
     }
index 2b0dfd691514590e576c2efc24eb4751dccb1bc3..43e8a3ec644163e204f324329f878873eebb0b6e 100644 (file)
@@ -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);
@@ -306,12 +306,12 @@ public final class Parser implements TokenId {
         while (lex.lookAhead() != '}') {
             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, lex.getLineNumber()));
         }
 
         lex.get();      // '}'
         if (body == null)
-            return new Stmnt(BLOCK);    // empty block
+            return new Stmnt(BLOCK, lex.getLineNumber());    // empty block
         return body;
     }
 
@@ -330,7 +330,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()), lex.getLineNumber()), lex.getLineNumber());
     }
 
     /* while.statement : WHILE "(" expression ")" statement
@@ -341,7 +341,7 @@ public final class Parser implements TokenId {
         int t = lex.get();      // WHILE
         ASTree expr = parseParExpression(tbl);
         Stmnt body = parseStatement(tbl);
-        return new Stmnt(t, expr, body);
+        return new Stmnt(t, expr, body, lex.getLineNumber());
     }
 
     /* do.statement : DO statement WHILE "(" expression ")" ";"
@@ -356,7 +356,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 ")"
@@ -397,7 +397,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, lex.getLineNumber()), lex.getLineNumber()), lex.getLineNumber());
     }
 
     /* switch.statement : SWITCH "(" expression ")" "{" switch.block "}"
@@ -411,7 +411,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 +428,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 +454,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 +477,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 +503,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 +512,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 +537,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 +554,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 +589,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 +597,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 +605,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 +618,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 +635,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 +653,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 +661,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 +683,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 +722,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 +744,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 +808,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 +829,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 +887,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 +922,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 +931,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 +1001,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 +1035,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 +1066,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 +1080,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 +1095,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 +1121,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 +1133,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 +1166,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 +1193,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 +1246,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 +1286,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 +1312,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 +1341,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
index bceba41961e2d879899f3f30ac026739f5fb630c..55c35507eef535a45eb3f19c59af2aa928a3cc75 100644 (file)
@@ -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);
     }
 
     /**
@@ -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))
@@ -702,7 +703,7 @@ 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)
@@ -717,7 +718,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
                 badMethod();
         }
         else
-            fatal();
+            fatal(expr.getLineNumber());
 
         MemberResolver.Method minfo
                 = atMethodCallCore(targetClass, mname, args);
@@ -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;
     }
@@ -1046,7 +1047,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
                 className = getSuperName();
             break;
         default :
-            fatal();
+            fatal(k.getLineNumber());
         }
     }
 
index d9232ca0485941e480a8cea35e24beb34ed18727..786957f5f30ef19cbadaa8296280b2bb8f7ad665 100644 (file)
@@ -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));
     }
 
     /**
index 3d4dd842bef91cd665b6ca1d0e478ce0eb76da51..f155fa87d5aa08862d3d6e9e446c74eb8e23a83b 100644 (file)
@@ -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;
+    }
 }
index 0b87200e773bfa47e147805c4557f7c548f389d4..bc3f06eac00c6f517f291199b6a3e96129585cea 100644 (file)
@@ -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);
     }
 
     /**
index a5e1857dc8b21abd8b9866df544404f0d079020a..97dfc6e736e7302d352931e978ff6f3caef96b73 100644 (file)
@@ -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
index 9630ada932db0a97ba9041587e49236ad3e12185..789312ecd26912c45b1f51225ae9479c59592e45 100644 (file)
@@ -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
index 395915ed0f1be1b1258790520e032d08e233f6e0..72a3ca51337d4c1b65ceba0ee6b544bad7b688c2 100644 (file)
@@ -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
index 903e5bbd03235e30e407116c84b33bd67cbe5d01..d3938078ee2dfa289aed6eab7f8b6242bd74505c 100644 (file)
@@ -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;
     }
index 46435012dd5bc3e85c4dc077449f2831f85a773c..e4b6e07bc34fe56de4e0b28e6a62d612258d4489 100644 (file)
@@ -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(); }
index c29f674081af055f6cce5f9165c948a9f0762673..1713d9088a0e983c91ac6aa46457e3e2add4a124 100644 (file)
@@ -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;
     }
 
index f8d0afdefa19de53374d4bff9faa27fd6e571304..d55821f0685022243a56be83b975762e9d8a4232 100644 (file)
@@ -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);
     }
 }
index ed5cb60b2a71d8f979ae38c90aa13631e83cf12d..4d2ce1a04c286d2f6c3c8331a682388c7dff52d2 100644 (file)
@@ -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; }
index e2a066e981988c5119ef081bc2d60269a2214ed5..44df192ec8697929079db837980519479b43bc00 100644 (file)
@@ -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(); }
index ddf07bd23e4e2e465c2b3cd7b5c8c5eeb86a2f6f..e012defe48691e37309252c347d50528cd72d5fc 100644 (file)
@@ -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
index 7040b0c909a652acd6f628c8ecc8139a5a8edd8c..8ffce4791f96f15cbf9b7d272d18eaae2004267b 100644 (file)
@@ -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());
     }
 }
index b509375c06124074ceac19ec4a87dbdb9651f57a..858316d5ae62bd0783d2419135b819d0bb1a58db 100644 (file)
@@ -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;
     }
 
index 192c9ef370c68fe74722f1f6b0745d5a19d721b4..279e25169d5047133df4da53407d8311abd31a91 100644 (file)
@@ -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;
     }
 
index d96e3d4de1d4604c0af634fc1e12674a9961e9b9..263775b0309b31a1cd5da24490b808ff67436b5e 100644 (file)
@@ -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() {
index 44b264c06110923fb8f5c8d8b1cfd160722e63c8..d4f7f4751d65536a7999810c3c1a6235d6e430e5 100644 (file)
@@ -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;
     }
index 949028a423775ca848ecbe98c756c0c95bb20757..44411b8d1e3e50f97f9a02fd64590d0ed36a3190 100644 (file)
@@ -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;
     }
index c5aa5df354f668ff960154fb0b827ab1a3dd0980..7333d026a1d56278ca5cddb80d6cfe60839b530d 100644 (file)
@@ -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
index 7c7e00c35408949400439b27b3ac318cf2ea3e55..063bb5ed99c7ff6d5fdb048ce5bae444d00547d7 100644 (file)
@@ -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;
     }
 
index 2b66207af86ad59397cd3a6db8beeca7879c63e2..64c598eb577551a8c30d77cfb28ddaed349d9845 100644 (file)
@@ -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;
     }
 
index c9224a7a112a30244f843c6b0e6a8be7a1e6128d..2e1869500f1576bfff965d2bfb34ad9c56aac929 100644 (file)
@@ -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;
     }
 
index eac420bc12a2e6f61a64aa7a428278378ca9d45f..b7ab1f33e4996ad04e0ebb299cfcd8951574ce15 100644 (file)
@@ -302,6 +302,41 @@ public class BytecodeTest extends TestCase {
         assertEquals(20, pc.line);
     }
 
+    public void testLineNumberCompiler() {
+        CtClass testClass = loader.makeClass("javassist.bytecode.LineNumberCompilerClass");
+        String run = String.join("\n",
+                "public void run() {",
+                "    return",
+                "}");
+        try {
+            testClass.addMethod(CtMethod.make(run, testClass));
+        } catch (CannotCompileException e) {
+            assertEquals("line 3: syntax error near \"  return\n}\"", e.getCause().getMessage());
+            return;
+        }
+        fail("should not happen");
+    }
+
+    public void testLineNumberException() {
+        CtClass testClass = loader.makeClass("javassist.bytecode.LineNumberExceptionClass");
+        String run = String.join("\n",
+                "public void run() {",
+                "    throw new java.lang.RuntimeException();",
+                "}");
+        try {
+            testClass.addInterface(loader.get("java.lang.Runnable"));
+            testClass.addMethod(CtMethod.make(run, testClass));
+            Class cls = testClass.toClass(BytecodeTest.class);
+            var runnable = (Runnable) cls.getConstructor().newInstance();
+            runnable.run();
+        } catch (Exception e) {
+            var lineNum = e.getStackTrace()[0].getLineNumber();
+            assertEquals("Line number should be right", 2, lineNum);
+            return;
+        }
+        fail("should not happen");
+    }
+
     public void testRenameClass() throws Exception {
         CtClass cc = loader.get("test1.RenameClass");
         cc.replaceClassName("test1.RenameClass2", "java.lang.String");