initial commit
This commit is contained in:
15
MicroJava Tests/MicroJava Tests2.iml
Normal file
15
MicroJava Tests/MicroJava Tests2.iml
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="lib2" level="project" />
|
||||
<orderEntry type="library" name="lib" level="project" />
|
||||
<orderEntry type="module" module-name="MicroJava Compiler" />
|
||||
<orderEntry type="module" module-name="MicroJava Compiler2" />
|
||||
</component>
|
||||
</module>
|
||||
54
MicroJava Tests/resources/animals.mj
Normal file
54
MicroJava Tests/resources/animals.mj
Normal file
@@ -0,0 +1,54 @@
|
||||
program Animals
|
||||
class Animal {
|
||||
char[] name;
|
||||
}
|
||||
{
|
||||
void setName(Animal a, char[] name) {
|
||||
a.name = name;
|
||||
}
|
||||
void aPrint(Animal a)
|
||||
int i, l;
|
||||
char c;
|
||||
{
|
||||
l = len(a.name);
|
||||
i = 0;
|
||||
while (i < l) {
|
||||
print(a.name[i]);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
void main()
|
||||
int a;
|
||||
Animal[] animals;
|
||||
char[] cat;
|
||||
char[] dog;
|
||||
char[] octopus;
|
||||
{
|
||||
cat = new char[3];
|
||||
cat[0] = 'c';
|
||||
cat[1] = 'a';
|
||||
cat[2] = 't';
|
||||
dog = new char[3];
|
||||
dog[0] = 'd';
|
||||
dog[1] = 'o';
|
||||
dog[2] = 'g';
|
||||
octopus = new char[7];
|
||||
octopus[0] = 'o';
|
||||
octopus[1] = 'c';
|
||||
octopus[2] = 't';
|
||||
octopus[3] = 'o';
|
||||
octopus[4] = 'p';
|
||||
octopus[5] = 'u';
|
||||
octopus[6] = 's';
|
||||
|
||||
animals = new Animal[3];
|
||||
animals[0] = new Animal;
|
||||
animals[1] = new Animal;
|
||||
animals[2] = new Animal;
|
||||
setName(animals[0],cat);
|
||||
setName(animals[1],dog);
|
||||
setName(animals[2],octopus);
|
||||
read(a);
|
||||
aPrint(animals[a]);
|
||||
}
|
||||
}
|
||||
1842
MicroJava Tests/resources/bytecodes.txt
Normal file
1842
MicroJava Tests/resources/bytecodes.txt
Normal file
File diff suppressed because it is too large
Load Diff
14
MicroJava Tests/resources/relops.mj
Normal file
14
MicroJava Tests/resources/relops.mj
Normal file
@@ -0,0 +1,14 @@
|
||||
program Test
|
||||
{
|
||||
void main()
|
||||
int a;
|
||||
{
|
||||
read(a);
|
||||
if (a == 1) { print('='); print('='); print(','); }
|
||||
if (a != 1) { print('!'); print('='); print(','); }
|
||||
if (a < 1) { print('<'); print(','); }
|
||||
if (a <= 1) { print('<'); print('='); print(','); }
|
||||
if (a > 1) { print('>'); print(','); }
|
||||
if (a >= 1) { print('>'); print('='); print(','); }
|
||||
}
|
||||
}
|
||||
880
MicroJava Tests/tests/ssw/mj/test/CodeGenerationTest.java
Normal file
880
MicroJava Tests/tests/ssw/mj/test/CodeGenerationTest.java
Normal file
@@ -0,0 +1,880 @@
|
||||
package ssw.mj.test;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import ssw.mj.test.support.BaseCompilerTestCase;
|
||||
|
||||
import static ssw.mj.Errors.Message.*;
|
||||
|
||||
public class CodeGenerationTest extends BaseCompilerTestCase {
|
||||
|
||||
/**
|
||||
* Symbol table for most examples of this test class.
|
||||
*/
|
||||
private void expectExampleSymTab() {
|
||||
expectSymTabUniverse();
|
||||
expectSymTab("Program A:");
|
||||
expectSymTab(" Constant: int max = 12");
|
||||
expectSymTab(" Global Variable 0: char c");
|
||||
expectSymTab(" Global Variable 1: int i");
|
||||
expectSymTab(" Type B: class (2 fields)");
|
||||
expectSymTab(" Local Variable 0: int x");
|
||||
expectSymTab(" Local Variable 1: int y");
|
||||
expectSymTab(" Method: void main (3 locals, 0 parameters)");
|
||||
expectSymTab(" Local Variable 0: int[] iarr");
|
||||
expectSymTab(" Local Variable 1: class (2 fields) b");
|
||||
expectSymTab(" Local Variable 2: int n");
|
||||
}
|
||||
|
||||
private void expectSymTabWithSum() {
|
||||
expectSymTabUniverse();
|
||||
expectSymTab("Program A:");
|
||||
expectSymTab(" Constant: int max = 12");
|
||||
expectSymTab(" Global Variable 0: char c");
|
||||
expectSymTab(" Global Variable 1: int i");
|
||||
expectSymTab(" Type B: class (2 fields)");
|
||||
expectSymTab(" Local Variable 0: int x");
|
||||
expectSymTab(" Local Variable 1: int y");
|
||||
expectSymTab(" Method: void main (4 locals, 0 parameters)");
|
||||
expectSymTab(" Local Variable 0: int[] iarr");
|
||||
expectSymTab(" Local Variable 1: class (2 fields) b");
|
||||
expectSymTab(" Local Variable 2: int n");
|
||||
expectSymTab(" Local Variable 3: int sum");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bsp11() {
|
||||
initCode("program A" + LF + //
|
||||
" final int max = 12;" + LF + //
|
||||
" char c; int i;" + LF + //
|
||||
" class B { int x, y; }" + LF + //
|
||||
"{" + LF + //
|
||||
" void main ()" + LF + //
|
||||
" int[] iarr; B b; int n;" + LF + //
|
||||
" {" + LF + //
|
||||
" read(i); " + LF + //
|
||||
" if (i <= n) n = 1;" + LF + //
|
||||
" print(n); " + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
|
||||
expectExampleSymTab();
|
||||
addExpectedRun("0", "1");
|
||||
addExpectedRun("1", "0");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bsp12() {
|
||||
initCode("program A" + LF + //
|
||||
" final int max = 12;" + LF + //
|
||||
" char c; int i;" + LF + //
|
||||
" class B { int x, y; }" + LF + //
|
||||
"{" + LF + //
|
||||
" void main ()" + LF + //
|
||||
" int[] iarr; B b; int n;" + LF + //
|
||||
" {" + LF + //
|
||||
" read(i); " + LF + //
|
||||
" n = 1; " + LF + //
|
||||
" if (i <= n && n < 0) n = 2;" + LF + //
|
||||
" print(n); " + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
|
||||
expectExampleSymTab();
|
||||
addExpectedRun("0", "1");
|
||||
addExpectedRun("2", "1");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bsp13() {
|
||||
initCode("program A" + LF + //
|
||||
" final int max = 12;" + LF + //
|
||||
" char c; int i;" + LF + //
|
||||
" class B { int x, y; }" + LF + //
|
||||
"{" + LF + //
|
||||
" void main ()" + LF + //
|
||||
" int[] iarr; B b; int n;" + LF + //
|
||||
" {" + LF + //
|
||||
" read(i); " + LF + //
|
||||
" n = 1; " + LF + //
|
||||
" if (i <= n || i < 10) n = 2;" + LF + //
|
||||
" print(n); " + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
|
||||
expectExampleSymTab();
|
||||
addExpectedRun("0", "2");
|
||||
addExpectedRun("2", "2");
|
||||
addExpectedRun("20", "1");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bsp14() {
|
||||
initCode("program A" + LF + //
|
||||
" final int max = 12;" + LF + //
|
||||
" char c; int i;" + LF + //
|
||||
" class B { int x, y; }" + LF + //
|
||||
"{" + LF + //
|
||||
" void main ()" + LF + //
|
||||
" int[] iarr; B b; int n;" + LF + //
|
||||
" {" + LF + //
|
||||
" read(i); " + LF + //
|
||||
" n = 1; " + LF + //
|
||||
" if (i <= n || i < 10 && i > 5) n = 2;" + LF + //
|
||||
" print(n); " + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
|
||||
expectExampleSymTab();
|
||||
addExpectedRun("0", "2");
|
||||
addExpectedRun("2", "1");
|
||||
addExpectedRun("6", "2");
|
||||
addExpectedRun("20", "1");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bsp15() {
|
||||
initCode("program A" + LF + //
|
||||
" final int max = 12;" + LF + //
|
||||
" char c; int i;" + LF + //
|
||||
" class B { int x, y; }" + LF + //
|
||||
"{" + LF + //
|
||||
" void main ()" + LF + //
|
||||
" int[] iarr; B b; int n;" + LF + //
|
||||
" {" + LF + //
|
||||
" read(n); " + LF + //
|
||||
" while (i <= n) { i++; }" + LF + //
|
||||
" print(i); " + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
|
||||
expectExampleSymTab();
|
||||
addExpectedRun("0", "1");
|
||||
addExpectedRun("-1", "0");
|
||||
addExpectedRun("1", "2");
|
||||
addExpectedRun("10", "11");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bsp16() {
|
||||
initCode("program A" + LF + //
|
||||
" final int max = 12;" + LF + //
|
||||
" char c; int i;" + LF + //
|
||||
" class B { int x, y; }" + LF + //
|
||||
"{" + LF + //
|
||||
" void main ()" + LF + //
|
||||
" int[] iarr; B b; int n;" + LF + //
|
||||
" {" + LF + //
|
||||
" read(i); " + LF + //
|
||||
" if (i <= max) n = 1; else n = 2;" + LF + //
|
||||
" print(n); " + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
|
||||
expectExampleSymTab();
|
||||
addExpectedRun("0", "1");
|
||||
addExpectedRun("13", "2");
|
||||
addExpectedRun("12", "1");
|
||||
addExpectedRun("-1", "1");
|
||||
addExpectedRun("-13", "1");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bsp17() {
|
||||
initCode("program A" + LF + //
|
||||
" final int max = 12;" + LF + //
|
||||
" char c; int i;" + LF + //
|
||||
" class B { int x, y; }" + LF + //
|
||||
"{" + LF + //
|
||||
" void main ()" + LF + //
|
||||
" int[] iarr; B b; int n; int sum;" + LF + //
|
||||
" {" + LF + //
|
||||
" read(n); " + LF + //
|
||||
" sum = 0; " + LF + //
|
||||
" while (i <= n) { sum += i; i++; }" + LF + //
|
||||
" print(sum); " + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
|
||||
expectSymTabWithSum();
|
||||
addExpectedRun("0", "0");
|
||||
addExpectedRun("-1", "0");
|
||||
addExpectedRun("1", "1");
|
||||
addExpectedRun("10", "55");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bsp18() {
|
||||
initCode("program A" + LF + //
|
||||
" final int max = 12;" + LF + //
|
||||
" char c; int i;" + LF + //
|
||||
" class B { int x, y; }" + LF + //
|
||||
"{" + LF + //
|
||||
" void main ()" + LF + //
|
||||
" int[] iarr; B b; int n; int sum;" + LF + //
|
||||
" {" + LF + //
|
||||
" read(n); " + LF + //
|
||||
" sum = 0; " + LF + //
|
||||
" i = 2;" + LF + //
|
||||
" while (i <= n) { sum += i; i++; }" + LF + //
|
||||
" print(sum); " + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
|
||||
expectSymTabWithSum();
|
||||
addExpectedRun("0", "0");
|
||||
addExpectedRun("-1", "0");
|
||||
addExpectedRun("1", "0");
|
||||
addExpectedRun("10", "54");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodCall() {
|
||||
initCode("program A" + LF + // 1
|
||||
"{" + LF + // 2
|
||||
" void bar() {" + LF + // 3
|
||||
" print('b');" + LF + // 4
|
||||
" print('a');" + LF + // 5
|
||||
" print('r');" + LF + // 6
|
||||
" }" + LF + // 7
|
||||
" void foo() {" + LF + // 8
|
||||
" print('f');" + LF + // 9
|
||||
" print('o');" + LF + // 10
|
||||
" print('o');" + LF + // 11
|
||||
" }" + LF + // 12
|
||||
" void main () {" + LF + // 13
|
||||
" foo();" + LF + // 14
|
||||
" }" + LF + // 15
|
||||
"}"); // 16
|
||||
|
||||
addExpectedRun("", "foo");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fib() {
|
||||
initCode("program A" + LF + //
|
||||
"{" + LF + //
|
||||
" int fib(int n) {" + LF + //
|
||||
" if (n <= 1) return 1; " + LF + //
|
||||
" return fib(n-1) + fib(n-2); " + LF + //
|
||||
" }" + LF + //
|
||||
" void main ()" + LF + //
|
||||
" int n;" + LF + //
|
||||
" {" + LF + //
|
||||
" read(n); " + LF + //
|
||||
" print(fib(n)); " + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
|
||||
addExpectedRun("-1", "1");
|
||||
addExpectedRun("0", "1");
|
||||
addExpectedRun("1", "1");
|
||||
addExpectedRun("2", "2");
|
||||
addExpectedRun("3", "3");
|
||||
addExpectedRun("4", "5");
|
||||
addExpectedRun("5", "8");
|
||||
addExpectedRun("6", "13");
|
||||
addExpectedRun("7", "21");
|
||||
addExpectedRun("8", "34");
|
||||
addExpectedRun("9", "55");
|
||||
addExpectedRun("10", "89");
|
||||
addExpectedRun("11", "144");
|
||||
addExpectedRun("22", "28657");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fibDyn() {
|
||||
initCode("program A" + LF + //
|
||||
" int[] matrix; " + LF + //
|
||||
"{" + LF + //
|
||||
" int fib(int n) int r; {" + LF + //
|
||||
" if (n <= 1) return 1; " + LF + //
|
||||
" if(matrix[n] != 0) return matrix[n]; " + LF + //
|
||||
" r = fib(n-1) + fib(n-2); " + LF + //
|
||||
" matrix[n] = r; " + LF + //
|
||||
" return r; " + LF + //
|
||||
" }" + LF + //
|
||||
" void main ()" + LF + //
|
||||
" int n;" + LF + //
|
||||
" {" + LF + //
|
||||
" matrix = new int[1000]; " + LF + //
|
||||
" read(n); " + LF + //
|
||||
" print(fib(n)); " + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
|
||||
addExpectedRun("-1", "1");
|
||||
addExpectedRun("0", "1");
|
||||
addExpectedRun("1", "1");
|
||||
addExpectedRun("2", "2");
|
||||
addExpectedRun("3", "3");
|
||||
addExpectedRun("4", "5");
|
||||
addExpectedRun("5", "8");
|
||||
addExpectedRun("6", "13");
|
||||
addExpectedRun("7", "21");
|
||||
addExpectedRun("8", "34");
|
||||
addExpectedRun("9", "55");
|
||||
addExpectedRun("10", "89");
|
||||
addExpectedRun("11", "144");
|
||||
addExpectedRun("22", "28657");
|
||||
addExpectedRun("30", "1346269");
|
||||
addExpectedRun("40", "165580141");
|
||||
addExpectedRun("45", "1836311903");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testElseIf() {
|
||||
initCode("program Test {" + LF + // 1
|
||||
" void main() int i; {" + LF + // 2
|
||||
" read(i);" + LF + // 3
|
||||
" if (i == 1) print(9);" + LF + // 4
|
||||
" else if (i == 2) print(8);" + LF + // 5
|
||||
" else print(7);" + LF + // 6
|
||||
" }" + LF + // 7
|
||||
"}");
|
||||
addExpectedRun("1", "9");
|
||||
addExpectedRun("2", "8");
|
||||
addExpectedRun("3", "7");
|
||||
addExpectedRun("4", "7");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mainVar() {
|
||||
initCode("program Test" + LF + //
|
||||
" int main;" + LF + //
|
||||
"{" + LF + //
|
||||
"}");
|
||||
expectError(4, 2, MAIN_NOT_FOUND);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mainNotVoid() {
|
||||
initCode("program Test {" + LF + //
|
||||
" char main() { }" + LF + //
|
||||
"}");
|
||||
expectError(2, 15, MAIN_NOT_VOID);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noLoop() {
|
||||
initCode("program Test {" + LF + //
|
||||
" void main() {" + LF + //
|
||||
" break;" + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
expectError(3, 10, BREAK_OUTSIDE_LOOP);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void returnVoid() {
|
||||
initCode("program Test {" + LF + //
|
||||
" void test() {" + LF + //
|
||||
" return 5;" + LF + //
|
||||
" }" + LF + //
|
||||
" void main() {}" + LF + //
|
||||
"}");
|
||||
expectError(3, 12, UNEXPECTED_RETURN_VALUE);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrongReturnType() {
|
||||
initCode("program Test {" + LF + //
|
||||
" int test() {" + LF + //
|
||||
" return 'x';" + LF + //
|
||||
" }" + LF + //
|
||||
" void main() {}" + LF + //
|
||||
"}");
|
||||
expectError(3, 15, RETURN_TYPE_MISMATCH);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrongReturnTypeNull() {
|
||||
initCode("program Test {" + LF + //
|
||||
" int test() {" + LF + //
|
||||
" return null;" + LF + //
|
||||
" }" + LF + //
|
||||
" void main() {}" + LF + //
|
||||
"}");
|
||||
expectError(3, 16, RETURN_TYPE_MISMATCH);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noReturnVal() {
|
||||
initCode("program Test {" + LF + //
|
||||
" int test() {" + LF + //
|
||||
" return;" + LF + //
|
||||
" }" + LF + //
|
||||
" void main() {}" + LF + //
|
||||
"}");
|
||||
expectError(3, 11, MISSING_RETURN_VALUE);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrongReturnTypeArr() {
|
||||
initCode("program Test {" + LF + //
|
||||
" int[] test() {" + LF + //
|
||||
" return new int[10];" + LF + //
|
||||
" }" + LF + //
|
||||
" void main() {}" + LF + //
|
||||
"}");
|
||||
expectError(2, 9, ILLEGAL_METHOD_RETURN_TYPE);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrongReturnClass() {
|
||||
initCode("program Test" + LF + //
|
||||
" class C1 { }" + LF + //
|
||||
"{" + LF + //
|
||||
" C1 test() {" + LF + //
|
||||
" return new C1;" + LF + //
|
||||
" }" + LF + //
|
||||
" void main() {}" + LF + //
|
||||
"}");
|
||||
expectError(4, 6, ILLEGAL_METHOD_RETURN_TYPE);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noMeth() {
|
||||
initCode("program Test {" + LF + //
|
||||
" void main() int i; {" + LF + //
|
||||
" i(10);" + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
expectError(3, 7, CALL_TO_NON_METHOD);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void paramType() {
|
||||
initCode("program Test {" + LF + //
|
||||
" void method(int x) { }" + LF + //
|
||||
" void main() {" + LF + //
|
||||
" method('a');" + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
expectError(4, 15, ARGUMENT_TYPE_MISMATCH);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void paramTypeArr() {
|
||||
initCode("program Test {" + LF + //
|
||||
" void method(int[] x) { }" + LF + //
|
||||
" void main() {" + LF + //
|
||||
" method(new char[10]);" + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
expectError(4, 24, ARGUMENT_TYPE_MISMATCH);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void paramTypeClass() {
|
||||
initCode("program Test" + LF + //
|
||||
" class C1 { }" + LF + //
|
||||
" class C2 { }" + LF + //
|
||||
"{" + LF + //
|
||||
" void method(C1 c1) { }" + LF + //
|
||||
" void main() {" + LF + //
|
||||
" method(new C2);" + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
expectError(7, 18, ARGUMENT_TYPE_MISMATCH);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void moreParams() {
|
||||
initCode("program Test {" + LF + //
|
||||
" void method(int x, char c) { }" + LF + //
|
||||
" void main() {" + LF + //
|
||||
" method(1, 'a', 1);" + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
expectError(4, 21, WRONG_ARGUMENT_COUNT);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lessParams() {
|
||||
initCode("program Test {" + LF + //
|
||||
" void method(int x, char c) { }" + LF + //
|
||||
" void main() {" + LF + //
|
||||
" method(1);" + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
expectError(4, 13, WRONG_ARGUMENT_COUNT);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incompTypesCond() {
|
||||
initCode("program Test {" + LF + //
|
||||
" void main() int i; { " + LF + //
|
||||
" if (i > null) { }" + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
expectError(3, 17, INCOMPATIBLE_TYPES);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incompTypesCondArr() {
|
||||
initCode("program Test {" + LF + //
|
||||
" void main() int[] ia; char[] ca; { " + LF + //
|
||||
" if (ia > ca) { }" + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
expectError(3, 16, INCOMPATIBLE_TYPES);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incompTypesCondClass() {
|
||||
initCode("program Test" + LF + //
|
||||
" class C1 { }" + LF + //
|
||||
"{" + LF + //
|
||||
" void main() C1 c1; int i; { " + LF + //
|
||||
" if (c1 > i) { };" + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
expectError(5, 15, INCOMPATIBLE_TYPES);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrongEqCheck() {
|
||||
initCode("program Test {" + LF + //
|
||||
" void main() int[] ia1, ia2; {" + LF + //
|
||||
" if (ia1 > ia2) { }" + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
expectError(3, 18, ILLEGAL_REFERENCE_COMPARISON);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleBreak() {
|
||||
initCode("program Test {" + LF + //
|
||||
" void main() {" + LF + //
|
||||
" while(42 > 0) /* while(true) */" + LF + //
|
||||
" {" + LF + //
|
||||
" break;" + LF + //
|
||||
" }" + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBreak() {
|
||||
initCode("program A" + LF + //
|
||||
" int i;" + LF + //
|
||||
"{" + LF + //
|
||||
" void main ()" + LF + //
|
||||
" int n;" + LF + //
|
||||
" {" + LF + //
|
||||
" read(n); " + LF + //
|
||||
" while (i <= n) { while(1 < 2) { if(1 == 1) { break; } } if(i == 5) break; i++; }"
|
||||
+ LF + //
|
||||
" print(i); " + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
addExpectedRun("10", "5");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNestedBreak() {
|
||||
initCode("program Test {" + LF + //
|
||||
" void main() " + LF + //
|
||||
" int n, o;" + LF + //
|
||||
" {" + LF + //
|
||||
" o = 21;" + LF + //
|
||||
" while(83 < 84)" + LF + //
|
||||
" {" + LF + //
|
||||
" while(167 < 168)" + LF + //
|
||||
" {" + LF + //
|
||||
" break;" + LF + //
|
||||
" }" + LF + //
|
||||
" break;" + LF + //
|
||||
" }" + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lenTest() {
|
||||
initCode("program A" + LF + //
|
||||
" class A { int[] x; }" + LF + //
|
||||
" class B { A a; }" + LF + //
|
||||
" class C { B b; }" + LF + //
|
||||
"{" + LF + //
|
||||
" void main ()" + LF + //
|
||||
" C[] c;" + LF + //
|
||||
" {" + LF + //
|
||||
" c = new C[5];" + LF + //
|
||||
" print(len(c));" + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
|
||||
addExpectedRun("5");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void basicOrdChrTest() {
|
||||
initCode("program Test {" + LF + //
|
||||
" void main() int i; char c; {" + LF + //
|
||||
" i = ord('A');" + LF + //
|
||||
" print(i);" + LF + //
|
||||
" i = ord('*');" + LF + //
|
||||
" print(i);" + LF + //
|
||||
" c = chr(49);" + LF + //
|
||||
" print(c);" + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
|
||||
addExpectedRun("65421");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void trappingOrdChrTest() {
|
||||
initCode("program Test {" + LF + //
|
||||
" int trap() {" + LF + //
|
||||
" print(7 * 7);" + LF + //
|
||||
" }" + LF + //
|
||||
" void main() int i; char c; {" + LF + //
|
||||
" ord('!');" + LF + //
|
||||
" chr(42);" + LF + //
|
||||
" i = ord('!');" + LF + //
|
||||
" c = chr(42);" + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
|
||||
addExpectedRun("");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unusedReturnVal() {
|
||||
initCode("program Test {" + LF + //
|
||||
" int getUnused() {" + LF + //
|
||||
" return 351;" + LF + //
|
||||
" }" + LF + //
|
||||
" int polluteAndGet() {" + LF + //
|
||||
" getUnused();" + LF + //
|
||||
" return 42;" + LF + //
|
||||
" }" + LF + //
|
||||
" void main() {" + LF + //
|
||||
" print(932 + polluteAndGet());" + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
|
||||
addExpectedRun("974");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void coverUniverseMethod() {
|
||||
initCode("program Test {" + LF + //
|
||||
" int cast(char c) { return ord(c); }" + LF + //
|
||||
" int ord(char c) { return cast(c) - 30; }" + LF + //
|
||||
" void main() {" + LF + //
|
||||
" print(chr(ord('A')));" + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
|
||||
addExpectedRun("#");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void paramType2() {
|
||||
initCode("program Test {" + LF + //
|
||||
" void method(int x, int y) { }" + LF + //
|
||||
" void main() {" + LF + //
|
||||
" method(1, 'a');" + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
expectError(4, 18, ARGUMENT_TYPE_MISMATCH);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void paramTypeArr2() {
|
||||
initCode("program Test {" + LF + //
|
||||
" void method(int[] x, int y) { }" + LF + //
|
||||
" void main() {" + LF + //
|
||||
" method(new int[10], new char[10]);" + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
expectError(4, 37, ARGUMENT_TYPE_MISMATCH);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void paramTypeClass2() {
|
||||
initCode("program Test" + LF + //
|
||||
" class C1 { }" + LF + //
|
||||
" class C2 { }" + LF + //
|
||||
"{" + LF + //
|
||||
" void method(C1 c1, C2 c2) { }" + LF + //
|
||||
" void main() {" + LF + //
|
||||
" method(new C1, new C1);" + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
expectError(7, 26, ARGUMENT_TYPE_MISMATCH);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRelops() {
|
||||
initFile("relops.mj");
|
||||
addExpectedRun("0", "!=,<,<=,");
|
||||
addExpectedRun("1", "==,<=,>=,");
|
||||
addExpectedRun("2", "!=,>,>=,");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAnimals() {
|
||||
initFile("animals.mj");
|
||||
addExpectedRun("0", "cat");
|
||||
addExpectedRun("1", "dog");
|
||||
addExpectedRun("2", "octopus");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compareNeg() {
|
||||
initCode("program A" + LF + //
|
||||
"{" + LF + //
|
||||
" void main ()" + LF + //
|
||||
" int neg;" + LF + //
|
||||
" {" + LF + //
|
||||
" neg = -42;" + LF + //
|
||||
" if (neg == -42) print(42);" + LF + //
|
||||
" else print(neg); " + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
|
||||
addExpectedRun("42");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
// index from end tests
|
||||
@Test
|
||||
public void arrayFromEndWithFunctionCall() {
|
||||
initCode("""
|
||||
program Test
|
||||
final int len = 2;
|
||||
{
|
||||
int const1() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void main() int[] a; {
|
||||
a = new int[len];
|
||||
a[0] = 13;
|
||||
a[~const1()] = 42;
|
||||
print(a[~const1()]);
|
||||
}
|
||||
}""");
|
||||
addExpectedRun("42");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createPalindrom() {
|
||||
initCode("""
|
||||
program Test {
|
||||
void toPalindrom(char[] in, char[] out) int i, l; {
|
||||
l = len(in);
|
||||
i = 0;
|
||||
while (i < l) {
|
||||
out[i] = in[i];
|
||||
out[~(i + 1)] = in[i];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void printText(char[] text) int i; {
|
||||
i = 0;
|
||||
while (i < len(text)) {
|
||||
print(text[i]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void main() char[] a, out; int i; {
|
||||
a = new char[5];
|
||||
a[0] = 'l';
|
||||
a[1] = 'a';
|
||||
a[2] = 'g';
|
||||
a[3] = 'e';
|
||||
a[4] = 'r';
|
||||
|
||||
out = new char[10];
|
||||
|
||||
toPalindrom(a, out);
|
||||
printText(out);
|
||||
|
||||
a = new char[2];
|
||||
a[0] = 'o';
|
||||
a[1] = 't';
|
||||
|
||||
out = new char[4];
|
||||
|
||||
toPalindrom(a, out);
|
||||
printText(out);
|
||||
}
|
||||
}""");
|
||||
addExpectedRun("lagerregalotto");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void iterateArrayFromEnd() {
|
||||
initCode("""
|
||||
program Test
|
||||
final int len = 3;
|
||||
{
|
||||
void main() int[] a; int i; {
|
||||
a = new int[len];
|
||||
a[0] = 1;
|
||||
a[1] = 2;
|
||||
a[2] = 3;
|
||||
i = 1;
|
||||
while (i <= len) {
|
||||
print(a[~i]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}""");
|
||||
addExpectedRun("321");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
}
|
||||
406
MicroJava Tests/tests/ssw/mj/test/ParserTest.java
Normal file
406
MicroJava Tests/tests/ssw/mj/test/ParserTest.java
Normal file
@@ -0,0 +1,406 @@
|
||||
package ssw.mj.test;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import ssw.mj.scanner.Token;
|
||||
import ssw.mj.test.support.BaseCompilerTestCase;
|
||||
|
||||
import static ssw.mj.Errors.Message.*;
|
||||
|
||||
public class ParserTest extends BaseCompilerTestCase {
|
||||
|
||||
@Test
|
||||
public void testWorkingFinalDecls() {
|
||||
initCode("program Test" + LF + // 1
|
||||
" final int i = 1;" + LF + // 2
|
||||
" final int j = 1;" + LF + // 3
|
||||
" final int k = 1;" + LF + // 4
|
||||
"{ void main() { } }"); // 5
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWorkingDecls() {
|
||||
initCode("program Test" + LF + // 1
|
||||
" int i;" + LF + // 2
|
||||
" int j, k;" + LF + // 3
|
||||
"{ void main() { } }"); // 4
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWorkingMethods() {
|
||||
initCode("program Test" + LF + // 1
|
||||
" int i;" + LF + // 2
|
||||
" int j, k;" + LF + // 3
|
||||
"{" + LF + // 4
|
||||
" void foo() { }" + LF + // 5
|
||||
" void bar() { }" + LF + // 6
|
||||
" void main() { }" + LF + // 7
|
||||
" }" + LF // 8
|
||||
);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWorkingMethodsWithParameters() {
|
||||
initCode("program Test" + LF + // 1
|
||||
"{" + LF + // 2
|
||||
" void foo(int i) { }" + LF + // 3
|
||||
" void bar(int i, char c) { }" + LF + // 4
|
||||
" void main() { }" + LF + // 5
|
||||
" }" + LF // 6
|
||||
);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWorkingMethodsWithLocals() {
|
||||
initCode("program Test" + LF + // 1
|
||||
"{" + LF + // 2
|
||||
" void foo() int i; { }" + LF + // 3
|
||||
" void bar() int i; char c; { }" + LF + // 4
|
||||
" void main() { }" + LF + // 5
|
||||
" }" + LF // 6
|
||||
);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWorkingMethodsWithParametersAndLocals() {
|
||||
initCode("program Test" + LF + // 1
|
||||
"{" + LF + // 2
|
||||
" void foo(char ch) int i; { }" + LF + // 3
|
||||
" void bar(int x, int y) int i; char c; { }" + LF + // 4
|
||||
" void main() { }" + LF + // 5
|
||||
" }" + LF // 6
|
||||
);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWorkingMethodCall() {
|
||||
initCode("program Test" + LF + // 1
|
||||
"{" + LF + // 2
|
||||
" void foo(char ch) int i; { }" + LF + // 3
|
||||
" void main() { foo('a'); }" + LF + // 4
|
||||
" }" + LF // 5
|
||||
);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWorkingMethodCallTwoParams() {
|
||||
initCode("program Test" + LF + // 1
|
||||
"{" + LF + // 2
|
||||
" void foo(char ch, int x) int i; { }" + LF + // 3
|
||||
" void main() { foo('a', 1); }" + LF + // 4
|
||||
" }" + LF // 5
|
||||
);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWorkingMethodCallThreeParams() {
|
||||
initCode("program Test" + LF + // 1
|
||||
"{" + LF + // 2
|
||||
" void foo(char ch, int x, char ch2) int i; { }" + LF + // 3
|
||||
" void main() { foo('a', 1, 'b'); }" + LF + // 4
|
||||
" }" + LF // 5
|
||||
);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWorkingClass() {
|
||||
initCode("program Test" + LF + // 1
|
||||
"class X { int i; int j; }" + LF + // 2
|
||||
"{" + LF + // 3
|
||||
" void main() X x; { x = new X; }" + LF + // 4
|
||||
"}" + LF // 5
|
||||
);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWorkingArray() {
|
||||
initCode("program Test" + LF + // 1
|
||||
"{" + LF + // 2
|
||||
" void main() int[] x; { x = new int[10]; }" + LF + // 3
|
||||
"}" + LF // 4
|
||||
);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWorkingIncDec() {
|
||||
initCode("program Test" + LF + // 1
|
||||
"{" + LF + // 2
|
||||
" void main() int i; { i--; i++; }" + LF + // 3
|
||||
" }" + LF // 4
|
||||
);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWorkingElseIf() {
|
||||
initCode("program Test {" + LF + // 1
|
||||
" void main() int i; {" + LF + // 2
|
||||
" if (i > 10) i++;" + LF + // 3
|
||||
" else if (i < 5) i--;" + LF + // 4
|
||||
" else i += 8;" + LF + // 5
|
||||
" }" + LF + // 6
|
||||
"}");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWorkingLoop() {
|
||||
initCode("program Test {" + LF + // 1
|
||||
" void main () int i; {" + LF + // 2
|
||||
" i = 0;" + LF + // 3
|
||||
" while (i < 42) {" + LF + // 4
|
||||
" i++;" + LF + // 5
|
||||
" }" + LF + // 6
|
||||
" }" + LF + // 7
|
||||
"}");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mulAssign() {
|
||||
initCode("program Test {" + LF + //
|
||||
" void main() int i; {" + LF + //
|
||||
" i = 2;" + LF + //
|
||||
" i *= 2;" + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void returnExpr() {
|
||||
initCode("program Test {" + LF + //
|
||||
" void main() { }" + LF + //
|
||||
" int wrong1() { " + LF + //
|
||||
" return 2 + 3;" + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrongConstDecl() {
|
||||
initCode("program Test" + LF + //
|
||||
" final int i = a;" + LF + //
|
||||
"{ void main() { } }");
|
||||
expectError(2, 17, INVALID_CONST_TYPE);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrongDesignFollow() {
|
||||
initCode("program Test {" + LF + //
|
||||
" void main() int i; {" + LF + //
|
||||
" i**;" + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
expectError(3, 6, INVALID_DESIGNATOR_STATEMENT);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrongFactor() {
|
||||
initCode("program Test {" + LF + //
|
||||
" void main () int i; { " + LF + //
|
||||
" i = i + if;" + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
expectError(3, 13, INVALID_FACTOR);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrongRelOp() {
|
||||
initCode("program Test {" + LF + //
|
||||
" void main() int i; {" + LF + //
|
||||
" if (i x 5);" + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
expectError(3, 11, INVALID_REL_OP);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrongStart() {
|
||||
initCode("noprogram Test { }");
|
||||
expectError(1, 1, TOKEN_EXPECTED, "program");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noProgName() {
|
||||
initCode("program { }");
|
||||
expectError(1, 9, TOKEN_EXPECTED, "identifier");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrongVarDecl() {
|
||||
initCode("program Test " + LF + //
|
||||
"int var1,,,,var2;" + LF + //
|
||||
"{ void main() { } }");
|
||||
expectError(2, 10, TOKEN_EXPECTED, Token.Kind.ident.label());
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void eofExpected() {
|
||||
initCode("program Test {" + LF + //
|
||||
" void main() {}" + LF + //
|
||||
"}moretext");
|
||||
expectError(3, 2, TOKEN_EXPECTED, "end of file");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidEOF1() {
|
||||
initCode("program Test {" + LF + //
|
||||
" void main() {");
|
||||
expectError(2, 16, TOKEN_EXPECTED, "}");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidEOF2() {
|
||||
initCode("program Test {" + LF + //
|
||||
" void main() {" + LF + //
|
||||
" if ()");
|
||||
expectError(3, 9, INVALID_FACTOR);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidEOF3() {
|
||||
initCode("program Test" + LF + //
|
||||
" class C {" + LF + //
|
||||
" int i");
|
||||
expectError(3, 10, TOKEN_EXPECTED, ";");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWorkingReadAndPrint() {
|
||||
initCode("program Test {" + LF + // 1
|
||||
" void main() int i; {" + LF + // 2
|
||||
" read(i);" + LF +
|
||||
" print(i);" + LF +
|
||||
" }" + LF + //3
|
||||
"}");//4
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
// index from end tests
|
||||
@Test
|
||||
public void wrongTildeInExpr() {
|
||||
initCode("""
|
||||
program Test {
|
||||
void main() int i; {
|
||||
i = ~1;
|
||||
}
|
||||
}""");
|
||||
expectError(3, 9, INVALID_FACTOR);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrongTildeCompoundAssign() {
|
||||
initCode("""
|
||||
program Test {
|
||||
void main() int i; {
|
||||
i ~= 2;
|
||||
}
|
||||
}""");
|
||||
expectError(3, 7, INVALID_DESIGNATOR_STATEMENT);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrongDoubleTilde() {
|
||||
initCode("""
|
||||
program Test {
|
||||
void main() int[] a; int i; {
|
||||
i = a[~~1];
|
||||
}
|
||||
}
|
||||
""");
|
||||
expectError(3, 12, INVALID_FACTOR);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constantArrayAccessFromEnd() {
|
||||
initCode("""
|
||||
program Test {
|
||||
void main() int[] a; int i; {
|
||||
a = new int[3];
|
||||
a[~1] = 3;
|
||||
a[~2] = 2;
|
||||
a[~3] = 1;
|
||||
i = a[~1];
|
||||
print(i);
|
||||
}
|
||||
}""");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void computedArrayAccessFromEnd() {
|
||||
initCode("""
|
||||
program Test {
|
||||
void main() int[] a; int i; {
|
||||
a = new int[3];
|
||||
a[~(2 * 6 - 11)] = 3;
|
||||
a[~(9 - 11 + 4)] = 2;
|
||||
a[~(-(-3))] = 1;
|
||||
i = a[~(a[0] + 2 * 6 - 11)];
|
||||
print(i);
|
||||
}
|
||||
}""");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dynamicArrayAccessFromEnd() {
|
||||
initCode("""
|
||||
program Test {
|
||||
void main() int[] a; int i; {
|
||||
read(i);
|
||||
a = new int[i];
|
||||
a[~i] = 1;
|
||||
a[~(i - 1)] = 2;
|
||||
a[~(i - 2)] = 3;
|
||||
i = a[~i];
|
||||
print(i);
|
||||
}
|
||||
}""");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void globalArrayAccessFromEnd() {
|
||||
initCode("""
|
||||
program Test
|
||||
final int len = 3;
|
||||
{
|
||||
void main() int[] a; int i; {
|
||||
a = new int[len];
|
||||
a[~len] = 1;
|
||||
a[~(len - 1)] = 2;
|
||||
a[~(len - 2)] = 3;
|
||||
i = a[~len];
|
||||
print(i);
|
||||
}
|
||||
}""");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
}
|
||||
177
MicroJava Tests/tests/ssw/mj/test/RecoverTest.java
Normal file
177
MicroJava Tests/tests/ssw/mj/test/RecoverTest.java
Normal file
@@ -0,0 +1,177 @@
|
||||
package ssw.mj.test;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import ssw.mj.Errors.Message;
|
||||
import ssw.mj.test.support.BaseCompilerTestCase;
|
||||
|
||||
import static ssw.mj.Errors.Message.*;
|
||||
|
||||
public class RecoverTest extends BaseCompilerTestCase {
|
||||
@Test
|
||||
public void wrongGlobalDecl() {
|
||||
initCode("program Test" + LF + //
|
||||
" 123;" + LF + //
|
||||
"{ void main() { } }");
|
||||
expectError(2, 3, DECLARATION_RECOVERY);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrongMethDecl1() {
|
||||
initCode("program Test {" + LF + //
|
||||
" void main() { }" + LF + //
|
||||
" program wrong1() { " + LF + //
|
||||
" if (1>2);" + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
expectError(3, 3, METHOD_DECL_RECOVERY);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrongMethDecl2() {
|
||||
initCode("program Test {" + LF + //
|
||||
" program wrong1() { " + LF + //
|
||||
" if (1>2);" + LF + //
|
||||
" }" + LF + //
|
||||
" void main() { }" + LF + //
|
||||
" program wrong2() {" + LF + //
|
||||
" if (1>2);" + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
expectError(2, 3, METHOD_DECL_RECOVERY);
|
||||
expectError(6, 3, METHOD_DECL_RECOVERY);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrongMethDecl3() {
|
||||
initCode("program Test {" + LF + //
|
||||
" program wrong1() { }" + LF + //
|
||||
" void main() { }" + LF + //
|
||||
" program wrong2() { }" + LF + //
|
||||
"}");
|
||||
expectError(2, 3, METHOD_DECL_RECOVERY);
|
||||
expectError(4, 3, METHOD_DECL_RECOVERY);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrongStat() {
|
||||
initCode("program Test {" + LF + //
|
||||
" void main() { " + LF + //
|
||||
" 123;" + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
expectError(3, 5, STATEMENT_RECOVERY);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipleErrors() {
|
||||
initCode("program Test " + LF + //
|
||||
" int x" + LF + //
|
||||
"{" + LF + //
|
||||
" void main( {" + LF + //
|
||||
" if (1 x 2);" + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
expectError(3, 1, TOKEN_EXPECTED, ";");
|
||||
expectError(4, 14, TOKEN_EXPECTED, ")");
|
||||
expectError(5, 11, INVALID_REL_OP);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
// ---- multiple errors & recovery
|
||||
@Test
|
||||
public void noRecover1() {
|
||||
initCode("program Test {" + LF + //
|
||||
" void main this method will never recover");
|
||||
|
||||
expectError(2, 13, TOKEN_EXPECTED, "(");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noRecover2() {
|
||||
initCode("program Test {" + LF + //
|
||||
" void main() { " + LF + //
|
||||
" if this method will never recover");
|
||||
|
||||
expectError(3, 8, TOKEN_EXPECTED, "(");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void recoverDecl1() {
|
||||
initCode("program Test" + LF + //
|
||||
" int i1, if" + LF + //
|
||||
" in i2;" + LF + //
|
||||
" final int i3 = 0;" + LF + //
|
||||
"{" + LF + //
|
||||
" void main() { " + LF + //
|
||||
" if (i1 < i3);" + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
|
||||
expectError(2, 11, TOKEN_EXPECTED, "identifier");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void recoverDecl2() {
|
||||
initCode("program Test" + LF + //
|
||||
" int i1, if" + LF + //
|
||||
" in i2;" + LF + //
|
||||
" int i3;" + LF + //
|
||||
"{" + LF + //
|
||||
" void main() { " + LF + //
|
||||
" if (i1 < i3);" + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
|
||||
expectError(2, 11, TOKEN_EXPECTED, "identifier");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void recoverStat() {
|
||||
initCode("program Test {" + LF + //
|
||||
" void main() { " + LF + //
|
||||
" 567 since distance stays too small no follow up errors here;" + LF + //
|
||||
" if (1 < 2);" + LF + //
|
||||
" if (1 x 2);" + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
|
||||
expectError(3, 5, STATEMENT_RECOVERY);
|
||||
expectError(5, 11, INVALID_REL_OP);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resetErrDist() {
|
||||
initCode("program Test {" + LF + //
|
||||
" void main() {" + LF + //
|
||||
" if () if () if();" + LF + //
|
||||
" }" + LF + //
|
||||
"}");
|
||||
expectError(3, 9, INVALID_FACTOR);
|
||||
expectError(3, 15, INVALID_FACTOR);
|
||||
expectError(3, 20, INVALID_FACTOR);
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void illegalMethodStart() {
|
||||
initCode("program Test" + LF + // 1
|
||||
"{" + LF + // 2
|
||||
" void foo()" + LF + // 3
|
||||
" void foo(char x) { }" + LF + // 4
|
||||
" void main() { }" + LF + // 5
|
||||
"}" + LF // 6
|
||||
);
|
||||
expectError(4, 3, Message.TOKEN_EXPECTED, "{");
|
||||
parseVerifyVisualize();
|
||||
}
|
||||
}
|
||||
888
MicroJava Tests/tests/ssw/mj/test/ScannerTest.java
Normal file
888
MicroJava Tests/tests/ssw/mj/test/ScannerTest.java
Normal file
@@ -0,0 +1,888 @@
|
||||
package ssw.mj.test;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import ssw.mj.test.support.BaseCompilerTestCase;
|
||||
|
||||
import static ssw.mj.Errors.Message.*;
|
||||
import static ssw.mj.scanner.Token.Kind.*;
|
||||
|
||||
public class ScannerTest extends BaseCompilerTestCase {
|
||||
private static final char invalidChar = (char) 65533;
|
||||
|
||||
@Test
|
||||
public void oneToken() {
|
||||
initScannerCode(";");
|
||||
|
||||
expectToken(semicolon, 1, 1);
|
||||
expectToken(eof, 1, 2);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void twoTokens() {
|
||||
initScannerCode(";;");
|
||||
|
||||
expectToken(semicolon, 1, 1);
|
||||
expectToken(semicolon, 1, 2);
|
||||
expectToken(eof, 1, 3);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void space() {
|
||||
initScannerCode("; ;");
|
||||
|
||||
expectToken(semicolon, 1, 1);
|
||||
expectToken(semicolon, 1, 4);
|
||||
expectToken(eof, 1, 5);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tabulator() {
|
||||
initScannerCode(";\t\t;");
|
||||
|
||||
expectToken(semicolon, 1, 1);
|
||||
expectToken(semicolon, 1, 4);
|
||||
expectToken(eof, 1, 5);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noToken() {
|
||||
initScannerCode("");
|
||||
|
||||
expectToken(eof, 1, 1);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void crLfLineSeparators() {
|
||||
initScannerCode(";" + CR + LF + " ;" + CR + LF + " ; ");
|
||||
|
||||
expectToken(semicolon, 1, 1);
|
||||
expectToken(semicolon, 2, 2);
|
||||
expectToken(semicolon, 3, 3);
|
||||
expectToken(eof, 3, 5);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lFLineSeparators() {
|
||||
initScannerCode(";" + LF + " ;" + LF + " ; ");
|
||||
|
||||
expectToken(semicolon, 1, 1);
|
||||
expectToken(semicolon, 2, 2);
|
||||
expectToken(semicolon, 3, 3);
|
||||
expectToken(eof, 3, 5);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidChar1() {
|
||||
initScannerCode(" {" + invalidChar + "} ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(none, 1, 3);
|
||||
expectError(1, 3, INVALID_CHAR, invalidChar);
|
||||
expectToken(rbrace, 1, 4);
|
||||
expectToken(eof, 1, 6);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidChar2() {
|
||||
initScannerCode(" {\0} ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(none, 1, 3);
|
||||
expectError(1, 3, INVALID_CHAR, '\0');
|
||||
expectToken(rbrace, 1, 4);
|
||||
expectToken(eof, 1, 6);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidChar3() {
|
||||
initScannerCode(" {&} ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(none, 1, 3);
|
||||
expectError(1, 3, INVALID_CHAR, '&');
|
||||
expectToken(rbrace, 1, 4);
|
||||
expectToken(eof, 1, 6);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidChar4() {
|
||||
initScannerCode(" {|} ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(none, 1, 3);
|
||||
expectError(1, 3, INVALID_CHAR, '|');
|
||||
expectToken(rbrace, 1, 4);
|
||||
expectToken(eof, 1, 6);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidChar5() {
|
||||
initScannerCode(" {!} ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(none, 1, 3);
|
||||
expectError(1, 3, INVALID_CHAR, '!');
|
||||
expectToken(rbrace, 1, 4);
|
||||
expectToken(eof, 1, 6);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidChar6() {
|
||||
initScannerCode(" {ident" + invalidChar + "} ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(ident, 1, 3, "ident");
|
||||
expectToken(none, 1, 8);
|
||||
expectError(1, 8, INVALID_CHAR, invalidChar);
|
||||
expectToken(rbrace, 1, 9);
|
||||
expectToken(eof, 1, 11);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ident() {
|
||||
initScannerCode(" {i I i1 i_ i1I_i} ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(ident, 1, 3, "i");
|
||||
expectToken(ident, 1, 5, "I");
|
||||
expectToken(ident, 1, 7, "i1");
|
||||
expectToken(ident, 1, 10, "i_");
|
||||
expectToken(ident, 1, 13, "i1I_i");
|
||||
expectToken(rbrace, 1, 18);
|
||||
expectToken(eof, 1, 20);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void indentSepararator() {
|
||||
initScannerCode(" {i[i<i0i_i>i]i} ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(ident, 1, 3, "i");
|
||||
expectToken(lbrack, 1, 4);
|
||||
expectToken(ident, 1, 5, "i");
|
||||
expectToken(lss, 1, 6);
|
||||
expectToken(ident, 1, 7, "i0i_i");
|
||||
expectToken(gtr, 1, 12);
|
||||
expectToken(ident, 1, 13, "i");
|
||||
expectToken(rbrack, 1, 14);
|
||||
expectToken(ident, 1, 15, "i");
|
||||
expectToken(rbrace, 1, 16);
|
||||
expectToken(eof, 1, 18);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void singleIdent() {
|
||||
initScannerCode("i");
|
||||
|
||||
expectToken(ident, 1, 1, "i");
|
||||
expectToken(eof, 1, 2);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void number() {
|
||||
initScannerCode(" {123 2147483647} ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(number, 1, 3, 123);
|
||||
expectToken(number, 1, 7, 2147483647);
|
||||
expectToken(rbrace, 1, 17);
|
||||
expectToken(eof, 1, 19);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void singleNumber() {
|
||||
initScannerCode("123");
|
||||
|
||||
expectToken(number, 1, 1, 123);
|
||||
expectToken(eof, 1, 4);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void negativeNumber() {
|
||||
initScannerCode(" {-123} ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(minus, 1, 3);
|
||||
expectToken(number, 1, 4, 123);
|
||||
expectToken(rbrace, 1, 7);
|
||||
expectToken(eof, 1, 9);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bigNumber() {
|
||||
initScannerCode(" {2147483648} ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectInvalidToken(number, 1, 3);
|
||||
expectError(1, 3, BIG_NUM, "2147483648");
|
||||
expectToken(rbrace, 1, 13);
|
||||
expectToken(eof, 1, 15);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void negativeBigNumber() {
|
||||
initScannerCode(" {-2147483648} ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(minus, 1, 3);
|
||||
expectInvalidToken(number, 1, 4);
|
||||
expectError(1, 4, BIG_NUM, "2147483648");
|
||||
expectToken(rbrace, 1, 14);
|
||||
expectToken(eof, 1, 16);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void reallyBigNumber() {
|
||||
initScannerCode(" {1234567890123456789012345678901234567890} ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectInvalidToken(number, 1, 3);
|
||||
expectError(1, 3, BIG_NUM, "1234567890123456789012345678901234567890");
|
||||
expectToken(rbrace, 1, 43);
|
||||
expectToken(eof, 1, 45);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void numberIdent() {
|
||||
initScannerCode(" {123abc123 123break} ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(number, 1, 3, 123);
|
||||
expectToken(ident, 1, 6, "abc123");
|
||||
expectToken(number, 1, 13, 123);
|
||||
expectToken(break_, 1, 16);
|
||||
expectToken(rbrace, 1, 21);
|
||||
expectToken(eof, 1, 23);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void numbersSeparated() {
|
||||
initScannerCode("123.456,789");
|
||||
|
||||
expectToken(number, 1, 1, 123);
|
||||
expectToken(period, 1, 4);
|
||||
expectToken(number, 1, 5, 456);
|
||||
expectToken(comma, 1, 8);
|
||||
expectToken(number, 1, 9, 789);
|
||||
expectToken(eof, 1, 12);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void identsSeparated() {
|
||||
initScannerCode("abc.def,ghi\njkl");
|
||||
|
||||
expectToken(ident, 1, 1, "abc");
|
||||
expectToken(period, 1, 4);
|
||||
expectToken(ident, 1, 5, "def");
|
||||
expectToken(comma, 1, 8);
|
||||
expectToken(ident, 1, 9, "ghi");
|
||||
expectToken(ident, 2, 1, "jkl");
|
||||
expectToken(eof, 2, 4);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void newlineBetweenIdentifiersAndTokens() {
|
||||
initScannerCode("anIdentifier" + LF + "class" + LF + "anotherIdentifier");
|
||||
|
||||
expectToken(ident, 1, 1, "anIdentifier");
|
||||
expectToken(class_, 2, 1);
|
||||
expectToken(ident, 3, 1, "anotherIdentifier");
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void newlineAndSpacesBetweenIdentifiersAndTokens() {
|
||||
initScannerCode(" anIdentifier" + LF + " class" + LF + " anotherIdentifier");
|
||||
|
||||
expectToken(ident, 1, 2, "anIdentifier");
|
||||
expectToken(class_, 2, 3);
|
||||
expectToken(ident, 3, 4, "anotherIdentifier");
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void charConst() {
|
||||
initScannerCode(" {' ' 'A' 'z' '0' '!' '\"' '" + invalidChar + "' '\0'} ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(charConst, 1, 3, ' ');
|
||||
expectToken(charConst, 1, 7, 'A');
|
||||
expectToken(charConst, 1, 11, 'z');
|
||||
expectToken(charConst, 1, 15, '0');
|
||||
expectToken(charConst, 1, 19, '!');
|
||||
expectToken(charConst, 1, 23, '"');
|
||||
expectToken(charConst, 1, 27, invalidChar);
|
||||
expectToken(charConst, 1, 31, '\0');
|
||||
expectToken(rbrace, 1, 34);
|
||||
expectToken(eof, 1, 36);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void singleCharConst() {
|
||||
initScannerCode("'x'");
|
||||
|
||||
expectToken(charConst, 1, 1, 'x');
|
||||
expectToken(eof, 1, 4);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void escapeCharConst() {
|
||||
initScannerCode(" {'\\n' '\\r' '\\\\' '\\''} ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(charConst, 1, 3, '\n');
|
||||
expectToken(charConst, 1, 8, '\r');
|
||||
expectToken(charConst, 1, 13, '\\');
|
||||
expectToken(charConst, 1, 18, '\'');
|
||||
expectToken(rbrace, 1, 22);
|
||||
expectToken(eof, 1, 24);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void singleEscapeCharConst() {
|
||||
initScannerCode("'\\n'");
|
||||
|
||||
expectToken(charConst, 1, 1, '\n');
|
||||
expectToken(eof, 1, 5);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void emptyCharConst() {
|
||||
initScannerCode(" {''} ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(charConst, 1, 3, '\0');
|
||||
expectError(1, 3, EMPTY_CHARCONST);
|
||||
expectToken(rbrace, 1, 5);
|
||||
expectToken(eof, 1, 7);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unclosedCharConst() {
|
||||
initScannerCode(" {'a} ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(charConst, 1, 3, '\0');
|
||||
expectError(1, 3, MISSING_QUOTE);
|
||||
expectToken(rbrace, 1, 5);
|
||||
expectToken(eof, 1, 7);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void emptyAndUnclosedCharConst() {
|
||||
initScannerCode(" ''' ");
|
||||
|
||||
expectToken(charConst, 1, 2, '\0');
|
||||
expectError(1, 2, EMPTY_CHARCONST);
|
||||
expectToken(charConst, 1, 4, '\0');
|
||||
expectError(1, 4, MISSING_QUOTE);
|
||||
expectToken(eof, 1, 6);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unclosedEscapeCharConst() {
|
||||
initScannerCode(" {'\\r} ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(charConst, 1, 3, '\0');
|
||||
expectError(1, 3, MISSING_QUOTE);
|
||||
expectToken(rbrace, 1, 6);
|
||||
expectToken(eof, 1, 8);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unclosedBackslashCharConst() {
|
||||
initScannerCode(" {'\\'} ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(charConst, 1, 3, '\0');
|
||||
expectError(1, 3, MISSING_QUOTE);
|
||||
expectToken(rbrace, 1, 6);
|
||||
expectToken(eof, 1, 8);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidEscapeCharConst() {
|
||||
initScannerCode(" {'\\a'} ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(charConst, 1, 3, '\0');
|
||||
expectError(1, 3, UNDEFINED_ESCAPE, 'a');
|
||||
expectToken(rbrace, 1, 7);
|
||||
expectToken(eof, 1, 9);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidEscapeCharMissingQuote() {
|
||||
initScannerCode(" '\\a ");
|
||||
|
||||
expectToken(charConst, 1, 2, '\0');
|
||||
expectError(1, 2, UNDEFINED_ESCAPE, 'a');
|
||||
expectError(1, 2, MISSING_QUOTE);
|
||||
expectToken(eof, 1, 6);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fileEndCharConst() {
|
||||
initScannerCode(" {'");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(charConst, 1, 3, '\0');
|
||||
expectError(1, 3, EOF_IN_CHAR);
|
||||
expectToken(eof, 1, 4);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lineEndCharConst() {
|
||||
initScannerCode(" {'" + LF + "'a'} ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(charConst, 1, 3, '\0');
|
||||
expectError(1, 3, ILLEGAL_LINE_END);
|
||||
expectToken(charConst, 2, 1, 'a');
|
||||
expectToken(rbrace, 2, 4);
|
||||
expectToken(eof, 2, 6);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lineEndWithCRCharConst() {
|
||||
initScannerCode(" {'" + CR + LF + "'a'} ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(charConst, 1, 3, '\0');
|
||||
expectError(1, 3, ILLEGAL_LINE_END);
|
||||
expectToken(charConst, 2, 1, 'a');
|
||||
expectToken(rbrace, 2, 4);
|
||||
expectToken(eof, 2, 6);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void keyword1() {
|
||||
initScannerCode(" { if } ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(if_, 1, 4);
|
||||
expectToken(rbrace, 1, 7);
|
||||
expectToken(eof, 1, 9);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void keyword2() {
|
||||
initScannerCode(" {if} ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(if_, 1, 3);
|
||||
expectToken(rbrace, 1, 5);
|
||||
expectToken(eof, 1, 7);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void singleKeyword() {
|
||||
initScannerCode("if");
|
||||
|
||||
expectToken(if_, 1, 1);
|
||||
expectToken(eof, 1, 3);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void keyword3() {
|
||||
initScannerCode(" {for_} ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(ident, 1, 3, "for_");
|
||||
expectToken(rbrace, 1, 7);
|
||||
expectToken(eof, 1, 9);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void keyword4() {
|
||||
initScannerCode(" {&if} ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(none, 1, 3);
|
||||
expectError(1, 3, INVALID_CHAR, '&');
|
||||
expectToken(if_, 1, 4);
|
||||
expectToken(rbrace, 1, 6);
|
||||
expectToken(eof, 1, 8);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void caseSensitive1() {
|
||||
initScannerCode(" {For} ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(ident, 1, 3, "For");
|
||||
expectToken(rbrace, 1, 6);
|
||||
expectToken(eof, 1, 8);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void caseSensitive2() {
|
||||
initScannerCode(" {FOR} ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(ident, 1, 3, "FOR");
|
||||
expectToken(rbrace, 1, 6);
|
||||
expectToken(eof, 1, 8);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleSingleLineComment() {
|
||||
initScannerCode(" {/* Simple / single * line comment. */} ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(rbrace, 1, 40);
|
||||
expectToken(eof, 1, 42);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleMultiLineComment() {
|
||||
initScannerCode(" {" + LF + " /* Simple " + LF + " / multi * line " + LF //
|
||||
+ " comment. */ " + LF + " } ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(rbrace, 5, 2);
|
||||
expectToken(eof, 5, 4);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nestedSingleLineComment2() {
|
||||
initScannerCode(" {/*//*///****/**/*/} ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(rbrace, 1, 21);
|
||||
expectToken(eof, 1, 23);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nestedSingleLineComment() {
|
||||
initScannerCode(" {/* This / is * a /* nested /* single line */ comment. */*/} ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(rbrace, 1, 62);
|
||||
expectToken(eof, 1, 64);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nestedMultiLineComment() {
|
||||
initScannerCode(" {" + LF + " /* This / is * a " + LF + " /* nested " + LF //
|
||||
+ " /* multi line */" + LF + " comment. " + LF + " */" + LF //
|
||||
+ " */ " + LF + " } ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(rbrace, 8, 2);
|
||||
expectToken(eof, 8, 4);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nestedMultiLineComment2() {
|
||||
initScannerCode(" {" + LF + " /* This / is * a " + LF + " /* nested " + LF //
|
||||
+ " /* multi /*/* double nestet */*/ line */" + LF + " comment. " + LF + " */" + LF //
|
||||
+ " */ " + LF + " } ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(rbrace, 8, 2);
|
||||
expectToken(eof, 8, 4);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void commentAtEnd1() {
|
||||
initScannerCode(" {/* This / is * a /* nested /* single line */ comment. */*/ ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(eof, 1, 63);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void commentAtEnd2() {
|
||||
initScannerCode(" {/* This / is * a /* nested /* single line */ comment. */*/");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(eof, 1, 62);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unclosedComment() {
|
||||
initScannerCode(" {/* This / is * a nested unclosed comment. } ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectError(1, 3, EOF_IN_COMMENT);
|
||||
expectToken(eof, 1, 47);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unclosedComment2() {
|
||||
initScannerCode(" {/*/");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectError(1, 3, EOF_IN_COMMENT);
|
||||
expectToken(eof, 1, 6);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nestedUnclosedComment() {
|
||||
initScannerCode(" {/* This / is * a /* nested /* unclosed comment. */} ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectError(1, 3, EOF_IN_COMMENT);
|
||||
expectToken(eof, 1, 55);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nestedUnclosedComment2() {
|
||||
initScannerCode(" {/* This / is * a nested unclosed /* comment. } */");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectError(1, 3, EOF_IN_COMMENT);
|
||||
expectToken(eof, 1, 52);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noLineComment() {
|
||||
initScannerCode(" {This is // no comment} ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(ident, 1, 3, "This");
|
||||
expectToken(ident, 1, 8, "is");
|
||||
expectToken(slash, 1, 11);
|
||||
expectToken(slash, 1, 12);
|
||||
expectToken(ident, 1, 14, "no");
|
||||
expectToken(ident, 1, 17, "comment");
|
||||
expectToken(rbrace, 1, 24);
|
||||
expectToken(eof, 1, 26);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipleComments() {
|
||||
initScannerCode(" {/*a*/ /*b*/ /*c*/ } ");
|
||||
|
||||
expectToken(lbrace, 1, 2);
|
||||
expectToken(rbrace, 1, 23);
|
||||
expectToken(eof, 1, 25);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
// index from end tests
|
||||
|
||||
@Test
|
||||
public void negativeIndexFromEnd() {
|
||||
initScannerCode("~-7");
|
||||
|
||||
expectToken(tilde, 1, 1);
|
||||
expectToken(minus, 1, 2);
|
||||
expectToken(number, 1, 3, 7);
|
||||
expectToken(eof, 1, 4);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void singleTildeChar() {
|
||||
initScannerCode("'~'");
|
||||
|
||||
expectToken(charConst, 1, 1, '~');
|
||||
expectToken(eof, 1, 4);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void commentInIndexFromEnd() {
|
||||
initScannerCode("~/*comment*/7");
|
||||
|
||||
expectToken(tilde, 1, 1);
|
||||
expectToken(number, 1, 13, 7);
|
||||
expectToken(eof, 1,14);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doubleTilde() {
|
||||
initScannerCode("~~");
|
||||
|
||||
expectToken(tilde, 1, 1);
|
||||
expectToken(tilde, 1, 2);
|
||||
expectToken(eof, 1,3);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void allTokens() {
|
||||
initScannerCode("anIdentifier 123 'c'" + LF //
|
||||
+ "+ - * / % == != < <= > >= && || = += -= *= /= %= ++ -- ; , . ( ) [ ] { }" + LF //
|
||||
+ "break class else final if new print program read return void while ~" + LF);
|
||||
|
||||
expectToken(ident, 1, 1, "anIdentifier");
|
||||
expectToken(number, 1, 14, 123);
|
||||
expectToken(charConst, 1, 18, 'c');
|
||||
expectToken(plus, 2, 1);
|
||||
expectToken(minus, 2, 3);
|
||||
expectToken(times, 2, 5);
|
||||
expectToken(slash, 2, 7);
|
||||
expectToken(rem, 2, 9);
|
||||
expectToken(eql, 2, 11);
|
||||
expectToken(neq, 2, 14);
|
||||
expectToken(lss, 2, 17);
|
||||
expectToken(leq, 2, 19);
|
||||
expectToken(gtr, 2, 22);
|
||||
expectToken(geq, 2, 24);
|
||||
expectToken(and, 2, 27);
|
||||
expectToken(or, 2, 30);
|
||||
expectToken(assign, 2, 33);
|
||||
expectToken(plusas, 2, 35);
|
||||
expectToken(minusas, 2, 38);
|
||||
expectToken(timesas, 2, 41);
|
||||
expectToken(slashas, 2, 44);
|
||||
expectToken(remas, 2, 47);
|
||||
expectToken(pplus, 2, 50);
|
||||
expectToken(mminus, 2, 53);
|
||||
expectToken(semicolon, 2, 56);
|
||||
expectToken(comma, 2, 58);
|
||||
expectToken(period, 2, 60);
|
||||
expectToken(lpar, 2, 62);
|
||||
expectToken(rpar, 2, 64);
|
||||
expectToken(lbrack, 2, 66);
|
||||
expectToken(rbrack, 2, 68);
|
||||
expectToken(lbrace, 2, 70);
|
||||
expectToken(rbrace, 2, 72);
|
||||
expectToken(break_, 3, 1);
|
||||
expectToken(class_, 3, 7);
|
||||
expectToken(else_, 3, 13);
|
||||
expectToken(final_, 3, 18);
|
||||
expectToken(if_, 3, 24);
|
||||
expectToken(new_, 3, 27);
|
||||
expectToken(print, 3, 31);
|
||||
expectToken(program, 3, 37);
|
||||
expectToken(read, 3, 45);
|
||||
expectToken(return_, 3, 50);
|
||||
expectToken(void_, 3, 57);
|
||||
expectToken(while_, 3, 62);
|
||||
expectToken(tilde, 3, 68);
|
||||
expectToken(eof, 4, 1);
|
||||
|
||||
scanVerifyVisualize();
|
||||
}
|
||||
}
|
||||
1076
MicroJava Tests/tests/ssw/mj/test/SimpleCodeGenerationTest.java
Normal file
1076
MicroJava Tests/tests/ssw/mj/test/SimpleCodeGenerationTest.java
Normal file
File diff suppressed because it is too large
Load Diff
1102
MicroJava Tests/tests/ssw/mj/test/SymbolTableTest.java
Normal file
1102
MicroJava Tests/tests/ssw/mj/test/SymbolTableTest.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,401 @@
|
||||
package ssw.mj.test.support;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Timeout;
|
||||
import ssw.mj.Errors;
|
||||
import ssw.mj.Interpreter;
|
||||
import ssw.mj.Visualizer;
|
||||
import ssw.mj.codegen.Decoder;
|
||||
import ssw.mj.impl.Parser;
|
||||
import ssw.mj.impl.Scanner;
|
||||
import ssw.mj.scanner.Token;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.StringReader;
|
||||
import java.net.URL;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* Base class for test cases with utility methods used by all tests.
|
||||
*/
|
||||
|
||||
@Timeout(value = Configuration.TIMEOUT, threadMode = Timeout.ThreadMode.SEPARATE_THREAD)
|
||||
public abstract class BaseCompilerTestCase {
|
||||
|
||||
public static final String CR = "\r";
|
||||
public static final String LF = "\n";
|
||||
private List<String> expectedErrors;
|
||||
private List<String> expectedTokens;
|
||||
private List<Token> expectedTokensFull;
|
||||
private List<String> expectedSymTab;
|
||||
private List<String> expectedRuntimeErrors;
|
||||
private String source;
|
||||
private Scanner scanner;
|
||||
protected Parser parser;
|
||||
private String callingClassAndMethod;
|
||||
private final List<String> runInputs = new ArrayList<>();
|
||||
private final List<String> expectedOutputs = new ArrayList<>();
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
// initialize expected compiler output
|
||||
expectedErrors = new ArrayList<>();
|
||||
expectedTokens = new ArrayList<>();
|
||||
expectedTokensFull = new ArrayList<>();
|
||||
expectedSymTab = new ArrayList<>();
|
||||
expectedRuntimeErrors = new ArrayList<>();
|
||||
|
||||
if (Configuration.ALSO_PRINT_SUCCESSFUL_TESTCASES) {
|
||||
// print header for console output
|
||||
System.out.println("--------------------------------------------------");
|
||||
}
|
||||
}
|
||||
|
||||
protected void initCode(String code) {
|
||||
initScannerCode(code);
|
||||
parser = new Parser(scanner);
|
||||
}
|
||||
|
||||
protected void initFile(String filename) {
|
||||
initScannerFile(filename);
|
||||
parser = new Parser(scanner);
|
||||
}
|
||||
|
||||
protected void initScannerCode(String code) {
|
||||
source = code;
|
||||
scanner = new Scanner(new StringReader(code));
|
||||
}
|
||||
|
||||
protected void initScannerFile(String filename) {
|
||||
try {
|
||||
ClassLoader classLoader = getClass().getClassLoader();
|
||||
URL resource = classLoader.getResource(filename);
|
||||
if (resource == null) {
|
||||
throw new RuntimeException("resource %s not found".formatted(filename));
|
||||
}
|
||||
String urlAsStr = resource.getFile();
|
||||
// replaces %20 Urlencoding with " " (blank space), as e.g. Linux cannot handle url paths
|
||||
String path = URLDecoder.decode(urlAsStr, StandardCharsets.UTF_8);
|
||||
File file = new File(path);
|
||||
scanner = new Scanner(new FileReader(file));
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new RuntimeException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> splitString(String s) {
|
||||
StringTokenizer st = new StringTokenizer(s, "\n");
|
||||
List<String> result = new ArrayList<>();
|
||||
while (st.hasMoreTokens()) {
|
||||
result.add(st.nextToken());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void print(String title, List<String> expected, List<String> actual) {
|
||||
if (expected.isEmpty() && actual.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
System.out.format("%s - %s\n", callingClassAndMethod, title);
|
||||
if (Configuration.ALSO_PRINT_SUCCESSFUL_TESTCASES || !expected.equals(actual)) {
|
||||
System.out.format(" %-60s %s\n", "expected", "actual");
|
||||
int lines = Math.max(expected.size(), actual.size());
|
||||
for (int i = 0; i < lines; i++) {
|
||||
String expectedLine = (i < expected.size() ? expected.get(i) : "");
|
||||
String actualLine = (i < actual.size() ? actual.get(i) : "");
|
||||
System.out.format("%s %-60s %s\n", (expectedLine.equals(actualLine) ? " " : "x"), expectedLine,
|
||||
actualLine);
|
||||
}
|
||||
} else {
|
||||
if (expected.equals(actual)) {
|
||||
System.out.println(" correct (exact comparison hidden, enable via Configuration.ALSO_PRINT_SUCCESSFUL_TESTCASES)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addRun(String input, String output, String error) {
|
||||
runInputs.add(input);
|
||||
expectedOutputs.add(output);
|
||||
expectedRuntimeErrors.add(error);
|
||||
}
|
||||
|
||||
protected void addExpectedRun(String output) {
|
||||
addExpectedRun("", output);
|
||||
}
|
||||
|
||||
protected void addExpectedRun(String input, String output) {
|
||||
addRun(input, output, "");
|
||||
}
|
||||
|
||||
protected void addFailingRun(String error) {
|
||||
addFailingRun("", error);
|
||||
}
|
||||
|
||||
protected void addFailingRun(String input, String error) {
|
||||
addRun(input, "", error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans the given code and checks the scanned tokens against the expected ones.
|
||||
* Also checks that expected errors occur.
|
||||
* Finally, the method creates a visualization of the scanned tokens if the test was run
|
||||
* with @link ssw.mj.TracingClassLoader as system classloader.
|
||||
*/
|
||||
protected void scanVerifyVisualize() {
|
||||
callingClassAndMethod = getCallingClassAndMethod(1);
|
||||
|
||||
List<Token> actualTokens = new ArrayList<>();
|
||||
|
||||
// scan only the expected number of tokens to prevent endless loops
|
||||
for (int i = 0; i < getExpectedTokens().size(); i++) {
|
||||
actualTokens.add(scanner.next());
|
||||
}
|
||||
|
||||
List<String> actualTokenStrings = actualTokens.stream().map(Token::toString).toList();
|
||||
|
||||
Visualizer.createScannerVisualization(source, actualTokens, getExpectedTokensFull(), false);
|
||||
|
||||
printErrors();
|
||||
printTokens(actualTokenStrings);
|
||||
|
||||
verifyErrors();
|
||||
verifyTokens(actualTokenStrings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the given code and checks it for expected errors, matching sym tab and matching byte code.
|
||||
* Then it executed the interpreter for all given inputs.
|
||||
* Finally, the method creates a visualization of the parse tree if the test was run
|
||||
* with @link ssw.mj.TracingClassLoader as system classloader.
|
||||
*/
|
||||
protected void parseVerifyVisualize() {
|
||||
callingClassAndMethod = getCallingClassAndMethod(1);
|
||||
|
||||
try {
|
||||
parser.parse();
|
||||
assertEquals(Token.Kind.eof, scanner.next().kind, "Complete input should be scanned");
|
||||
} catch (Errors.PanicMode error) {
|
||||
// Ignore, nothing to do
|
||||
}
|
||||
|
||||
printErrors();
|
||||
printSymTab();
|
||||
|
||||
verifyErrors();
|
||||
verifySymTab();
|
||||
|
||||
if (ByteCodeTestSupport.GENERATE_REFERENCE_BYTE_CODE && expectedErrors.isEmpty()) {
|
||||
ByteCodeTestSupport.generateReferenceByteCode(callingClassAndMethod, parser);
|
||||
} else {
|
||||
printAndVerifyByteCode(callingClassAndMethod);
|
||||
}
|
||||
|
||||
for (int i = 0; i < runInputs.size(); i++) {
|
||||
run(i);
|
||||
}
|
||||
|
||||
Visualizer.createParserVisualization(source, false);
|
||||
}
|
||||
|
||||
private static String getCallingClassAndMethod(int up) {
|
||||
// [0] getStackTrace -> [1] getCallingMethodName -> [2] caller of getCallingMethodName -> [3] ...
|
||||
StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
|
||||
StackTraceElement e = stacktrace[2 + up];
|
||||
String fullyQualifiedClassName = e.getClassName();
|
||||
String className = fullyQualifiedClassName.substring(Math.max(fullyQualifiedClassName.lastIndexOf(".") + 1, 0));
|
||||
return className + "." + e.getMethodName() + "()";
|
||||
}
|
||||
|
||||
private void run(int i) {
|
||||
Interpreter.BufferIO io = new Interpreter.BufferIO(runInputs.get(i));
|
||||
Interpreter interpreter = new Interpreter(
|
||||
parser.code.buf,
|
||||
parser.code.mainpc,
|
||||
parser.code.dataSize,
|
||||
io,
|
||||
Configuration.PRINT_INTERPRETER_DEBUG_OUTPUT);
|
||||
try {
|
||||
interpreter.run();
|
||||
} catch (IllegalStateException e) {
|
||||
verifyRuntimeError(i, e);
|
||||
}
|
||||
String output = io.getOutput();
|
||||
verifyOutput(i, output);
|
||||
}
|
||||
|
||||
|
||||
private void printErrors() {
|
||||
print("Errors", expectedErrors, getActualErrors());
|
||||
}
|
||||
|
||||
private void printTokens(List<String> actualTokens) {
|
||||
print("Tokens", getExpectedTokens(), actualTokens);
|
||||
}
|
||||
|
||||
private void printSymTab() {
|
||||
if (!expectedSymTab.isEmpty()) {
|
||||
print("Symbol Table", getExpectedSymTab(), getActualSymTab());
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyErrors() {
|
||||
assertEquals(expectedErrors, getActualErrors(), "Errors");
|
||||
}
|
||||
|
||||
private void verifyTokens(List<String> actualTokens) {
|
||||
assertEquals(getExpectedTokens(), actualTokens, "Tokens");
|
||||
assertTrue(scanner.next().toString().contains("end of file"), "Complete Input Scanned");
|
||||
}
|
||||
|
||||
private void verifySymTab() {
|
||||
if (!expectedSymTab.isEmpty()) {
|
||||
assertEquals(getExpectedSymTab(), getActualSymTab(), "Symbol Table");
|
||||
}
|
||||
}
|
||||
|
||||
private void printAndVerifyByteCode(String callingClassAndMethod) {
|
||||
if (ByteCodeTestSupport.BYTE_CODES.containsKey(callingClassAndMethod)) {
|
||||
List<String> possibleByteCodes = ByteCodeTestSupport.BYTE_CODES.get(callingClassAndMethod);
|
||||
if (possibleByteCodes.size() == 1) {
|
||||
List<String> expected = getExpectedByteCodeLines(possibleByteCodes.get(0));
|
||||
print("Bytecode", expected, getActualByteCodeLines());
|
||||
// Verify that the bytecode is correct
|
||||
assertEquals(expected, getActualByteCodeLines(), "Byte Code");
|
||||
} else {
|
||||
int matchIdx = -1;
|
||||
for (int i = 0; i < possibleByteCodes.size(); i++) {
|
||||
List<String> expected = getExpectedByteCodeLines(possibleByteCodes.get(i));
|
||||
if (expected.equals(getActualByteCodeLines())) {
|
||||
matchIdx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (matchIdx < 0) {
|
||||
// No bytecode matched
|
||||
// print all
|
||||
for (int i = 0; i < possibleByteCodes.size(); i++) {
|
||||
List<String> expected = getExpectedByteCodeLines(possibleByteCodes.get(i));
|
||||
print("Possible Bytecode %d".formatted(i + 1), expected, getActualByteCodeLines());
|
||||
}
|
||||
// fail assert on first
|
||||
assertEquals(getExpectedByteCodeLines(possibleByteCodes.get(0)), getActualByteCodeLines(), "Byte Code");
|
||||
} else {
|
||||
// bytecode at idx matchIdx correctly generated
|
||||
// print working bytecode
|
||||
print("Bytecode", getExpectedByteCodeLines(possibleByteCodes.get(matchIdx)), getActualByteCodeLines());
|
||||
// assert not really necessary since we already know we matched successfully
|
||||
assertEquals(getExpectedByteCodeLines(possibleByteCodes.get(matchIdx)), getActualByteCodeLines(), "Byte Code");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyOutput(int runIdx, String actualOutput) {
|
||||
assertEquals(expectedOutputs.get(runIdx), actualOutput, "Unexpected result when input is \"" + runInputs.get(runIdx) + "\": ");
|
||||
}
|
||||
|
||||
private void verifyRuntimeError(int runIdx, IllegalStateException e) {
|
||||
assertEquals(expectedRuntimeErrors.get(runIdx), e.getMessage(), "Unexpected runtime error message when input is \"" + runInputs.get(runIdx) + "\": ");
|
||||
}
|
||||
|
||||
private List<String> getExpectedByteCodeLines(String bytecode) {
|
||||
return Arrays.stream(bytecode.split("\n")).toList();
|
||||
}
|
||||
|
||||
private List<String> getActualByteCodeLines() {
|
||||
return Arrays.stream(new Decoder().decode(parser.code).split("\n")).toList();
|
||||
}
|
||||
|
||||
private List<String> getActualErrors() {
|
||||
return splitString(scanner.errors.dump());
|
||||
}
|
||||
|
||||
private List<String> getExpectedTokens() {
|
||||
return expectedTokens;
|
||||
}
|
||||
|
||||
private List<Token> getExpectedTokensFull() {
|
||||
return expectedTokensFull;
|
||||
}
|
||||
|
||||
private List<String> getExpectedSymTab() {
|
||||
return expectedSymTab;
|
||||
}
|
||||
|
||||
private List<String> getActualSymTab() {
|
||||
return splitString(SymTabDumper.dump(parser.tab));
|
||||
}
|
||||
|
||||
protected void expectError(int line, int col, Errors.Message msg, Object... msgParams) {
|
||||
expectedErrors.add("-- line " + line + " col " + col + ": " + msg.format(msgParams));
|
||||
}
|
||||
|
||||
protected void expectToken(Token.Kind kind, int line, int col) {
|
||||
expectedTokens.add("line " + line + ", col " + col + ", kind " + kind);
|
||||
expectedTokensFull.add(new Token(kind, line, col));
|
||||
}
|
||||
|
||||
protected void expectToken(Token.Kind kind, int line, int col, String val) {
|
||||
expectedTokens.add("line " + line + ", col " + col + ", kind " + kind + ", val " + val);
|
||||
|
||||
Token token = new Token(kind, line, col);
|
||||
token.val = val;
|
||||
expectedTokensFull.add(token);
|
||||
}
|
||||
|
||||
protected void expectToken(Token.Kind kind, int line, int col, int val) {
|
||||
expectedTokens.add("line " + line + ", col " + col + ", kind " + kind + ", val " + val + ", numVal " + val);
|
||||
|
||||
Token token = new Token(kind, line, col);
|
||||
token.val = String.valueOf(val);
|
||||
token.numVal = val;
|
||||
expectedTokensFull.add(token);
|
||||
}
|
||||
|
||||
protected void expectToken(Token.Kind kind, int line, int col, char ch) {
|
||||
expectedTokens.add("line " + line + ", col " + col + ", kind " + kind + ", val " + ch + ", numVal " + (int) ch);
|
||||
|
||||
Token token = new Token(kind, line, col);
|
||||
token.val = String.valueOf(ch);
|
||||
token.numVal = ch;
|
||||
expectedTokensFull.add(token);
|
||||
}
|
||||
|
||||
protected void expectInvalidToken(Token.Kind kind, int line, int col) {
|
||||
expectedTokens.add("line " + line + ", col " + col + ", kind " + kind + ", val null, numVal 0");
|
||||
|
||||
Token token = new Token(kind, line, col);
|
||||
token.val = null;
|
||||
token.numVal = 0;
|
||||
expectedTokensFull.add(token);
|
||||
}
|
||||
|
||||
protected void expectSymTab(String line) {
|
||||
expectedSymTab.add(line);
|
||||
}
|
||||
|
||||
protected void expectSymTabUniverse() {
|
||||
// first part of the symbol table (universe) that is equal for all
|
||||
// programs
|
||||
expectSymTab("-- begin scope (0 variables) --");
|
||||
expectSymTab("Type int: int");
|
||||
expectSymTab("Type char: char");
|
||||
expectSymTab("Constant: class (0 fields) null = 0");
|
||||
expectSymTab("Method: char chr (1 locals, 1 parameters)");
|
||||
expectSymTab(" Local Variable 0: int i");
|
||||
expectSymTab("Method: int ord (1 locals, 1 parameters)");
|
||||
expectSymTab(" Local Variable 0: char ch");
|
||||
expectSymTab("Method: int len (1 locals, 1 parameters)");
|
||||
expectSymTab(" Local Variable 0: void[] arr");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package ssw.mj.test.support;
|
||||
|
||||
import ssw.mj.codegen.Decoder;
|
||||
import ssw.mj.impl.Parser;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class ByteCodeTestSupport {
|
||||
/**
|
||||
* This flag is used by the lecturers to generate the reference solutions for
|
||||
* the bytecodes generated during code generation.
|
||||
* Students should not change this flag, it should stay false for the whole course.
|
||||
*/
|
||||
public static final boolean GENERATE_REFERENCE_BYTE_CODE = false;
|
||||
|
||||
// For each test, 0 to n correct byte codes can be added to bytecodes.txt
|
||||
// If one of these codes is generated by the Parser, the test does not fail.
|
||||
// This way, we can provide multiple correct solutions for the same test case.
|
||||
//
|
||||
// The keys of this map are in the format "TestClass.TestMethodName()"
|
||||
public static final HashMap<String, List<String>> BYTE_CODES = new HashMap<>();
|
||||
|
||||
static {
|
||||
File bytecodesFile = getBytecodesFile();
|
||||
if (bytecodesFile.exists()) {
|
||||
String[] lineArr;
|
||||
try (Stream<String> lines = Files.lines(bytecodesFile.toPath())) {
|
||||
lineArr = lines.toArray(String[]::new);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
String currentlyReadClassAndMethod = null;
|
||||
StringBuilder currentReadBytecode = null;
|
||||
for (String line : lineArr) {
|
||||
if (line.isBlank()) {
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("#")) {
|
||||
if (currentlyReadClassAndMethod != null) {
|
||||
if (!BYTE_CODES.containsKey(currentlyReadClassAndMethod)) {
|
||||
BYTE_CODES.put(currentlyReadClassAndMethod, new ArrayList<>());
|
||||
}
|
||||
BYTE_CODES.get(currentlyReadClassAndMethod).add(currentReadBytecode.toString());
|
||||
}
|
||||
currentlyReadClassAndMethod = line.substring(1);
|
||||
currentReadBytecode = new StringBuilder();
|
||||
} else {
|
||||
currentReadBytecode.append(line).append("\n");
|
||||
}
|
||||
}
|
||||
if (currentlyReadClassAndMethod != null) {
|
||||
if (!BYTE_CODES.containsKey(currentlyReadClassAndMethod)) {
|
||||
BYTE_CODES.put(currentlyReadClassAndMethod, new ArrayList<>());
|
||||
}
|
||||
BYTE_CODES.get(currentlyReadClassAndMethod).add(currentReadBytecode.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static File getBytecodesFile() {
|
||||
String filename = "bytecodes.txt";
|
||||
ClassLoader classLoader = BaseCompilerTestCase.class.getClassLoader();
|
||||
URL resource = classLoader.getResource(filename);
|
||||
if (resource == null) {
|
||||
throw new RuntimeException("resource %s not found".formatted(filename));
|
||||
}
|
||||
String urlAsStr = resource.getFile();
|
||||
// replaces %20 Urlencoding with " " (blank space), as e.g. Linux cannot handle url paths
|
||||
String path = URLDecoder.decode(urlAsStr, StandardCharsets.UTF_8);
|
||||
return new File(path);
|
||||
}
|
||||
|
||||
|
||||
public static void generateReferenceByteCode(String classAndMethod, Parser parser) {
|
||||
// Generate and store bytecode for correct test programs
|
||||
|
||||
// Output is in the form:
|
||||
// #TestClass.TestMethodName()
|
||||
// ... output from Decoder.decode() ...
|
||||
File bytecodesFile = ByteCodeTestSupport.getBytecodesFile();
|
||||
try (BufferedWriter bw = Files.newBufferedWriter(bytecodesFile.toPath(), StandardOpenOption.WRITE, StandardOpenOption.APPEND)) {
|
||||
String bytecode = new Decoder().decode(parser.code);
|
||||
bw.write("#");
|
||||
bw.write(classAndMethod);
|
||||
bw.write("\n");
|
||||
bw.write(bytecode);
|
||||
bw.flush();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
27
MicroJava Tests/tests/ssw/mj/test/support/Configuration.java
Normal file
27
MicroJava Tests/tests/ssw/mj/test/support/Configuration.java
Normal file
@@ -0,0 +1,27 @@
|
||||
package ssw.mj.test.support;
|
||||
|
||||
public class Configuration {
|
||||
/**
|
||||
* set to true to print expected and actual values of all testcases,
|
||||
* not only failing ones (prints expected errors, tokens, symbol table, code)
|
||||
*/
|
||||
public static final boolean ALSO_PRINT_SUCCESSFUL_TESTCASES = Boolean.getBoolean("microjava.testcaseOutput");
|
||||
|
||||
/**
|
||||
* Set to true to print debug information of the interpreter. Equal to
|
||||
* "-debug" on the command line. <br>
|
||||
* Remark:<br>
|
||||
* This is a lot of output, some test cases might time out, e.g.
|
||||
* CodeGenerationTest.fib
|
||||
*/
|
||||
public static final boolean PRINT_INTERPRETER_DEBUG_OUTPUT = Boolean.getBoolean("microjava.interpreterOutput");
|
||||
|
||||
/**
|
||||
* Determines the timeout after which a test case should fail automatically.
|
||||
* Default: 10 seconds. The default should work for all test cases
|
||||
* on most machines.<br>
|
||||
* <em>Attention</em>: For most computers it is likely that there is an
|
||||
* endless loop in the MicroJava compiler if a test fails for a timeout.
|
||||
*/
|
||||
public static final long TIMEOUT = 10;
|
||||
}
|
||||
119
MicroJava Tests/tests/ssw/mj/test/support/SymTabDumper.java
Normal file
119
MicroJava Tests/tests/ssw/mj/test/support/SymTabDumper.java
Normal file
@@ -0,0 +1,119 @@
|
||||
package ssw.mj.test.support;
|
||||
|
||||
import ssw.mj.impl.Tab;
|
||||
import ssw.mj.symtab.Obj;
|
||||
import ssw.mj.symtab.Scope;
|
||||
import ssw.mj.symtab.Struct;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class SymTabDumper {
|
||||
public static String dump(Tab tab) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (tab.curScope != null) {
|
||||
dump(tab.curScope, sb);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static void dump(Scope scope, StringBuilder sb) {
|
||||
sb.append("-- begin scope (").append(scope.nVars()).append(" variables) --\n");
|
||||
if (!scope.locals().isEmpty()) {
|
||||
dump(scope.locals().values(), sb, "");
|
||||
}
|
||||
if (scope.outer() != null) {
|
||||
sb.append("\n");
|
||||
dump(scope.outer(), sb);
|
||||
}
|
||||
}
|
||||
|
||||
private static void dump(Collection<Obj> objects, StringBuilder sb, String indent) {
|
||||
for (Obj obj : objects) {
|
||||
dump(obj, sb, indent);
|
||||
}
|
||||
}
|
||||
|
||||
private static void dump(Obj obj, StringBuilder sb, String indent) {
|
||||
sb.append(indent);
|
||||
|
||||
switch (obj.kind) {
|
||||
case Con -> dumpCon(obj, sb, indent);
|
||||
case Var -> dumpVar(obj, sb, indent);
|
||||
case Type -> dumpType(obj, sb, indent);
|
||||
case Meth -> dumpMethod(obj, sb, indent);
|
||||
case Prog -> dumpProgram(obj, sb);
|
||||
}
|
||||
|
||||
if (obj.locals != null) {
|
||||
sb.append("\n");
|
||||
dump(obj.locals.values(), sb, indent + " ");
|
||||
}
|
||||
sb.append("\n");
|
||||
}
|
||||
|
||||
private static void dumpCon(Obj obj, StringBuilder sb, String indent) {
|
||||
sb.append("Constant: ");
|
||||
if (obj.type != null) {
|
||||
dump(obj.type, sb, indent, false);
|
||||
}
|
||||
sb.append(" ").append(obj.name).append(" = ");
|
||||
if (obj.type == Tab.charType) {
|
||||
sb.append("'").append((char) obj.val).append("'");
|
||||
} else {
|
||||
sb.append(obj.val);
|
||||
}
|
||||
}
|
||||
|
||||
private static void dumpVar(Obj obj, StringBuilder sb, String indent) {
|
||||
if (obj.level == 0) {
|
||||
sb.append("Global Variable ");
|
||||
} else {
|
||||
sb.append("Local Variable ");
|
||||
}
|
||||
sb.append(obj.adr).append(": ");
|
||||
if (obj.type != null) {
|
||||
dump(obj.type, sb, indent, false);
|
||||
}
|
||||
sb.append(" ").append(obj.name);
|
||||
}
|
||||
|
||||
private static void dumpType(Obj type, StringBuilder sb, String indent) {
|
||||
sb.append("Type ").append(type.name).append(": ");
|
||||
if (type.type != null) {
|
||||
dump(type.type, sb, indent + " ", true);
|
||||
}
|
||||
}
|
||||
|
||||
private static void dumpMethod(Obj meth, StringBuilder sb, String indent) {
|
||||
sb.append("Method: ");
|
||||
if (meth.type != null) {
|
||||
dump(meth.type, sb, indent, false);
|
||||
}
|
||||
sb.append(" ").append(meth.name).append(" (").append(meth.locals.size()).append(" locals, ").append(meth.nPars).append(" parameters").append(")");
|
||||
}
|
||||
|
||||
private static void dumpProgram(Obj obj, StringBuilder sb) {
|
||||
sb.append("Program ").append(obj.name).append(":");
|
||||
}
|
||||
|
||||
private static void dump(Struct struct, StringBuilder sb, String indent, boolean dumpFields) {
|
||||
switch (struct.kind) {
|
||||
case None -> sb.append("void");
|
||||
case Int -> sb.append("int");
|
||||
case Char -> sb.append("char");
|
||||
case Arr -> {
|
||||
if (struct.elemType != null) {
|
||||
dump(struct.elemType, sb, indent, dumpFields);
|
||||
}
|
||||
sb.append("[]");
|
||||
}
|
||||
case Class -> {
|
||||
sb.append("class (").append(struct.nrFields()).append(" fields)");
|
||||
if (dumpFields && struct.fields != null) {
|
||||
sb.append("\n");
|
||||
dump(struct.fields.values(), sb, indent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user