Skip to content

Commit

Permalink
Methods can now be called with null as argument
Browse files Browse the repository at this point in the history
  • Loading branch information
raphaelsack committed May 21, 2022
1 parent 7be5f82 commit 19e4e6a
Show file tree
Hide file tree
Showing 12 changed files with 364 additions and 29 deletions.
2 changes: 1 addition & 1 deletion HouseOfCompiler/src/main/java/common/PrintableVector.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public class PrintableVector<T> extends Vector<T> {
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("");
for (int i = 0; i < elementData.length; i++) {
for (int i = 0; i < elementCount; i++) {
if (elementData[i] != null) {
sb.append(i + ": ").append(elementData[i]).append("\n");
}
Expand Down
53 changes: 31 additions & 22 deletions HouseOfCompiler/src/main/java/semantic/SemanticCheck.java
Original file line number Diff line number Diff line change
Expand Up @@ -504,11 +504,7 @@ public TypeCheckResult typeCheck(MethodCall methodCall) {
}

try {
var method = TypeHelper.getMethodInType(methodCall, methodCall.getReceiver().getType(), context); // Throws
// an
// Error,
// cant
// be
var method = TypeHelper.getMethodInType(methodCall, methodCall.getReceiver().getType(), context);
var returnType = method.getType();
methodCall.setType(returnType);
return new TypeCheckResult(valid, null);
Expand Down Expand Up @@ -614,13 +610,18 @@ public TypeCheckResult typeCheck(LocalOrFieldVar localOrFieldVar) {
}

// check if the variable is declared in the current class
try {
var fieldVar = TypeHelper.getFieldInType(localOrFieldVar.getIdentifier(),
new ReferenceType(this.currentClass.getIdentifier()), context);

var fieldVar = TypeHelper.getFieldInType(localOrFieldVar.getIdentifier(),
new ReferenceType(this.currentClass.getIdentifier()), context);

if (fieldVar != null) {
localOrFieldVar.setType(fieldVar.getType());
return new TypeCheckResult(true, fieldVar.getType());
if (fieldVar != null) {
localOrFieldVar.setType(fieldVar.getType());
return new TypeCheckResult(true, fieldVar.getType());
}
} catch (TypeMismatchException e) {
errors.add(new SemanticError(e.getMessage() + TypeHelper.generateLocationString(localOrFieldVar.line,
localOrFieldVar.column, fileName)));
return new TypeCheckResult(false, null);
}

var importStaticField = context.getImports().get(localOrFieldVar.getIdentifier());
Expand Down Expand Up @@ -676,20 +677,28 @@ public TypeCheckResult typeCheck(InstVar instVar) {
+ TypeHelper.generateLocationString(instVar.line, instVar.column, fileName)));
valid = false;
}
var nextInstVar = TypeHelper.getFieldInType(instVar.getIdentifier(), type, this.context);
try {

// Check if the identifier exists in current Type
if (nextInstVar == null) {
errors.add(
new FieldNotFoundException("Field: " + instVar.getIdentifier() + " not found in Class: " + type
+ TypeHelper.generateLocationString(instVar.line, instVar.column, fileName)));
var nextInstVar = TypeHelper.getFieldInType(instVar.getIdentifier(), type, this.context);

// Check if the identifier exists in current Type
if (nextInstVar == null) {
errors.add(
new FieldNotFoundException("Field: " + instVar.getIdentifier() + " not found in Class: " + type
+ TypeHelper.generateLocationString(instVar.line, instVar.column, fileName)));
valid = false;
}
valid = valid && result.isValid();
var newType = nextInstVar == null ? null : nextInstVar.getType();
instVar.setType(newType);
instVar.setAccessModifier(nextInstVar == null ? null : nextInstVar.getAccessModifier());
return new TypeCheckResult(valid, newType);
} catch (TypeMismatchException e) {
errors.add(new TypeMismatchException(e.getMessage() + TypeHelper.generateLocationString(instVar.line,
instVar.column, fileName)));
valid = false;
return new TypeCheckResult(valid, null);
}
valid = valid && result.isValid();
var newType = nextInstVar.getType();
instVar.setType(newType);
instVar.setAccessModifier(nextInstVar.getAccessModifier());
return new TypeCheckResult(valid, newType);
}

/**
Expand Down
26 changes: 22 additions & 4 deletions HouseOfCompiler/src/main/java/semantic/TypeHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@

import common.BaseType;
import common.Primitives;
import common.PrintableVector;
import common.ReferenceType;
import common.Type;
import context.ConstructorContext;
import context.Context;
import context.FieldContext;
import context.MethodContext;
import semantic.exceptions.TypeMismatchException;
import syntaxtree.expressions.Null;
import syntaxtree.statementexpression.MethodCall;
import syntaxtree.statementexpression.NewDecl;

Expand Down Expand Up @@ -108,25 +110,41 @@ public static MethodContext getMethodInType(MethodCall methodCall, Type type, Co
throw new TypeMismatchException("No declared Method " + methodCall.getIdentifier() + " with Arguments: "
+ methodCall.printTypes() + " in Type " + type);
}
var foundMethods = new PrintableVector<MethodContext>();
var methods = classContext.getMethods().get(methodCall.getIdentifier());
for (var method : methods) {
if (method.getParameterTypes().size() == methodCall.getArguments().size()) {
boolean isSame = true;
for (int i = 0; i < method.getParameterTypes().size(); i++) {
var parameterType = method.getParameterTypes().get(i);
var argument = methodCall.getArguments().get(i);
if (!parameterType.equals(argument.getType())) {
if (!((argument instanceof Null && parameterType instanceof ReferenceType)
|| (!(argument instanceof Null) && parameterType.equals(argument.getType())))) {
isSame = false;
break;
}
}
if (isSame) {
return method;
foundMethods.add(method);
}
}
}
throw new TypeMismatchException("No declared Method " + methodCall.getIdentifier() + " with Arguments: "
+ methodCall.printTypes() + " in Type " + type);
if (foundMethods.size() == 0) {
throw new TypeMismatchException("No declared Method " + methodCall.getIdentifier() + " with Arguments: "
+ methodCall.printTypes() + " in Type " + type);
} else if (foundMethods.size() == 1) {
for (int i = 0; i < foundMethods.get(0).getParameterTypes().size(); i++) {
var parameterType = foundMethods.get(0).getParameterTypes().get(i);
var argument = methodCall.getArguments().get(i);
if (argument instanceof Null) {
((Null) argument).setType(parameterType);
}
}
return foundMethods.get(0);
} else {
throw new TypeMismatchException("Cannot resolve Method-Call with Arguments: " + methodCall.printTypes()
+ " in Type " + type + ". Multiple Methods found: \n" + foundMethods);
}
} else {
throw new TypeMismatchException("Base Type " + type + " does not have Methods");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public int hashCode() {
*/
@Override
public String toString() {
return "null";
return "null" + " [" + type + "]";
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,9 @@ public String printTypes() {
returnString += expression.getType() + ", ";
}
// delete the last ", "
returnString = returnString.substring(0, returnString.length() - 2);
if (returnString.length() > 1) {
returnString = returnString.substring(0, returnString.length() - 2);
}
returnString += ")";
return returnString;

Expand Down
107 changes: 107 additions & 0 deletions HouseOfCompiler/src/test/java/All/TestRunner.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package All;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.fail;

import java.io.ByteArrayOutputStream;
Expand All @@ -15,6 +16,7 @@
import Helper.ReflectLoader;
import Helper.Resources;
import common.Compiler;
import semantic.exceptions.SemanticError;
import syntaxtree.structure.Program;

@DisplayName("All")
Expand Down Expand Up @@ -927,4 +929,109 @@ void stackTest() {
}
}

@Test
@DisplayName("OverridingTest")
void OverridingTest() {
Program program = Resources.getProgram("SimpleTests/OverridingTest.java");
Program tast = Compiler.getFactory().getTastAdapter().getTast(program);
var bc = Compiler.getFactory().getProgramGenerator().generateBytecode(tast);
ReflectLoader loader = new ReflectLoader(bc);
Class<?> c = loader.findClass("OverridingTest");
Object o = null;
try {
o = c.getDeclaredConstructor().newInstance();
var foo = loader.getMethod("OverridingTest", "foo", int.class);
assertEquals(1337, foo.invoke(o, 30));
assertEquals(8, foo.invoke(o, 8));
assertEquals(0, foo.invoke(o, 2));
} catch (Exception e) {
fail(e.getMessage());
}
}

@Test
@DisplayName("OverridingTestNull")
void OverridingTestNull() {
Program program = Resources.getProgram("SimpleTests/OverridingTestNull.java");
Program tast = Compiler.getFactory().getTastAdapter().getTast(program);
System.out.println(tast);
var bc = Compiler.getFactory().getProgramGenerator().generateBytecode(tast);
ReflectLoader loader = new ReflectLoader(bc);
Class<?> c = loader.findClass("OverridingTestNull");
Object o = null;
try {
o = c.getDeclaredConstructor().newInstance();
var foo = loader.getMethod("OverridingTestNull", "foo", int.class);
assertEquals(1337, foo.invoke(o, 40));
assertEquals(1337, foo.invoke(o, 15));
assertEquals(8, foo.invoke(o, 8));
assertEquals(0, foo.invoke(o, 2));
} catch (Exception e) {
fail(e.getMessage());
}
}

@Test
@DisplayName("OverridingTestNullMultiple")
void OverridingTestNullMultiple() {
Program program = Resources.getProgram("SimpleTests/OverridingTestNullMultiple.java");
Program tast = Compiler.getFactory().getTastAdapter().getTast(program);
System.out.println(tast);
var bc = Compiler.getFactory().getProgramGenerator().generateBytecode(tast);
ReflectLoader loader = new ReflectLoader(bc);
Class<?> c = loader.findClass("OverridingTestNullMultiple");
Object o = null;
try {
o = c.getDeclaredConstructor().newInstance();
var foo = loader.getMethod("OverridingTestNullMultiple", "foo", int.class);
assertEquals(1337, foo.invoke(o, 40));
assertEquals(1337, foo.invoke(o, 20));
assertEquals(1337, foo.invoke(o, 15));
assertEquals(8, foo.invoke(o, 8));
assertEquals(0, foo.invoke(o, 2));
} catch (Exception e) {
fail(e.getMessage());
}
}

@Test
@DisplayName("MultipleMethodsConflictTest")
void MultipleMethodsConflictTest() {
Program program = Resources.getProgram("FailTests/MultipleMethodsConflict.java");
System.err.print(assertThrows(
SemanticError.class,
() -> Compiler.getFactory().getTastAdapter().getTast(program),
"Expected SemanticError to be thrown").getMessage());
}

@Test
@DisplayName("LOFOI")
void lOFOITest() {
Program program = Resources.getProgram("Integration/LOFOI.java");
Program tast = Compiler.getFactory().getTastAdapter().getTast(program);
var bc = Compiler.getFactory().getProgramGenerator().generateBytecode(tast);
ReflectLoader loader = new ReflectLoader(bc);
Class<?> c = loader.findClass("LOFOI");
Object o = null;
try {
o = c.getDeclaredConstructor().newInstance();
var foo = loader.getMethod("LOFOI", "foo");
var bar = loader.getMethod("LOFOI", "bar");
assertEquals(20, foo.invoke(o));
assertEquals(10, bar.invoke(o));
} catch (Exception e) {
fail(e.getMessage());
}
}

@Test
@DisplayName("LOFOIFailTest")
void lOFOIFailTest() {
Program program = Resources.getProgram("FailTests/LOFOI.java");
System.err.print(assertThrows(
SemanticError.class,
() -> Compiler.getFactory().getTastAdapter().getTast(program),
"Expected SemanticError to be thrown").getMessage());
}

}
35 changes: 35 additions & 0 deletions HouseOfCompiler/src/test/resources/FailTests/LOFOI.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Local or Field or Imported var Test
class LOFOI {

// This test is to determine wheter the order of finding the vars is correct

int System;

public LOFOI() {
System = 10;
}

public int foo() {
int System = 20;
return System;
}

public int bar() {
return System;
}

public int baz() {
System.out.println('1');
}

}

class OtherLOFOI {

LOFOI System;

void foo() {
System.out.println('1');
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
class MultipleMethodsConflict {

// Test is used to determine wheter the Right method with the right types is
// called

public int foo(int i) {
Helper help = new Helper();
if (i < 5) {
return test();
} else if (i < 10) {
return test(i);
} else if (i < 20) {
return test(this, null);
} else if (i < 30) {
return test(null, null);
} else {
return test(this, this);
}
}

public int test() {
System.out.println(0);
return 0;
}

public int test(int i) {
System.out.println(i);
return i;
}

public int test(MultipleMethodsConflict o, MultipleMethodsConflict b) {
System.out.println(1337);
return 1337;
}

public int test(MultipleMethodsConflict o, Helper b) {
System.out.println(420);
return 420;
}

}

class Helper {

}
21 changes: 21 additions & 0 deletions HouseOfCompiler/src/test/resources/Integration/LOFOI.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Local or Field or Imported var Test
class LOFOI {

// This test is to determine wheter the order of finding the vars is correct

int System;

public LOFOI() {
System = 10;
}

public int foo() {
int System = 20;
return System;
}

public int bar() {
return System;
}

}
Loading

0 comments on commit 19e4e6a

Please sign in to comment.