JavaTXCompilerInJavaTXNoMaven/javatx-src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java

493 lines
20 KiB
Java

package de.dhbwstuttgart.target.generate;
import de.dhbwstuttgart.exceptions.DebugException;
import de.dhbwstuttgart.exceptions.NotImplementedException;
import de.dhbwstuttgart.parser.NullToken;
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.TargetGeneric;
import de.dhbwstuttgart.target.tree.TargetMethod;
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<MethodParameter> captures = new ArrayList<>();
lambdaExpression.methodBody.accept(new TracingStatementVisitor() {
// TODO The same mechanism is implemented in Codegen, maybe use it from there?
final Stack<Set<String>> 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
});
TargetMethod.Signature signature = new TargetMethod.Signature(Set.of(), parameters, converter.convert(lambdaExpression.getReturnType()));;
var tpe = converter.convert(lambdaExpression.getType());
result = new TargetLambdaExpression(tpe, captures, signature, 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.BAnd(converter.convert(binary.getType()), converter.convert(binary.lexpr), converter.convert(binary.rexpr));
case OR -> new TargetBinaryOp.BOr(converter.convert(binary.getType()), converter.convert(binary.lexpr), converter.convert(binary.rexpr));
case XOR -> new TargetBinaryOp.XOr(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(),
forStmt.condition != null ? converter.convert(forStmt.condition) : null,
forStmt.loopExpr.stream().map(converter::convert).toList(),
converter.convertWrapInBlock(forStmt.block)
);
}
@Override
public void visit(ForEachStmt forEachStmt) {
result = new TargetForEach(converter.convert(forEachStmt.statement), converter.convert(forEachStmt.expression), converter.convertWrapInBlock(forEachStmt.block));
}
@Override
public void visit(IfStmt ifStmt) {
result = new TargetIf(converter.convert(ifStmt.expr), converter.convertWrapInBlock(ifStmt.then_block), ifStmt.else_block != null ? converter.convertWrapInBlock(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<Method> findMethod(JavaClassName className, String name, List<TargetType> 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 isPrivate = false;
var signature = methodCall.signatureArguments().stream().map(converter::convert).toList();
var receiverClass = converter.compiler.getClass(receiverName);
if (methodCall.receiver instanceof ExpressionReceiver expressionReceiver && expressionReceiver.expr instanceof This) {
if (receiverClass == null) throw new DebugException("Class " + receiverName + " does not exist!");
var thisMethod = converter.findMethod(receiverClass, methodCall.name, signature);
ClassOrInterface finalReceiverClass = receiverClass;
foundMethod = thisMethod.orElseGet(() -> findMethod(finalReceiverClass.getSuperClass().getName(), methodCall.name, signature).orElseThrow());
} else if (!isFunNType) {
receiverClass = converter.compiler.getClass(receiverName);
if (receiverClass == null) throw new DebugException("Class " + receiverName + " does not exist!");
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);
isPrivate = Modifier.isPrivate(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, isPrivate);
}
@Override
public void visit(NewClass newClass) {
var receiverName = new JavaClassName(newClass.name);
var ctor = converter.findConstructor(converter.compiler.getClass(receiverName), newClass.signatureArguments().stream().map(converter::convert).toList());
var signature = ctor.orElseThrow().getParameterList().getFormalparalist().stream().map(e -> converter.convert(e.getType())).toList();
result = new TargetNew(new TargetRefType(newClass.name), signature, 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(superCall.receiver.getType());
var type = converter.convert(superCall.getType());
var receiverName = new JavaClassName(converter.convert(superCall.receiver.getType()).name());
var clazz = converter.compiler.getClass(receiverName);
var signature = superCall.signatureArguments().stream().map(converter::convert).toList();
var method = converter.findConstructor(clazz, signature);
var params = superCall.getArgumentList().getArguments().stream().map(converter::convert).toList();
List<TargetType> argList;
if (method.isPresent()) {
argList = method.get().getParameterList().getFormalparalist().stream().map(e -> converter.convert(e.getType())).toList();
} else {
argList = params.stream().map(TargetExpression::type).toList();
}
result = new TargetMethodCall(type, null, argList, new TargetSuper(aSuper), params, aSuper, superCall.name, false, false, false);
}
@Override
public void visit(ThisCall thisCall) {
var aThis = converter.convert(thisCall.receiver.getType());
var type = converter.convert(thisCall.getType());
var parameters = thisCall.arglist.getArguments().stream().map(par -> converter.convert(par.getType())).toList();
result = new TargetMethodCall(type, type, parameters, new TargetThis(aThis), thisCall.getArgumentList().getArguments().stream().map(converter::convert).toList(), aThis, thisCall.name, false, 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);
} else if (literal.value == null) {
result = new TargetLiteral.Null();
}
}
@Override
public void visit(Throw aThrow) {
result = new TargetThrow(converter.convert(aThrow.expr));
}
@Override
public void visit(Ternary ternary) {
result = new TargetTernary(converter.convert(ternary.getType()), converter.convert(ternary.cond), converter.convert(ternary.iftrue), converter.convert(ternary.iffalse));
}
@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()));
}
}