493 lines
20 KiB
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()));
|
|
}
|
|
}
|