package de.dhbwstuttgart.target.generate; import de.dhbwstuttgart.exceptions.NotImplementedException; import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal; import de.dhbwstuttgart.parser.scope.JavaClassName; import de.dhbwstuttgart.syntaxtree.*; import de.dhbwstuttgart.syntaxtree.factory.PrimitiveMethodsGenerator; import de.dhbwstuttgart.syntaxtree.statement.*; import de.dhbwstuttgart.syntaxtree.type.*; import de.dhbwstuttgart.target.tree.MethodParameter; import de.dhbwstuttgart.target.tree.expression.*; import de.dhbwstuttgart.target.tree.type.*; import javax.swing.text.html.Option; import java.lang.reflect.Modifier; import java.util.*; import java.util.stream.Stream; import java.util.stream.StreamSupport; public class StatementToTargetExpression implements ASTVisitor { public StatementToTargetExpression(ASTToTargetAST converter) { this.converter = converter; } public TargetExpression result; private final ASTToTargetAST converter; @Override public void visit(ArgumentList argumentList) { throw new NotImplementedException(); } @Override public void visit(LambdaExpression lambdaExpression) { var parameters = StreamSupport.stream(lambdaExpression.params.spliterator(), false) .map(p -> (FormalParameter) p) .map(p -> new MethodParameter(new TargetTypePattern(converter.convert(p.getType()), p.getName()))) .toList(); List captures = new ArrayList<>(); lambdaExpression.methodBody.accept(new TracingStatementVisitor() { // TODO The same mechanism is implemented in Codegen, maybe use it from there? final Stack> localVariables = new Stack<>(); { localVariables.push(new HashSet<>()); } boolean hasLocalVar(String name) { for (var localVariables : this.localVariables) { if (localVariables.contains(name)) return true; } return false; } @Override public void visit(Block block) { localVariables.push(new HashSet<>()); super.visit(block); localVariables.pop(); } @Override public void visit(LocalVar localVar) { super.visit(localVar); var capture = new MethodParameter(new TargetTypePattern(converter.convert(localVar.getType()), localVar.name)); if (!hasLocalVar(localVar.name) && !parameters.contains(capture) && !captures.contains(capture)) captures.add(capture); } @Override public void visit(LocalVarDecl varDecl) { var localVariables = this.localVariables.peek(); localVariables.add(varDecl.getName()); } @Override public void visit(LambdaExpression lambda) { } // Don't look at lambda expressions }); result = new TargetLambdaExpression(converter.convert(lambdaExpression.getType()), captures, parameters, converter.convert(lambdaExpression.getReturnType()), converter.convert(lambdaExpression.methodBody)); } @Override public void visit(Assign assign) { TargetExpression left; if (assign.lefSide instanceof AssignToLocal) { left = converter.convert(((AssignToLocal) assign.lefSide).localVar); } else { left = converter.convert(((AssignToField) assign.lefSide).field); } result = new TargetAssign(converter.convert(assign.getType()), left, converter.convert(assign.rightSide)); } @Override public void visit(BinaryExpr binary) { result = switch (binary.operation) { case ADD -> new TargetBinaryOp.Add(converter.convert(binary.getType()), converter.convert(binary.lexpr), converter.convert(binary.rexpr)); case SUB -> new TargetBinaryOp.Sub(converter.convert(binary.getType()), converter.convert(binary.lexpr), converter.convert(binary.rexpr)); case MUL -> new TargetBinaryOp.Mul(converter.convert(binary.getType()), converter.convert(binary.lexpr), converter.convert(binary.rexpr)); case MOD -> new TargetBinaryOp.Rem(converter.convert(binary.getType()), converter.convert(binary.lexpr), converter.convert(binary.rexpr)); case AND -> new TargetBinaryOp.And(converter.convert(binary.getType()), converter.convert(binary.lexpr), converter.convert(binary.rexpr)); case OR -> new TargetBinaryOp.Or(converter.convert(binary.getType()), converter.convert(binary.lexpr), converter.convert(binary.rexpr)); case DIV -> new TargetBinaryOp.Div(converter.convert(binary.getType()), converter.convert(binary.lexpr), converter.convert(binary.rexpr)); case LESSTHAN -> new TargetBinaryOp.Less(converter.convert(binary.getType()), converter.convert(binary.lexpr), converter.convert(binary.rexpr)); case BIGGERTHAN -> new TargetBinaryOp.Greater(converter.convert(binary.getType()), converter.convert(binary.lexpr), converter.convert(binary.rexpr)); case LESSEQUAL -> new TargetBinaryOp.LessOrEqual(converter.convert(binary.getType()), converter.convert(binary.lexpr), converter.convert(binary.rexpr)); case BIGGEREQUAL -> new TargetBinaryOp.GreaterOrEqual(converter.convert(binary.getType()), converter.convert(binary.lexpr), converter.convert(binary.rexpr)); case EQUAL -> new TargetBinaryOp.Equal(converter.convert(binary.getType()), converter.convert(binary.lexpr), converter.convert(binary.rexpr)); case NOTEQUAL -> new TargetBinaryOp.NotEqual(converter.convert(binary.getType()), converter.convert(binary.lexpr), converter.convert(binary.rexpr)); }; } @Override public void visit(BoolExpression bool) { System.out.println("BoolExpression"); } @Override public void visit(Block block) { result = converter.convert(block); } @Override public void visit(CastExpr castExpr) { result = new TargetCast(converter.convert(castExpr.getType()), converter.convert(castExpr.expr)); } @Override public void visit(EmptyStmt emptyStmt) { result = null; } @Override public void visit(FieldVar fieldVar) { result = new TargetFieldVar(converter.convert(fieldVar.getType()), converter.convert(fieldVar.receiver.getType()), fieldVar.isStatic, converter.convert(fieldVar.receiver), fieldVar.fieldVarName); } @Override public void visit(ForStmt forStmt) { result = new TargetFor(forStmt.initializer.stream().map(converter::convert).toList(), converter.convert(forStmt.condition), forStmt.loopExpr.stream().map(converter::convert).toList(), converter.convert(forStmt.block)); } @Override public void visit(IfStmt ifStmt) { result = new TargetIf(converter.convert(ifStmt.expr), converter.convert(ifStmt.then_block), ifStmt.else_block != null ? converter.convert(ifStmt.else_block) : null); } @Override public void visit(InstanceOf instanceOf) { result = new TargetInstanceOf(converter.convert(instanceOf.getExpression()), converter.convert(instanceOf.getPattern())); } @Override public void visit(LocalVar localVar) { result = new TargetLocalVar(converter.convert(localVar.getType()), localVar.name); } @Override public void visit(LocalVarDecl localVarDecl) { // TODO No value, is this correct? result = new TargetVarDecl(converter.convert(localVarDecl.getType()), localVarDecl.getName(), null); } static boolean convertsTo(TargetType from, TargetType to) { if (to.equals(TargetType.Object)) return true; // TODO Consider type coercion and subtyping return to.equals(from); } Optional findMethod(JavaClassName className, String name, List args) { return converter.findMethod(converter.compiler.getClass(className), name, args); } @Override public void visit(MethodCall methodCall) { var receiverType = converter.convert(methodCall.receiver.getType()); var isFunNType = receiverType instanceof TargetFunNType; var returnType = isFunNType ? TargetType.Object : converter.convert(methodCall.signature.get(methodCall.signature.size() - 1)); var receiverName = new JavaClassName(converter.convert(methodCall.receiver.getType()).name()); var argList = methodCall.signature.stream().map(converter::convert).toList(); argList = argList.subList(0, argList.size() - 1); Method foundMethod = null; var isStatic = false; var isInterface = true; var signature = methodCall.signatureArguments().stream().map(converter::convert).toList(); var receiverClass = converter.currentClass; if (methodCall.receiver instanceof ExpressionReceiver expressionReceiver && expressionReceiver.expr instanceof This) { var thisMethod = converter.findMethod(converter.currentClass, methodCall.name, signature); foundMethod = thisMethod.orElseGet(() -> findMethod(converter.currentClass.getSuperClass().getName(), methodCall.name, signature).orElseThrow()); } else if (!isFunNType) { receiverClass = converter.compiler.getClass(receiverName); foundMethod = findMethod(receiverName, methodCall.name, signature).orElseThrow(); } if (!isFunNType) { returnType = converter.convert(foundMethod.getReturnType()); argList = foundMethod.getParameterList().getFormalparalist().stream().map(e -> converter.convert(e.getType())).toList(); isStatic = Modifier.isStatic(foundMethod.modifier); isInterface = receiverClass.isInterface(); } result = new TargetMethodCall(converter.convert(methodCall.getType()), returnType, argList, converter.convert(methodCall.receiver), methodCall.getArgumentList().getArguments().stream().map(converter::convert).toList(), receiverType, methodCall.name, isStatic, isInterface); } @Override public void visit(NewClass newClass) { result = new TargetNew(new TargetRefType(newClass.name), newClass.getArgumentList().getArguments().stream().map(converter::convert).toList()); } @Override public void visit(NewArray newArray) { // TODO throw new NotImplementedException(); } @Override public void visit(Return aReturn) { result = new TargetReturn(converter.convert(aReturn.retexpr)); } @Override public void visit(ReturnVoid aReturn) { result = new TargetReturn(null); } @Override public void visit(Break aBreak) { result = new TargetBreak(); } @Override public void visit(StaticClassName staticClassName) { result = new TargetClassName(converter.convert(staticClassName.getType())); } @Override public void visit(Super aSuper) { result = new TargetSuper(converter.convert(aSuper.getType())); } @Override public void visit(This aThis) { result = new TargetThis(converter.convert(aThis.getType())); } @Override public void visit(WhileStmt whileStmt) { result = new TargetWhile(converter.convert(whileStmt.expr), converter.convert(whileStmt.loopBlock)); } @Override public void visit(DoStmt whileStmt) { throw new NotImplementedException(); } // TODO These two might not be necessary @Override public void visit(AssignToField assignLeftSide) { result = converter.convert(assignLeftSide.field); } @Override public void visit(AssignToLocal assignLeftSide) { result = converter.convert(assignLeftSide.localVar); } @Override public void visit(SuperCall superCall) { var aSuper = converter.convert(converter.currentClass.getSuperClass()); var type = converter.convert(superCall.getType()); var parameters = superCall.arglist.getArguments().stream().map(par -> converter.convert(par.getType())).toList(); result = new TargetMethodCall(type, type, parameters, new TargetSuper(aSuper), superCall.getArgumentList().getArguments().stream().map(converter::convert).toList(), aSuper, superCall.name, false, false); } @Override public void visit(ExpressionReceiver expressionReceiver) { result = converter.convert(expressionReceiver.expr); } @Override public void visit(UnaryExpr unaryExpr) { result = switch (unaryExpr.operation) { case NOT -> new TargetUnaryOp.Not(converter.convert(unaryExpr.getType()), converter.convert(unaryExpr.expr)); case MINUS -> new TargetUnaryOp.Negate(converter.convert(unaryExpr.getType()), converter.convert(unaryExpr.expr)); case PREINCREMENT -> new TargetUnaryOp.PreIncrement(converter.convert(unaryExpr.getType()), converter.convert(unaryExpr.expr)); case PREDECREMENT -> new TargetUnaryOp.PreDecrement(converter.convert(unaryExpr.getType()), converter.convert(unaryExpr.expr)); case POSTINCREMENT -> new TargetUnaryOp.PostIncrement(converter.convert(unaryExpr.getType()), converter.convert(unaryExpr.expr)); case PLUS -> new TargetUnaryOp.Add(converter.convert(unaryExpr.getType()), converter.convert(unaryExpr.expr)); case POSTDECREMENT -> new TargetUnaryOp.PostDecrement(converter.convert(unaryExpr.getType()), converter.convert(unaryExpr.expr)); }; } @Override public void visit(Literal literal) { if (literal.value instanceof Integer || literal.value instanceof Short || literal.value instanceof Byte) { result = new TargetLiteral.IntLiteral((int) literal.value); } else if (literal.value instanceof Float) { result = new TargetLiteral.FloatLiteral((float) literal.value); } else if (literal.value instanceof Double) { result = new TargetLiteral.DoubleLiteral((double) literal.value); } else if (literal.value instanceof Long) { result = new TargetLiteral.LongLiteral((long) literal.value); } else if (literal.value instanceof Character) { result = new TargetLiteral.CharLiteral((char) literal.value); } else if (literal.value instanceof String) { result = new TargetLiteral.StringLiteral((String) literal.value); } else if (literal.value instanceof Boolean) { result = new TargetLiteral.BooleanLiteral((boolean) literal.value); } } @Override public void visit(Switch switchStmt) { var cases = switchStmt.getBlocks().stream().filter(s -> !s.isDefault()).map(converter::convert).toList(); TargetSwitch.Case default_ = null; for (var block : switchStmt.getBlocks()) { if (block.isDefault()) { default_ = new TargetSwitch.Case(converter.convert((Block) block), block.isExpression); } } result = new TargetSwitch(converter.convert(switchStmt.getSwitch()), cases, default_ , converter.convert(switchStmt.getType()), !switchStmt.getStatement()); } @Override public void visit(SwitchBlock switchBlock) {} @Override public void visit(SwitchLabel switchLabel) { result = converter.convert(switchLabel.getPattern()); } @Override public void visit(Yield aYield) { result = new TargetYield(converter.convert(aYield.retexpr)); } @Override public void visit(SourceFile sourceFile) { } @Override public void visit(GenericTypeVar genericTypeVar) { } @Override public void visit(GenericDeclarationList genericTypeVars) { } @Override public void visit(Field field) { } @Override public void visit(de.dhbwstuttgart.syntaxtree.Method field) { } @Override public void visit(Constructor field) { } @Override public void visit(ParameterList formalParameters) { } @Override public void visit(ClassOrInterface classOrInterface) { } @Override public void visit(RefType refType) { } @Override public void visit(SuperWildcardType superWildcardType) { } @Override public void visit(TypePlaceholder typePlaceholder) { } @Override public void visit(ExtendsWildcardType extendsWildcardType) { } @Override public void visit(GenericRefType genericRefType) { } @Override public void visit(FormalParameter aPattern) { result = new TargetTypePattern(converter.convert(aPattern.getType()), aPattern.getName()); } @Override public void visit(ExpressionPattern aPattern) { result = converter.convert(aPattern.getExpression()); } @Override public void visit(RecordPattern aRecordPattern) { result = new TargetComplexPattern( converter.convert(aRecordPattern.getType()), aRecordPattern.getName(), aRecordPattern.getSubPattern().stream().map(x -> (TargetPattern) converter.convert(x)).toList() ); } @Override public void visit(GuardedPattern aGuardedPattern) { result = new TargetGuard((TargetPattern) converter.convert(aGuardedPattern.getNestedPattern()), converter.convert(aGuardedPattern.getCondition())); } }