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) {
generateByteCodeFileFromFile(List.of("src/main/resources/JavaTestfiles/ClassWithConstructor.java",
"src/main/resources/JavaTestfiles/ClassWithConstructorAndMethodCall.java"),
List.of("ClassWithConstructor","ClassWithConstructorAndMethodCall"));
"src/main/resources/JavaTestfiles/ClassWithConstructorAndMethodCall.java",
"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);
ctxList.remove(lastElement);
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) {
List<Expression> args = new ArrayList<>();

View File

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

View File

@ -31,20 +31,24 @@ public class TypedAssignment implements TypedStatement {
public Type typeCheck(TypedProgram typedProgram) {
Type typeLeft = null;
if (typedProgram.getCurrentClass().isThereField(location.getName())) {
if (typedProgram.getCurrentClass().isThereField(location.getName()) && location.getField()) {
typeLeft = typedProgram.getCurrentClass().getFieldType(location.getName());
} else {
if (typedProgram.getCurrentClass().isCurrentMethodPresent() && !typedProgram.getCurrentClass().isCurrentConstructorPresent()) {
if (typedProgram.getCurrentClass().getCurrentMethod().isLocalVariableInMethod(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");
}
}
if (!typedProgram.getCurrentClass().isCurrentMethodPresent() && typedProgram.getCurrentClass().isCurrentConstructorPresent()) {
if (typedProgram.getCurrentClass().getCurrentConstructor().isLocalVariableInConstructor(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");
}
}

View File

@ -28,13 +28,11 @@ public class TypedClass implements TypedNode {
private TypedConstructor currentConstructor;
private Type type;
public TypedClass(TypedProgram typedProgram, Class c) {
public TypedClass(Class c) {
className = c.classname();
type = Type.REFERENCE(className);
convertMethodsAndConstructorsAndFields(typedProgram, c);
}
public boolean isParameterNameInCurrentConstructor(String parameterName) {
if (currentConstructor == null) {
return false;
@ -47,7 +45,7 @@ public class TypedClass implements TypedNode {
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.
// damit die Methoden verwendet werden können, bevor deren Blöcke ausgeführt werden
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
int i = 0;
for (Constructor constructor : c.constructors()) {

View File

@ -53,11 +53,19 @@ public class TypedConstructor implements TypedNode {
name = unTypedConstructor.className();
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;
}
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) {
this.typedBlock = new TypedBlock(typedProgram, unTypedConstructor.block());
typeCheck(typedProgram);

View File

@ -9,7 +9,6 @@ import lombok.NoArgsConstructor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import static de.maishai.typedast.Type.Kind.REFERENCE;
@Data
@AllArgsConstructor
@ -30,27 +29,20 @@ public final class TypedDeclaration implements TypedNode {
@Override
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)) {
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;
}
/*
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) {
int access = Opcodes.ACC_PUBLIC; // laut Andi ist es ok, dass alle Felder public sind
cw.visitField(access, name, type.getDescriptor(), null, null).visitEnd();

View File

@ -34,7 +34,10 @@ public class TypedFieldVarAccess implements TypedExpression {
if (field) {
if (typedProgram.getCurrentClass().isThereField(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{
throw new RuntimeException("Field " + name + " not declared ");
}

View File

@ -28,7 +28,10 @@ public class TypedMethod implements TypedNode {
name = unTypedMethod.methodName();
returnType = unTypedMethod.type();
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(
@ -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) {
typedBlock = new TypedBlock(typedProgram, unTypedMethod.block());

View File

@ -8,10 +8,10 @@ import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import static de.maishai.typedast.Help.TypedExpressionHelp.convertExpression;
//TODO: test this after fixing error from parser
@Data
@NoArgsConstructor
@ -26,38 +26,60 @@ public class TypedMethodCall implements TypedExpression, TypedStatement {
public void convertToTypedMethodCall(TypedProgram typedProgram, MethodCall unTypedMethodCall) {
recipient = new TypedFieldVarAccess(typedProgram, unTypedMethodCall.recipient());
for (Expression arg : unTypedMethodCall.args()) {
args.add(convertExpression(typedProgram, arg));
}
recipient.typeCheck(typedProgram);
for (Expression arg : unTypedMethodCall.args()) {
args.add(convertExpression(typedProgram, arg));
}
}
@Override
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()
.filter(method -> method.getName().equals(recipient.getName()))
.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).typeCheck(typedProgram).equals(method.getTypedParameters().get(i).getType())) {
allMatch = false;
break;
}
}
if (allMatch) {
type = method.getReturnType();
return type;
}
}
if (!typedProgram.getCurrentClass().getClassName().equals(ownerChainName) && ownerChainName != null) {
Optional<Type> matchingMethod = findMatchingMethod(typedProgram.getTypedClass(ownerChainName), recipient.getName());
if (matchingMethod.isPresent()) {
type = matchingMethod.get();
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");
}
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
public void codeGen(MethodContext ctx) {

View File

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

View File

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