Homework 3

This commit is contained in:
Carlos Galindo 2020-01-15 22:32:25 +01:00
parent bf60a078d7
commit 0afc86ceeb
Signed by: kauron
GPG key ID: 83E68706DEE119A3
129 changed files with 3163 additions and 4316 deletions

View file

@ -2,9 +2,10 @@
<classpath> <classpath>
<classpathentry kind="src" path="src"/> <classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="test"/> <classpathentry kind="src" path="test"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<classpathentry kind="lib" path="lib/antlr-4.4-complete.jar"/>
<classpathentry kind="lib" path="lib/junit-4.12.jar"/> <classpathentry kind="lib" path="lib/junit-4.12.jar"/>
<classpathentry kind="lib" path="lib/hamcrest-core-1.3.jar"/> <classpathentry kind="lib" path="lib/hamcrest-core-1.3.jar"/>
<classpathentry kind="lib" path="lib/antlr-4.7.1-complete.jar"/> <classpathentry kind="lib" path="lib/javaliParserObf.jar"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<classpathentry kind="output" path="bin"/> <classpathentry kind="output" path="bin"/>
</classpath> </classpath>

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<projectDescription> <projectDescription>
<name>Javali-HW2</name> <name>Javali-HW3</name>
<comment></comment> <comment></comment>
<projects> <projects>
</projects> </projects>

View file

@ -1,13 +0,0 @@
antlr4.antlrRegisteredTools=4.4@/tmp/antlr-4.4-complete.jar\:4.7.1@/home/carlos/eth/cd/nop90/HW2/lib/antlr-4.7.1-complete.jar
antlr4.antlrToolPath=/home/carlos/eth/cd/nop90/HW2/lib/antlr-4.7.1-complete.jar
antlr4.encoding=UTF-8
antlr4.listener=true
antlr4.visitor=false
antlr4.vmArgs=
antlr4ide.is_project_specific=true
autobuilding=true
eclipse.preferences.version=1
is_project_specific=
outlet.DEFAULT_OUTPUT.cleanupDerived=true
outlet.DEFAULT_OUTPUT.derived=true
outlet.DEFAULT_OUTPUT.directory=./target/generated-sources/antlr4

View file

@ -1,7 +0,0 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.8

View file

@ -1,5 +1,6 @@
Grade: 29/30 Grade: 25/25
251/251 tests passed [25/25] 105/105 tests passed [20/20]
Submitted test cases: [5/5]
Submitted test cases: [4/5]

55
README.md Normal file
View file

@ -0,0 +1,55 @@
# Compiler design
## Parser and syntactic analysis
See repo containing [Homework #2](https://svn.inf.ethz.ch/svn/trg/cd_students/ss18/teams/nop90/HW2).
## Semantic analysis
This project checks a list class declaration as trees of Ast nodes for
possible semantic errors.
### Design
The semantic checks described [here](./SemanticChecks.md) are implemented in three
phases.
1. Circular inheritance check (just with the names, and checking for non-existent
types) to avoid stack overflow problems in the main analysis. May throw a
`NO_SUCH_TYPE` error if the parent of a given class doesn't exist.
2. Main semantic analysis, performed by `StmtAnalyzer` and `ExprAnalyzer`,
two visitors that traverse each `ClassDecl` and all of its contents looking
for semantic errors. Some types and methods may not have been discovered
when they are accessed, and to that end the functions `findType(String)`
and `findMethod(String,ClassSymbol)` lookup both, searching unvisited class
and method declarations in order to find the corresponding symbol.
3. Lookup of start point (method `void main()` in `Main` class)
### Testing
A set of test cases (Javali programs, valid and invalid) are provided. The ones
designed specifically for this homework assignment are located in
`javali_tests/HW3_nop90`, and they cover all the code in the `cd.frontend.semantic`
and `cd.ir` packages. They cover all the kinds of errors that can arise
from a semantic analysis of Javali programs. As the order of the errors
is not determined, each test case only checks one failing condition, and
therefore many more test cases are needed for this homework than for
previous ones.
The test files are organized in folders, with names ending in Tests or Errors,
the latter only contain test cases that result in semantic errors.
To run the tests that exist in the `javali_tests` folder you can simply run
$ ant clean clean-test compile test
### Development environment
This project is designed for Eclipse and GNU/Linux, but it can be run
in other environments, as long as they have a 32bit `IA 86x assembly` compiler
and a `JVM`. Check the `Config` class for more information.
### Documentation
Available as [javadoc](javadoc/index.html). It is generated running the following command:
$ ant clean-doc generate-doc
### Important files
* `TODO.md`: contains tasks to complete
* `SemanticChecks.md`: contains the semantic checks numbered for quick reference
* [Javali Grammar](https://www.ethz.ch/content/dam/ethz/special-interest/infk/inst-cs/lst-dam/documents/Education/Classes/Spring2018/210_Compiler_Design/Homework/javali.pdf)
* [HW3 statement](https://www.ethz.ch/content/dam/ethz/special-interest/infk/inst-cs/lst-dam/documents/Education/Classes/Spring2018/210_Compiler_Design/Homework/hw3.pdf)

43
SemanticChecks.md Normal file
View file

@ -0,0 +1,43 @@
# Class and method declaration errors
1. All programs must have a method main() with void return type in the class Main (`INVALID_START_POINT`)
2. The superclass of each class exists (`NO_SUCH_TYPE`)
3. There is no circular inheritance (`CIRCULAR_INHERITANCE`)
4. No class is declared with the name `Object` (`OBJECT_CLASS_DEFINED`)
5. Unique names (`DOUBLE_DECLARATION`) for each group:
1. Class names
2. Field names in a single class (field shadowing is allowed)
3. Method names in a single class (Override is allowed, overloading not)
4. Method parameters and local variable names
6. Overridden methods must: (`INVALID_OVERRIDE`)
1. Have the same number of parameters
2. The return types must match
3. The type of the parameters must match (name can differ)
# Method body errors
1. `write()` must take one argument of type `int` (`TYPE_ERROR`)
2. `read()` and `writeln()` must take no arguments (`WRONG_NUMBER_OF_ARGUMENTS`)
3. The condition of a `while` or `if` statement must be typed `booelan` (`TYPE_ERROR`)
4. Assignments: the type of the right-hand side must be a suptype of the type of the left-hand side. (`TYPE_ERROR`)
5. Operators (`TYPE_ERROR`):
1. `*`, `/`, `%`, `+`, `-`, `<`, `>`, `<=`, `>=` take `int` arguments only.
2. `!`, `&&`, `||` take `boolean` arguments only.
3. `==` and `!=` takes any couple of arguments as long as one of the types is a subtype of the other.
4. A cast is only possible if one of the types is a subtype of the other
6. Method invocation, must match with declaration:
1. The number of parameters (`WRONG_NUMBER_OF_ARGUMENTS`)
2. The type of each of the parameters (`TYPE_ERROR`)
7. Arrays:
1. When indexing, the index expression must be an `int` (`TYPE_ERROR`)
2. When creating one, the index expression must be an `int` (`TYPE_ERROR`)
8. The constant `null` can be assigned to any reference type.
9. The type name in a `new` statement must exist (`NO_SUCH_TYPE`)
10. The left-hand side of an assignment can only be: (`NOT_ASSIGNABLE`)
1. A variable
2. A field
3. Array dereferences (indexing)
11. There must be no attempt to access the field or method of a
non-object type, such as arrays or primitive types (`TYPE_ERROR`)
12. A method with a return type must have a return statement at the end
of all its paths (`MISSING_RETURN`). A while loop is not a valid return
regardless of the condition. A ifElse must have a return on both the
else and otherwise block. There may be some statements after a return.

75
TODO.md Normal file
View file

@ -0,0 +1,75 @@
## Possible code changes
### General
* DONE Use more specific messages when throwing a `SemanticFailure` exception. This has the caveat that the automated testing relies on those tests?
### StmtAnalyzer
* DONE Propagate the change of class parameter from `ExprAnalyzer`.
* DONE Complete checks for `MISSING_RETURN`, some ideas:
* DONE Assume no instructions will appear after a return statement and analyze only the last `Stmt` using other visitor
with different class parameters (for example passing the desired type and returning a `Optional<TypeSymbol>`).
* DONE Decide the logic behind a return statement in a `while` loop, maybe treat it as an `if` with an empty `else` block.
* A `while` as last instruction is not a valid return.
* A `if` as last instruction must have a valid return a the end of its then and otherwise blocks.
### ExprAnalyzer
* DONE Change the second class parameter to give method AND class information (needed by var and this nodes)
* DISCARDED Add a ClassSymbol to MethodSymbol and use it as class parameter, the problem arises when visiting a method,
should an empty method with the proper class be provided? Could also be solved by using `Symbol` as class parameter.
* DONE Create a new class that includes a `ClassSymbol` and a `MethodSymbol` and use that. Keep `MethodSymbol == null`
when appropriate.
## Tests
This tests have been selected to increase to 100% the code coverage obtained by running the tests designed for the previous HW,
which are in folder svn/HW2/javali_tests/HW2_nop90
As they are mostly related to errors that haven't been triggered, each test should be separate, in order to generate all
of the errors.
### Remaining
### Done
* access var from class or superclass
* test ! operator
* type error in unaryOp
* type error in array size
* call method from superclass
* call a method that doesn't exist
* call a method with the wrong type of params
* call a method with the wrong number of params
* assign to all possible syntactically correct options
* field
* var
* array index
* method (error)
* this (error)
* indexing both types error
* try to access a field of something that is not a class type
* typing error in cast
* AND and OR operations
* equals operators (a case that is OK and another that's not)
* binary operation with wrong type (any but == and !=)
* search for a type that doesn't exist in a method body
* don't have a Main class
* don't have a main() method in the Main class (all possibilities)
* wrong name
* wrong return value
* wrong parameters
* inherited main method (it should work)
* write something that is not an integer
* declare a variable mutiple times (local variables)
* declare a local variable with the same name as a parameter
* check MISSING_RETURN
* nested ifElse as end of method
* while as end of method
* normal returns at the end of the method
* return with further statements after it
* while with non-int condition
* use a array type that hasn't been discovered yet
* ```class A { B[] name; } class B {}```
* name a class Object
* name a class like another class
* name a parameter like another
* override methods and try to break that
* same return type
* same number of params
* same type of params
* name a variable like another (field level)

View file

@ -1,4 +1,4 @@
<project name="compiler-design" default="generate-parser" basedir="." xmlns:jacoco="antlib:org.jacoco.ant"> <project name="compiler-design" default="test" basedir="." xmlns:jacoco="antlib:org.jacoco.ant">
<!-- A very simple ant file that primarily exists to run cup and lex; <!-- A very simple ant file that primarily exists to run cup and lex;
it also includes targets to build the compiler and run tests for those it also includes targets to build the compiler and run tests for those
@ -8,55 +8,25 @@
<property name="src.dir" value="${basedir}/src"/> <property name="src.dir" value="${basedir}/src"/>
<property name="test.dir" value="${basedir}/test"/> <property name="test.dir" value="${basedir}/test"/>
<property name="javali_tests.dir" value="${basedir}/javali_tests"/> <property name="javali_tests.dir" value="${basedir}/javali_tests"/>
<property name="parser.dir" value="${src.dir}/cd/frontend/parser"/>
<property name="parser.jar" value="${basedir}/lib/javaliParserObf.jar"/> <property name="parser.jar" value="${basedir}/lib/javaliParserObf.jar"/>
<property name="build.dir" value="${basedir}/bin"/> <property name="build.dir" value="${basedir}/bin"/>
<property name="junit.jar" value="${basedir}/lib/junit-4.12.jar"/> <property name="junit.jar" value="${basedir}/lib/junit-4.12.jar"/>
<property name="hamcrest.jar" value="${basedir}/lib/hamcrest-core-1.3.jar"/> <property name="hamcrest.jar" value="${basedir}/lib/hamcrest-core-1.3.jar"/>
<property name="antlr.jar" value="${basedir}/lib/antlr-4.7.1-complete.jar"/> <property name="antlr.jar" value="${basedir}/lib/antlr-4.4-complete.jar"/>
<property name="antlr.profile" value="false"/> <property name="antlr.profile" value="false"/>
<property name="antlr.report" value="false"/> <property name="antlr.report" value="false"/>
<property name="jacocoant.jar" value="${basedir}/lib/jacocoant.jar"/> <property name="jacocoant.jar" value="${basedir}/lib/jacocoant.jar"/>
<property name="coverage.file" location="${build.dir}/jacoco.exec"/> <property name="coverage.file" location="${build.dir}/jacoco.exec"/>
<property name="min.coverage" value="0.5"/> <property name="min.coverage" value="0.5"/>
<property name="coverage.check" value="cd.frontend.*:cd.backend.*"/> <property name="coverage.check" value="cd.frontend.*:cd.backend.*"/>
<property name="doc.dir" value="javadoc"/>
<target name="generate-parser">
<echo message="ANTLR4 ${parser.dir}/Javali.g4" level="info"/>
<echo>${basedir}</echo>
<java classname="org.antlr.v4.Tool" failonerror="true" classpath="${antlr.jar}">
<arg value="${parser.dir}/Javali.g4" />
<arg value="-o" />
<arg value="${parser.dir}" />
<arg value="-no-listener" />
<arg value="-visitor" />
</java>
</target>
<!-- Deletes the generated ANTLR parser files. Don't use in HW1! -->
<target name="clean-parser">
<delete file="${parser.dir}/Javali.tokens"/>
<delete file="${parser.dir}/JavaliLexer.java"/>
<delete file="${parser.dir}/JavaliParser.java"/>
<delete file="${parser.dir}/JavaliWalker.tokens"/>
<delete file="${parser.dir}/JavaliWalker.java"/>
<delete file="${parser.dir}/JavaliBaseListener.java"/>
<delete file="${parser.dir}/JavaliBaseVisitor.java"/>
<delete file="${parser.dir}/JavaliListener.java"/>
<delete file="${parser.dir}/JavaliVisitor.java"/>
<delete file="${parser.dir}/JavaliLexer.tokens"/>
<delete file="${parser.dir}/Javali.interp"/>
<delete file="${parser.dir}/JavaliLexer.interp"/>
</target>
<!-- Cleans generated code, but NOT the parser source! --> <!-- Cleans generated code, but NOT the parser source! -->
<target name="clean"> <target name="clean">
<delete dir="${build.dir}"/> <delete dir="${build.dir}"/>
</target> </target>
<!-- Builds the compiler framework for HW > HW1. --> <target name="compile">
<target name="compile" depends="generate-parser">
<mkdir dir="${build.dir}"/> <mkdir dir="${build.dir}"/>
<javac debug="true" destdir="${build.dir}" includeantruntime="false"> <javac debug="true" destdir="${build.dir}" includeantruntime="false">
@ -66,6 +36,7 @@
<pathelement location="${antlr.jar}"/> <pathelement location="${antlr.jar}"/>
<pathelement location="${junit.jar}"/> <pathelement location="${junit.jar}"/>
<pathelement location="${hamcrest.jar}"/> <pathelement location="${hamcrest.jar}"/>
<pathelement location="${parser.jar}"/>
</classpath> </classpath>
</javac> </javac>
</target> </target>
@ -108,4 +79,40 @@
<fail if="tests-failed" /> <fail if="tests-failed" />
</target> </target>
<target name="test-coverage-report">
<jacoco:report>
<executiondata>
<file file="${coverage.file}"/>
</executiondata>
<structure name="JaCoCo Ant Example">
<classfiles>
<fileset dir="${build.dir}"/>
</classfiles>
<sourcefiles encoding="UTF-8">
<fileset dir="${src.dir}"/>
</sourcefiles>
</structure>
<check>
<rule element="PACKAGE" includes="${coverage.check}">
<limit counter="LINE" value="COVEREDRATIO" minimum="${min.coverage}"/>
</rule>
</check>
</jacoco:report>
<echo message="Coverage above ${min.coverage} in ${coverage.check}: OK" level="info"/>
</target>
<target name="clean-doc">
<delete dir="javadoc"/>
</target>
<target name="generate-doc">
<javadoc sourcepath="${src.dir}" destdir="${doc.dir}"
private="true" use="true" author="true">
<package name="cd"/>
<package name="cd.frontend.semantic"/>
<package name="cd.ir"/>
<arg value="-notimestamp"/>
</javadoc>
</target>
</project> </project>

View file

@ -0,0 +1,9 @@
// Test that you cannot invoke a method on an integer.
class Main {
void main() {
int x;
x = 1;
x.foo();
}
}

View file

@ -0,0 +1,9 @@
/* Test that the circular inheritance between Foo and Bar is detected */
class Foo extends Bar { }
class Bar extends Foo { }
class Main {
void main() {
writeln();
}
}

View file

@ -0,0 +1,11 @@
/* Test that if conditions must be boolean */
class Main {
void main() {
if (84 / 2) {
write(1);
writeln();
}
write(2);
writeln();
}
}

View file

@ -0,0 +1,14 @@
/* Test that an invalid field name is detected */
class X {
int field;
}
class Main {
void main() {
X x;
x = new X();
x.field = 0;
x.notafield = 1; /* ILLEGAL: bad field name */
}
}

View file

@ -0,0 +1,30 @@
/* Test that fields are inherited */
class A {
int foo;
}
class B extends A {
int bar;
}
class Main {
void main() {
A a;
B b;
a = new A();
a.foo = 1;
write(a.foo);
a = new B();
a.foo = 2;
write(a.foo);
b = new B();
b.foo = 3;
b.bar = 4;
write(b.foo);
write(b.bar);
}
}

View file

@ -0,0 +1,16 @@
// Test that arrays are not covariant
class Main {
void main() {
boolean y;
A[] Array1;
B[] Array2;
Array2 = new B[10];
Array1 = Array2;
}
}
class B extends A {}
class A {}

View file

@ -0,0 +1,11 @@
// The left-hand side of an assignment cannot be a method call
// Valid options are variable accesses, fields or an indexed array
class Main {
void main() {
action() = read();
}
int action() {
return 0;
}
}

View file

@ -0,0 +1,15 @@
// The left-hand side of an assignment cannot be a reference to this
// Valid options are variable accesses, fields or an indexed array
class Main {
void main () {
int b;
int[] c;
c = new int[5];
this.a = 10;
b = 10;
c[4] = 10;
this = null;
}
int a;
}

View file

@ -0,0 +1,14 @@
// any array is a subtype of Object
// assignment and 'is equal' with an object of type 'Object' is fine
class Main {
void main() {
boolean y;
Object x;
int[] testArray;
testArray = new int[10];
x = testArray;
testArray = null;
x = null;
}
}

View file

@ -0,0 +1,8 @@
// Multiple classes can't share the same name
class Aclass {}
class Aclass {}
class Main {
void main() {}
}

View file

@ -0,0 +1,8 @@
// Two fields in a class cannot share the same name
class Main {
void main() {}
int a;
Object b;
Main a;
}

View file

@ -0,0 +1,8 @@
// Two local variables in a method cannot share the same name
class Main {
void main() {}
void test() {
int a, a;
}
}

View file

@ -0,0 +1,10 @@
// test double declaration
// test local variable and parameter have same name
class Main {
void main() {}
int action(int p1, boolean p2) {
Object p1;
return 1;
}
}

View file

@ -0,0 +1,6 @@
// No pair of parameters in a method declaration can have the same name
class Main {
void main() {}
int action(int p1, boolean p2, Object p, Object p) {}
}

View file

@ -0,0 +1,7 @@
// No class can have the name "Object"
class Aclass {}
class Object extends Aclass {}
class Main extends Object {
void main() {}
}

View file

@ -0,0 +1,7 @@
// Error: the return type of the "main" method must be "void"
class Main {
int main() {
return 10;
}
}

View file

@ -0,0 +1,5 @@
// Error: the main method must have no arguments
class Main {
void main(Object[] args) {}
}

View file

@ -0,0 +1,4 @@
// Error: there is no class called Main (case-sensitive)
class MAIN {}
class main extends Object {}

View file

@ -0,0 +1,11 @@
// Error: the "Main" class does not contain a method called "main"
class Main {
void maini() {}
void mein() {}
void moon() {}
}
class NotMain extends Main {
void main() {}
}

View file

@ -0,0 +1,7 @@
// The main method can be inherited from another class
class OtherMain {
void main () {}
}
class Main extends OtherMain {}

View file

@ -0,0 +1,15 @@
// The main method can be overridden in the inherit process, as any other method can
class A {
void main() {
write(1);
}
}
class B extends A {
void main() {
write(2);
}
}
class Main extends B {}

View file

@ -0,0 +1,7 @@
// Methods cannot be overloaded
class Main {
void main() {}
void method(int a) {}
void method(int[] a) {}
}

View file

@ -0,0 +1,21 @@
// Test 'NO SUCH FIELD'
class Main {
void main() {
C1 c1;
C2 c2;
c1 = new C1();
c2 = new C2();
c1.a = 5;
c2.b = 6;
}
}
class C1{
int a;
}
class C2 extends C1 {}
class C3 extends C2 {}

View file

@ -0,0 +1,9 @@
// Access a field from an array (error, not a class type). Not even the length field exists
class Main {
void main() {
int[] c;
c = new int[10];
write(c.length);
}
}

View file

@ -0,0 +1,8 @@
// Error: access a field from a non-class type (primitive type int)
class Main {
void main() {
int a;
write(a.end);
}
}

View file

@ -0,0 +1,27 @@
// access a field from a class and a superclass (also includes hidden fields)
class Main {
void main() {
C1 c1;
C2 c2;
C4 c4;
c1 = new C1();
c2 = new C2();
c4 = new C4();
c1.a = 5;
c2.a = 6;
c4.a = false;
}
}
class C1{
int a;
}
class C2 extends C1 {}
class C3 extends C2 {}
class C4 extends C3 {
boolean a;
}

View file

@ -0,0 +1,17 @@
// Test more complex/nested cases of CIRCULAR INHERITANCE
class Main {
void main() {}
}
class D1 extends C{}
class E extends D1{}
class D2 extends C{}
class E2 extends D2{}
class F extends E2{}
class C extends F{}

View file

@ -0,0 +1,28 @@
// Test long loops of circular inheritance
class A extends Z {}
class B extends A {}
class C extends B {}
class D extends C {}
class E extends D {}
class F extends E {}
class G extends F {}
class H extends G {}
class I extends H {}
class J extends I {}
class K extends J {}
class L extends K {}
class M extends L {}
class N extends M {}
class O extends N {}
class P extends O {}
class Q extends P {}
class R extends Q {}
class S extends R {}
class T extends S {}
class U extends T {}
class V extends U {}
class W extends V {}
class X extends W {}
class Y extends X {}
class Z extends Y {}

View file

@ -0,0 +1,5 @@
// Test inheritance of itself
class Main extends Main {
void main() {}
}

View file

@ -0,0 +1,7 @@
// Simple circular inheritance loop
class Main extends Other {
void main() {}
}
class Other extends Main {}

View file

@ -0,0 +1,10 @@
// Inherited methods cannot be overloaded
class Main extends Other {
void main() {}
void method(int a) {}
}
class Other {
void method() {}
}

View file

@ -0,0 +1,30 @@
// Access inherited and hidden fields (general check)
class Other {
int a;
int b;
Object c;
Other o;
}
class Main extends Other {
int a, b;
void main() {
Other o;
o = (Other) this;
a = 1;
b = 2;
o.a = -1;
o.b = -2;
write(a);
write(b);
write(o.a);
write(o.b);
if (c != null) {
if (o.o != null) {
write(0);
}
}
}
}

View file

@ -0,0 +1,17 @@
// call an method from a superclass
class Main {
void main() {
C2 c;
c = new C2();
c.aux();
}
}
class C1{
void aux(){
write(2);
}
}
class C2 extends C1 {}

View file

@ -0,0 +1,16 @@
// Hide a field from a superclass (type doesn't need to match)
class Parent {
int a;
}
class Main extends Parent {
Object a;
Main b;
void main() {
Parent c;
b = new Main();
b.a = new Object();
c = new Parent();
c.a = 10;
}
}

View file

@ -0,0 +1,16 @@
// The number of parameters when overriding a method must be equal
class Other {
void action() {
write(10);
}
}
class Main extends Other {
void action(int num) {
write(num);
return num + 1;
}
void main() {}
}

View file

@ -0,0 +1,14 @@
// The return type when overriding a method must be equal
class Other {
void action() {}
}
class Main extends Other {
int action() {
write(10);
return 8;
}
void main() {}
}

View file

@ -0,0 +1,17 @@
// The type of parameters when overriding a method must match the overridden method
class Other {
void action(int num) {
write(num);
}
}
class Main extends Other{
void action(boolean name) {
if (name) {
writeln();
}
}
void main() {}
}

View file

@ -0,0 +1,16 @@
// Call method that has been overridden (both the new and old one)
class Other {
void method() {}
}
class Main extends Other {
void main() {
Other o;
method();
o = (Other) this;
o.method();
}
void method() {}
}

View file

@ -0,0 +1,8 @@
// An array doesn't have methods
class Main {
Object[] array;
void main() {
array.go();
}
}

View file

@ -0,0 +1,8 @@
// A primitive variable doesn't have methods
class Main {
int a;
void main() {
a.go();
}
}

View file

@ -0,0 +1,9 @@
// call an method with wrong number of parameters
class Main {
void main() {
aux(a, b, c);
}
void aux(int a, int b) {}
}

View file

@ -0,0 +1,11 @@
// call an method with wrong types of parameters
class Main {
void main() {
int a;
boolean b;
aux(a, b);
}
void aux(int a, int b) {}
}

View file

@ -0,0 +1,19 @@
// call an method that does not exist (even in superclass)
class Main extends Other {
void main() {
aux();
go();
}
void aux() {}
}
class Other {
void aux() {}
void otherAux() {}
void noGo() {}
void GO() {}
void gO() {}
void Go() {}
}

View file

@ -0,0 +1,6 @@
// No such type in method body (handled by TypeGenerator)
class Main {
void method(NoSuchType param) {}
void main() {}
}

View file

@ -0,0 +1,5 @@
// No such type in method body (handled by checkCircularInheritance)
class Main extends NoSuchType {
void main() {}
}

View file

@ -0,0 +1,8 @@
// No such type in method body (handled by ExprVisitor and StmtVisitor)
class Main {
void main() {
Object a;
write((NoType) a);
}
}

View file

@ -0,0 +1,28 @@
// Test NO SUCH VARIABLE
// All referenced variables must exist.
class Main extends Other {
int a;
int b;
int C;
Object notC;
void main() {
int a;
boolean b;
write(c + 1);
}
}
class Other {
boolean a;
boolean b;
boolean C;
Object[] notC;
void main() {
int a;
boolean b;
Object c;
}
}

View file

@ -0,0 +1,22 @@
// Names are case-sensitive
// There exists different scopes for fields, methods, class types, parameters and local variables
class main extends Main {
main main;
Main Main;
main main(Main main, main Main) {
Main MAIN;
main maiN;
maiN = new Main();
return maiN;
}
}
class Main {
main main;
Main Main;
void main() {
}
}

View file

@ -0,0 +1,31 @@
// This method is used to force TypeGenerator to search through the list of class declarations and find
// types that don't exist in the type list but have a class declared for them.
class Other {
// Must discover in class declaration list
Main[] array;
Third third;
// Already exist
Fourth fourth; // discovered as parent of Third
Other other; // already visited
int a; // primitive and object types (and corresponding arrays) created before visiting classes
boolean b;
int[] As;
boolean[] Bs;
Object o;
Object[] Os;
Third[] thirds; // array types created when visiting corresponding classes
Other[] others;
}
class Main {
void main() {}
}
class Third extends Fourth {
}
class Fourth {
}

View file

@ -0,0 +1,9 @@
// The arguments of a BinaryOp (except == and !=) must be of the type specified by the operator
class Main {
void main() {
int a;
boolean b;
write( a + b );
}
}

View file

@ -0,0 +1,11 @@
// Error: both sides of a BinaryOp (except == and !=) must be of the same type
class Main {
void main() {
int a, b, c;
boolean d, e;
a = a + b;
d = a <= b;
d = b && c;
}
}

View file

@ -0,0 +1,25 @@
// Test the equal/not equal operations
// this test should trigger an TYPE ERROR
class Main {
void main() {
C1 a;
C3 d;
D1 f;
boolean x,y,z;
a = new C1();
d = new C3();
f = new D1();
y = f == d;
x = a != f;
}
}
class C1 {}
class C2 extends C1{}
class C3 extends C2{}
class D1 {}

View file

@ -0,0 +1,19 @@
// Test type errors with unary operator
class Main {
void main() {
int x,y,z;
boolean a;
x = -100;
y = 5;
a = -true;
z = -y;
x = +x;
write(x);
writeln();
write(z);
writeln();
write(-a);
}
}

View file

@ -0,0 +1,8 @@
// Test boolean && and || operators
class Main {
void main() {
boolean a, b, c;
a = b && c || a;
}
}

View file

@ -0,0 +1,31 @@
// Test the equal/not equal operations, one of the types must be a subtype of the other
class Main {
void main() {
C1 c1;
C2 c2;
C3 c3;
Object o1, o2;
boolean s;
o1 = new Object();
o2 = new Object();
c1 = new C1();
c2 = new C2();
c3 = new C3();
s = o1 == o2;
s = c1 != c2;
s = c3 == c1;
s = o2 != o1;
s = null == c2;
s = o1 == c2;
s = null == o;
}
}
class C1 {}
class C2 extends C1{}
class C3 extends C2{}

View file

@ -0,0 +1,36 @@
// Test '!' operator
class Main {
void main() {
boolean a,b,c,d;
int x,y;
a = true;
c = !false;
b = !a;
x = 100;
y = 5;
if (a) {
write(1);}
writeln();
if (!b){
write(2);
}
writeln();
while(c){
write(3);
c = false;
}
writeln();
// !x < 2 * y --> !x type error
// !(x < 2 * y) --> correct syntax
while(!(x<2*y)){
write(y);
y = y*2;
}
}
}

View file

@ -0,0 +1,9 @@
// A method that returns a non-void type should have arguments in all returns
class Main {
int method() {
return;
}
void main() {}
}

View file

@ -0,0 +1,18 @@
// For a if/else to be a valid return, it needs to have a return statement in both sides
class Main {
void main() {
write(things());
writeln();
}
int things() {
Object c, d;
c = new Object();
d = new Object();
if (c == d) {
return 10;
}
}
}

View file

@ -0,0 +1,20 @@
// The return type must be a subtype of the method's return type
class Main {
Main main;
Object object;
void main() {}
Object method() {
return null;
return object;
return main;
}
Main otherMethod() {
return null;
return main;
return object; // error
}
}

View file

@ -0,0 +1,20 @@
// A method with a non-void return type must have a return statement
class Main {
void main() {
write(things());
writeln();
}
int things() {
int a;
int b;
Object c, d;
a = 10;
b = 100;
c = new Object();
d = new Object();
a = b;
c = d;
}
}

View file

@ -0,0 +1,29 @@
// Test nested return statement
// the return statement is nested in if/else statements
// conditions for the if/else aren't checked
class Main {
void main() {}
int aux (boolean e){
boolean a,b,c,d;
a = true;
b = true;
c = false;
if (a){
if (b){
if (c){
} else {
if (e) {
return 1;
} else {
return 0;
}
}
}
}
}
}

View file

@ -0,0 +1,11 @@
// Test return statement in while loop
class Main {
void main() {}
int aux() {
while (true) {
return 1;
}
}
}

View file

@ -0,0 +1,7 @@
// A method that returns void can't have a return with an argument
class Main {
void main() {
return 3;
}
}

View file

@ -0,0 +1,79 @@
// A if/else block is valid return statment if all possible branches return some value
// Also serves to check subtyping
// The return logic leads to nonsensical programs with statements after the return, but that's ok
class Main {
// All returns must be empty, but we don't care for their existence
void main() {
int a, b, c;
if (a == b) {
return;
} else {
while (a > b) {
return;
}
if (c > b) {
return;
}
}
}
// All returns must be null, Main (all subtypes of Main), and there must be an unconditional return
Main action1() {
Main a;
Object b;
boolean x, y;
if (x) {
if (y) {
if (x || y) {
if (x == y && x != y) {
return null;
} else {
return a;
}
} else {
if (b == null) {
return a;
} else {
return a;
}
}
} else {
if (b == a || a == null) {
return null;
} else {
return a;
}
}
} else {
return null;
}
}
// All returns must be null, Main[] (all subtypes of Main[]), and there must be an unconditional return
Main[] action2() {
Main[] a, b;
if (a == b) {
return a;
} else {
if (b != null) {
return b;
} else {
return null;
}
}
}
// All returns must be int (no subtypes), and there must be an unconditional return
int action3() {
int a, b, c, d;
if (a > b) {
return c - d;
while (a != a) {
return b;
}
} else {
return c * d / a + b % c - a;
}
}
}

View file

@ -0,0 +1,21 @@
// The return statement can be placed in the middle of the method, and no warning will be thrown about unexecuted
// statements
class Main {
void main() {
write(things());
writeln();
}
int things() {
int a;
a = 10;
return a;
// These statements won't be reached
// but there is a complete return statement
a = 20;
writeln();
writeln();
}
}

View file

@ -0,0 +1,24 @@
// A if/else with a return in both branches is valid
class Main {
void main() {
write(things());
writeln();
}
int things() {
int a;
int b;
Object c, d;
a = 10;
b = 100;
c = new Object();
d = new Object();
if (c == d) {
return 10;
} else {
return 5;
}
}
}

View file

@ -0,0 +1,12 @@
// Test type errors when accessing an Array
class Main {
void main() {
boolean x;
int y;
int [] testArray;
testArray = new int[10];
y = testArray[x];
}
}

View file

@ -0,0 +1,22 @@
// Test types in a Cast (cannot cast to unrelated type)
// Casts to primitive types and arrays are controlled by the parser
class Main {
void main() {
C1 a, b;
C2 c, d;
Object o;
c = new C2();
a = new C1();
b = (C1) c;
d = (C2) a;
o = (Object) a;
o = (Object) c;
o = (Main) c;
}
}
class C1 {}
class C2 extends C1{}

View file

@ -0,0 +1,9 @@
// The condition of an if statement must be an int
class Main {
void main() {
if (null) {
return;
}
}
}

View file

@ -0,0 +1,7 @@
// The condition of a while must be an boolean
class Main {
void main() {
while (null) {}
}
}

View file

@ -0,0 +1,8 @@
// A object (non-array) type cannot be indexed
class Main {
void main() {
Object a;
a[1] = new Object();
}
}

View file

@ -0,0 +1,8 @@
// A primitive type cannot be indexed
class Main {
void main() {
int a;
a[1] = 10;
}
}

View file

@ -0,0 +1,8 @@
// The size for a new array declaration must be an int
class Main {
void main() {
Object[] array;
array = new Object[array];
}
}

View file

@ -0,0 +1,10 @@
// Test type error in write() statement
class Main {
void main() {
boolean a;
a = true;
write(10);
write(a);
}
}

View file

@ -0,0 +1,24 @@
/* testing arrays with primitive types as well as new objects
the if/else statements shows that the array is boolean array is initialized with false
*/
class Main {
void main() {
int [] testArray;
boolean [] boolarray;
boolarray = new boolean [3];
testArray = new int [10];
testArray[5] = 3;
boolarray[1] = true;
if (boolarray[0]){
write(1);}
else{
write(5);}
writeln();
if (boolarray[1]){
write(1);}
}
}

View file

@ -0,0 +1,12 @@
/* testing assign statements*/
class Main {
void main() {
a = read();
b = methodCall();
c = methodCall(param1, param2);
d = object.access;
e = new Ast();
d = new int[size];
f = new Object[size];
}
}

View file

@ -0,0 +1,16 @@
/* testing casting as well as creating new Objects*/
class Main
{
void main()
{
int a;
int b;
Object c;
Object d;
c = null;
d = new Object();
a = 10;
c = (Object) d;
}
}

View file

@ -0,0 +1,21 @@
class Main {
void main() {
int a, b, c, d, e;
a = 10;
b = -1;
c = 0;
d = 100;
e = 2;
write(a / b); writeln();
write(d / e); writeln();
write(c / d); writeln();
write(b / a + c); writeln();
write(d / e * a / b * c); writeln();
write(d / e * a / b); writeln();
write(d / e + a / b); writeln();
write(d / e * a * b * c); writeln();
write(d / e * a - b + c); writeln();
}
}

View file

@ -0,0 +1,9 @@
/* testing basic inheritance*/
class C1 {}
class C2 extends C1 {}
class C3 extends C2 {}
class C4 extends C2 {}
class C5 extends C3 {}
class Main {
void main() {}
}

View file

@ -0,0 +1,20 @@
/* Test expression evaluation with 8 variables */
class Main {
void main() {
int r1, r2, r3;
int i0, i1, i2, i3, i4, i5, i6, i7;
i0 = 0;
i1 = 1;
i2 = 2;
i3 = 3;
i4 = 4;
i5 = 5;
i6 = 6;
i7 = 7;
write(i0 + (i1 + ( i2 + ( i3 + ( i4 + (i5 + (i6 + i7))))))); writeln();
write(((((((i0 + i1) + i2) + i3) + i4) + i5) + i6) + i7); writeln();
write(((i0 + i1) + (i2 + i3)) + ((i4 + i5) + (i6 + i7))); writeln();
}
}

View file

@ -0,0 +1,22 @@
/* testing different expressions
compiler should recognize Type error: Return statement of method with void return type should not have arguments
*/
class Main {
void main() {
return;
return true;
return false;
return 0x10;
return 10;
return variable;
return array[index];
return methodAccess();
return object.field;
return object.call();
return op + op2;
return op / asd * asd && a == true;
return this.run();
return this;
return this.field;
}
}

View file

@ -0,0 +1,31 @@
class Main {
void main() {
int r1;
int i0, i1;
int x,y,z;
i0 = 5;
i1 = 2;
r1 = i1 * 3;
write(r1); writeln();
r1 = i0 * i1;
write(r1); writeln();
r1 = r1 * i0 * i1 * 3;
write(r1); writeln();
y = 5;
z = 10;
x = (-y * z);
write(x); writeln();
y = 0;
z = - 10;
x = (y * z);
write(x); writeln();
write(y * z); writeln();
write(0 * -10); writeln();
}
}

View file

@ -0,0 +1,20 @@
/* testing null references:
assigning null to an int or a boolean results in an error
write(null) results in a parser failure
*/
class Main {
void main() {
int a;
boolean b;
Object c;
a = null;
b = null;
c = null;
write(a);
writeln();
//write(null)
}
}

View file

@ -0,0 +1,8 @@
/*Check the order of the declarations in the generated parser
* Do the variables come always first or in their place? */
class ClassName {
void a() {}
int a;
void a() {}
void tests(boolean d, nulle a) {}
}

View file

@ -0,0 +1,25 @@
/* Test what happens for Integers that are to big for 32bits
2147483647 (=0x7FFFFFFF) is the biggest integer in 32bits (IntMAX)
*/
class Main {
void main() {
int x,y,z;
x = 2147483647;
write( x ); writeln();
/* add 1 to IntMax and output it */
write( x + 1); writeln();
/* read an int bigger than IntMAX */
x = read();
write(x); writeln();
/* performe some operation that should generate an int overflow */
x = 21474836400;
y = 60000;
write( x + y); writeln();
z = 20000000;
write( y * z); writeln();
write( (y * z) ); writeln();
}
}

View file

@ -0,0 +1 @@
2147483647

View file

@ -0,0 +1,15 @@
/*Testing all related to methods (declaration and execution)*/
class Main {
void main() {
callWithParams(a, b, c, 0, false);
object.call(a, b, d);
}
int method(int a, String b, int[] c) {
}
int[] method2() {}
Object method3() {}
Model[] method4() {}
}

View file

@ -0,0 +1,26 @@
/* Test read/write native functions */
class Main {
void main() {
int r1, r2, readvar, a1;
r1 = 6;
/* r2 = 22 */
r2 = read();
write(r1); writeln(); // 6
/* test expressions inside write() */
write(r1 - 3); writeln(); // 3
write(r1 - 6); writeln(); // 0
write(r1 - 7); writeln(); // -1
/* should output 111 */
readvar = read(); // 1
write( (r1 + (r2 * 5)) + readvar); // 117
write(- r1); // -6
writeln();
/* should output 15 */
a1 = read(); // -15
write(- a1); // 15
}
}

View file

@ -0,0 +1,6 @@
22
1
-15

View file

@ -0,0 +1,34 @@
/* testing different statements
'condition' is not initialized
*/
class Main {
void main() {
if (condition) {
instructions();
asd.b = c;
if (cond2) {
} else {
nonEmptyBlock = a;
}
} else {
}
// Whiles
while (condition) {
while (anotherLoop == false) {
nestedLoops();
}
}
while (false) {} // emptyloop
// Returns
return; // empty
return expr; // with expressions (expressions already tested)
return array[index];
// Writes
write(a);
write(9 + 10);
writeln();
write(call());
}
}

View file

@ -0,0 +1,15 @@
class Main {
void main() {
int a, b;
a = 1;
b = 2;
write(+a); writeln();
write(-a); writeln();
write(+a --b); writeln();
write(-a--b); writeln();
write(-----a-----5--b); writeln();
write(-----a*---------b);writeln();
}
}

Some files were not shown because too many files have changed in this diff Show more