Procházet zdrojové kódy

fix line numbers in blocks & refactor test

pull/484/head
akuznetsov před 6 měsíci
rodič
revize
0824a7a04e

+ 13
- 5
src/main/javassist/compiler/Parser.java Zobrazit soubor

/* block.statement : "{" statement* "}" /* block.statement : "{" statement* "}"
*/ */
private Stmnt parseBlock(SymbolTable tbl) throws CompileError { private Stmnt parseBlock(SymbolTable tbl) throws CompileError {
int blockLineNumber = lex.getLineNumber();
if (lex.get() != '{') if (lex.get() != '{')
throw new SyntaxError(lex); throw new SyntaxError(lex);


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


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


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


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


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


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


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


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


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


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


/* switch.statement : SWITCH "(" expression ")" "{" switch.block "}" /* switch.statement : SWITCH "(" expression ")" "{" switch.block "}"

+ 79
- 0
src/test/javassist/LineNumberTest.java Zobrazit soubor

package javassist;

import junit.framework.TestCase;

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

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

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

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

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

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

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

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

+ 0
- 60
src/test/javassist/bytecode/BytecodeTest.java Zobrazit soubor

assertEquals(20, pc.line); 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 testLineNumberCompiler2() {
CtClass testClass = loader.makeClass("javassist.bytecode.LineNumberCompilerClass2");
String ctor = String.join("\n",
"public LineNumberCompilerClass2() {",
" super();",
"}");
String run = String.join("\n",
"public void run() {",
" return;",
"}");
String run2 = String.join("\n",
"public void run2() {",
" run()",
"}");
try {
testClass.addConstructor(CtNewConstructor.make(ctor, testClass));
testClass.addMethod(CtMethod.make(run, testClass));
testClass.addMethod(CtMethod.make(run2, testClass));
} catch (CannotCompileException e) {
assertEquals("line 9: ; is missing", 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 { public void testRenameClass() throws Exception {
CtClass cc = loader.get("test1.RenameClass"); CtClass cc = loader.get("test1.RenameClass");
cc.replaceClassName("test1.RenameClass2", "java.lang.String"); cc.replaceClassName("test1.RenameClass2", "java.lang.String");

Načítá se…
Zrušit
Uložit