Merge branch 'targetBytecode' of ssh://gohorb.ba-horb.de/bahome/projekt/git/JavaCompilerCore into targetBytecode

This commit is contained in:
pl@gohorb.ba-horb.de 2024-03-04 19:37:40 +01:00
commit 1c1f5ae29f
50 changed files with 722 additions and 210 deletions

View File

@ -0,0 +1,7 @@
public class Bug112 {
m(x) {
var y;
x = y;
return y;
}
}

View File

@ -0,0 +1,12 @@
import java.lang.Integer;
import java.lang.Boolean;
class Bug122 {
void main() {
if (true) {
for (Integer i = 0; i < 10; i++) {
}
}
}
}

View File

@ -0,0 +1,13 @@
import java.lang.Boolean;
import java.lang.Integer;
class Bug123 {
Boolean works(){
if(true) return true;
else return false;
}
void fails(){
Boolean a = true;
if(true) a = false;
}
}

View File

@ -0,0 +1,16 @@
import java.lang.Boolean;
import java.lang.Integer;
import java.lang.String;
import java.util.List;
import java.util.LinkedList;
import java.util.ArrayList;
class Bug125 {
static ArrayList<String> works = new ArrayList<>();
static List<String> fails = new ArrayList<>();
void main() {
works.toString();
fails.toString();
}
}

View File

@ -1,3 +1,8 @@
import java.lang.String;
import java.lang.RuntimeException;
public class Exceptions {
// m(Integer i) throws
m() {
throw new RuntimeException("Some Exception");
}
}

View File

@ -0,0 +1,15 @@
import java.util.ArrayList;
import java.lang.Integer;
public class ForEach {
m() {
var list = new ArrayList<>();
list.add(1); list.add(2); list.add(3);
var sum = 0;
for (var i : list) {
sum = sum + i;
}
return sum;
}
}

View File

@ -1,18 +1,18 @@
import java.lang.Number;
import java.lang.Object;
import java.lang.Integer;
import java.lang.Double;
import java.lang.String;
import java.lang.Boolean;
interface Interface {}
class Test implements Interface {
}
class Test2 {
}
public class InstanceOf {
main(n) {
if (n instanceof Integer i) {
takes(i);
return "Integer";
} else if (n instanceof Double d) {
takes(d);
return "Double";
}
}
a = new Test();
takes(i) {} // Should be overloaded
test1() { return this.a instanceof Test; }
test2() { return this.a instanceof Interface; }
test3() { return this.a instanceof Integer; }
}

View File

@ -1,8 +1,15 @@
import java.lang.Runnable;
import java.lang.System;
import java.lang.String;
import java.io.PrintStream;
public class LamRunnable {
public LamRunnable() {
Runnable lam = () -> {
System.out.println("lambda");
};
Runnable lam = () -> {System.out.println("lambda");};
lam.run();
}
}

View File

@ -0,0 +1,6 @@
import java.lang.Character;
public class Literal {
m() { return null; }
m2() { return 'C'; }
}

View File

@ -0,0 +1,17 @@
import java.lang.Integer;
public class Parent {
public Integer x;
public Parent(Integer a) {
this.x = a;
}
public Parent() {}
}
class Child extends Parent {
Child() {
super(3);
}
}

View File

@ -1,10 +1,16 @@
import java.lang.Integer;
import java.lang.Double;
import java.lang.String;
public class Op2 {
m(){
var x = "";
var a = 5+x;
//var x = "";
//var a = 5+x;
Integer x = 10;
Double y = 10.5;
var a = x - y;
return a;
}

View File

@ -0,0 +1,11 @@
import java.lang.Integer;
class Parent {
public Parent(Integer x) {}
}
public class SuperCall extends Parent {
public SuperCall() {
super(20);
}
}

View File

@ -2,6 +2,7 @@ package de.dhbwstuttgart.bytecode;
import de.dhbwstuttgart.core.JavaTXCompiler;
import de.dhbwstuttgart.exceptions.NotImplementedException;
import de.dhbwstuttgart.parser.NullToken;
import de.dhbwstuttgart.parser.scope.JavaClassName;
import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
import de.dhbwstuttgart.syntaxtree.type.RefType;
@ -135,7 +136,7 @@ public class Codegen {
} else if (type.equals(TargetType.Short) || type.equals(TargetType.short_)) {
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false);
} else if (type.equals(TargetType.Char) || type.equals(TargetType.char_)) {
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Char", "valueOf", "(C)Ljava/lang/Char;", false);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false);
}
}
@ -156,7 +157,7 @@ public class Codegen {
} else if (type.equals(TargetType.Short)) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S", false);
} else if (type.equals(TargetType.Char)) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Char", "charValue", "()C", false);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C", false);
}
}
@ -805,6 +806,7 @@ public class Codegen {
case StringLiteral stringLiteral -> mv.visitLdcInsn(stringLiteral.value());
case CharLiteral charLiteral -> mv.visitIntInsn(BIPUSH, charLiteral.value());
case DoubleLiteral doubleLiteral -> mv.visitLdcInsn(doubleLiteral.value());
case Null ignored -> mv.visitInsn(ACONST_NULL);
case BooleanLiteral booleanLiteral -> {
if (booleanLiteral.value()) {
mv.visitInsn(ICONST_1);
@ -884,8 +886,12 @@ public class Codegen {
case TargetFor _for: {
state.enterScope();
var localCounter = state.localCounter;
if (_for.init() != null)
_for.init().forEach(e -> generate(state, e));
if (_for.init() != null) {
for (var e : _for.init()) {
generate(state, e);
if (e instanceof TargetAssign) mv.visitInsn(POP);
}
}
Label start = new Label();
Label end = new Label();
@ -918,6 +924,9 @@ public class Codegen {
state.localCounter = localCounter;
break;
}
case TargetForEach forEach:
generateForEach(forEach, state);
break;
case TargetWhile _while: {
Label start = new Label();
Label end = new Label();
@ -1036,15 +1045,50 @@ public class Codegen {
mv.visitMethodInsn(INVOKESPECIAL, _new.type().getInternalName(), "<init>", _new.getDescriptor(), false);
break;
}
case TargetThrow _throw: {
generate(state, _throw.expr());
mv.visitInsn(ATHROW);
break;
}
default:
throw new CodeGenException("Unexpected value: " + expr);
}
}
private void generateForEach(TargetForEach forEach, State state) {
state.enterScope();
TargetVarDecl vd = (TargetVarDecl) forEach.vardecl();
var localVar = state.createVariable(vd.name(), vd.varType());
var expr = forEach.expression();
// TODO Check for arrays
var mv = state.mv;
generate(state, expr);
mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/Iterable", "iterator", "()Ljava/util/Iterator;", true);
var start = new Label();
var end = new Label();
mv.visitLabel(start);
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Iterator", "hasNext", "()Z", true);
mv.visitJumpInsn(IFEQ, end);
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Iterator", "next", "()Ljava/lang/Object;", true);
mv.visitVarInsn(ASTORE, localVar.index);
generate(state, forEach.body());
mv.visitJumpInsn(GOTO, start);
mv.visitLabel(end);
mv.visitInsn(POP);
state.exitScope();
}
private void generateInstanceOf(State state, TargetInstanceOf instanceOf) {
var mv = state.mv;
if (instanceOf.right() instanceof TargetTypePattern right && right.name() == null) {
generate(state, instanceOf.left());
mv.visitTypeInsn(INSTANCEOF, right.type().getInternalName());
return;
}
@ -1349,8 +1393,8 @@ public class Codegen {
generate(state, stmts.get(0));
if (constructor.fieldInitializer() != null) {
var stmts2 = constructor.fieldInitializer().statements();
for (var i = 1; i < stmts2.size(); i++) {
generate(state, stmts2.get(i));
for (TargetExpression expression : stmts2) {
generate(state, expression);
}
}
for (var i = 1; i < stmts.size(); i++)

View File

@ -651,7 +651,7 @@ public class JavaTXCompiler {
private SourceFile parse(File sourceFile) throws IOException, java.lang.ClassNotFoundException {
SourceFileContext tree = JavaTXParser.parse(sourceFile);
environment.addClassesToRegistry(classRegistry, tree, sourceFile, this);
SyntaxTreeGenerator generator = new SyntaxTreeGenerator(this, classRegistry, new GenericsRegistry(null));
SyntaxTreeGenerator generator = new SyntaxTreeGenerator(this, classRegistry, new GenericsRegistry(null), sourceFile.getName());
var classes = new ArrayList<ClassOrInterface>();
var sf = new SourceFile(generator.pkgName, classes, generator.imports);
addSourceFile(sourceFile, sf);
@ -672,7 +672,7 @@ public class JavaTXCompiler {
var tree = JavaTXParser.parse(file);
classRegistry.addName(name.toString(), 0); // TODO This gets overwritten later, is it bad if we don't know this right away?
environment.addClassesToRegistry(classRegistry, tree, file, this);
SyntaxTreeGenerator generator = new SyntaxTreeGenerator(this, classRegistry, new GenericsRegistry(null));
SyntaxTreeGenerator generator = new SyntaxTreeGenerator(this, classRegistry, new GenericsRegistry(null), file.getName());
var classes = new ArrayList<ClassOrInterface>();
var sf = new SourceFile(generator.pkgName, classes, generator.imports);
addSourceFile(file, sf);

View File

@ -0,0 +1,4 @@
package de.dhbwstuttgart.parser;
public record SourceLoc(String file, int line) {
}

View File

@ -60,7 +60,7 @@ public class FCGenerator {
.collect(Collectors.toList()));
tl.add(m.getReturnType().acceptTV(new TypeExchanger(gtvs)));
return new Pair(new RefType(new JavaClassName("Fun" + (tl.size()-1) + "$$"), tl, new NullToken()),
fIType);
fIType, PairOperator.SMALLER);
}
return null; //kann nicht passieren, da die Methode nur aufgerufen wird wenn cl Functional Interface ist
}

View File

@ -490,15 +490,33 @@ public class StatementGenerator {
private Statement convert(Java17Parser.ForloopContext stmt) {
var control = stmt.forControl();
var block = convert(stmt.statement());
if (control.enhancedForControl() != null)
throw new NotImplementedException();
else {
if (control.enhancedForControl() != null) {
var forCtrl = control.enhancedForControl();
var name = forCtrl.variableDeclaratorId().identifier();
RefTypeOrTPHOrWildcardOrGeneric type;
if (Objects.isNull(forCtrl.typeType()) || !Objects.isNull(forCtrl.VAR())) {
type = TypePlaceholder.fresh(forCtrl.getStart());
} else {
type = TypeGenerator.convert(forCtrl.typeType(), reg, generics);
}
var vardecl = new LocalVarDecl(name.getText(), type, name.getStart());
this.localVars.put(name.getText(), type);
return new ForEachStmt(
stmt.getStart(),
vardecl,
convert(forCtrl.expression()),
convert(stmt.statement())
);
} else {
return new ForStmt(
stmt.getStart(),
convert(control.forInit().localVariableDeclaration()),
convert(control.expression()), control.forUpdate.expression().stream().map(this::convert).toList(),
block
control.forInit() != null ? convert(control.forInit().localVariableDeclaration()) : List.of(),
control.expression() != null ? convert(control.expression()) : null,
control.forUpdate != null ? control.forUpdate.expression().stream().map(this::convert).toList() : List.of(),
convert(stmt.statement())
);
}
}
@ -594,8 +612,7 @@ public class StatementGenerator {
}
private Statement convert(Java17Parser.ThrowstmtContext stmt) {
// TODO
throw new NotImplementedException();
return new Throw(convert(stmt.expression()), stmt.getStart());
}
private Statement convert(Java17Parser.SynchronizedstmtContext stmt) {
@ -616,7 +633,6 @@ public class StatementGenerator {
/*
*************** + Expression Conversions:
*/
private Expression convert(Java17Parser.ExpressionContext expression) {
switch (expression) {
case PrimaryExpression2Context primary:
@ -690,13 +706,19 @@ public class StatementGenerator {
} else if (!Objects.isNull(expr.SUPER())) {
// if(methodInvocationContext.Identifier() != null){
name = expr.SUPER().getText();
receiver = new Super(offset);
}
ArgumentList argumentList = convertArguments(expr.expressionList());
ArrayList<RefTypeOrTPHOrWildcardOrGeneric> signature = argumentList.getArguments().stream().map(x -> (RefTypeOrTPHOrWildcardOrGeneric) TypePlaceholder.fresh(offset)).collect(Collectors.toCollection(ArrayList::new));
signature.add(TypePlaceholder.fresh(offset)); // return type
MethodCall ret = new MethodCall(TypePlaceholder.fresh(offset), getReceiver(receiver), name, argumentList, TypePlaceholder.fresh(offset), signature, offset);
MethodCall ret;
if (expr.SUPER() != null) {
ret = new SuperCall(argumentList, TypePlaceholder.fresh(offset), signature, offset);
} else {
ret = new MethodCall(TypePlaceholder.fresh(offset), getReceiver(receiver), name, argumentList, TypePlaceholder.fresh(offset), signature, offset);
}
ret.setStatement();
return ret;
}
@ -779,7 +801,7 @@ public class StatementGenerator {
receiver = new This(offset);
isStatic = Modifier.isStatic(fields.get(fieldName).modifiers());
} else if (parts[0].contentEquals("super")) {
receiver = new Super(offset);
receiver = new Super(TypePlaceholder.fresh(offset), offset);
isStatic = Modifier.isStatic(compiler.getClass(new JavaClassName(superClass.getName().toString())).getField(fieldName).orElseThrow().modifier);
} else if (receiver == null) { // Handelt es sich um keinen Statischen Klassennamen:
String part = expression.substring(0, expression.length() - (1 + parts[parts.length - 1].length()));

View File

@ -16,6 +16,7 @@ import de.dhbwstuttgart.core.JavaTXCompiler;
import de.dhbwstuttgart.parser.NullToken;
import de.dhbwstuttgart.syntaxtree.*;
import de.dhbwstuttgart.syntaxtree.Record;
import de.dhbwstuttgart.syntaxtree.statement.*;
import org.antlr.v4.runtime.CommonToken;
import org.antlr.v4.runtime.Token;
@ -66,15 +67,6 @@ import de.dhbwstuttgart.parser.scope.GenericsRegistry;
import de.dhbwstuttgart.parser.scope.JavaClassName;
import de.dhbwstuttgart.parser.scope.JavaClassRegistry;
import de.dhbwstuttgart.syntaxtree.factory.ASTFactory;
import de.dhbwstuttgart.syntaxtree.statement.Assign;
import de.dhbwstuttgart.syntaxtree.statement.AssignLeftSide;
import de.dhbwstuttgart.syntaxtree.statement.AssignToField;
import de.dhbwstuttgart.syntaxtree.statement.Block;
import de.dhbwstuttgart.syntaxtree.statement.FieldVar;
import de.dhbwstuttgart.syntaxtree.statement.LocalVar;
import de.dhbwstuttgart.syntaxtree.statement.Return;
import de.dhbwstuttgart.syntaxtree.statement.Statement;
import de.dhbwstuttgart.syntaxtree.statement.This;
import de.dhbwstuttgart.syntaxtree.type.RefType;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
@ -100,7 +92,9 @@ public class SyntaxTreeGenerator {
private final JavaTXCompiler compiler;
private RefType superClass;
public SyntaxTreeGenerator(JavaTXCompiler compiler, JavaClassRegistry reg, GenericsRegistry globalGenerics) {
public final String fileName;
public SyntaxTreeGenerator(JavaTXCompiler compiler, JavaClassRegistry reg, GenericsRegistry globalGenerics, String fileName) {
// Die Generics müssen während des Bauens des AST erstellt werden,
// da diese mit der Methode oder Klasse, in welcher sie deklariert werden
// verknüpft sein müssen. Dennoch werden die Namen aller Generics in einer
@ -125,6 +119,7 @@ public class SyntaxTreeGenerator {
this.allmodifiers.put("strictfp", 32768);
this.compiler = compiler;
this.fileName = fileName;
}
public JavaClassRegistry getReg() {
@ -234,7 +229,7 @@ public class SyntaxTreeGenerator {
}
var ctor = Optional.of(this.generatePseudoConstructor(ctx.identifier().getText(), fieldInitializations, genericClassParameters, offset));
var staticCtor = Optional.of(this.generateStaticConstructor(ctx.identifier().getText(), staticFieldInitializations, genericClassParameters, offset));
return new ClassOrInterface(modifiers, name, fielddecl, ctor, staticCtor, methods, constructors, genericClassParameters, superClass, isInterface, isFunctionalInterface, implementedInterfaces, permittedSubtypes, offset);
return new ClassOrInterface(modifiers, name, fielddecl, ctor, staticCtor, methods, constructors, genericClassParameters, superClass, isInterface, isFunctionalInterface, implementedInterfaces, permittedSubtypes, offset, fileName);
}
@ -280,8 +275,8 @@ public class SyntaxTreeGenerator {
methods.add(new Method(allmodifiers.get("public"), fieldname, fieldtype, new ParameterList(new ArrayList<>(), offset), new Block(Arrays.asList(returnStatement), offset), new GenericDeclarationList(new ArrayList<>(), offset), offset));
}
RefType classType = ClassOrInterface.generateTypeOfClass(reg.getName(className), genericClassParameters, offset);
Constructor implicitConstructor = new Constructor(allmodifiers.get("public"), identifier, classType, new ParameterList(constructorParameters, offset), new Block(constructorStatements, offset), genericClassParameters, offset);
Optional<Constructor> initializations = Optional.of(implicitConstructor);
Constructor implicitConstructor = new Constructor(allmodifiers.get("public"), identifier, classType, new ParameterList(constructorParameters, offset), prepareBlock(new Block(constructorStatements, offset), superClass), genericClassParameters, offset);
//Optional<Constructor> initializations = Optional.of(implicitConstructor);
constructors.add(implicitConstructor);
for (ClassBodyDeclarationContext bodyDeclaration : recordDeclaration.recordBody().classBodyDeclaration()) {
convert(bodyDeclaration, fielddecl, constructors, methods, name, superClass, generics);
@ -290,7 +285,7 @@ public class SyntaxTreeGenerator {
implementedInterfaces.addAll(convert(recordDeclaration.typeList(), generics));
}
var staticCtor = Optional.of(this.generateStaticConstructor(recordDeclaration.identifier().getText(), staticFieldInitializations, genericClassParameters, offset));
return new Record(modifiers, name, fielddecl, initializations, staticCtor, methods, constructors, genericClassParameters, superClass, isInterface, implementedInterfaces, offset);
return new Record(modifiers, name, fielddecl, Optional.empty(), staticCtor, methods, constructors, genericClassParameters, superClass, isInterface, implementedInterfaces, offset, fileName);
}
private void convert(ClassBodyDeclarationContext classBody, List<Field> fields, List<Constructor> constructors, List<Method> methods, JavaClassName name, RefType superClass, GenericsRegistry generics) {
@ -409,7 +404,7 @@ public class SyntaxTreeGenerator {
}
var staticCtor = Optional.of(this.generateStaticConstructor(ctx.identifier().getText(), staticFieldInitializations, genericParams, ctx.getStart()));
return new ClassOrInterface(modifiers, name, fields, Optional.empty(), staticCtor, methods, new ArrayList<>(), genericParams, superClass, true, methods.size() == 1 ? true : false, extendedInterfaces, permittedSubtypes, ctx.getStart());
return new ClassOrInterface(modifiers, name, fields, Optional.empty(), staticCtor, methods, new ArrayList<>(), genericParams, superClass, true, methods.size() == 1 ? true : false, extendedInterfaces, permittedSubtypes, ctx.getStart(), fileName);
}
private GenericDeclarationList createEmptyGenericDeclarationList(Token classNameIdentifier) {
@ -451,18 +446,24 @@ public class SyntaxTreeGenerator {
return new Method(modifiers, name, retType, paramlist, block, gtvDeclarations, bodydeclaration.getStart());
}
protected static Block prepareBlock(Block constructorBlock, RefType superClass) {
List<Statement> statements = constructorBlock.getStatements();
if (statements.isEmpty() || !(statements.get(0) instanceof SuperCall)) {
var signature = new ArrayList<RefTypeOrTPHOrWildcardOrGeneric>();
signature.add(new Void(new NullToken()));
statements.add(0, new SuperCall(superClass, signature, constructorBlock.getOffset()));
}
/* statements.addAll(fieldInitializations); geloescht PL 2018-11-24 */
return new Block(statements, constructorBlock.getOffset());
}
/**
* http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.8.9
*/
private Constructor generateStandardConstructor(String className, JavaClassName parentClass, RefType superClass, GenericDeclarationList classGenerics, Token offset) {
RefType classType = ClassOrInterface.generateTypeOfClass(reg.getName(className), classGenerics, offset);
ParameterList params = new ParameterList(new ArrayList<>(), offset);
Block block = new Block(new ArrayList<>(), offset);
//
//
return new Constructor(Modifier.PUBLIC, className, classType, params, block, classGenerics, offset); // fieldInitializations
// geloescht PL
// 2018-11-24
return new Constructor(Modifier.PUBLIC, className, classType, params, prepareBlock(new Block(new ArrayList<>(), offset), superClass), classGenerics, offset); // fieldInitializations // 2018-11-24
}
/*
@ -471,10 +472,7 @@ public class SyntaxTreeGenerator {
private Constructor generatePseudoConstructor(String className, List<Statement> initializations, GenericDeclarationList classGenerics, Token offset) {
RefType classType = ClassOrInterface.generateTypeOfClass(reg.getName(className), classGenerics, offset);
ParameterList params = new ParameterList(new ArrayList<>(), offset);
Block block = new Block(new ArrayList<>(initializations), offset);
return new Constructor(Modifier.PUBLIC, className, classType, params, block, classGenerics, offset /*
* fieldInitializations geloescht PL 2018-11-24
*/);
return new Constructor(Modifier.PUBLIC, className, classType, params, new Block(new ArrayList<>(initializations), offset), classGenerics, offset);
}
private Method generateStaticConstructor(String className, List<Statement> initializations, GenericDeclarationList classGenerics, Token offset) {
@ -553,7 +551,7 @@ public class SyntaxTreeGenerator {
block = stmtgen.convert(methodblock.block(), true);
}
if (name.equals(parentClass.getClassName())) {
return new Constructor(modifiers, name, retType, paramlist, block, gtvDeclarations, methoddeclaration.getStart());
return new Constructor(modifiers, name, retType, paramlist, prepareBlock(block, superClass), gtvDeclarations, methoddeclaration.getStart());
} else {
return new Method(modifiers, name, retType, paramlist, block, gtvDeclarations, methoddeclaration.getStart());
}
@ -582,7 +580,7 @@ public class SyntaxTreeGenerator {
RefTypeOrTPHOrWildcardOrGeneric retType = TypeGenerator.convertTypeName(name, constructordeclaration.getStart(), reg, localgenerics);
StatementGenerator stmtgen = new StatementGenerator(superClass, compiler, reg, localgenerics, fields, new HashMap<>());
ParameterList paramlist = stmtgen.convert(constructordeclaration.formalParameters().formalParameterList());
Block block = stmtgen.convert(constructordeclaration.constructorBody, true);
Block block = prepareBlock(stmtgen.convert(constructordeclaration.constructorBody, true), superClass);
return new Constructor(modifiers, name, retType, paramlist, block, gtvDeclarations, constructordeclaration.getStart());
}

View File

@ -31,7 +31,7 @@ public class JavaClassRegistry {
if (name.equals(new JavaClassName(className)))
return name;
}
throw new NotImplementedException();
throw new RuntimeException("Class " + className + " not found!");
}
@Override

View File

@ -166,6 +166,11 @@ public abstract class AbstractASTWalker implements ASTVisitor {
forStmt.block.accept(this);
}
@Override
public void visit(ForEachStmt forEachStmt) {
forEachStmt.block.accept(this);
}
@Override
public void visit(IfStmt ifStmt) {
ifStmt.then_block.accept(this);
@ -261,6 +266,11 @@ public abstract class AbstractASTWalker implements ASTVisitor {
}
@Override
public void visit(Throw aThrow) {
}
@Override
public void visit(AssignToField assignLeftSide) {
assignLeftSide.field.accept(this);

View File

@ -21,6 +21,8 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope {
private Boolean methodAdded = false; // wird benoetigt bei in JavaTXCompiler.getConstraints()
protected int modifiers;
protected JavaClassName name;
private final String fileName;
private List<Field> fields = new ArrayList<>();
private Optional<Constructor> fieldInitializations; // PL 2018-11-24: Noetig, um Bytecode fuer initializators nur einmal zu erzeugen
private Optional<Method> staticInitializer;
@ -33,7 +35,7 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope {
private List<RefType> permittedSubtypes;
private List<Constructor> constructors;
public ClassOrInterface(int modifiers, JavaClassName name, List<Field> fielddecl, Optional<Constructor> fieldInitializations, Optional<Method> staticInitializer, List<Method> methods, List<Constructor> constructors, GenericDeclarationList genericClassParameters, RefType superClass, Boolean isInterface, Boolean isFunctionalInterface, List<RefType> implementedInterfaces, List<RefType> permittedSubtypes, Token offset) {
public ClassOrInterface(int modifiers, JavaClassName name, List<Field> fielddecl, Optional<Constructor> fieldInitializations, Optional<Method> staticInitializer, List<Method> methods, List<Constructor> constructors, GenericDeclarationList genericClassParameters, RefType superClass, Boolean isInterface, Boolean isFunctionalInterface, List<RefType> implementedInterfaces, List<RefType> permittedSubtypes, Token offset, String fileName) {
super(offset);
if (isInterface) {
modifiers |= Modifier.INTERFACE | Modifier.ABSTRACT;
@ -51,6 +53,7 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope {
this.permittedSubtypes = permittedSubtypes;
this.methods = methods;
this.constructors = constructors;
this.fileName = fileName;
}
/*
@ -70,6 +73,11 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope {
this.implementedInterfaces = cl.implementedInterfaces;
this.methods = new ArrayList<>(cl.methods);
this.constructors = new ArrayList<>(cl.constructors);
this.fileName = cl.fileName;
}
public String getFileName() {
return fileName;
}
public Optional<Field> getField(String name) {

View File

@ -1,31 +1,25 @@
package de.dhbwstuttgart.syntaxtree;
import de.dhbwstuttgart.parser.NullToken;
import de.dhbwstuttgart.syntaxtree.statement.Statement;
import de.dhbwstuttgart.syntaxtree.statement.Super;
import de.dhbwstuttgart.syntaxtree.statement.SuperCall;
import de.dhbwstuttgart.syntaxtree.type.RefType;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import de.dhbwstuttgart.syntaxtree.type.Void;
import org.antlr.v4.runtime.Token;
import de.dhbwstuttgart.syntaxtree.statement.Block;
import java.sql.Ref;
import java.util.ArrayList;
import java.util.List;
public class Constructor extends Method {
// TODO: Constructor braucht ein super-Statement
public Constructor(int modifier, String name, RefTypeOrTPHOrWildcardOrGeneric returnType, ParameterList parameterList, Block codeInsideConstructor, GenericDeclarationList gtvDeclarations, Token offset /* , List<Statement> fieldInitializations geloescht PL 2018-11-24 */) {
super(modifier, name, returnType, parameterList, /* codeInsideConstructor, */ prepareBlock(codeInsideConstructor) /* ,fieldInitializations )geloescht PL 2018-11-24 ) */, gtvDeclarations, offset);
}
/**
* @param fieldInitializations - Das sind die Statements, welche die Felder der zugehörigen Klasse dieses Konstruktor initialisieren
*/
protected static Block prepareBlock(Block constructorBlock /* , List<Statement> fieldInitializations new ArrayList<>() geloescht PL 2018-11-24 */) {
List<Statement> statements = constructorBlock.getStatements();
statements.add(0, new SuperCall(null, null, constructorBlock.getOffset()));
/* statements.addAll(fieldInitializations); geloescht PL 2018-11-24 */
return new Block(statements, constructorBlock.getOffset());
public Constructor(int modifier, String name, RefTypeOrTPHOrWildcardOrGeneric returnType, ParameterList parameterList, Block codeInsideConstructor, GenericDeclarationList gtvDeclarations, Token offset) {
super(modifier, name, returnType, parameterList, codeInsideConstructor, gtvDeclarations, offset);
}
@Override

View File

@ -13,7 +13,7 @@ import javax.swing.text.html.Option;
public class Record extends ClassOrInterface {
public Record(int modifiers, JavaClassName name, List<Field> fielddecl, Optional<Constructor> fieldInitializations, Optional<Method> staticInitializer, List<Method> methods, List<Constructor> constructors, GenericDeclarationList genericClassParameters, RefType superClass, Boolean isInterface, List<RefType> implementedInterfaces, Token offset) {
super(modifiers, name, fielddecl, fieldInitializations, staticInitializer, methods, constructors, genericClassParameters, superClass, isInterface, methods.size() == 1 ? true : false, implementedInterfaces, new ArrayList<>(), offset);
public Record(int modifiers, JavaClassName name, List<Field> fielddecl, Optional<Constructor> fieldInitializations, Optional<Method> staticInitializer, List<Method> methods, List<Constructor> constructors, GenericDeclarationList genericClassParameters, RefType superClass, Boolean isInterface, List<RefType> implementedInterfaces, Token offset, String fileName) {
super(modifiers, name, fielddecl, fieldInitializations, staticInitializer, methods, constructors, genericClassParameters, superClass, isInterface, methods.size() == 1 ? true : false, implementedInterfaces, new ArrayList<>(), offset, fileName);
}
}

View File

@ -25,6 +25,8 @@ public interface StatementVisitor {
void visit(ForStmt forStmt);
void visit(ForEachStmt forEachStmt);
void visit(IfStmt ifStmt);
void visit(InstanceOf instanceOf);
@ -74,4 +76,6 @@ public interface StatementVisitor {
void visit(UnaryExpr unaryExpr);
void visit(Literal literal);
void visit(Throw aThrow);
}

View File

@ -148,7 +148,7 @@ public class ASTFactory {
Token offset = new NullToken(); // Braucht keinen Offset, da diese Klasse nicht aus einem Quellcode geparst wurde
var cinf = new ClassOrInterface(modifier, name, felder, Optional.empty() /* eingefuegt PL 2018-11-24 */, Optional.empty(), methoden, konstruktoren, genericDeclarationList, superClass, isInterface, isFunctionalInterface, implementedInterfaces, permittedSubtypes, offset);
var cinf = new ClassOrInterface(modifier, name, felder, Optional.empty() /* eingefuegt PL 2018-11-24 */, Optional.empty(), methoden, konstruktoren, genericDeclarationList, superClass, isInterface, isFunctionalInterface, implementedInterfaces, permittedSubtypes, offset, null);
cache.put(jreClass, cinf);
return cinf;
}
@ -361,7 +361,7 @@ public class ASTFactory {
} else if (type.getTypeName().equals("boolean")) {
return new RefType(new JavaClassName("java.lang.Boolean"), new ArrayList<>(), new NullToken(), true);
} else if (type.getTypeName().equals("char")) {
return new RefType(new JavaClassName("java.lang.Char"), new ArrayList<>(), new NullToken(), true);
return new RefType(new JavaClassName("java.lang.Character"), new ArrayList<>(), new NullToken(), true);
} else if (type.getTypeName().equals("short")) {
return new RefType(new JavaClassName("java.lang.Short"), new ArrayList<>(), new NullToken(), true);
} else if (type.getTypeName().equals("double")) {

View File

@ -1,6 +1,5 @@
package de.dhbwstuttgart.syntaxtree.factory;
import java.io.FileWriter;
import java.io.Writer;
import java.util.*;
import java.util.regex.Matcher;
@ -9,13 +8,13 @@ import java.util.stream.Collectors;
import de.dhbwstuttgart.exceptions.NotImplementedException;
import de.dhbwstuttgart.parser.NullToken;
import de.dhbwstuttgart.parser.SourceLoc;
import de.dhbwstuttgart.parser.SyntaxTreeGenerator.FCGenerator;
import de.dhbwstuttgart.parser.scope.JavaClassName;
import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
import de.dhbwstuttgart.syntaxtree.type.*;
import de.dhbwstuttgart.syntaxtree.type.Void;
import de.dhbwstuttgart.syntaxtree.type.WildcardType;
import de.dhbwstuttgart.typeinference.constraints.Constraint;
import de.dhbwstuttgart.typeinference.constraints.ConstraintSet;
import de.dhbwstuttgart.typeinference.constraints.Pair;
import de.dhbwstuttgart.typeinference.result.PairNoResult;
@ -24,6 +23,7 @@ import de.dhbwstuttgart.typeinference.result.PairTPHequalRefTypeOrWildcardType;
import de.dhbwstuttgart.typeinference.result.PairTPHsmallerTPH;
import de.dhbwstuttgart.typeinference.result.ResultPair;
import de.dhbwstuttgart.typeinference.unify.model.*;
import org.antlr.v4.runtime.Token;
public class UnifyTypeFactory {
@ -43,20 +43,20 @@ public class UnifyTypeFactory {
return new FiniteClosure(FCGenerator.toUnifyFC(fromClasses, classLoader), logFile);
}
public static UnifyPair generateSmallerPair(UnifyType tl, UnifyType tr){
return new UnifyPair(tl, tr, PairOperator.SMALLER);
public static UnifyPair generateSmallerPair(UnifyType tl, UnifyType tr, SourceLoc location){
return new UnifyPair(tl, tr, PairOperator.SMALLER, location);
}
public static UnifyPair generateSmallerDotPair(UnifyType tl, UnifyType tr){
return new UnifyPair(tl, tr, PairOperator.SMALLERDOT);
public static UnifyPair generateSmallerDotPair(UnifyType tl, UnifyType tr, SourceLoc location){
return new UnifyPair(tl, tr, PairOperator.SMALLERDOT, location);
}
public static UnifyPair generateSmallNotEqualDotPair(UnifyType tl, UnifyType tr){
return new UnifyPair(tl, tr, PairOperator.SMALLERNEQDOT);
public static UnifyPair generateSmallNotEqualDotPair(UnifyType tl, UnifyType tr, SourceLoc location){
return new UnifyPair(tl, tr, PairOperator.SMALLERNEQDOT, location);
}
public static UnifyPair generateEqualDotPair(UnifyType tl, UnifyType tr){
return new UnifyPair(tl, tr, PairOperator.EQUALSDOT);
public static UnifyPair generateEqualDotPair(UnifyType tl, UnifyType tr, SourceLoc location){
return new UnifyPair(tl, tr, PairOperator.EQUALSDOT, location);
}
/**
@ -164,19 +164,19 @@ public class UnifyTypeFactory {
UnifyPair ret = null;
if(p.GetOperator().equals(PairOperator.SMALLERDOT)) {
ret = generateSmallerDotPair(UnifyTypeFactory.convert(p.TA1, false)
, UnifyTypeFactory.convert(p.TA2, false));
, UnifyTypeFactory.convert(p.TA2, false), p.getLocation());
//return ret;
}else if(p.GetOperator().equals(PairOperator.SMALLERNEQDOT)) {
ret = generateSmallNotEqualDotPair(UnifyTypeFactory.convert(p.TA1, false)
, UnifyTypeFactory.convert(p.TA2, false));
, UnifyTypeFactory.convert(p.TA2, false), p.getLocation());
//return ret;
}else if(p.GetOperator().equals(PairOperator.EQUALSDOT)) {
ret = generateEqualDotPair(UnifyTypeFactory.convert(p.TA1, false)
, UnifyTypeFactory.convert(p.TA2, false));
, UnifyTypeFactory.convert(p.TA2, false), p.getLocation());
//return ret;
}else if(p.GetOperator().equals(PairOperator.SMALLER)){
ret = generateSmallerPair(UnifyTypeFactory.convert(p.TA1, false),
UnifyTypeFactory.convert(p.TA2, false));
UnifyTypeFactory.convert(p.TA2, false), p.getLocation());
}else throw new NotImplementedException();
UnifyType lhs, rhs;
if (((lhs = ret.getLhsType()) instanceof PlaceholderType)

View File

@ -0,0 +1,26 @@
package de.dhbwstuttgart.syntaxtree.statement;
import de.dhbwstuttgart.parser.NullToken;
import de.dhbwstuttgart.syntaxtree.StatementVisitor;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import de.dhbwstuttgart.syntaxtree.type.Void;
import org.antlr.v4.runtime.Token;
public class ForEachStmt extends Statement {
public final Statement statement;
public final Expression expression;
public final Statement block;
public ForEachStmt(Token offset, Statement stmt, Expression expression, Statement block) {
super(new Void(new NullToken()), offset);
this.statement = stmt;
this.expression = expression;
this.block = block;
}
@Override
public void accept(StatementVisitor visitor) {
visitor.visit(this);
}
}

View File

@ -37,6 +37,7 @@ public class MethodCall extends Statement
this.receiver = receiver;
this.receiverType = receiverType;
this.signature = signature;
if (signature == null) throw new NullPointerException();
}
public List<RefTypeOrTPHOrWildcardOrGeneric> signatureArguments() {

View File

@ -1,6 +1,9 @@
package de.dhbwstuttgart.syntaxtree.statement;
import de.dhbwstuttgart.parser.NullToken;
import de.dhbwstuttgart.syntaxtree.StatementVisitor;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import de.dhbwstuttgart.syntaxtree.type.Void;
import de.dhbwstuttgart.typeinference.assumptions.TypeInferenceBlockInformation;
import de.dhbwstuttgart.typeinference.constraints.ConstraintSet;
import de.dhbwstuttgart.typeinference.assumptions.TypeInferenceInformation;
@ -9,9 +12,9 @@ import de.dhbwstuttgart.exceptions.NotImplementedException;
public class Super extends Expression
{
public Super(Token offset)
public Super(RefTypeOrTPHOrWildcardOrGeneric type, Token offset)
{
super(null,null);
super(type, offset);
}
@Override

View File

@ -1,5 +1,6 @@
package de.dhbwstuttgart.syntaxtree.statement;
import de.dhbwstuttgart.parser.NullToken;
import de.dhbwstuttgart.syntaxtree.StatementVisitor;
import de.dhbwstuttgart.syntaxtree.type.RefType;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
@ -9,6 +10,7 @@ import org.antlr.v4.runtime.Token;
import de.dhbwstuttgart.syntaxtree.SyntaxTreeNode;
import java.util.ArrayList;
import java.util.List;
public class SuperCall extends MethodCall
@ -20,7 +22,7 @@ public class SuperCall extends MethodCall
public SuperCall(ArgumentList argumentList, RefTypeOrTPHOrWildcardOrGeneric receiverType,
ArrayList<RefTypeOrTPHOrWildcardOrGeneric> argTypes, Token offset){
super(new Void(offset), new ExpressionReceiver(new This(offset)), "<init>", argumentList, receiverType, argTypes, offset);
super(new Void(offset), new ExpressionReceiver(new Super(receiverType, offset)), "<init>", argumentList, receiverType, argTypes, offset);
}

View File

@ -0,0 +1,21 @@
package de.dhbwstuttgart.syntaxtree.statement;
import de.dhbwstuttgart.syntaxtree.StatementVisitor;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import de.dhbwstuttgart.syntaxtree.type.Void;
import org.antlr.v4.runtime.Token;
public class Throw extends Statement {
public final Expression expr;
public Throw(Expression expr, Token offset) {
super(new Void(offset), offset);
this.expr = expr;
}
@Override
public void accept(StatementVisitor visitor) {
visitor.visit(this);
}
}

View File

@ -244,6 +244,11 @@ public class OutputGenerator implements ASTVisitor {
}
@Override
public void visit(ForEachStmt forEachStmt) {
}
@Override
public void visit(IfStmt ifStmt) {
out.append("if(");
@ -402,6 +407,11 @@ public class OutputGenerator implements ASTVisitor {
out.append(literal.value);
}
@Override
public void visit(Throw aThrow) {
// TODO implement
}
@Override
public void visit(Switch switchStmt) {
out.append("switch(");

View File

@ -380,6 +380,13 @@ public class ASTToTargetAST {
return new TargetBlock(block.statements.stream().map(this::convert).toList());
}
protected TargetBlock convertWrapInBlock(Expression expression) {
var res = convert(expression);
if (!(res instanceof TargetBlock))
return new TargetBlock(List.of(res));
return (TargetBlock) res;
}
protected TargetExpression convert(Expression expr) {
var converter = new StatementToTargetExpression(this);
expr.accept(converter);

View File

@ -141,12 +141,22 @@ public class StatementToTargetExpression implements ASTVisitor {
@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));
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.convert(ifStmt.then_block), ifStmt.else_block != null ? converter.convert(ifStmt.else_block) : null);
result = new TargetIf(converter.convert(ifStmt.expr), converter.convertWrapInBlock(ifStmt.then_block), ifStmt.else_block != null ? converter.convertWrapInBlock(ifStmt.else_block) : null);
}
@Override
@ -315,9 +325,16 @@ public class StatementToTargetExpression implements ASTVisitor {
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(Switch switchStmt) {
var cases = switchStmt.getBlocks().stream().filter(s -> !s.isDefault()).map(converter::convert).toList();

View File

@ -66,6 +66,11 @@ public abstract class TracingStatementVisitor implements StatementVisitor {
forStmt.block.accept(this);
}
@Override
public void visit(ForEachStmt forEachStmt) {
forEachStmt.block.accept(this);
}
@Override
public void visit(IfStmt ifStmt) {
ifStmt.then_block.accept(this);
@ -168,6 +173,11 @@ public abstract class TracingStatementVisitor implements StatementVisitor {
}
@Override
public void visit(Throw aThrow) {
}
@Override
public void visit(Switch switchStmt) {

View File

@ -3,7 +3,7 @@ package de.dhbwstuttgart.target.tree.expression;
import de.dhbwstuttgart.target.tree.type.*;
public sealed interface TargetExpression
permits TargetBinaryOp, TargetBlock, TargetBreak, TargetCast, TargetClassName, TargetContinue, TargetFieldVar, TargetFor, TargetForEach, TargetIf, TargetInstanceOf, TargetLambdaExpression, TargetLiteral, TargetLocalVar, TargetReturn, TargetStatementExpression, TargetSuper, TargetSwitch, TargetPattern, TargetTernary, TargetThis, TargetUnaryOp, TargetVarDecl, TargetWhile, TargetYield {
permits TargetBinaryOp, TargetBlock, TargetBreak, TargetCast, TargetClassName, TargetContinue, TargetFieldVar, TargetFor, TargetForEach, TargetIf, TargetInstanceOf, TargetLambdaExpression, TargetLiteral, TargetLocalVar, TargetPattern, TargetReturn, TargetStatementExpression, TargetSuper, TargetSwitch, TargetTernary, TargetThis, TargetThrow, TargetUnaryOp, TargetVarDecl, TargetWhile, TargetYield {
default TargetType type() {
return null;

View File

@ -1,4 +1,4 @@
package de.dhbwstuttgart.target.tree.expression;
public record TargetForEach(TargetExpression vardecl, TargetExpression list) implements TargetExpression {
public record TargetForEach(TargetExpression vardecl, TargetExpression expression, TargetExpression body) implements TargetExpression {
}

View File

@ -53,4 +53,16 @@ public sealed interface TargetLiteral extends TargetExpression {
return TargetType.String;
}
}
record Null() implements TargetLiteral {
@Override
public TargetType type() {
return TargetType.Object;
}
@Override
public Object value() {
return null;
}
}
}

View File

@ -0,0 +1,4 @@
package de.dhbwstuttgart.target.tree.expression;
public record TargetThrow(TargetExpression expr) implements TargetExpression {
}

View File

@ -22,7 +22,7 @@ import java.util.Optional;
public class FunNClass extends ClassOrInterface {
public FunNClass(List<GenericRefType> funNParams) {
super(0, new JavaClassName("Fun" + (funNParams.size() - 1)), new ArrayList<>(), Optional.empty(), Optional.empty() /* eingefuegt PL 2018-11-24 */, createMethods(funNParams), new ArrayList<>(), createGenerics(funNParams), ASTFactory.createObjectType(), true, false, new ArrayList<>(), new ArrayList<>(), new NullToken());
super(0, new JavaClassName("Fun" + (funNParams.size() - 1)), new ArrayList<>(), Optional.empty(), Optional.empty() /* eingefuegt PL 2018-11-24 */, createMethods(funNParams), new ArrayList<>(), createGenerics(funNParams), ASTFactory.createObjectType(), true, false, new ArrayList<>(), new ArrayList<>(), new NullToken(), null);
}

View File

@ -8,6 +8,7 @@ import de.dhbwstuttgart.syntaxtree.TypeScope;
import de.dhbwstuttgart.syntaxtree.type.GenericRefType;
import de.dhbwstuttgart.syntaxtree.type.RefType;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import de.dhbwstuttgart.syntaxtree.type.Void;
import de.dhbwstuttgart.typeinference.constraints.GenericsResolver;
import java.util.ArrayList;
@ -66,6 +67,7 @@ public class MethodAssumption extends Assumption{
* @return
*/
public RefTypeOrTPHOrWildcardOrGeneric getReceiverType(GenericsResolver resolver) {
if (receiver == null) return null;
List<RefTypeOrTPHOrWildcardOrGeneric> params = new ArrayList<>();
for(GenericTypeVar gtv : receiver.getGenerics()){
//Die Generics werden alle zu TPHs umgewandelt.

View File

@ -3,9 +3,12 @@ import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import de.dhbwstuttgart.parser.NullToken;
import de.dhbwstuttgart.parser.SourceLoc;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
import de.dhbwstuttgart.typeinference.unify.model.PairOperator;
import org.antlr.v4.runtime.Token;
public class Pair implements Serializable
@ -13,11 +16,13 @@ public class Pair implements Serializable
public final RefTypeOrTPHOrWildcardOrGeneric TA1;
public final RefTypeOrTPHOrWildcardOrGeneric TA2;
private SourceLoc location;
private PairOperator eOperator = PairOperator.SMALLER;
private Boolean noUnification = false;
public Pair(RefTypeOrTPHOrWildcardOrGeneric TA1, RefTypeOrTPHOrWildcardOrGeneric TA2 )
private Pair(RefTypeOrTPHOrWildcardOrGeneric TA1, RefTypeOrTPHOrWildcardOrGeneric TA2 )
{
this.TA1 = TA1;
this.TA2 = TA2;
@ -33,6 +38,10 @@ public class Pair implements Serializable
this.eOperator = eOp;
}
public Pair(RefTypeOrTPHOrWildcardOrGeneric TA1, RefTypeOrTPHOrWildcardOrGeneric TA2, PairOperator e0p, SourceLoc location) {
this(TA1, TA2, e0p);
this.location = location;
}
public Pair(RefTypeOrTPHOrWildcardOrGeneric TA1, RefTypeOrTPHOrWildcardOrGeneric TA2, PairOperator eOp, Boolean noUnification)
{
@ -42,6 +51,10 @@ public class Pair implements Serializable
this.noUnification = noUnification;
}
public SourceLoc getLocation() {
return this.location;
}
public String toString()
{
// otth: Gibt ein Paar als String aus --> zum Debuggen und Vergleichen

View File

@ -7,6 +7,7 @@ import java.util.stream.Collectors;
import de.dhbwstuttgart.exceptions.NotImplementedException;
import de.dhbwstuttgart.exceptions.TypeinferenceException;
import de.dhbwstuttgart.parser.NullToken;
import de.dhbwstuttgart.parser.SourceLoc;
import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal;
import de.dhbwstuttgart.parser.scope.JavaClassName;
import de.dhbwstuttgart.syntaxtree.*;
@ -28,6 +29,7 @@ import de.dhbwstuttgart.typeinference.constraints.ConstraintSet;
import de.dhbwstuttgart.typeinference.constraints.GenericsResolver;
import de.dhbwstuttgart.typeinference.constraints.Pair;
import de.dhbwstuttgart.typeinference.unify.model.PairOperator;
import org.antlr.v4.runtime.Token;
public class TYPEStmt implements StatementVisitor {
@ -43,6 +45,10 @@ public class TYPEStmt implements StatementVisitor {
return constraintsSet;
}
private SourceLoc loc(Token token) {
return new SourceLoc(info.getCurrentClass().getFileName(), token.getLine());
};
/**
* Erstellt einen neuen GenericResolver Die Idee dieser Datenstruktur ist es, GTVs einen eindeutigen TPH zuzuweisen. Bei Methodenaufrufen oder anderen Zugriffen, bei denen alle benutzten GTVs jeweils einen einheitlichen TPH bekommen müssen kann diese Klasse eingesetzt werden. Wichtig ist, dass hierfür jeweils eine frische Instanz benutzt wird.
*
@ -71,8 +77,8 @@ public class TYPEStmt implements StatementVisitor {
// lambdaParams.add(0,tphRetType);
constraintsSet.addUndConstraint(new Pair(lambdaExpression.getType(), new RefType(new JavaClassName("Fun" + (lambdaParams.size() - 1) + "$$"), lambdaParams, new NullToken()),
// new FunN(lambdaParams),
PairOperator.EQUALSDOT));
constraintsSet.addUndConstraint(new Pair(lambdaExpression.getReturnType(), tphRetType, PairOperator.EQUALSDOT));
PairOperator.EQUALSDOT, loc(lambdaExpression.getOffset())));
constraintsSet.addUndConstraint(new Pair(lambdaExpression.getReturnType(), tphRetType, PairOperator.EQUALSDOT, loc(lambdaExpression.getOffset())));
// Constraints des Bodys generieren:
TYPEStmt lambdaScope = new TYPEStmt(new TypeInferenceBlockInformation(info, lambdaExpression));
@ -84,7 +90,7 @@ public class TYPEStmt implements StatementVisitor {
public void visit(Assign assign) {
assign.lefSide.accept(this);
assign.rightSide.accept(this);
constraintsSet.addUndConstraint(new Pair(assign.rightSide.getType(), assign.lefSide.getType(), PairOperator.SMALLERDOT));
constraintsSet.addUndConstraint(new Pair(assign.rightSide.getType(), assign.lefSide.getType(), PairOperator.SMALLERDOT, loc(assign.getOffset())));
}
@Override
@ -111,8 +117,8 @@ public class TYPEStmt implements StatementVisitor {
for (FieldAssumption fieldAssumption : info.getFields(fieldVar.fieldVarName)) {
Constraint constraint = new Constraint();
GenericsResolver resolver = getResolverInstance();
constraint.add(new Pair(fieldVar.receiver.getType(), fieldAssumption.getReceiverType(resolver), PairOperator.SMALLERDOT)); // PL 2019-12-09: SMALLERDOT eingefuegt, EQUALSDOT entfernt, wenn ds Field privat ist muesste es EQUALSDOT lauten
constraint.add(new Pair(fieldVar.getType(), fieldAssumption.getType(resolver), PairOperator.EQUALSDOT));
constraint.add(new Pair(fieldVar.receiver.getType(), fieldAssumption.getReceiverType(resolver), PairOperator.SMALLERDOT, loc(fieldVar.getOffset()))); // PL 2019-12-09: SMALLERDOT eingefuegt, EQUALSDOT entfernt, wenn ds Field privat ist muesste es EQUALSDOT lauten
constraint.add(new Pair(fieldVar.getType(), fieldAssumption.getType(resolver), PairOperator.EQUALSDOT, loc(fieldVar.getOffset())));
oderConstraints.add(constraint);
}
if (oderConstraints.size() == 0)
@ -123,32 +129,42 @@ public class TYPEStmt implements StatementVisitor {
@Override
public void visit(ForStmt forStmt) {
forStmt.initializer.forEach(s -> s.accept(this));
if (forStmt.condition != null)
forStmt.condition.accept(this);
forStmt.loopExpr.forEach(e -> e.accept(this));
forStmt.block.accept(this);
}
@Override
public void visit(ForEachStmt forEachStmt) {
var iterableType = new RefType(ASTFactory.createClass(java.lang.Iterable.class).getClassName(), Arrays.asList(forEachStmt.statement.getType()), new NullToken());
constraintsSet.addUndConstraint(new Pair(forEachStmt.expression.getType(), iterableType, PairOperator.SMALLERDOT, loc(forEachStmt.getOffset())));
forEachStmt.statement.accept(this);
forEachStmt.expression.accept(this);
forEachStmt.block.accept(this);
}
@Override
public void visit(IfStmt ifStmt) {
RefType booleanType = new RefType(ASTFactory.createClass(java.lang.Boolean.class).getClassName(), new NullToken());
// Expression inferieren:
ifStmt.expr.accept(this);
// Expression muss boolean sein:
constraintsSet.addUndConstraint(new Pair(ifStmt.expr.getType(), booleanType, PairOperator.EQUALSDOT));
constraintsSet.addUndConstraint(new Pair(ifStmt.expr.getType(), booleanType, PairOperator.EQUALSDOT, loc(ifStmt.getOffset())));
// Blöcke inferieren:
ifStmt.then_block.accept(this);
// Beide Blöcke müssen den gleichen Supertyp haben, welcher den Rückgabetyp des If-Stmts darstellt
//constraintsSet.addUndConstraint(new Pair(ifStmt.else_block.getType(), ifStmt.getType(), PairOperator.SMALLERDOT));
if (ifStmt.else_block != null) {
ifStmt.else_block.accept(this);
constraintsSet.addUndConstraint(new Pair(ifStmt.else_block.getType(), ifStmt.getType(), PairOperator.SMALLERDOT));
constraintsSet.addUndConstraint(new Pair(ifStmt.else_block.getType(), ifStmt.getType(), PairOperator.SMALLERDOT, loc(ifStmt.getOffset())));
}
}
@Override
public void visit(InstanceOf instanceOf) {
//throw new NotImplementedException();
instanceOf.getExpression().accept(this);
}
@Override
@ -218,14 +234,16 @@ public class TYPEStmt implements StatementVisitor {
private final RefType string = new RefType(ASTFactory.createClass(String.class).getClassName(), new NullToken());
private final RefType bool = new RefType(ASTFactory.createClass(Boolean.class).getClassName(), new NullToken());
private final RefType charr = new RefType(ASTFactory.createClass(Character.class).getClassName(), new NullToken());
@Override
public void visit(UnaryExpr unaryExpr) {
if (unaryExpr.operation == UnaryExpr.Operation.POSTDECREMENT || unaryExpr.operation == UnaryExpr.Operation.POSTINCREMENT || unaryExpr.operation == UnaryExpr.Operation.PREDECREMENT || unaryExpr.operation == UnaryExpr.Operation.PREINCREMENT) {
// @see: https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.14.2
// Expression muss zu Numeric Convertierbar sein. also von Numeric erben
constraintsSet.addUndConstraint(new Pair(unaryExpr.expr.getType(), number, PairOperator.SMALLERNEQDOT));
constraintsSet.addUndConstraint(new Pair(unaryExpr.expr.getType(), number, PairOperator.SMALLERNEQDOT, loc(unaryExpr.getOffset())));
// The type of the postfix increment expression is the type of the variable
constraintsSet.addUndConstraint(new Pair(unaryExpr.expr.getType(), unaryExpr.getType(), PairOperator.EQUALSDOT));
constraintsSet.addUndConstraint(new Pair(unaryExpr.expr.getType(), unaryExpr.getType(), PairOperator.EQUALSDOT, loc(unaryExpr.getOffset())));
} else {
throw new NotImplementedException();
}
@ -252,49 +270,49 @@ public class TYPEStmt implements StatementVisitor {
// PL eingefuegt 2018-07-17
if (info.getAvailableClasses().stream().map(x -> x.getClassName()).collect(Collectors.toCollection(HashSet::new)).contains(bytee.getName())) {
numeric = new Constraint<>();
numeric.add(new Pair(binary.lexpr.getType(), bytee, PairOperator.SMALLERDOT));
numeric.add(new Pair(binary.rexpr.getType(), bytee, PairOperator.SMALLERDOT));
numeric.add(new Pair(binary.getType(), integer, PairOperator.EQUALSDOT));
numeric.add(new Pair(binary.lexpr.getType(), bytee, PairOperator.SMALLERDOT, loc(binary.getOffset())));
numeric.add(new Pair(binary.rexpr.getType(), bytee, PairOperator.SMALLERDOT, loc(binary.getOffset())));
numeric.add(new Pair(binary.getType(), integer, PairOperator.EQUALSDOT, loc(binary.getOffset())));
numericAdditionOrStringConcatenation.add(numeric);
}
// PL eingefuegt 2018-07-17
if (info.getAvailableClasses().stream().map(x -> x.getClassName()).collect(Collectors.toCollection(HashSet::new)).contains(shortt.getName())) {
numeric = new Constraint<>();
numeric.add(new Pair(binary.lexpr.getType(), shortt, PairOperator.SMALLERDOT));
numeric.add(new Pair(binary.rexpr.getType(), shortt, PairOperator.SMALLERDOT));
numeric.add(new Pair(binary.getType(), integer, PairOperator.EQUALSDOT));
numeric.add(new Pair(binary.lexpr.getType(), shortt, PairOperator.SMALLERDOT, loc(binary.getOffset())));
numeric.add(new Pair(binary.rexpr.getType(), shortt, PairOperator.SMALLERDOT, loc(binary.getOffset())));
numeric.add(new Pair(binary.getType(), integer, PairOperator.EQUALSDOT, loc(binary.getOffset())));
numericAdditionOrStringConcatenation.add(numeric);
}
// PL eingefuegt 2018-07-17
if (info.getAvailableClasses().stream().map(x -> x.getClassName()).collect(Collectors.toCollection(HashSet::new)).contains(integer.getName())) {
numeric = new Constraint<>();
numeric.add(new Pair(binary.lexpr.getType(), integer, PairOperator.SMALLERDOT));
numeric.add(new Pair(binary.rexpr.getType(), integer, PairOperator.SMALLERDOT));
numeric.add(new Pair(integer, binary.getType(), PairOperator.EQUALSDOT));
numeric.add(new Pair(binary.lexpr.getType(), integer, PairOperator.SMALLERDOT, loc(binary.getOffset())));
numeric.add(new Pair(binary.rexpr.getType(), integer, PairOperator.SMALLERDOT, loc(binary.getOffset())));
numeric.add(new Pair(integer, binary.getType(), PairOperator.EQUALSDOT, loc(binary.getOffset())));
numericAdditionOrStringConcatenation.add(numeric);
}
// PL eingefuegt 2018-07-17
if (info.getAvailableClasses().stream().map(x -> x.getClassName()).collect(Collectors.toCollection(HashSet::new)).contains(longg.getName())) {
numeric = new Constraint<>();
numeric.add(new Pair(binary.lexpr.getType(), longg, PairOperator.SMALLERDOT));
numeric.add(new Pair(binary.rexpr.getType(), longg, PairOperator.SMALLERDOT));
numeric.add(new Pair(longg, binary.getType(), PairOperator.EQUALSDOT));
numeric.add(new Pair(binary.lexpr.getType(), longg, PairOperator.SMALLERDOT, loc(binary.getOffset())));
numeric.add(new Pair(binary.rexpr.getType(), longg, PairOperator.SMALLERDOT, loc(binary.getOffset())));
numeric.add(new Pair(longg, binary.getType(), PairOperator.EQUALSDOT, loc(binary.getOffset())));
numericAdditionOrStringConcatenation.add(numeric);
}
// PL eingefuegt 2018-07-17
if (info.getAvailableClasses().stream().map(x -> x.getClassName()).collect(Collectors.toCollection(HashSet::new)).contains(floatt.getName())) {
numeric = new Constraint<>();
numeric.add(new Pair(binary.lexpr.getType(), floatt, PairOperator.SMALLERDOT));
numeric.add(new Pair(binary.rexpr.getType(), floatt, PairOperator.SMALLERDOT));
numeric.add(new Pair(floatt, binary.getType(), PairOperator.EQUALSDOT));
numeric.add(new Pair(binary.lexpr.getType(), floatt, PairOperator.SMALLERDOT, loc(binary.getOffset())));
numeric.add(new Pair(binary.rexpr.getType(), floatt, PairOperator.SMALLERDOT, loc(binary.getOffset())));
numeric.add(new Pair(floatt, binary.getType(), PairOperator.EQUALSDOT, loc(binary.getOffset())));
numericAdditionOrStringConcatenation.add(numeric);
}
// PL eingefuegt 2018-07-17
if (info.getAvailableClasses().stream().map(x -> x.getClassName()).collect(Collectors.toCollection(HashSet::new)).contains(doublee.getName())) {
numeric = new Constraint<>();
numeric.add(new Pair(binary.lexpr.getType(), doublee, PairOperator.SMALLERDOT));
numeric.add(new Pair(binary.rexpr.getType(), doublee, PairOperator.SMALLERDOT));
numeric.add(new Pair(doublee, binary.getType(), PairOperator.EQUALSDOT));
numeric.add(new Pair(binary.lexpr.getType(), doublee, PairOperator.SMALLERDOT, loc(binary.getOffset())));
numeric.add(new Pair(binary.rexpr.getType(), doublee, PairOperator.SMALLERDOT, loc(binary.getOffset())));
numeric.add(new Pair(doublee, binary.getType(), PairOperator.EQUALSDOT, loc(binary.getOffset())));
numericAdditionOrStringConcatenation.add(numeric);
}
/*
@ -307,9 +325,9 @@ public class TYPEStmt implements StatementVisitor {
// Dann kann der Ausdruck auch das aneinanderfügen zweier Strings sein: ("a" + "b") oder (1 + 2)
if (info.getAvailableClasses().stream().map(x -> x.getClassName()).collect(Collectors.toCollection(HashSet::new)).contains(string.getName())) {
Constraint<Pair> stringConcat = new Constraint<>();
stringConcat.add(new Pair(binary.lexpr.getType(), string, PairOperator.EQUALSDOT));
stringConcat.add(new Pair(binary.rexpr.getType(), string, PairOperator.EQUALSDOT));
stringConcat.add(new Pair(string, binary.getType(), PairOperator.EQUALSDOT));
stringConcat.add(new Pair(binary.lexpr.getType(), string, PairOperator.EQUALSDOT, loc(binary.getOffset())));
stringConcat.add(new Pair(binary.rexpr.getType(), string, PairOperator.EQUALSDOT, loc(binary.getOffset())));
stringConcat.add(new Pair(string, binary.getType(), PairOperator.EQUALSDOT, loc(binary.getOffset())));
numericAdditionOrStringConcatenation.add(stringConcat);
}
}
@ -328,10 +346,10 @@ public class TYPEStmt implements StatementVisitor {
*/
// Testeise eingefuegt PL 2018-05-24
// Hier sollte evtl. noch importe angefragt werden PL 2019-05-07
constraintsSet.addUndConstraint(new Pair(binary.lexpr.getType(), number, PairOperator.SMALLERNEQDOT));
constraintsSet.addUndConstraint(new Pair(binary.rexpr.getType(), number, PairOperator.SMALLERNEQDOT));
constraintsSet.addUndConstraint(new Pair(binary.lexpr.getType(), number, PairOperator.SMALLERNEQDOT, loc(binary.getOffset())));
constraintsSet.addUndConstraint(new Pair(binary.rexpr.getType(), number, PairOperator.SMALLERNEQDOT, loc(binary.getOffset())));
// Rückgabetyp ist Boolean
constraintsSet.addUndConstraint(new Pair(bool, binary.getType(), PairOperator.EQUALSDOT));
constraintsSet.addUndConstraint(new Pair(bool, binary.getType(), PairOperator.EQUALSDOT, loc(binary.getOffset())));
// auskommentiert PL 2018-05-24
// constraintsSet.addUndConstraint(new Pair(binary.lexpr.getType(), number, PairOperator.SMALLERDOT));
@ -343,7 +361,7 @@ public class TYPEStmt implements StatementVisitor {
* Auszug aus https://docs.oracle.com/javase/specs/jls/se9/html/jls-15.html#jls-15.21 The equality operators may be used to compare two operands that are convertible (§5.1.8) to numeric type, or two operands of type boolean or Boolean, or two operands that are each of either reference type or the null type. All other cases result in a compile-time error.
*/
// Der Equals Operator geht mit fast allen Typen, daher werden hier keine Constraints gesetzt
constraintsSet.addUndConstraint(new Pair(bool, binary.getType(), PairOperator.EQUALSDOT));
constraintsSet.addUndConstraint(new Pair(bool, binary.getType(), PairOperator.EQUALSDOT, loc(binary.getOffset())));
} else {
throw new NotImplementedException();
}
@ -352,9 +370,9 @@ public class TYPEStmt implements StatementVisitor {
@Override
public void visit(BoolExpression expr) {
constraintsSet.addUndConstraint(new Pair(bool, expr.getType(), PairOperator.EQUALSDOT));
constraintsSet.addUndConstraint(new Pair(bool, expr.lexpr.getType(), PairOperator.EQUALSDOT));
constraintsSet.addUndConstraint(new Pair(bool, expr.rexpr.getType(), PairOperator.EQUALSDOT));
constraintsSet.addUndConstraint(new Pair(bool, expr.getType(), PairOperator.EQUALSDOT, loc(expr.getOffset())));
constraintsSet.addUndConstraint(new Pair(bool, expr.lexpr.getType(), PairOperator.EQUALSDOT, loc(expr.getOffset())));
constraintsSet.addUndConstraint(new Pair(bool, expr.rexpr.getType(), PairOperator.EQUALSDOT, loc(expr.getOffset())));
// TODO
return;
@ -367,23 +385,23 @@ public class TYPEStmt implements StatementVisitor {
// wie hier fuer double gezeigt. Im Momment auskommentiert, weil zu wenige Literaltypen
// funktionieren
if (literal.value instanceof Short) {
constraintsSet.addUndConstraint(new Pair(literal.getType(), shortt, PairOperator.EQUALSDOT));
constraintsSet.addUndConstraint(new Pair(literal.getType(), shortt, PairOperator.EQUALSDOT, loc(literal.getOffset())));
return;
}
if (literal.value instanceof Byte) {
constraintsSet.addUndConstraint(new Pair(literal.getType(), bytee, PairOperator.EQUALSDOT));
constraintsSet.addUndConstraint(new Pair(literal.getType(), bytee, PairOperator.EQUALSDOT, loc(literal.getOffset())));
return;
}
if (literal.value instanceof Float) {
constraintsSet.addUndConstraint(new Pair(literal.getType(), floatt, PairOperator.EQUALSDOT));
constraintsSet.addUndConstraint(new Pair(literal.getType(), floatt, PairOperator.EQUALSDOT, loc(literal.getOffset())));
return;
}
if (literal.value instanceof Double) {
constraintsSet.addUndConstraint(new Pair(literal.getType(), doublee, PairOperator.EQUALSDOT));
constraintsSet.addUndConstraint(new Pair(literal.getType(), doublee, PairOperator.EQUALSDOT, loc(literal.getOffset())));
return;
}
if (literal.value instanceof Long) {
constraintsSet.addUndConstraint(new Pair(literal.getType(), longg, PairOperator.EQUALSDOT));
constraintsSet.addUndConstraint(new Pair(literal.getType(), longg, PairOperator.EQUALSDOT, loc(literal.getOffset())));
return;
}
if (literal.value instanceof Integer) {
@ -392,31 +410,31 @@ public class TYPEStmt implements StatementVisitor {
HashSet<JavaClassName> clNames = info.getAvailableClasses().stream().map(x -> x.getClassName()).collect(Collectors.toCollection(HashSet::new));
Set<Constraint> oderConstraints = new HashSet<>();
Constraint constraint = new Constraint();
constraint.add(new Pair(literal.getType(), integer, PairOperator.EQUALSDOT));
constraint.add(new Pair(literal.getType(), integer, PairOperator.EQUALSDOT, loc(literal.getOffset())));
oderConstraints.add(constraint);
if (clNames.stream().filter(x -> x.toString().equals("java.lang.Double")).findAny().isPresent()) {
constraint = new Constraint();
constraint.add(new Pair(literal.getType(), doublee, PairOperator.EQUALSDOT));
constraint.add(new Pair(literal.getType(), doublee, PairOperator.EQUALSDOT, loc(literal.getOffset())));
oderConstraints.add(constraint);
}
if (clNames.stream().filter(x -> x.toString().equals("java.lang.Long")).findAny().isPresent()) {
constraint = new Constraint();
constraint.add(new Pair(literal.getType(), longg, PairOperator.EQUALSDOT));
constraint.add(new Pair(literal.getType(), longg, PairOperator.EQUALSDOT, loc(literal.getOffset())));
oderConstraints.add(constraint);
}
if (clNames.stream().filter(x -> x.toString().equals("java.lang.Float")).findAny().isPresent()) {
constraint = new Constraint();
constraint.add(new Pair(literal.getType(), floatt, PairOperator.EQUALSDOT));
constraint.add(new Pair(literal.getType(), floatt, PairOperator.EQUALSDOT, loc(literal.getOffset())));
oderConstraints.add(constraint);
}
if (clNames.stream().filter(x -> x.toString().equals("java.lang.Short")).findAny().isPresent()) {
constraint = new Constraint();
constraint.add(new Pair(literal.getType(), shortt, PairOperator.EQUALSDOT));
constraint.add(new Pair(literal.getType(), shortt, PairOperator.EQUALSDOT, loc(literal.getOffset())));
oderConstraints.add(constraint);
}
if (clNames.stream().filter(x -> x.toString().equals("java.lang.Byte")).findAny().isPresent()) {
constraint = new Constraint();
constraint.add(new Pair(literal.getType(), bytee, PairOperator.EQUALSDOT));
constraint.add(new Pair(literal.getType(), bytee, PairOperator.EQUALSDOT, loc(literal.getOffset())));
oderConstraints.add(constraint);
}
constraintsSet.addOderConstraint(oderConstraints);
@ -424,33 +442,43 @@ public class TYPEStmt implements StatementVisitor {
return;
}
if (literal.value instanceof Short) {
constraintsSet.addUndConstraint(new Pair(literal.getType(), shortt, PairOperator.EQUALSDOT));
constraintsSet.addUndConstraint(new Pair(literal.getType(), shortt, PairOperator.EQUALSDOT, loc(literal.getOffset())));
return;
}
if (literal.value instanceof Byte) {
constraintsSet.addUndConstraint(new Pair(literal.getType(), bytee, PairOperator.EQUALSDOT));
constraintsSet.addUndConstraint(new Pair(literal.getType(), bytee, PairOperator.EQUALSDOT, loc(literal.getOffset())));
return;
}
if (literal.value instanceof Float) {
constraintsSet.addUndConstraint(new Pair(literal.getType(), floatt, PairOperator.EQUALSDOT));
constraintsSet.addUndConstraint(new Pair(literal.getType(), floatt, PairOperator.EQUALSDOT, loc(literal.getOffset())));
return;
}
if (literal.value instanceof String) {
constraintsSet.addUndConstraint(new Pair(literal.getType(), string, PairOperator.EQUALSDOT));
constraintsSet.addUndConstraint(new Pair(literal.getType(), string, PairOperator.EQUALSDOT, loc(literal.getOffset())));
return;
}
if (literal.value instanceof Boolean) {
constraintsSet.addUndConstraint(new Pair(literal.getType(), bool, PairOperator.EQUALSDOT));
constraintsSet.addUndConstraint(new Pair(literal.getType(), bool, PairOperator.EQUALSDOT, loc(literal.getOffset())));
return;
} else {
}
if (literal.value instanceof Character) {
constraintsSet.addUndConstraint(new Pair(literal.getType(), charr, PairOperator.EQUALSDOT, loc(literal.getOffset())));
return;
}
if (literal.value != null) {
throw new NotImplementedException();
}
}
@Override
public void visit(Throw aThrow) {
aThrow.expr.accept(this);
}
@Override
public void visit(Return returnExpr) {
returnExpr.retexpr.accept(this);
constraintsSet.addUndConstraint(new Pair(returnExpr.getType(), info.getCurrentTypeScope().getReturnType(), PairOperator.SMALLERDOT));
constraintsSet.addUndConstraint(new Pair(returnExpr.getType(), info.getCurrentTypeScope().getReturnType(), PairOperator.SMALLERDOT, loc(returnExpr.getOffset())));
}
@Override
@ -482,7 +510,7 @@ public class TYPEStmt implements StatementVisitor {
params.add(new GenericRefType(gtv.getName(), aThis.getOffset()));
}
RefType thisType = new RefType(currentClass.getClassName(), params, aThis.getOffset());
constraintsSet.addUndConstraint(new Pair(aThis.getType(), thisType, PairOperator.EQUALSDOT));
constraintsSet.addUndConstraint(new Pair(aThis.getType(), thisType, PairOperator.EQUALSDOT, loc(aThis.getOffset())));
}
private static TypeScope createNullTypeScope() {
@ -505,7 +533,7 @@ public class TYPEStmt implements StatementVisitor {
// Expression inferieren:
whileStmt.expr.accept(this);
// Expression muss boolean sein:
constraintsSet.addUndConstraint(new Pair(whileStmt.expr.getType(), booleanType, PairOperator.EQUALSDOT));
constraintsSet.addUndConstraint(new Pair(whileStmt.expr.getType(), booleanType, PairOperator.EQUALSDOT, loc(whileStmt.expr.getOffset())));
// LoopBlock inferieren:
whileStmt.loopBlock.accept(this);
}
@ -529,7 +557,22 @@ public class TYPEStmt implements StatementVisitor {
@Override
public void visit(SuperCall superCall) {
// TODO: Für einen super-Call werden keine Constraints erzeugt bisher
Set<Constraint<Pair>> methodConstraints = new HashSet<>();
for (var clazz : info.getAvailableClasses()) {
if (clazz.getClassName().equals(info.getCurrentClass().getSuperClass().getName())) {
for (var ctor : clazz.getConstructors()) {
var params = convertParams(ctor.getParameterList(), info);
if (params.size() != superCall.arglist.getArguments().size()) continue;
var assumption = new MethodAssumption(null, new Void(new NullToken()), params, createTypeScope(clazz, ctor), ctor.isInherited);
GenericsResolver resolver = getResolverInstance();
Set<Constraint<Pair>> oneMethodConstraints = generateConstraint(superCall, assumption, info, resolver);
methodConstraints.addAll(oneMethodConstraints);
}
break;
}
}
constraintsSet.addOderConstraint(methodConstraints);
}
/*
@ -549,10 +592,12 @@ public class TYPEStmt implements StatementVisitor {
*/
RefTypeOrTPHOrWildcardOrGeneric receiverType = assumption.getReceiverType(resolver);
methodConstraint.add(new Pair(forMethod.receiver.getType(), receiverType, PairOperator.EQUALSDOT));// PL 2020-03-17 SMALLERDOT in EQUALSDOT umgewandelt, weil alle geerbten Methoden in den jeweilen Klassen enthalten sind.
if (receiverType != null) {
methodConstraint.add(new Pair(forMethod.receiver.getType(), receiverType, PairOperator.EQUALSDOT, loc(forMethod.getOffset())));// PL 2020-03-17 SMALLERDOT in EQUALSDOT umgewandelt, weil alle geerbten Methoden in den jeweilen Klassen enthalten sind.
// PL 2023-01-24: dafuer ? extends receiverType noch ergaenzt
extendsMethodConstraint.add(new Pair(forMethod.receiver.getType(), new ExtendsWildcardType(receiverType, receiverType.getOffset()), PairOperator.EQUALSDOT));
extendsMethodConstraint.add(new Pair(forMethod.receiver.getType(), new ExtendsWildcardType(receiverType, receiverType.getOffset()), PairOperator.EQUALSDOT, loc(forMethod.getOffset())));
}
// gegenseite Verschraenkung der beiden Mengen von Typannahmen
methodConstraint.setExtendConstraint(extendsMethodConstraint);
@ -563,13 +608,14 @@ public class TYPEStmt implements StatementVisitor {
// PairOperator.EQUALSDOT));
// Fuer Bytecodegenerierung PL 2020-03-09 wird derzeit nicht benutzt ENDE
methodConstraint.add(new Pair(assumption.getReturnType(resolver), forMethod.getType(), PairOperator.SMALLERDOT));
extendsMethodConstraint.add(new Pair(assumption.getReturnType(resolver), forMethod.getType(), PairOperator.SMALLERDOT));
methodConstraint.add(new Pair(assumption.getReturnType(resolver), forMethod.getType(), PairOperator.SMALLERDOT, loc(forMethod.getOffset())));
extendsMethodConstraint.add(new Pair(assumption.getReturnType(resolver), forMethod.getType(), PairOperator.SMALLERDOT, loc(forMethod.getOffset())));
// methodConstraint.add(new Pair(assumption.getReturnType(resolver), forMethod.getType(), PairOperator.EQUALSDOT));
// extendsMethodConstraint.add(new Pair(assumption.getReturnType(resolver), forMethod.getType(), PairOperator.EQUALSDOT));
((TypePlaceholder) forMethod.getType()).setOrCons((byte) -1);// fuer Maximums-Bestimmung
if (forMethod.getType() instanceof TypePlaceholder tph)
tph.setOrCons((byte) -1);// fuer Maximums-Bestimmung
Set<Pair> parameterContraints = generateParameterConstraints(forMethod, assumption, info, resolver);
@ -596,7 +642,7 @@ public class TYPEStmt implements StatementVisitor {
RefTypeOrTPHOrWildcardOrGeneric argType = foMethod.arglist.getArguments().get(i).getType();
RefTypeOrTPHOrWildcardOrGeneric assType = assumption.getArgTypes(resolver).get(i);
ret.add(new Pair(argType, assType, PairOperator.SMALLERDOT));
ret.add(new Pair(argType, assType, PairOperator.SMALLERDOT, loc(foMethod.getOffset())));
// Fuer Bytecodegenerierung PL 2020-03-09 wird derzeit nicht benutzt ANFANG
// ret.add(new Pair(foMethod.argTypes.get(i), assType, PairOperator.EQUALSDOT));
@ -616,7 +662,6 @@ public class TYPEStmt implements StatementVisitor {
}
// Zuordnung von MethodCall.signature(ReturnType) zu dem ReturnType der ausgewaehlten Methode (assumption.returnType)
System.out.println(foMethod.name);
ret.add(new Pair(foMethod.signature.get(foMethod.signature.size() - 1), assumption.getReturnType(), PairOperator.EQUALSDOT));
return ret;
}
@ -691,7 +736,7 @@ public class TYPEStmt implements StatementVisitor {
Constraint methodConstraint = new Constraint();
// WELCHEN SINN MACHT DIESER CONSTRAINT???
// Ist er nicht immer classname <. classname und damit redundant?
methodConstraint.add(new Pair(assumption.getReturnType(resolver), forConstructor.getType(), PairOperator.SMALLERDOT));
methodConstraint.add(new Pair(assumption.getReturnType(resolver), forConstructor.getType(), PairOperator.SMALLERDOT, loc(forConstructor.getOffset())));
// WELCHEN SINN MACHT DIESER CONSTRAINT???
methodConstraint.addAll(generateParameterConstraints(forConstructor, assumption, info, resolver));
return methodConstraint;
@ -715,17 +760,17 @@ public class TYPEStmt implements StatementVisitor {
for (var child : switchStmt.getBlocks()) {
for (var label : child.getLabels()) {
if (label.getPattern() instanceof FormalParameter) {
constraintsSet.addUndConstraint(new Pair(label.getPattern().getType(), switchStmt.getSwitch().getType(), PairOperator.SMALLERDOT));
constraintsSet.addUndConstraint(new Pair(label.getPattern().getType(), switchStmt.getSwitch().getType(), PairOperator.SMALLERDOT, loc(label.getOffset())));
}
}
}
} else {
constraintsSet.addUndConstraint(new Pair(caseExpressionType, switchStmt.getSwitch().getType(), PairOperator.EQUALSDOT));
constraintsSet.addUndConstraint(new Pair(caseExpressionType, switchStmt.getSwitch().getType(), PairOperator.EQUALSDOT, loc(switchStmt.getSwitch().getOffset())));
}
for (var child : switchStmt.getBlocks()) {
child.accept(this);
constraintsSet.addUndConstraint(new Pair(child.getType(), switchStmt.getType(), PairOperator.SMALLERDOT));
constraintsSet.addUndConstraint(new Pair(child.getType(), switchStmt.getType(), PairOperator.SMALLERDOT, loc(switchStmt.getOffset())));
}
switchStack.pop();
@ -746,7 +791,7 @@ public class TYPEStmt implements StatementVisitor {
@Override
public void visit(Yield aYield) {
aYield.retexpr.accept(this);
constraintsSet.addUndConstraint(new Pair(aYield.getType(), switchStack.peek().getType(), PairOperator.EQUALSDOT));
constraintsSet.addUndConstraint(new Pair(aYield.getType(), switchStack.peek().getType(), PairOperator.EQUALSDOT, loc(aYield.getOffset())));
// TODO Auto-generated method stub
}
}

View File

@ -439,7 +439,7 @@ public class RuleSet implements IRuleSet{
if(!(rhsType instanceof ReferenceType) && !(rhsType instanceof PlaceholderType))
return false;
return fc.greater(lhsType, new HashSet<>()).contains(rhsType);
return fc.greater(lhsType, new HashSet<>(), pair.getLocation()).contains(rhsType);
}
@Override

View File

@ -3,6 +3,7 @@ package de.dhbwstuttgart.typeinference.unify.interfaces;
import java.util.Optional;
import java.util.Set;
import de.dhbwstuttgart.parser.SourceLoc;
import de.dhbwstuttgart.typeinference.unify.model.ExtendsType;
import de.dhbwstuttgart.typeinference.unify.model.FunNType;
import de.dhbwstuttgart.typeinference.unify.model.PairOperator;
@ -10,6 +11,7 @@ import de.dhbwstuttgart.typeinference.unify.model.PlaceholderType;
import de.dhbwstuttgart.typeinference.unify.model.ReferenceType;
import de.dhbwstuttgart.typeinference.unify.model.SuperType;
import de.dhbwstuttgart.typeinference.unify.model.UnifyType;
import org.antlr.v4.runtime.Token;
/**
*
@ -22,13 +24,19 @@ public interface IFiniteClosure {
* Returns all types of the finite closure that are subtypes of the argument.
* @return The set of subtypes of the argument.
*/
public Set<UnifyType> smaller(UnifyType type, Set<UnifyType> fBounded);
public Set<UnifyType> smaller(UnifyType type, Set<UnifyType> fBounded, Token position);
public default Set<UnifyType> smaller(UnifyType type, Set<UnifyType> fBounded) {
return this.smaller(type, fBounded, null);
}
/**
* Returns all types of the finite closure that are supertypes of the argument.
* @return The set of supertypes of the argument.
*/
public Set<UnifyType> greater(UnifyType type, Set<UnifyType> fBounded);
public Set<UnifyType> greater(UnifyType type, Set<UnifyType> fBounded, SourceLoc position);
public default Set<UnifyType> greater(UnifyType type, Set<UnifyType> fBounded) {
return this.greater(type, fBounded, null);
}
/**
* Wo passt Type rein?

View File

@ -20,6 +20,7 @@ import com.google.common.collect.Ordering;
//PL 18-02-05/18-04-05 Unifier durch Matcher ersetzt
//muss greater noch ersetzt werden ja erledigt 18--04-05
import de.dhbwstuttgart.parser.SourceLoc;
import de.dhbwstuttgart.typeinference.unify.MartelliMontanariUnify;
import de.dhbwstuttgart.typeinference.unify.Match;
@ -27,6 +28,7 @@ import de.dhbwstuttgart.typeinference.unify.TypeUnifyTask;
import de.dhbwstuttgart.typeinference.unify.interfaces.IFiniteClosure;
import de.dhbwstuttgart.typeinference.unify.interfaces.IUnify;
import de.dhbwstuttgart.util.Pair;
import org.antlr.v4.runtime.Token;
/**
* The finite closure for the type unification
@ -145,7 +147,7 @@ implements IFiniteClosure {
* @return The set of subtypes of the argument.
*/
@Override
public Set<UnifyType> smaller(UnifyType type, Set<UnifyType> fBounded) {
public Set<UnifyType> smaller(UnifyType type, Set<UnifyType> fBounded, Token position) {
Set<UnifyType> ret;
if ((ret = smallerHash.get(new hashKeyType(type))) != null) {
@ -260,8 +262,7 @@ implements IFiniteClosure {
*/
@Override
//Eingefuegt PL 2018-05-24 F-Bounded Problematik
public Set<UnifyType> greater(UnifyType type, Set<UnifyType> fBounded) {
public Set<UnifyType> greater(UnifyType type, Set<UnifyType> fBounded, SourceLoc location) {
Set<UnifyType> ret;
if ((ret = greaterHash.get(new hashKeyType(type))) != null) {
//System.out.println(greaterHash);
@ -302,7 +303,7 @@ implements IFiniteClosure {
//PL 18-04-05 Unifier durch Matcher ersetzt ANFANG
ArrayList<UnifyPair> termList= new ArrayList<UnifyPair>();
termList.add(new UnifyPair(theta1,type, PairOperator.EQUALSDOT));
termList.add(new UnifyPair(theta1,type, PairOperator.EQUALSDOT, location));
Optional<Unifier> optSigma = match.match(termList);
//PL 18-04-05 Unifier durch Matcher ersetzt ENDE
if(!optSigma.isPresent()) {
@ -344,7 +345,7 @@ implements IFiniteClosure {
BiFunction<Boolean,UnifyType,Boolean> f = (x,y) ->
{
ArrayList<UnifyPair> termList = new ArrayList<UnifyPair>();
termList.add(new UnifyPair(y,t.getTypeParams().get(i_ef), PairOperator.EQUALSDOT));
termList.add(new UnifyPair(y,t.getTypeParams().get(i_ef), PairOperator.EQUALSDOT, location));
return ((match.match(termList).isPresent()) || x);
};
//if (parai.getName().equals("java.lang.Integer")) {

View File

@ -102,7 +102,7 @@ public class Unifier implements Function<UnifyType, UnifyType>, Iterable<Entry<P
}
return new UnifyPair(newLhs, newRhs, p.getPairOp(), suniUnifyPair, p);
}
return new UnifyPair(newLhs, newRhs, p.getPairOp(), p.getSubstitution(), p.getBasePair(), p.getfBounded());
return new UnifyPair(newLhs, newRhs, p.getPairOp(), p.getSubstitution(), p.getBasePair(), p.getfBounded(), p.getLocation());
}
/**

View File

@ -1,5 +1,10 @@
package de.dhbwstuttgart.typeinference.unify.model;
import com.google.common.collect.ObjectArrays;
import de.dhbwstuttgart.parser.SourceLoc;
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
import org.antlr.v4.runtime.Token;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
@ -14,6 +19,8 @@ import java.util.Set;
*/
public class UnifyPair {
private SourceLoc location;
/**
* The type on the left hand side of the pair.
*/
@ -68,22 +75,36 @@ public class UnifyPair {
hashCode = 17 + 31 * lhs.hashCode() + 31 * rhs.hashCode() + 31 * pairOp.hashCode();
}
public UnifyPair(UnifyType lhs, UnifyType rhs, PairOperator op, SourceLoc location) {
this(lhs, rhs, op);
this.location = location;
}
public UnifyPair(UnifyType lhs, UnifyType rhs, PairOperator op, Set<UnifyPair> uni, UnifyPair base) {
this(lhs, rhs, op, uni, base, null);
}
public UnifyPair(UnifyType lhs, UnifyType rhs, PairOperator op, Set<UnifyPair> uni, UnifyPair base, Set<UnifyType> fBounded) {
this(lhs, rhs, op, uni, base, fBounded, null);
}
public UnifyPair(UnifyType lhs, UnifyType rhs, PairOperator op, Set<UnifyPair> uni, UnifyPair base, Set<UnifyType> fBounded, SourceLoc location) {
this.lhs = lhs;
this.rhs = rhs;
pairOp = op;
substitution = uni;
basePair = base;
this.location = location;
//this.fBounded = fBounded; // what?
// Caching hashcode
hashCode = 17 + 31 * lhs.hashCode() + 31 * rhs.hashCode() + 31 * pairOp.hashCode();
}
public UnifyPair(UnifyType lhs, UnifyType rhs, PairOperator op, Set<UnifyPair> uni, UnifyPair base, Set<UnifyType> fBounded) {
this(lhs, rhs, op, uni, base);
this.fBounded = fBounded;
public SourceLoc getLocation() {
if (location != null) return location;
else if (basePair != null) return basePair.getLocation();
return null;
}
/**
@ -231,7 +252,13 @@ public class UnifyPair {
+ "WC: " + ((PlaceholderType)rhs).isWildcardable()
+ ", IT: " + ((PlaceholderType)rhs).isInnerType();
}
return "(" + lhs + " " + pairOp + " " + rhs + ", " + ret + ")"; //+ ", [" + getfBounded().toString()+ "])";
var res = "(" + lhs + " " + pairOp + " " + rhs + ", " + ret + ")"; //+ ", [" + getfBounded().toString()+ "])";
var location = this.getLocation();
if (location != null) {
res += "@" + location.line() + " in " + location.file();
}
return res;
}
/*

View File

@ -1,9 +1,9 @@
import de.dhbwstuttgart.environment.ByteArrayClassLoader;
import de.dhbwstuttgart.syntaxtree.statement.Expression;
import org.junit.Ignore;
import org.junit.Test;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.Arrays;
@ -234,7 +234,7 @@ public class TestComplete {
}
@Test
//@Ignore("This is to complex")
//@Ignore("This is too complex")
public void matrixTest() throws Exception {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "Matrix.jav");
var matrix = classFiles.get("Matrix");
@ -738,6 +738,15 @@ public class TestComplete {
assertEquals(m.invoke(instance, 10), 60);
}
@Test
public void testForEach() throws Exception {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "ForEach.jav");
var clazz = classFiles.get("ForEach");
var instance = clazz.getDeclaredConstructor().newInstance();
var m = clazz.getDeclaredMethod("m");
assertEquals(m.invoke(instance), 6);
}
@Test
public void testLambdaRunnable() throws Exception {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "LambdaRunnable.jav");
@ -772,4 +781,99 @@ public class TestComplete {
var hello = clazz.getDeclaredMethod("hello");
hello.invoke(null);
}
@Test
public void testSuperCall() throws Exception {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "SuperCall.jav");
var clazz = classFiles.get("SuperCall");
var instance = clazz.getDeclaredConstructor().newInstance();
}
@Test
public void testInstanceOf() throws Exception {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "InstanceOf.jav");
var clazz = classFiles.get("InstanceOf");
var instance = clazz.getDeclaredConstructor().newInstance();
assertTrue((Boolean) clazz.getDeclaredMethod("test1").invoke(instance));
assertTrue((Boolean) clazz.getDeclaredMethod("test2").invoke(instance));
assertFalse((Boolean) clazz.getDeclaredMethod("test3").invoke(instance));
}
@Test
public void testExceptions() throws Exception {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "Exceptions.jav");
var clazz = classFiles.get("Exceptions");
var instance = clazz.getDeclaredConstructor().newInstance();
try {
clazz.getDeclaredMethod("m").invoke(instance);
fail("No exception thrown!");
} catch (InvocationTargetException exception) {
var exc = exception.getTargetException();
if (!(exc instanceof RuntimeException rexp) || !rexp.getMessage().equals("Some Exception")) {
fail("Wrong exception thrown!");
}
}
}
@Test
public void testLiteral() throws Exception {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "Literal.jav");
var clazz = classFiles.get("Literal");
var instance = clazz.getDeclaredConstructor().newInstance();
assertNull(clazz.getDeclaredMethod("m").invoke(instance));
assertEquals(clazz.getDeclaredMethod("m2").invoke(instance), 'C');
}
@Test
public void testOLConstructor() throws Exception {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "OLConstructor.jav");
var clazz = classFiles.get("Child");
var instance = clazz.getDeclaredConstructor().newInstance();
assertEquals(clazz.getSuperclass().getDeclaredField("x").get(instance), 3);
}
@Test
public void testStringConcat() throws Exception {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "Op2.jav");
var clazz = classFiles.get("Op2");
var instance = clazz.getDeclaredConstructor().newInstance();
}
@Test
public void testLamRunnable() throws Exception {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "LamRunnable.jav");
var clazz = classFiles.get("LamRunnable");
var instance = clazz.getDeclaredConstructor().newInstance();
}
@Test
public void testBug122() throws Exception {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "Bug122.jav");
var clazz = classFiles.get("Bug122");
var instance = clazz.getDeclaredConstructor().newInstance();
}
@Test
public void testBug123() throws Exception {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "Bug123.jav");
var clazz = classFiles.get("Bug123");
var instance = clazz.getDeclaredConstructor().newInstance();
}
@Test
public void testBug125() throws Exception {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "Bug125.jav");
var clazz = classFiles.get("Bug125");
var instance = clazz.getDeclaredConstructor().newInstance();
}
@Test
public void testBug112() throws Exception {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "Bug112.jav");
var clazz = classFiles.get("Bug112");
var instance = clazz.getDeclaredConstructor().newInstance();
}
}

View File

@ -22,7 +22,7 @@ public class ASTToTypedTargetAST {
@Test
public void emptyClass() {
ClassOrInterface emptyClass = new ClassOrInterface(0, new JavaClassName("EmptyClass"), new ArrayList<>(), Optional.empty(), Optional.empty(), new ArrayList<>(), new ArrayList<>(), new GenericDeclarationList(new ArrayList<>(), new NullToken()), new RefType(new JavaClassName("Object"), new NullToken()), false, false, new ArrayList<>(), new ArrayList<>(), new NullToken());
ClassOrInterface emptyClass = new ClassOrInterface(0, new JavaClassName("EmptyClass"), new ArrayList<>(), Optional.empty(), Optional.empty(), new ArrayList<>(), new ArrayList<>(), new GenericDeclarationList(new ArrayList<>(), new NullToken()), new RefType(new JavaClassName("Object"), new NullToken()), false, false, new ArrayList<>(), new ArrayList<>(), new NullToken(), null);
ResultSet emptyResultSet = new ResultSet(new HashSet<>());
TargetStructure emptyTargetClass = new ASTToTargetAST(List.of(emptyResultSet)).convert(emptyClass);
assert emptyTargetClass.getName().equals("EmptyClass");