Doing typeCheck for multi classes

This commit is contained in:
ahmad 2024-05-15 16:42:09 +02:00
parent fdac5aa346
commit aaa8a27ff9
12 changed files with 100 additions and 56 deletions

View File

@ -99,7 +99,8 @@ public class Compiler {
public static void main(String[] args) { public static void main(String[] args) {
generateByteCodeFileFromFile(List.of("src/main/resources/JavaTestfiles/ClassWithConstructor.java", generateByteCodeFileFromFile(List.of("src/main/resources/JavaTestfiles/ClassWithConstructor.java",
"src/main/resources/JavaTestfiles/ClassWithConstructorAndMethodCall.java"), "src/main/resources/JavaTestfiles/ClassWithConstructorAndMethodCall.java",
List.of("ClassWithConstructor","ClassWithConstructorAndMethodCall")); "src/main/resources/JavaTestfiles/ComplexClass.java"),
List.of("ClassWithConstructor","ClassWithConstructorAndMethodCall","ComplexClass"));
} }
} }

View File

@ -123,7 +123,7 @@ public class ExpressionGenerator extends DecafBaseVisitor<Expression> {
DecafParser.RecipientContext ctx = ctxList.get(lastElement); DecafParser.RecipientContext ctx = ctxList.get(lastElement);
ctxList.remove(lastElement); ctxList.remove(lastElement);
if (ctx.id() != null) { if (ctx.id() != null) {
return new FieldVarAccess(false, generateRecursiveOwnerChain(ctxList, recipient), ctx.id().IDENTIFIER().getText()); return new FieldVarAccess(true, generateRecursiveOwnerChain(ctxList, recipient), ctx.id().IDENTIFIER().getText());
} }
if (ctx.methName() != null) { if (ctx.methName() != null) {
List<Expression> args = new ArrayList<>(); List<Expression> args = new ArrayList<>();

View File

@ -34,7 +34,7 @@ public class TypedExpressionHelp {
} }
else if (expression instanceof MethodCall methodCall) { else if (expression instanceof MethodCall methodCall) {
TypedMethodCall typedMethodCall = new TypedMethodCall( typedProgram, methodCall); TypedMethodCall typedMethodCall = new TypedMethodCall( typedProgram, methodCall);
typedMethodCall.typeCheck( typedProgram); typedMethodCall.typeCheck(typedProgram);
return typedMethodCall; return typedMethodCall;
} }
else if (expression instanceof New newStmt) { else if (expression instanceof New newStmt) {

View File

@ -31,20 +31,24 @@ public class TypedAssignment implements TypedStatement {
public Type typeCheck(TypedProgram typedProgram) { public Type typeCheck(TypedProgram typedProgram) {
Type typeLeft = null; Type typeLeft = null;
if (typedProgram.getCurrentClass().isThereField(location.getName())) { if (typedProgram.getCurrentClass().isThereField(location.getName()) && location.getField()) {
typeLeft = typedProgram.getCurrentClass().getFieldType(location.getName()); typeLeft = typedProgram.getCurrentClass().getFieldType(location.getName());
} else { } else {
if (typedProgram.getCurrentClass().isCurrentMethodPresent() && !typedProgram.getCurrentClass().isCurrentConstructorPresent()) { if (typedProgram.getCurrentClass().isCurrentMethodPresent() && !typedProgram.getCurrentClass().isCurrentConstructorPresent()) {
if (typedProgram.getCurrentClass().getCurrentMethod().isLocalVariableInMethod(location.getName())) { if (typedProgram.getCurrentClass().getCurrentMethod().isLocalVariableInMethod(location.getName())) {
typeLeft = typedProgram.getCurrentClass().getCurrentMethod().getLocalVariableType(location.getName()); typeLeft = typedProgram.getCurrentClass().getCurrentMethod().getLocalVariableType(location.getName());
} else { } else if(typedProgram.getCurrentClass().isThereField(location.getName())){
typeLeft = typedProgram.getCurrentClass().getFieldType(location.getName());
}else {
throw new RuntimeException("Variable " + location.getName() + " not declared in method"); throw new RuntimeException("Variable " + location.getName() + " not declared in method");
} }
} }
if (!typedProgram.getCurrentClass().isCurrentMethodPresent() && typedProgram.getCurrentClass().isCurrentConstructorPresent()) { if (!typedProgram.getCurrentClass().isCurrentMethodPresent() && typedProgram.getCurrentClass().isCurrentConstructorPresent()) {
if (typedProgram.getCurrentClass().getCurrentConstructor().isLocalVariableInConstructor(location.getName())) { if (typedProgram.getCurrentClass().getCurrentConstructor().isLocalVariableInConstructor(location.getName())) {
typeLeft = typedProgram.getCurrentClass().getCurrentConstructor().getLocalVariableType(location.getName()); typeLeft = typedProgram.getCurrentClass().getCurrentConstructor().getLocalVariableType(location.getName());
} else { }else if(typedProgram.getCurrentClass().isThereField(location.getName())){
typeLeft = typedProgram.getCurrentClass().getFieldType(location.getName());
}else {
throw new RuntimeException("Variable " + location.getName() + " not declared in constructor"); throw new RuntimeException("Variable " + location.getName() + " not declared in constructor");
} }
} }

View File

@ -28,13 +28,11 @@ public class TypedClass implements TypedNode {
private TypedConstructor currentConstructor; private TypedConstructor currentConstructor;
private Type type; private Type type;
public TypedClass(TypedProgram typedProgram, Class c) { public TypedClass(Class c) {
className = c.classname(); className = c.classname();
type = Type.REFERENCE(className); type = Type.REFERENCE(className);
convertMethodsAndConstructorsAndFields(typedProgram, c);
} }
public boolean isParameterNameInCurrentConstructor(String parameterName) { public boolean isParameterNameInCurrentConstructor(String parameterName) {
if (currentConstructor == null) { if (currentConstructor == null) {
return false; return false;
@ -47,7 +45,7 @@ public class TypedClass implements TypedNode {
return false; return false;
} }
public void convertMethodsAndConstructorsAndFields(TypedProgram typedProgram, Class c){ public void convertMethodsAndConstructorsAndFields(TypedProgram typedProgram, Class c) {
// Am Anfang werden die Attribute, die Konstruktoren und Methoden in die jeweilige Liste eingefügt. // Am Anfang werden die Attribute, die Konstruktoren und Methoden in die jeweilige Liste eingefügt.
// damit die Methoden verwendet werden können, bevor deren Blöcke ausgeführt werden // damit die Methoden verwendet werden können, bevor deren Blöcke ausgeführt werden
for (Declaration declaration : c.fieldDeclarations()) { for (Declaration declaration : c.fieldDeclarations()) {
@ -62,7 +60,7 @@ public class TypedClass implements TypedNode {
} }
} }
public void covertBlocksOfConstructorsAndMethods(TypedProgram typedProgram, Class c){ public void covertBlocksOfConstructorsAndMethods(TypedProgram typedProgram, Class c) {
// Hier werden die Blöcke der Konstruktoren ausgeführt // Hier werden die Blöcke der Konstruktoren ausgeführt
int i = 0; int i = 0;
for (Constructor constructor : c.constructors()) { for (Constructor constructor : c.constructors()) {

View File

@ -53,11 +53,19 @@ public class TypedConstructor implements TypedNode {
name = unTypedConstructor.className(); name = unTypedConstructor.className();
for (Parameter param : unTypedConstructor.params()) { for (Parameter param : unTypedConstructor.params()) {
typedParameters.add(new TypedParameter(typedProgram, param)); TypedParameter typedParameter = new TypedParameter(typedProgram, param);
checkIfParameterExists(typedParameter.getParaName());
typedParameters.add(typedParameter);
localVariables.add(new TypedLocalVariable(typedParameter.getParaName(), typedParameter.getType()));
} }
type = Type.VOID; type = Type.VOID;
} }
public void checkIfParameterExists(String paraName) {
if (typedParameters.stream().anyMatch(parameter -> parameter.getParaName().equals(paraName))) {
throw new RuntimeException("Parameter " + paraName + " already exists");
}
}
public void convertToBlock(TypedProgram typedProgram, Constructor unTypedConstructor) { public void convertToBlock(TypedProgram typedProgram, Constructor unTypedConstructor) {
this.typedBlock = new TypedBlock(typedProgram, unTypedConstructor.block()); this.typedBlock = new TypedBlock(typedProgram, unTypedConstructor.block());
typeCheck(typedProgram); typeCheck(typedProgram);

View File

@ -9,7 +9,6 @@ import lombok.NoArgsConstructor;
import org.objectweb.asm.ClassWriter; import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;
import static de.maishai.typedast.Type.Kind.REFERENCE;
@Data @Data
@AllArgsConstructor @AllArgsConstructor
@ -30,27 +29,20 @@ public final class TypedDeclaration implements TypedNode {
@Override @Override
public Type typeCheck(TypedProgram typedProgram) { public Type typeCheck(TypedProgram typedProgram) {
if(type.getReference() != null && !typedProgram.getCurrentClass().getClassName().equals(type.getReference())) {
if (!typedProgram.isTypedClassPresent(type.getReference())) {
throw new RuntimeException("Type " + type.getReference() + " not found");
}
}
if (typedProgram.getCurrentClass().isThereField(name)) { if (typedProgram.getCurrentClass().isThereField(name)) {
throw new RuntimeException("Field " + name + " already declared"); throw new RuntimeException("Field " + name + " already declared");
} }
if (type.getKind() == REFERENCE) {
if (!type.getReference().equals(typedProgram.getCurrentClass().getClassName())) {
throw new RuntimeException("Field " + name + " has wrong type");
}
}
return type; return type;
} }
/*
public void codeGen(MethodVisitor mv, MethodContext ctx) {
System.out.println("Generating code for local variable " + name);
int index = ctx.addVariable(name);
mv.visitLocalVariable(name, type.getDescriptor(), null, ctx.getStartLabel(), ctx.getEndLabel(), index);
}
*/
public void codeGen(ClassWriter cw) { public void codeGen(ClassWriter cw) {
int access = Opcodes.ACC_PUBLIC; // laut Andi ist es ok, dass alle Felder public sind int access = Opcodes.ACC_PUBLIC; // laut Andi ist es ok, dass alle Felder public sind
cw.visitField(access, name, type.getDescriptor(), null, null).visitEnd(); cw.visitField(access, name, type.getDescriptor(), null, null).visitEnd();

View File

@ -34,7 +34,10 @@ public class TypedFieldVarAccess implements TypedExpression {
if (field) { if (field) {
if (typedProgram.getCurrentClass().isThereField(name)) { if (typedProgram.getCurrentClass().isThereField(name)) {
type = typedProgram.getCurrentClass().getFieldType(name); type = typedProgram.getCurrentClass().getFieldType(name);
return typedProgram.getCurrentClass().getFieldType(name); return type;
}else if(recursiveOwnerChain instanceof TypedFieldVarAccess typedFieldVarAccess){
type = typedProgram.getCurrentClass().getFieldType(typedFieldVarAccess.getName());
return type;
}else{ }else{
throw new RuntimeException("Field " + name + " not declared "); throw new RuntimeException("Field " + name + " not declared ");
} }

View File

@ -28,7 +28,10 @@ public class TypedMethod implements TypedNode {
name = unTypedMethod.methodName(); name = unTypedMethod.methodName();
returnType = unTypedMethod.type(); returnType = unTypedMethod.type();
for (var parameter : unTypedMethod.params()) { for (var parameter : unTypedMethod.params()) {
typedParameters.add(new TypedParameter(typedProgram, parameter)); TypedParameter typedParameter = new TypedParameter(typedProgram, parameter);
checkIfParameterExists(typedParameter.getParaName());
typedParameters.add(typedParameter);
localVariables.add(new TypedLocalVariable(typedParameter.getParaName(), typedParameter.getType()));
} }
typedProgram.getCurrentClass().getTypedMethods().stream().filter(method -> method.equals(this)).findFirst().ifPresentOrElse( typedProgram.getCurrentClass().getTypedMethods().stream().filter(method -> method.equals(this)).findFirst().ifPresentOrElse(
@ -37,6 +40,11 @@ public class TypedMethod implements TypedNode {
}, () -> { }, () -> {
}); });
} }
public void checkIfParameterExists(String parameterName) {
if (typedParameters.stream().anyMatch(parameter -> parameter.getParaName().equals(parameterName))) {
throw new RuntimeException("Parameter " + parameterName + " already exists");
}
}
public void convertToTypedBlock(TypedProgram typedProgram, Method unTypedMethod) { public void convertToTypedBlock(TypedProgram typedProgram, Method unTypedMethod) {
typedBlock = new TypedBlock(typedProgram, unTypedMethod.block()); typedBlock = new TypedBlock(typedProgram, unTypedMethod.block());

View File

@ -8,10 +8,10 @@ import lombok.NoArgsConstructor;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional;
import static de.maishai.typedast.Help.TypedExpressionHelp.convertExpression; import static de.maishai.typedast.Help.TypedExpressionHelp.convertExpression;
//TODO: test this after fixing error from parser
@Data @Data
@NoArgsConstructor @NoArgsConstructor
@ -26,38 +26,60 @@ public class TypedMethodCall implements TypedExpression, TypedStatement {
public void convertToTypedMethodCall(TypedProgram typedProgram, MethodCall unTypedMethodCall) { public void convertToTypedMethodCall(TypedProgram typedProgram, MethodCall unTypedMethodCall) {
recipient = new TypedFieldVarAccess(typedProgram, unTypedMethodCall.recipient()); recipient = new TypedFieldVarAccess(typedProgram, unTypedMethodCall.recipient());
for (Expression arg : unTypedMethodCall.args()) { recipient.typeCheck(typedProgram);
args.add(convertExpression(typedProgram, arg)); for (Expression arg : unTypedMethodCall.args()) {
} args.add(convertExpression(typedProgram, arg));
}
} }
@Override @Override
public Type typeCheck(TypedProgram typedProgram) { public Type typeCheck(TypedProgram typedProgram) {
if (typedProgram.getCurrentClass().isCurrentMethodPresent() || typedProgram.getCurrentClass().isCurrentConstructorPresent()) { String ownerChainName = null;
if (recipient.getRecursiveOwnerChain() != null) {
ownerChainName = recipient.getRecursiveOwnerChain().getType().getReference();
}
List<TypedMethod> methods = typedProgram.getCurrentClass().getTypedMethods().stream() if (!typedProgram.getCurrentClass().getClassName().equals(ownerChainName) && ownerChainName != null) {
.filter(method -> method.getName().equals(recipient.getName())) Optional<Type> matchingMethod = findMatchingMethod(typedProgram.getTypedClass(ownerChainName), recipient.getName());
.toList(); if (matchingMethod.isPresent()) {
type = matchingMethod.get();
for (TypedMethod method : methods) { return type;
if (method.getTypedParameters().size() == args.size()) {
boolean allMatch = true;
for (int i = 0; i < args.size(); i++) {
if (!args.get(i).typeCheck(typedProgram).equals(method.getTypedParameters().get(i).getType())) {
allMatch = false;
break;
}
}
if (allMatch) {
type = method.getReturnType();
return type;
}
}
} }
} }
if (typedProgram.getCurrentClass().isCurrentMethodPresent() || typedProgram.getCurrentClass().isCurrentConstructorPresent()) {
Optional<Type> matchingMethod = findMatchingMethod(typedProgram.getCurrentClass(), recipient.getName());
if (matchingMethod.isPresent()) {
type = matchingMethod.get();
return type;
}
}
throw new RuntimeException("Method not found"); throw new RuntimeException("Method not found");
} }
public Optional<Type> findMatchingMethod(TypedClass ownerChain, String methodName) {
List<TypedMethod> methods = ownerChain.getTypedMethods().stream()
.filter(method -> method.getName().equals(methodName))
.toList();
for (TypedMethod method : methods) {
if (method.getTypedParameters().size() == args.size()) {
boolean allMatch = true;
for (int i = 0; i < args.size(); i++) {
if (!args.get(i).getType().equals(method.getTypedParameters().get(i).getType())) {
allMatch = false;
break;
}
}
if (allMatch) {
return Optional.of(method.getReturnType());
}
}
}
return Optional.empty();
}
@Override @Override
public void codeGen(MethodContext ctx) { public void codeGen(MethodContext ctx) {

View File

@ -28,6 +28,11 @@ public class TypedNew implements TypedExpression, TypedStatement {
@Override @Override
public Type typeCheck(TypedProgram typedProgram) { public Type typeCheck(TypedProgram typedProgram) {
if(typedProgram.isTypedClassPresent(type.getReference())){
return Type.REFERENCE(type.getReference());
}
for (var constructor : typedProgram.getCurrentClass().getTypedConstructors()) { for (var constructor : typedProgram.getCurrentClass().getTypedConstructors()) {
if (constructor.getTypedParameters().size() == args.size()) { if (constructor.getTypedParameters().size() == args.size()) {
boolean valid = true; boolean valid = true;

View File

@ -19,10 +19,14 @@ public class TypedProgram {
public void startConversion(Program program) { public void startConversion(Program program) {
for(var clas : program.classes()){
typedClasses.add(new TypedClass(clas));
}
int k = 0; int k = 0;
for (var clas : program.classes()) { for (var clas : program.classes()) {
enterCurrentClass(typedClasses.get(k)); enterCurrentClass(typedClasses.get(k));
typedClasses.add(new TypedClass(this, clas)); typedClasses.get(k).convertMethodsAndConstructorsAndFields(this, clas);
exitCurrentClass(); exitCurrentClass();
k++; k++;
} }
@ -39,9 +43,8 @@ public class TypedProgram {
public TypedClass getTypedClass(String className) { public TypedClass getTypedClass(String className) {
return typedClasses.stream().filter(clas -> clas.getClassName().equals(className)).findFirst().get(); return typedClasses.stream().filter(clas -> clas.getClassName().equals(className)).findFirst().get();
} }
public boolean isTypedClassPresent(String className) {
public boolean isCurrentClassPresent() { return typedClasses.stream().anyMatch(clas -> clas.getClassName().equals(className));
return currentClass != null;
} }
public void enterCurrentClass(TypedClass clas) { public void enterCurrentClass(TypedClass clas) {