From a23bf7c16c969bfbe7882125f309e53129f135e7 Mon Sep 17 00:00:00 2001 From: Ruben Date: Wed, 4 Dec 2024 17:16:24 +0100 Subject: [PATCH] feat: add Compiler to LSP and add Stub for Interface Class --- .../compiler/bytecode/CodeGenException.java | 7 + .../de/dhbw/compiler/bytecode/Codegen.java | 1801 +++++++++++ .../dhbw/compiler/bytecode/FunNGenerator.java | 212 ++ .../bytecode/JavaTXSignatureAttribute.java | 30 + .../dhbw/compiler/core/ConsoleInterface.java | 46 + .../dhbw/compiler/core/IItemWithOffset.java | 9 + .../de/dhbw/compiler/core/JavaTXCompiler.java | 708 +++++ .../environment/ByteArrayClassLoader.java | 13 + .../environment/CompilationEnvironment.java | 107 + .../environment/DirectoryClassLoader.java | 78 + .../environment/IByteArrayClassLoader.java | 23 + .../compiler/environment/PackageCrawler.java | 52 + .../compiler/exceptions/DebugException.java | 8 + .../exceptions/NotImplementedException.java | 11 + .../dhbw/compiler/exceptions/ParserError.java | 10 + .../exceptions/TypeinferenceException.java | 46 + .../LanguageServerInterface.java | 25 + .../de/dhbw/compiler/parser/JavaTXParser.java | 37 + .../de/dhbw/compiler/parser/NullToken.java | 57 + .../de/dhbw/compiler/parser/SourceLoc.java | 4 + .../SyntaxTreeGenerator/AssignToLocal.java | 20 + .../SyntaxTreeGenerator/FCGenerator.java | 252 ++ .../SyntaxTreeGenerator/FieldEntry.java | 6 + .../SyntaxTreeGenerator/GenericContext.java | 14 + .../StatementGenerator.java | 1036 +++++++ .../SyntaxTreeGenerator/SyntacticSugar.java | 51 + .../SyntaxTreeGenerator.java | 604 ++++ .../SyntaxTreeGenerator/TypeGenerator.java | 209 ++ .../main/java/de/dhbw/compiler/parser/TODO | 5 + .../de/dhbw/compiler/parser/notes/GetNames | 15 + .../java/de/dhbw/compiler/parser/notes/TODO | 3 + .../de/dhbw/compiler/parser/notes/questions | 2 + .../java/de/dhbw/compiler/parser/parse_tree | 18 + .../compiler/parser/scope/GatherNames.java | 154 + .../parser/scope/GenericsRegistry.java | 50 + .../compiler/parser/scope/JavaClassName.java | 159 + .../parser/scope/JavaClassRegistry.java | 65 + .../dhbw/compiler/syntaxtree/ASTVisitor.java | 43 + .../syntaxtree/AbstractASTWalker.java | 352 +++ .../compiler/syntaxtree/ClassOrInterface.java | 202 ++ .../dhbw/compiler/syntaxtree/Constructor.java | 29 + .../compiler/syntaxtree/ExceptionList.java | 14 + .../syntaxtree/ExpressionPattern.java | 28 + .../de/dhbw/compiler/syntaxtree/Field.java | 43 + .../compiler/syntaxtree/FieldDeclaration.java | 28 + .../compiler/syntaxtree/FormalParameter.java | 27 + .../syntaxtree/GenericDeclarationList.java | 65 + .../compiler/syntaxtree/GenericTypeVar.java | 78 + .../compiler/syntaxtree/GuardedPattern.java | 35 + .../compiler/syntaxtree/LiteralPattern.java | 29 + .../de/dhbw/compiler/syntaxtree/Method.java | 119 + .../compiler/syntaxtree/ParameterList.java | 36 + .../de/dhbw/compiler/syntaxtree/Pattern.java | 19 + .../de/dhbw/compiler/syntaxtree/Record.java | 19 + .../compiler/syntaxtree/RecordPattern.java | 33 + .../dhbw/compiler/syntaxtree/SourceFile.java | 78 + .../compiler/syntaxtree/StatementVisitor.java | 88 + .../compiler/syntaxtree/SyntaxTreeNode.java | 24 + .../dhbw/compiler/syntaxtree/TypeScope.java | 12 + .../syntaxtree/factory/ASTFactory.java | 487 +++ .../syntaxtree/factory/NameGenerator.java | 91 + .../factory/PrimitiveMethodsGenerator.java | 9 + .../syntaxtree/factory/UnifyTypeFactory.java | 297 ++ .../syntaxtree/statement/ArgumentList.java | 33 + .../compiler/syntaxtree/statement/Assign.java | 28 + .../syntaxtree/statement/AssignLeftSide.java | 12 + .../syntaxtree/statement/AssignToField.java | 17 + .../syntaxtree/statement/BinaryExpr.java | 42 + .../compiler/syntaxtree/statement/Block.java | 27 + .../syntaxtree/statement/BoolExpression.java | 31 + .../compiler/syntaxtree/statement/Break.java | 19 + .../syntaxtree/statement/CastExpr.java | 25 + .../syntaxtree/statement/Continue.java | 18 + .../compiler/syntaxtree/statement/DoStmt.java | 18 + .../syntaxtree/statement/EmptyStmt.java | 22 + .../syntaxtree/statement/Expression.java | 16 + .../statement/ExpressionReceiver.java | 21 + .../syntaxtree/statement/FieldVar.java | 31 + .../syntaxtree/statement/ForEachStmt.java | 26 + .../syntaxtree/statement/ForStmt.java | 34 + .../compiler/syntaxtree/statement/IfStmt.java | 26 + .../syntaxtree/statement/InstanceOf.java | 38 + .../statement/JavaInternalExpression.java | 12 + .../statement/LambdaExpression.java | 42 + .../syntaxtree/statement/Literal.java | 24 + .../syntaxtree/statement/LocalVar.java | 25 + .../syntaxtree/statement/LocalVarDecl.java | 31 + .../syntaxtree/statement/MethodCall.java | 56 + .../syntaxtree/statement/NewArray.java | 24 + .../syntaxtree/statement/NewClass.java | 43 + .../syntaxtree/statement/Receiver.java | 12 + .../compiler/syntaxtree/statement/Return.java | 18 + .../syntaxtree/statement/ReturnVoid.java | 15 + .../syntaxtree/statement/Statement.java | 25 + .../syntaxtree/statement/StaticClassName.java | 21 + .../compiler/syntaxtree/statement/Super.java | 29 + .../syntaxtree/statement/SuperCall.java | 34 + .../compiler/syntaxtree/statement/Switch.java | 37 + .../syntaxtree/statement/SwitchBlock.java | 43 + .../syntaxtree/statement/SwitchLabel.java | 37 + .../syntaxtree/statement/Ternary.java | 24 + .../compiler/syntaxtree/statement/This.java | 25 + .../syntaxtree/statement/ThisCall.java | 25 + .../compiler/syntaxtree/statement/Throw.java | 21 + .../statement/TypableStatement.java | 28 + .../syntaxtree/statement/UnaryExpr.java | 37 + .../syntaxtree/statement/WhileStmt.java | 28 + .../compiler/syntaxtree/statement/Yield.java | 18 + .../syntaxtree/type/ExtendsWildcardType.java | 71 + .../syntaxtree/type/GenericRefType.java | 57 + .../compiler/syntaxtree/type/RefType.java | 132 + .../type/RefTypeOrTPHOrWildcardOrGeneric.java | 22 + .../syntaxtree/type/SuperWildcardType.java | 83 + .../syntaxtree/type/TypePlaceholder.java | 142 + .../compiler/syntaxtree/type/TypeVisitor.java | 13 + .../dhbw/compiler/syntaxtree/type/Void.java | 14 + .../syntaxtree/type/WildcardType.java | 42 + .../syntaxtree/visual/ASTPrinter.java | 13 + .../syntaxtree/visual/ASTTypePrinter.java | 13 + .../syntaxtree/visual/OutputGenerator.java | 533 ++++ .../visual/ResultSetOutputGenerator.java | 34 + .../syntaxtree/visual/ResultSetPrinter.java | 20 + .../visual/TypeOutputGenerator.java | 224 ++ .../target/generate/ASTToTargetAST.java | 713 +++++ .../dhbw/compiler/target/generate/Bound.java | 24 + .../compiler/target/generate/BoundsList.java | 52 + .../compiler/target/generate/CycleFinder.java | 104 + .../target/generate/GenerateGenerics.java | 990 +++++++ .../target/generate/GenericsResult.java | 76 + .../target/generate/GenericsResultSet.java | 43 + .../target/generate/JavaGenerics.java | 30 + .../generate/StatementToTargetExpression.java | 594 ++++ .../generate/TracingStatementVisitor.java | 218 ++ .../compiler/target/generate/TxGenerics.java | 25 + .../compiler/target/tree/MethodParameter.java | 18 + .../compiler/target/tree/TargetClass.java | 27 + .../target/tree/TargetConstructor.java | 24 + .../compiler/target/tree/TargetField.java | 11 + .../compiler/target/tree/TargetGeneric.java | 6 + .../compiler/target/tree/TargetInterface.java | 24 + .../compiler/target/tree/TargetMethod.java | 97 + .../compiler/target/tree/TargetRecord.java | 16 + .../compiler/target/tree/TargetStructure.java | 44 + .../target/tree/expression/TargetAssign.java | 6 + .../tree/expression/TargetBinaryOp.java | 85 + .../target/tree/expression/TargetBlock.java | 8 + .../target/tree/expression/TargetBreak.java | 7 + .../target/tree/expression/TargetCast.java | 6 + .../tree/expression/TargetClassName.java | 6 + .../tree/expression/TargetComplexPattern.java | 17 + .../tree/expression/TargetContinue.java | 6 + .../target/tree/expression/TargetDo.java | 4 + .../tree/expression/TargetExpression.java | 11 + .../expression/TargetExpressionPattern.java | 20 + .../tree/expression/TargetFieldVar.java | 7 + .../target/tree/expression/TargetFor.java | 6 + .../target/tree/expression/TargetForEach.java | 4 + .../target/tree/expression/TargetGuard.java | 20 + .../target/tree/expression/TargetIf.java | 6 + .../tree/expression/TargetInstanceOf.java | 12 + .../expression/TargetLambdaExpression.java | 11 + .../target/tree/expression/TargetLiteral.java | 68 + .../tree/expression/TargetLocalVar.java | 6 + .../tree/expression/TargetMethodCall.java | 17 + .../target/tree/expression/TargetNew.java | 12 + .../target/tree/expression/TargetPattern.java | 15 + .../target/tree/expression/TargetReturn.java | 6 + .../expression/TargetStatementExpression.java | 4 + .../target/tree/expression/TargetSuper.java | 6 + .../target/tree/expression/TargetSwitch.java | 30 + .../target/tree/expression/TargetTernary.java | 6 + .../target/tree/expression/TargetThis.java | 6 + .../target/tree/expression/TargetThrow.java | 4 + .../tree/expression/TargetTypePattern.java | 15 + .../target/tree/expression/TargetUnaryOp.java | 16 + .../target/tree/expression/TargetVarDecl.java | 11 + .../target/tree/expression/TargetWhile.java | 4 + .../target/tree/expression/TargetYield.java | 10 + .../tree/type/TargetExtendsWildcard.java | 24 + .../target/tree/type/TargetFunNType.java | 41 + .../target/tree/type/TargetGenericType.java | 18 + .../target/tree/type/TargetPrimitiveType.java | 19 + .../target/tree/type/TargetRefType.java | 33 + .../tree/type/TargetSpecializedType.java | 21 + .../target/tree/type/TargetSuperWildcard.java | 25 + .../compiler/target/tree/type/TargetType.java | 73 + .../typedeployment/KindOfTypeInsertPoint.java | 7 + .../compiler/typedeployment/TypeInsert.java | 82 + .../typedeployment/TypeInsertFactory.java | 204 ++ .../typedeployment/TypeInsertPlacer.java | 88 + .../typedeployment/TypeInsertPoint.java | 93 + .../typeinference/assumptions/Assumption.java | 15 + .../assumptions/FieldAssumption.java | 49 + .../typeinference/assumptions/FunNClass.java | 42 + .../assumptions/MethodAssumption.java | 83 + .../TypeInferenceBlockInformation.java | 46 + .../assumptions/TypeInferenceInformation.java | 61 + .../assumptions/TypeScopeContainer.java | 32 + .../typeinference/constraints/Constraint.java | 77 + .../constraints/ConstraintSet.java | 130 + .../constraints/GenericsResolver.java | 14 + .../typeinference/constraints/Pair.java | 155 + .../result/GenericInsertPair.java | 31 + .../typeinference/result/PairNoResult.java | 32 + .../typeinference/result/PairTPHEqualTPH.java | 15 + .../PairTPHequalRefTypeOrWildcardType.java | 29 + .../result/PairTPHsmallerTPH.java | 39 + .../typeinference/result/ResolvedType.java | 27 + .../typeinference/result/ResultPair.java | 62 + .../result/ResultPairVisitor.java | 10 + .../typeinference/result/ResultSet.java | 309 ++ .../result/ResultSetVisitor.java | 17 + .../typeAlgo/GenericsResolverSameName.java | 56 + .../compiler/typeinference/typeAlgo/TYPE.java | 138 + .../typeinference/typeAlgo/TYPEStmt.java | 944 ++++++ .../unify/GuavaSetOperations.java | 23 + .../unify/MartelliMontanariUnify.java | 108 + .../compiler/typeinference/unify/Match.java | 93 + .../compiler/typeinference/unify/RuleSet.java | 1091 +++++++ .../typeinference/unify/TypeUnify.java | 121 + .../typeinference/unify/TypeUnify2Task.java | 66 + .../typeinference/unify/TypeUnifyTask.java | 2628 +++++++++++++++++ .../unify/Unifikationsalgorithmus.java | 11 + .../typeinference/unify/UnifyResultEvent.java | 18 + .../unify/UnifyResultListener.java | 7 + .../unify/UnifyResultListenerImpl.java | 21 + .../typeinference/unify/UnifyResultModel.java | 59 + .../typeinference/unify/UnifyTaskModel.java | 18 + .../unify/distributeVariance.java | 54 + .../typeinference/unify/freshPlaceholder.java | 15 + .../unify/interfaces/IFiniteClosure.java | 78 + .../unify/interfaces/IMatch.java | 29 + .../unify/interfaces/IRuleSet.java | 104 + .../unify/interfaces/ISetOperations.java | 16 + .../unify/interfaces/IUnify.java | 35 + .../unify/interfaces/UnifyTypeVisitor.java | 23 + .../unify/model/ExtendsType.java | 96 + .../unify/model/FiniteClosure.java | 806 +++++ .../unify/model/FunInterfaceType.java | 49 + .../typeinference/unify/model/FunNType.java | 103 + .../typeinference/unify/model/Node.java | 118 + .../unify/model/OrderingExtend.java | 89 + .../unify/model/OrderingUnifyPair.java | 457 +++ .../unify/model/PairOperator.java | 49 + .../unify/model/PlaceholderType.java | 219 ++ .../unify/model/ReferenceType.java | 100 + .../typeinference/unify/model/SuperType.java | 88 + .../typeinference/unify/model/TypeParams.java | 191 ++ .../typeinference/unify/model/Unifier.java | 189 ++ .../typeinference/unify/model/UnifyPair.java | 274 ++ .../typeinference/unify/model/UnifyType.java | 120 + .../unify/model/WildcardType.java | 72 + .../unify/model/hashKeyType.java | 25 + .../unify/visitUnifyTypeVisitor.java | 47 + .../de/dhbw/compiler/util/BiRelation.java | 19 + .../main/java/de/dhbw/compiler/util/Pair.java | 39 + .../main/java/de/dhbw/parser/Java17Lexer.java | 5 +- .../java/de/dhbw/parser/Java17Parser.java | 77 +- .../dhbw/parser/Java17ParserBaseListener.java | 2 +- .../dhbw/parser/Java17ParserBaseVisitor.java | 2 +- .../de/dhbw/parser/Java17ParserListener.java | 2 +- .../de/dhbw/parser/Java17ParserVisitor.java | 2 +- 262 files changed, 25434 insertions(+), 42 deletions(-) create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/bytecode/CodeGenException.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/bytecode/Codegen.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/bytecode/FunNGenerator.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/bytecode/JavaTXSignatureAttribute.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/core/ConsoleInterface.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/core/IItemWithOffset.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/core/JavaTXCompiler.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/environment/ByteArrayClassLoader.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/environment/CompilationEnvironment.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/environment/DirectoryClassLoader.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/environment/IByteArrayClassLoader.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/environment/PackageCrawler.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/exceptions/DebugException.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/exceptions/NotImplementedException.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/exceptions/ParserError.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/exceptions/TypeinferenceException.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/languageServerInterface/LanguageServerInterface.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/parser/JavaTXParser.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/parser/NullToken.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/parser/SourceLoc.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/parser/SyntaxTreeGenerator/AssignToLocal.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/parser/SyntaxTreeGenerator/FCGenerator.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/parser/SyntaxTreeGenerator/FieldEntry.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/parser/SyntaxTreeGenerator/GenericContext.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/parser/SyntaxTreeGenerator/StatementGenerator.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/parser/SyntaxTreeGenerator/SyntacticSugar.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/parser/SyntaxTreeGenerator/SyntaxTreeGenerator.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/parser/SyntaxTreeGenerator/TypeGenerator.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/parser/TODO create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/parser/notes/GetNames create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/parser/notes/TODO create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/parser/notes/questions create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/parser/parse_tree create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/parser/scope/GatherNames.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/parser/scope/GenericsRegistry.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/parser/scope/JavaClassName.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/parser/scope/JavaClassRegistry.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/ASTVisitor.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/AbstractASTWalker.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/ClassOrInterface.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/Constructor.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/ExceptionList.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/ExpressionPattern.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/Field.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/FieldDeclaration.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/FormalParameter.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/GenericDeclarationList.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/GenericTypeVar.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/GuardedPattern.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/LiteralPattern.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/Method.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/ParameterList.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/Pattern.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/Record.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/RecordPattern.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/SourceFile.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/StatementVisitor.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/SyntaxTreeNode.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/TypeScope.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/factory/ASTFactory.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/factory/NameGenerator.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/factory/PrimitiveMethodsGenerator.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/factory/UnifyTypeFactory.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/ArgumentList.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Assign.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/AssignLeftSide.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/AssignToField.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/BinaryExpr.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Block.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/BoolExpression.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Break.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/CastExpr.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Continue.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/DoStmt.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/EmptyStmt.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Expression.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/ExpressionReceiver.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/FieldVar.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/ForEachStmt.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/ForStmt.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/IfStmt.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/InstanceOf.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/JavaInternalExpression.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/LambdaExpression.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Literal.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/LocalVar.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/LocalVarDecl.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/MethodCall.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/NewArray.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/NewClass.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Receiver.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Return.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/ReturnVoid.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Statement.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/StaticClassName.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Super.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/SuperCall.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Switch.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/SwitchBlock.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/SwitchLabel.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Ternary.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/This.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/ThisCall.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Throw.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/TypableStatement.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/UnaryExpr.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/WhileStmt.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Yield.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/type/ExtendsWildcardType.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/type/GenericRefType.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/type/RefType.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/type/RefTypeOrTPHOrWildcardOrGeneric.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/type/SuperWildcardType.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/type/TypePlaceholder.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/type/TypeVisitor.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/type/Void.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/type/WildcardType.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/visual/ASTPrinter.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/visual/ASTTypePrinter.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/visual/OutputGenerator.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/visual/ResultSetOutputGenerator.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/visual/ResultSetPrinter.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/visual/TypeOutputGenerator.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/generate/ASTToTargetAST.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/generate/Bound.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/generate/BoundsList.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/generate/CycleFinder.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/generate/GenerateGenerics.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/generate/GenericsResult.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/generate/GenericsResultSet.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/generate/JavaGenerics.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/generate/StatementToTargetExpression.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/generate/TracingStatementVisitor.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/generate/TxGenerics.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/MethodParameter.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/TargetClass.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/TargetConstructor.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/TargetField.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/TargetGeneric.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/TargetInterface.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/TargetMethod.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/TargetRecord.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/TargetStructure.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetAssign.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetBinaryOp.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetBlock.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetBreak.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetCast.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetClassName.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetComplexPattern.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetContinue.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetDo.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetExpression.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetExpressionPattern.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetFieldVar.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetFor.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetForEach.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetGuard.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetIf.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetInstanceOf.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetLambdaExpression.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetLiteral.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetLocalVar.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetMethodCall.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetNew.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetPattern.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetReturn.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetStatementExpression.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetSuper.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetSwitch.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetTernary.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetThis.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetThrow.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetTypePattern.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetUnaryOp.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetVarDecl.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetWhile.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetYield.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/type/TargetExtendsWildcard.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/type/TargetFunNType.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/type/TargetGenericType.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/type/TargetPrimitiveType.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/type/TargetRefType.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/type/TargetSpecializedType.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/type/TargetSuperWildcard.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/target/tree/type/TargetType.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typedeployment/KindOfTypeInsertPoint.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typedeployment/TypeInsert.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typedeployment/TypeInsertFactory.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typedeployment/TypeInsertPlacer.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typedeployment/TypeInsertPoint.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/assumptions/Assumption.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/assumptions/FieldAssumption.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/assumptions/FunNClass.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/assumptions/MethodAssumption.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/assumptions/TypeInferenceBlockInformation.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/assumptions/TypeInferenceInformation.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/assumptions/TypeScopeContainer.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/constraints/Constraint.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/constraints/ConstraintSet.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/constraints/GenericsResolver.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/constraints/Pair.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/GenericInsertPair.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/PairNoResult.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/PairTPHEqualTPH.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/PairTPHequalRefTypeOrWildcardType.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/PairTPHsmallerTPH.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/ResolvedType.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/ResultPair.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/ResultPairVisitor.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/ResultSet.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/ResultSetVisitor.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/typeAlgo/GenericsResolverSameName.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/typeAlgo/TYPE.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/typeAlgo/TYPEStmt.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/GuavaSetOperations.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/MartelliMontanariUnify.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/Match.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/RuleSet.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/TypeUnify.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/TypeUnify2Task.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/TypeUnifyTask.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/Unifikationsalgorithmus.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/UnifyResultEvent.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/UnifyResultListener.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/UnifyResultListenerImpl.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/UnifyResultModel.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/UnifyTaskModel.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/distributeVariance.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/freshPlaceholder.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/interfaces/IFiniteClosure.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/interfaces/IMatch.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/interfaces/IRuleSet.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/interfaces/ISetOperations.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/interfaces/IUnify.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/interfaces/UnifyTypeVisitor.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/ExtendsType.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/FiniteClosure.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/FunInterfaceType.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/FunNType.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/Node.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/OrderingExtend.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/OrderingUnifyPair.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/PairOperator.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/PlaceholderType.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/ReferenceType.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/SuperType.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/TypeParams.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/Unifier.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/UnifyPair.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/UnifyType.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/WildcardType.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/hashKeyType.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/visitUnifyTypeVisitor.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/util/BiRelation.java create mode 100644 LanguageServer/src/main/java/de/dhbw/compiler/util/Pair.java diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/bytecode/CodeGenException.java b/LanguageServer/src/main/java/de/dhbw/compiler/bytecode/CodeGenException.java new file mode 100644 index 0000000..0c2be3e --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/bytecode/CodeGenException.java @@ -0,0 +1,7 @@ +package de.dhbw.compiler.bytecode; + +public class CodeGenException extends RuntimeException { + public CodeGenException(String cause) { + super(cause); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/bytecode/Codegen.java b/LanguageServer/src/main/java/de/dhbw/compiler/bytecode/Codegen.java new file mode 100644 index 0000000..5ac6df8 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/bytecode/Codegen.java @@ -0,0 +1,1801 @@ +package de.dhbw.compiler.bytecode; + +import de.dhbw.compiler.core.JavaTXCompiler; +import de.dhbw.compiler.exceptions.NotImplementedException; +import de.dhbw.compiler.parser.NullToken; +import de.dhbw.compiler.parser.scope.JavaClassName; +import de.dhbw.compiler.syntaxtree.ClassOrInterface; +import de.dhbw.compiler.syntaxtree.Method; +import de.dhbw.compiler.syntaxtree.Pattern; +import de.dhbw.compiler.syntaxtree.type.RefType; +import de.dhbw.compiler.target.generate.ASTToTargetAST; +import de.dhbw.compiler.target.generate.StatementToTargetExpression; +import de.dhbw.compiler.target.tree.*; +import de.dhbw.compiler.target.tree.expression.*; +import de.dhbw.compiler.target.tree.type.*; +import org.antlr.v4.codegen.Target; +import org.objectweb.asm.*; + +import java.lang.invoke.*; +import java.lang.reflect.Modifier; +import java.util.*; +import java.util.stream.IntStream; + +import static org.objectweb.asm.Opcodes.*; +import static de.dhbw.compiler.target.tree.expression.TargetBinaryOp.*; +import static de.dhbw.compiler.target.tree.expression.TargetLiteral.*; + +public class Codegen { + private final TargetStructure clazz; + private final ClassWriter cw; + public final String className; + private int lambdaCounter = 0; + private final HashMap lambdas = new HashMap<>(); + private final JavaTXCompiler compiler; + private final ASTToTargetAST converter; + + private class CustomClassWriter extends ClassWriter { + public CustomClassWriter() { + super(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); + } + + @Override + protected ClassLoader getClassLoader() { + return compiler.getClassLoader(); + } + } + + public Codegen(TargetStructure clazz, JavaTXCompiler compiler, ASTToTargetAST converter) { + this.clazz = clazz; + this.className = clazz.qualifiedName().getClassName(); + this.cw = new CustomClassWriter(); + this.compiler = compiler; + this.converter = converter; + } + + private record LocalVar(int index, String name, TargetType type) { + } + + private static class Scope { + Scope parent; + Map locals = new HashMap<>(); + + Scope(Scope parent) { + this.parent = parent; + } + + void add(LocalVar var) { + locals.put(var.name, var); + } + + LocalVar get(String name) { + var local = locals.get(name); + if (local != null) { + return local; + } + if (parent != null) { + return parent.get(name); + } + throw new CodeGenException("Unknown symbol '" + name + "'"); + } + } + + private static class BreakEnv { + String labelName; // TODO This is for labeled statements (Not implemented) + Label startLabel; + Label endLabel; + } + + private static class State { + Scope scope = new Scope(null); + int localCounter; + MethodVisitor mv; + TargetType returnType; + + Stack breakStack = new Stack<>(); + Stack switchResultValue = new Stack<>(); + + State(TargetType returnType, MethodVisitor mv, int localCounter) { + this.returnType = returnType; + this.mv = mv; + this.localCounter = localCounter; + } + + void enterScope() { + this.scope = new Scope(this.scope); + } + + void exitScope() { + this.scope = this.scope.parent; + } + + LocalVar createVariable(TargetType type) { + return createVariable("__var" + this.localCounter, type); + } + + LocalVar createVariable(String name, TargetType type) { + var local = new LocalVar(localCounter, name, type); + scope.add(local); + localCounter += 1; + return local; + } + + void pushSwitch() { + switchResultValue.push(this.localCounter++); + } + void popSwitch() { + switchResultValue.pop(); + } + } + + private void popValue(State state, TargetType type) { + if (type.equals(TargetType.Double) || type.equals(TargetType.Long)) + state.mv.visitInsn(POP2); + else + state.mv.visitInsn(POP); + } + + private void boxPrimitive(State state, TargetType type) { + var mv = state.mv; + if (type.equals(TargetType.Boolean) || type.equals(TargetType.boolean_)) { + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false); + } else if (type.equals(TargetType.Byte) || type.equals(TargetType.byte_)) { + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false); + } else if (type.equals(TargetType.Double) || type.equals(TargetType.double_)) { + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false); + } else if (type.equals(TargetType.Long) || type.equals(TargetType.long_)) { + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false); + } else if (type.equals(TargetType.Integer) || type.equals(TargetType.int_)) { + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); + } else if (type.equals(TargetType.Float) || type.equals(TargetType.float_)) { + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false); + } 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/Character", "valueOf", "(C)Ljava/lang/Character;", false); + } + } + + private void unboxPrimitive(State state, TargetType type) { + var mv = state.mv; + if (type.equals(TargetType.Boolean)) { + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false); + } else if (type.equals(TargetType.Byte)) { + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B", false); + } else if (type.equals(TargetType.Double)) { + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D", false); + } else if (type.equals(TargetType.Long)) { + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J", false); + } else if (type.equals(TargetType.Integer)) { + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); + } else if (type.equals(TargetType.Float)) { + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F", false); + } 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/Character", "charValue", "()C", false); + } + } + + private void generateRelationalOperator(State state, TargetRelationalOp op, TargetType type, int code) { + var mv = state.mv; + Label if_true = new Label(); + Label end = new Label(); + generate(state, op.left()); + convertTo(state, op.left().type(), type); + generate(state, op.right()); + convertTo(state, op.right().type(), type); + mv.visitJumpInsn(code, if_true); + mv.visitInsn(ICONST_0); + mv.visitJumpInsn(GOTO, end); + mv.visitLabel(if_true); + mv.visitInsn(ICONST_1); + mv.visitLabel(end); + } + + private void generateRelationalOperator(State state, TargetRelationalOp op, TargetType type, int cmp, int code) { + var mv = state.mv; + Label if_true = new Label(); + Label end = new Label(); + generate(state, op.left()); + convertTo(state, op.left().type(), type); + generate(state, op.right()); + convertTo(state, op.right().type(), type); + mv.visitInsn(cmp); + mv.visitJumpInsn(code, if_true); + mv.visitInsn(ICONST_0); + mv.visitJumpInsn(GOTO, end); + mv.visitLabel(if_true); + mv.visitInsn(ICONST_1); + mv.visitLabel(end); + } + + private void convertToString(State state, TargetType type) { + var mv = state.mv; + if (type.equals(TargetType.Boolean)) { + mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(Z)Ljava/lang/Boolean;", false); + } else if (type.equals(TargetType.Byte)) { + mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(B)Ljava/lang/Byte;", false); + } else if (type.equals(TargetType.Double)) { + mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(D)Ljava/lang/Double;", false); + } else if (type.equals(TargetType.Long)) { + mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(J)Ljava/lang/Long;", false); + } else if (type.equals(TargetType.Integer)) { + mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(I)Ljava/lang/Integer;", false); + } else if (type.equals(TargetType.Float)) { + mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(F)Ljava/lang/Float;", false); + } else if (type.equals(TargetType.Short)) { + mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(S)Ljava/lang/Short;", false); + } else if (type.equals(TargetType.Char)) { + mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(C)Ljava/lang/Char;", false); + } + } + + private void convertTo(State state, TargetType source, TargetType dest) { + var mv = state.mv; + if (source.equals(dest)) + return; + if (source.equals(TargetType.Long)) { + if (dest.equals(TargetType.Integer)) { + mv.visitInsn(L2I); + } else if (dest.equals(TargetType.Float)) + mv.visitInsn(L2F); + else if (dest.equals(TargetType.Double)) + mv.visitInsn(L2D); + else if (dest.equals(TargetType.Byte) || dest.equals(TargetType.Char) || dest.equals(TargetType.Short)) { + mv.visitInsn(L2I); + convertTo(state, TargetType.Integer, dest); + } + } else if (source.equals(TargetType.Float)) { + if (dest.equals(TargetType.Integer)) + mv.visitInsn(F2I); + else if (dest.equals(TargetType.Double)) + mv.visitInsn(F2D); + else if (dest.equals(TargetType.Long)) + mv.visitInsn(F2L); + else if (dest.equals(TargetType.Byte) || dest.equals(TargetType.Char) || dest.equals(TargetType.Short)) { + mv.visitInsn(F2I); + convertTo(state, TargetType.Integer, dest); + } + } else if (source.equals(TargetType.Double)) { + if (dest.equals(TargetType.Integer)) + mv.visitInsn(D2I); + else if (dest.equals(TargetType.Float)) + mv.visitInsn(D2F); + else if (dest.equals(TargetType.Long)) + mv.visitInsn(D2L); + else if (dest.equals(TargetType.Byte) || dest.equals(TargetType.Char) || dest.equals(TargetType.Short)) { + mv.visitInsn(D2I); + convertTo(state, TargetType.Integer, dest); + } + } else if (source.equals(TargetType.Byte) || source.equals(TargetType.Char) || source.equals(TargetType.Short) || source.equals(TargetType.Integer)) { + if (dest.equals(TargetType.Byte)) + mv.visitInsn(I2B); + else if (dest.equals(TargetType.Char)) + mv.visitInsn(I2C); + else if (dest.equals(TargetType.Short)) + mv.visitInsn(I2S); + else if (dest.equals(TargetType.Long)) + mv.visitInsn(I2L); + else if (dest.equals(TargetType.Float)) + mv.visitInsn(I2F); + else if (dest.equals(TargetType.Double)) + mv.visitInsn(I2D); + } else if (isFunctionalInterface(source) && isFunctionalInterface(dest) && + !(source instanceof TargetFunNType && dest instanceof TargetFunNType)) { + boxFunctionalInterface(state, source, dest); + } else if (!(dest instanceof TargetGenericType)) { + //boxPrimitive(state, source); + mv.visitTypeInsn(CHECKCAST, dest.getInternalName()); + unboxPrimitive(state, dest); + } + } + + record TypePair(TargetType from, TargetType to) {} + private Map funWrapperClasses = new HashMap<>(); + + private void boxFunctionalInterface(State state, TargetType source, TargetType dest) { + var mv = state.mv; + var className = "FunWrapper$$" + + source.name().replaceAll("\\.", "\\$") + + "$_$" + + dest.name().replaceAll("\\.", "\\$"); + + funWrapperClasses.put(new TypePair(source, dest), className); + mv.visitTypeInsn(NEW, className); + mv.visitInsn(DUP_X1); + mv.visitInsn(SWAP); + mv.visitMethodInsn(INVOKESPECIAL, className, "", "(" + source.toDescriptor() + ")V", false); + } + + private boolean isFunctionalInterface(TargetType type) { + if (type instanceof TargetFunNType) return true; + if (type instanceof TargetRefType) { + var clazz = compiler.getClass(new JavaClassName(type.name())); + return (clazz.getModifiers() & Modifier.INTERFACE) != 0 && clazz.isFunctionalInterface(); + } + + return false; + } + + private TargetType largerType(TargetType left, TargetType right) { + if (left.equals(TargetType.String) || right.equals(TargetType.String)) { + return TargetType.String; + } else if (left.equals(TargetType.Double) || right.equals(TargetType.Double)) { + return TargetType.Double; + } else if (left.equals(TargetType.Float) || right.equals(TargetType.Float)) { + return TargetType.Float; + } else if (left.equals(TargetType.Long) || right.equals(TargetType.Long)) { + return TargetType.Long; + } else if (left.equals(TargetType.Integer) || right.equals(TargetType.Integer)) { + return TargetType.Integer; + } else if (left.equals(TargetType.Short) || right.equals(TargetType.Short)) { + return TargetType.Short; + } + return left; + } + + private void generateBinaryOp(State state, TargetBinaryOp op) { + var mv = state.mv; + switch (op) { + case Add add: { + if (add.type().equals(TargetType.String)) { + mv.visitTypeInsn(NEW, "java/lang/StringBuilder"); + mv.visitInsn(DUP); + generate(state, add.left()); + convertToString(state, add.left().type()); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "", "(Ljava/lang/String;)V", false); + } else { + generate(state, add.left()); + convertTo(state, add.left().type(), add.type()); + generate(state, add.right()); + convertTo(state, add.right().type(), add.type()); + var type = add.type(); + if (type.equals(TargetType.Byte) || type.equals(TargetType.Char) || type.equals(TargetType.Integer) || type.equals(TargetType.Short)) { + mv.visitInsn(IADD); + } else if (type.equals(TargetType.Long)) { + mv.visitInsn(LADD); + } else if (type.equals(TargetType.Float)) { + mv.visitInsn(FADD); + } else if (type.equals(TargetType.Double)) { + mv.visitInsn(DADD); + } else { + throw new CodeGenException("Invalid argument to Add expression, type: " + add.type()); + } + } + if (add.type().equals(TargetType.String)) { + generate(state, add.right()); + convertToString(state, add.right().type()); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false); + } + break; + } + case Sub sub: { + generate(state, sub.left()); + convertTo(state, sub.left().type(), op.type()); + generate(state, sub.right()); + convertTo(state, sub.right().type(), op.type()); + var type = sub.type(); + if (type.equals(TargetType.Byte) || type.equals(TargetType.Char) || type.equals(TargetType.Integer) || type.equals(TargetType.Short)) { + mv.visitInsn(ISUB); + } else if (type.equals(TargetType.Long)) { + mv.visitInsn(LSUB); + } else if (type.equals(TargetType.Float)) { + mv.visitInsn(FSUB); + } else if (type.equals(TargetType.Double)) { + mv.visitInsn(DSUB); + } else { + throw new CodeGenException("Invalid argument to Sub expression"); + } + break; + } + case Div div: { + generate(state, div.left()); + convertTo(state, div.left().type(), op.type()); + generate(state, div.right()); + convertTo(state, div.right().type(), op.type()); + var type = div.type(); + if (type.equals(TargetType.Byte) || type.equals(TargetType.Char) || type.equals(TargetType.Integer) || type.equals(TargetType.Short)) { + mv.visitInsn(IDIV); + } else if (type.equals(TargetType.Long)) { + mv.visitInsn(LDIV); + } else if (type.equals(TargetType.Float)) { + mv.visitInsn(FDIV); + } else if (type.equals(TargetType.Double)) { + mv.visitInsn(DDIV); + } else { + throw new CodeGenException("Invalid argument to Div expression"); + } + break; + } + case Mul mul: { + generate(state, mul.left()); + convertTo(state, mul.left().type(), op.type()); + generate(state, mul.right()); + convertTo(state, mul.right().type(), op.type()); + var type = mul.type(); + if (type.equals(TargetType.Byte) || type.equals(TargetType.Char) || type.equals(TargetType.Integer) || type.equals(TargetType.Short)) { + mv.visitInsn(IMUL); + } else if (type.equals(TargetType.Long)) { + mv.visitInsn(LMUL); + } else if (type.equals(TargetType.Float)) { + mv.visitInsn(FMUL); + } else if (type.equals(TargetType.Double)) { + mv.visitInsn(DMUL); + } else { + throw new CodeGenException("Invalid argument to Mul expression"); + } + break; + } + case Rem rem: { + generate(state, rem.left()); + convertTo(state, rem.left().type(), op.type()); + generate(state, rem.right()); + convertTo(state, rem.right().type(), op.type()); + var type = rem.type(); + if (type.equals(TargetType.Byte) || type.equals(TargetType.Char) || type.equals(TargetType.Integer) || type.equals(TargetType.Short)) { + mv.visitInsn(IREM); + } else if (type.equals(TargetType.Long)) { + mv.visitInsn(LREM); + } else if (type.equals(TargetType.Float)) { + mv.visitInsn(FREM); + } else if (type.equals(TargetType.Double)) { + mv.visitInsn(DREM); + } else { + throw new CodeGenException("Invalid argument to Rem expression"); + } + break; + } + case Or or: { + Label or_false = new Label(); + Label or_true = new Label(); + Label end = new Label(); + generate(state, or.left()); + mv.visitJumpInsn(IFNE, or_true); + generate(state, or.right()); + mv.visitJumpInsn(IFEQ, or_false); + mv.visitLabel(or_true); + mv.visitInsn(ICONST_1); + mv.visitJumpInsn(GOTO, end); + mv.visitLabel(or_false); + mv.visitInsn(ICONST_0); + mv.visitLabel(end); + break; + } + case And and: { + Label and_false = new Label(); + Label end = new Label(); + generate(state, and.left()); + mv.visitJumpInsn(IFEQ, and_false); + generate(state, and.right()); + mv.visitJumpInsn(IFEQ, and_false); + mv.visitInsn(ICONST_1); + mv.visitJumpInsn(GOTO, end); + mv.visitLabel(and_false); + mv.visitInsn(ICONST_0); + mv.visitLabel(end); + break; + } + case BAnd band: { + generate(state, band.left()); + convertTo(state, band.left().type(), op.type()); + generate(state, band.right()); + convertTo(state, band.right().type(), op.type()); + if (band.type().equals(TargetType.Long)) + mv.visitInsn(LAND); + else + mv.visitInsn(IAND); + break; + } + case BOr bor: { + generate(state, bor.left()); + convertTo(state, bor.left().type(), op.type()); + generate(state, bor.right()); + convertTo(state, bor.right().type(), op.type()); + if (bor.type().equals(TargetType.Long)) + mv.visitInsn(LOR); + else + mv.visitInsn(IOR); + break; + } + case XOr xor: { + generate(state, xor.left()); + convertTo(state, xor.left().type(), op.type()); + generate(state, xor.right()); + convertTo(state, xor.right().type(), op.type()); + if (xor.type().equals(TargetType.Long)) + mv.visitInsn(LXOR); + else + mv.visitInsn(IXOR); + break; + } + case Instof instof: { + // TODO + throw new NotImplementedException(); + } + case Shl shl: { + generate(state, shl.left()); + convertTo(state, shl.left().type(), op.type()); + generate(state, shl.right()); + convertTo(state, shl.right().type(), op.type()); + if (shl.type().equals(TargetType.Long)) + mv.visitInsn(LSHL); + else + mv.visitInsn(ISHL); + break; + } + case Shr shr: { + generate(state, shr.left()); + convertTo(state, shr.left().type(), op.type()); + generate(state, shr.right()); + convertTo(state, shr.right().type(), op.type()); + if (shr.type().equals(TargetType.Long)) + mv.visitInsn(LSHR); + else + mv.visitInsn(ISHR); + break; + } + case UShr ushr: { + generate(state, ushr.left()); + convertTo(state, ushr.left().type(), op.type()); + generate(state, ushr.right()); + convertTo(state, ushr.right().type(), op.type()); + if (ushr.type().equals(TargetType.Long)) + mv.visitInsn(LUSHR); + else + mv.visitInsn(IUSHR); + break; + } + case Greater greater: { + var type = largerType(greater.left().type(), greater.right().type()); + if (type.equals(TargetType.Long)) { + generateRelationalOperator(state, greater, type, LCMP, IFGT); + } else if (type.equals(TargetType.Float)) { + generateRelationalOperator(state, greater, type, FCMPL, IFGT); + } else if (type.equals(TargetType.Double)) { + generateRelationalOperator(state, greater, type, DCMPL, IFGT); + } else { + generateRelationalOperator(state, greater, type, IF_ICMPGT); + } + break; + } + case Less less: { + var type = largerType(less.left().type(), less.right().type()); + if (type.equals(TargetType.Long)) { + generateRelationalOperator(state, less, type, LCMP, IFLT); + } else if (type.equals(TargetType.Float)) { + generateRelationalOperator(state, less, type, FCMPL, IFLT); + } else if (type.equals(TargetType.Double)) { + generateRelationalOperator(state, less, type, DCMPL, IFLT); + } else { + generateRelationalOperator(state, less, type, IF_ICMPLT); + } + break; + } + case GreaterOrEqual greaterOrEqual: { + var type = largerType(greaterOrEqual.left().type(), greaterOrEqual.right().type()); + if (type.equals(TargetType.Long)) { + generateRelationalOperator(state, greaterOrEqual, type, LCMP, IFGE); + } else if (type.equals(TargetType.Float)) { + generateRelationalOperator(state, greaterOrEqual, type, FCMPL, IFGE); + } else if (type.equals(TargetType.Double)) { + generateRelationalOperator(state, greaterOrEqual, type, DCMPL, IFGE); + } else { + generateRelationalOperator(state, greaterOrEqual, type, IF_ICMPGE); + } + break; + } + case LessOrEqual lessOrEqual: { + var type = largerType(lessOrEqual.left().type(), lessOrEqual.right().type()); + if (type.equals(TargetType.Long)) { + generateRelationalOperator(state, lessOrEqual, type, LCMP, IFLE); + } else if (type.equals(TargetType.Float)) { + generateRelationalOperator(state, lessOrEqual, type, FCMPL, IFLE); + } else if (type.equals(TargetType.Double)) { + generateRelationalOperator(state, lessOrEqual, type, DCMPL, IFLE); + } else { + generateRelationalOperator(state, lessOrEqual, type, IF_ICMPLE); + } + break; + } + case Equal equal: { + var type = largerType(equal.left().type(), equal.right().type()); + if (type.equals(TargetType.Long)) { + generateRelationalOperator(state, equal, type, LCMP, IFEQ); + } else if (type.equals(TargetType.Float)) { + generateRelationalOperator(state, equal, type, FCMPL, IFEQ); + } else if (type.equals(TargetType.Double)) { + generateRelationalOperator(state, equal, type, DCMPL, IFEQ); + } else if (type.equals(TargetType.Char) || type.equals(TargetType.Short) || type.equals(TargetType.Byte) || type.equals(TargetType.Integer) || type.equals(TargetType.Boolean)) { + generateRelationalOperator(state, equal, type, IF_ICMPEQ); + } else { + generateRelationalOperator(state, equal, type, IF_ACMPEQ); + } + break; + } + case NotEqual notEqual: { + var type = largerType(notEqual.left().type(), notEqual.right().type()); + if (type.equals(TargetType.Long)) { + generateRelationalOperator(state, notEqual, type, LCMP, IFNE); + } else if (type.equals(TargetType.Float)) { + generateRelationalOperator(state, notEqual, type, FCMPL, IFNE); + } else if (type.equals(TargetType.Double)) { + generateRelationalOperator(state, notEqual, type, DCMPL, IFNE); + } else if (type.equals(TargetType.Char) || type.equals(TargetType.Short) || type.equals(TargetType.Byte) || type.equals(TargetType.Integer)) { + generateRelationalOperator(state, notEqual, type, IF_ICMPNE); + } else { + generateRelationalOperator(state, notEqual, type, IF_ACMPNE); + } + break; + } + default: { + throw new NotImplementedException(); + } + } + } + + private void afterIncDec(State state, TargetUnaryOp op) { + var mv = state.mv; + if (op.expr() instanceof TargetLocalVar localVar) { + mv.visitVarInsn(ASTORE, state.scope.get(localVar.name()).index); + } else if (op.expr() instanceof TargetFieldVar fieldVar) { + generate(state, fieldVar.left()); + mv.visitInsn(SWAP); + mv.visitFieldInsn(PUTFIELD, fieldVar.owner().getInternalName(), fieldVar.right(), fieldVar.type().toSignature()); + } + } + + private void generateUnaryOp(State state, TargetUnaryOp op) { + var mv = state.mv; + switch (op) { + case TargetUnaryOp.Add add -> + // This literally does nothing + generate(state, add.expr()); + case TargetUnaryOp.Negate negate -> { + generate(state, negate.expr()); + if (negate.type().equals(TargetType.Double)) + mv.visitInsn(DNEG); + else if (negate.type().equals(TargetType.Float)) + mv.visitInsn(FNEG); + else if (negate.type().equals(TargetType.Long)) + mv.visitInsn(LNEG); + else + mv.visitInsn(INEG); + } + case TargetUnaryOp.Not not -> { + generate(state, not.expr()); + if (not.type().equals(TargetType.Long)) { + mv.visitLdcInsn(-1L); + mv.visitInsn(LXOR); + } else { + mv.visitInsn(ICONST_M1); + mv.visitInsn(IXOR); + } + } + case TargetUnaryOp.PreIncrement preIncrement -> { + generate(state, preIncrement.expr()); + if (preIncrement.type().equals(TargetType.Float)) { + mv.visitLdcInsn(1F); + mv.visitInsn(FADD); + mv.visitInsn(DUP); + } else if (preIncrement.type().equals(TargetType.Double)) { + mv.visitLdcInsn(1D); + mv.visitInsn(DADD); + mv.visitInsn(DUP2); + } else if (preIncrement.type().equals(TargetType.Long)) { + mv.visitLdcInsn(1L); + mv.visitInsn(LADD); + mv.visitInsn(DUP2); + } else { + mv.visitLdcInsn(1); + mv.visitInsn(IADD); + mv.visitInsn(DUP); + } + boxPrimitive(state, preIncrement.type()); + afterIncDec(state, preIncrement); + } + case TargetUnaryOp.PreDecrement preDecrement -> { + generate(state, preDecrement.expr()); + if (preDecrement.type().equals(TargetType.Float)) { + mv.visitLdcInsn(1F); + mv.visitInsn(FSUB); + mv.visitInsn(DUP); + } else if (preDecrement.type().equals(TargetType.Double)) { + mv.visitLdcInsn(1D); + mv.visitInsn(DSUB); + mv.visitInsn(DUP2); + } else if (preDecrement.type().equals(TargetType.Long)) { + mv.visitLdcInsn(1L); + mv.visitInsn(LSUB); + mv.visitInsn(DUP2); + } else { + mv.visitLdcInsn(1); + mv.visitInsn(ISUB); + mv.visitInsn(DUP); + } + boxPrimitive(state, preDecrement.type()); + afterIncDec(state, preDecrement); + } + case TargetUnaryOp.PostIncrement postIncrement -> { + generate(state, postIncrement.expr()); + if (postIncrement.type().equals(TargetType.Float)) { + mv.visitInsn(DUP); + mv.visitLdcInsn(1F); + mv.visitInsn(FADD); + } else if (postIncrement.type().equals(TargetType.Double)) { + mv.visitInsn(DUP2); + mv.visitLdcInsn(1D); + mv.visitInsn(DADD); + } else if (postIncrement.type().equals(TargetType.Long)) { + mv.visitInsn(DUP2); + mv.visitLdcInsn(1L); + mv.visitInsn(LADD); + } else { + mv.visitInsn(DUP); + mv.visitLdcInsn(1); + mv.visitInsn(IADD); + } + boxPrimitive(state, postIncrement.type()); + afterIncDec(state, postIncrement); + } + case TargetUnaryOp.PostDecrement postDecrement -> { + generate(state, postDecrement.expr()); + if (postDecrement.type().equals(TargetType.Float)) { + mv.visitInsn(DUP); + mv.visitLdcInsn(1F); + mv.visitInsn(FSUB); + } else if (postDecrement.type().equals(TargetType.Double)) { + mv.visitInsn(DUP2); + mv.visitLdcInsn(1D); + mv.visitInsn(DSUB); + } else if (postDecrement.type().equals(TargetType.Long)) { + mv.visitInsn(DUP2); + mv.visitLdcInsn(1L); + mv.visitInsn(LSUB); + } else { + mv.visitInsn(DUP); + mv.visitLdcInsn(1); + mv.visitInsn(ISUB); + } + boxPrimitive(state, postDecrement.type()); + afterIncDec(state, postDecrement); + } + } + } + + private void generateLambdaExpression(State state, TargetLambdaExpression lambda) { + var mv = state.mv; + + String methodName = "apply"; + TargetMethod.Signature signature = new TargetMethod.Signature(Set.of(), + lambda.signature().parameters().stream().map( + par -> par.withType(TargetType.Object)).toList(), + lambda.signature().returnType() != null ? TargetType.Object : null); + + var parameters = new ArrayList<>(lambda.captures()); + parameters.addAll(signature.parameters()); + var implSignature = new TargetMethod.Signature(Set.of(), parameters, lambda.signature().returnType()); + + TargetMethod impl; + if (lambdas.containsKey(lambda)) { + impl = lambdas.get(lambda); + } else { + var name = "lambda$" + lambdaCounter++; + + impl = new TargetMethod(0, name, lambda.block(), implSignature, null); + generateMethod(impl); + lambdas.put(lambda, impl); + } + + var mt = MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, MethodType.class, MethodHandle.class, MethodType.class); + + var bootstrap = new Handle(H_INVOKESTATIC, "java/lang/invoke/LambdaMetafactory", "metafactory", mt.toMethodDescriptorString(), false); + var handle = new Handle(H_INVOKEVIRTUAL, clazz.getName(), impl.name(), implSignature.getDescriptor(), false); + + var params = new ArrayList(); + params.add(new TargetRefType(clazz.qualifiedName().getClassName())); + params.addAll(lambda.captures().stream().map(mp -> mp.pattern().type()).toList()); + + mv.visitVarInsn(ALOAD, 0); + for (var index = 0; index < lambda.captures().size(); index++) { + var capture = lambda.captures().get(index); + var pattern = (TargetTypePattern) capture.pattern(); + var variable = state.scope.get(pattern.name()); + mv.visitVarInsn(ALOAD, variable.index); + mv.visitTypeInsn(CHECKCAST, capture.pattern().type().getInternalName()); + } + + var descriptor = TargetMethod.getDescriptor(lambda.type(), params.toArray(TargetType[]::new)); + mv.visitInvokeDynamicInsn(methodName, descriptor, bootstrap, Type.getType(signature.getSignature()), handle, Type.getType(signature.getDescriptor())); + } + + private int findReturnCode(TargetType returnType) { + if (returnType.equals(TargetType.boolean_) + || returnType.equals(TargetType.char_) + || returnType.equals(TargetType.int_) + || returnType.equals(TargetType.short_) + || returnType.equals(TargetType.byte_)) + return IRETURN; + else if (returnType.equals(TargetType.long_)) + return LRETURN; + else if (returnType.equals(TargetType.float_)) + return FRETURN; + else if (returnType.equals(TargetType.double_)) + return DRETURN; + return ARETURN; + } + + private int findLoadCode(TargetType loadType) { + if (loadType.equals(TargetType.boolean_) + || loadType.equals(TargetType.char_) + || loadType.equals(TargetType.int_) + || loadType.equals(TargetType.short_) + || loadType.equals(TargetType.byte_)) + return ILOAD; + else if (loadType.equals(TargetType.long_)) + return LLOAD; + else if (loadType.equals(TargetType.float_)) + return FLOAD; + else if (loadType.equals(TargetType.double_)) + return DLOAD; + return ALOAD; + } + + private void generate(State state, TargetExpression expr) { + var mv = state.mv; + switch (expr) { + case TargetClassName ignored: + break; // NOP + case TargetBlock block: { + var localCounter = state.localCounter; + state.enterScope(); + for (var e : block.statements()) { + generate(state, e); + if (e instanceof TargetMethodCall) { + if (e.type() != null) + popValue(state, e.type()); + } else if (e instanceof TargetAssign) { + mv.visitInsn(POP); // TODO Nasty fix, we don't know if it is a primitive double or long + } else if (e instanceof TargetStatementExpression se) { + popValue(state, se.type()); + } + } + state.exitScope(); + state.localCounter = localCounter; + break; + } + case TargetCast cast: + generate(state, cast.expr()); + convertTo(state, cast.expr().type(), cast.type()); + break; + case TargetInstanceOf instanceOf: + generateInstanceOf(state, instanceOf); + break; + case TargetLiteral literal: + switch (literal) { + case IntLiteral intLiteral -> mv.visitLdcInsn(intLiteral.value()); + case FloatLiteral floatLiteral -> mv.visitLdcInsn(floatLiteral.value()); + case LongLiteral longLiteral -> mv.visitLdcInsn(longLiteral.value()); + 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); + } else { + mv.visitInsn(ICONST_0); + } + } + } + break; + case TargetVarDecl varDecl: { + var local = state.createVariable(varDecl.name(), varDecl.varType()); + if (varDecl.value() != null) { + generate(state, varDecl.value()); + boxPrimitive(state, varDecl.varType()); + mv.visitVarInsn(ASTORE, local.index()); + } else { + mv.visitInsn(ACONST_NULL); + mv.visitVarInsn(ASTORE, local.index()); + } + break; + } + case TargetBinaryOp op: + generateBinaryOp(state, op); + break; + case TargetUnaryOp op: + generateUnaryOp(state, op); + break; + case TargetAssign assign: { + switch (assign.left()) { + case TargetLocalVar localVar -> { + generate(state, assign.right()); + + convertTo(state, assign.right().type(), localVar.type()); + boxPrimitive(state, localVar.type()); + var local = state.scope.get(localVar.name()); + mv.visitInsn(DUP); + mv.visitVarInsn(ASTORE, local.index()); + } + case TargetFieldVar dot -> { + var fieldType = dot.type(); + if (!(dot.left() instanceof TargetThis && dot.isStatic())) + generate(state, dot.left()); + + generate(state, assign.right()); + + convertTo(state, assign.right().type(), fieldType); + boxPrimitive(state, fieldType); + if (dot.isStatic()) + mv.visitInsn(DUP); + else + mv.visitInsn(DUP_X1); + mv.visitFieldInsn(dot.isStatic() ? PUTSTATIC : PUTFIELD, dot.owner().getInternalName(), dot.right(), fieldType.toSignature()); + } + default -> throw new CodeGenException("Invalid assignment"); + } + break; + } + case TargetLocalVar localVar: { + LocalVar local = state.scope.get(localVar.name()); + mv.visitVarInsn(ALOAD, local.index()); + // This is a bit weird but sometimes the types don't match (see lambda expressions) + convertTo(state, local.type(), localVar.type()); + unboxPrimitive(state, local.type()); + break; + } + case TargetFieldVar dot: { + if (!dot.isStatic()) + generate(state, dot.left()); + mv.visitFieldInsn(dot.isStatic() ? GETSTATIC : GETFIELD, dot.left().type().getInternalName(), dot.right(), dot.type().toSignature()); + unboxPrimitive(state, dot.type()); + break; + } + case TargetFor _for: { + state.enterScope(); + var localCounter = state.localCounter; + 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(); + mv.visitLabel(start); + if (_for.termination() != null) + generate(state, _for.termination()); + else + mv.visitInsn(ICONST_1); + mv.visitJumpInsn(IFEQ, end); + + var env = new BreakEnv(); + env.startLabel = start; + env.endLabel = end; + + state.breakStack.push(env); + generate(state, _for.body()); + state.breakStack.pop(); + + if (_for.increment() != null) { + _for.increment().forEach(e -> { + generate(state, e); + if (e.type() != null) { + popValue(state, e.type()); + } + }); + } + mv.visitJumpInsn(GOTO, start); + mv.visitLabel(end); + state.exitScope(); + state.localCounter = localCounter; + break; + } + case TargetForEach forEach: + generateForEach(forEach, state); + break; + case TargetWhile _while: { + Label start = new Label(); + Label end = new Label(); + mv.visitLabel(start); + generate(state, _while.cond()); + mv.visitJumpInsn(IFEQ, end); + + var env = new BreakEnv(); + env.startLabel = start; + env.endLabel = end; + + state.breakStack.push(env); + generate(state, _while.body()); + state.breakStack.pop(); + + mv.visitJumpInsn(GOTO, start); + mv.visitLabel(end); + break; + } + case TargetDo _do: { + Label start = new Label(); + Label end = new Label(); + Label check = new Label(); + + var env = new BreakEnv(); + env.startLabel = check; + env.endLabel = end; + + mv.visitLabel(start); + state.breakStack.push(env); + generate(state, _do.body()); + state.breakStack.pop(); + + mv.visitLabel(check); + generate(state, _do.cond()); + mv.visitJumpInsn(IFEQ, end); + mv.visitJumpInsn(GOTO, start); + mv.visitLabel(end); + break; + } + case TargetIf _if: { + generate(state, _if.cond()); + Label _else = new Label(); + Label end = new Label(); + mv.visitJumpInsn(IFEQ, _else); + generate(state, _if.if_body()); + mv.visitJumpInsn(GOTO, end); + mv.visitLabel(_else); + if (_if.else_body() != null) { + generate(state, _if.else_body()); + } + mv.visitLabel(end); + break; + } + case TargetReturn ret: { + if (ret.expression() != null && state.returnType != null) { + if (state.returnType instanceof TargetPrimitiveType) { + generate(state, ret.expression()); + + unboxPrimitive(state, state.returnType); + mv.visitInsn(findReturnCode(state.returnType)); + } else { + generate(state, ret.expression()); + boxPrimitive(state, ret.expression().type()); + convertTo(state, ret.expression().type(), state.returnType); + mv.visitInsn(ARETURN); + } + } else + mv.visitInsn(RETURN); + break; + } + case TargetYield yield: { + generate(state, yield.expression()); + try { + yieldValue(state, yield.expression().type()); + mv.visitJumpInsn(GOTO, state.breakStack.peek().endLabel); + } catch (EmptyStackException e) { + throw new CodeGenException("Yield outside of switch expression"); + } + break; + } + case TargetSwitch _switch: { + generateSwitch(state, _switch); + break; + } + case TargetBreak brk: { + if (state.breakStack.isEmpty()) throw new CodeGenException("Break outside of switch or loop"); + mv.visitJumpInsn(GOTO, state.breakStack.peek().endLabel); + break; + } + case TargetContinue cnt: { + if (state.breakStack.isEmpty()) throw new CodeGenException("Continue outside of loop"); + var env = state.breakStack.peek(); + if (env.startLabel == null) throw new CodeGenException("Continue outside of loop"); + mv.visitJumpInsn(GOTO, env.startLabel); + break; + } + case TargetThis _this: { + mv.visitVarInsn(ALOAD, 0); + break; + } + case TargetSuper _super: { + mv.visitVarInsn(ALOAD, 0); + break; + } + case TargetMethodCall call: { + if (!call.isStatic()) { + generate(state, call.expr()); + boxPrimitive(state, call.expr().type()); + } + for (var i = 0; i < call.args().size(); i++) { + var e = call.args().get(i); + var arg = call.parameterTypes().get(i); + generate(state, e); + convertTo(state, e.type(), arg); + if (!(arg instanceof TargetPrimitiveType)) + boxPrimitive(state, e.type()); + } + var descriptor = call.getDescriptor(); + if (call.owner() instanceof TargetFunNType) // Decay FunN + descriptor = TargetMethod.getDescriptor(call.returnType() == null ? null : TargetType.Object, call.parameterTypes().stream().map(x -> TargetType.Object).toArray(TargetType[]::new)); + + int insn = INVOKEVIRTUAL; + if (call.isStatic()) insn = INVOKESTATIC; + else if (call.isInterface()) insn = INVOKEINTERFACE; + else if (call.name().equals("") || call.expr() instanceof TargetSuper || call.isPrivate()) insn = INVOKESPECIAL; + + mv.visitMethodInsn(insn, call.owner().getInternalName(), call.name(), descriptor, call.isInterface()); + + if (call.type() != null && call.returnType() != null && !(call.returnType() instanceof TargetPrimitiveType)) { + if (!call.returnType().equals(call.type()) && !(call.type() instanceof TargetGenericType)) + mv.visitTypeInsn(CHECKCAST, call.type().getInternalName()); + unboxPrimitive(state, call.type()); + } + break; + } + case TargetLambdaExpression lambda: + generateLambdaExpression(state, lambda); + break; + case TargetNew _new: { + mv.visitTypeInsn(NEW, _new.type().getInternalName()); + mv.visitInsn(DUP); + for (TargetExpression e : _new.params()) { + generate(state, e); + boxPrimitive(state, e.type()); + } + mv.visitMethodInsn(INVOKESPECIAL, _new.type().getInternalName(), "", _new.getDescriptor(), false); + break; + } + case TargetThrow _throw: { + generate(state, _throw.expr()); + mv.visitInsn(ATHROW); + break; + } + case TargetTernary ternary: { + generate(state, ternary.cond()); + var iffalse = new Label(); + var end = new Label(); + mv.visitJumpInsn(IFEQ, iffalse); + generate(state, ternary.iftrue()); + convertTo(state, ternary.iftrue().type(), ternary.type()); + mv.visitJumpInsn(GOTO, end); + mv.visitLabel(iffalse); + generate(state, ternary.iffalse()); + convertTo(state, ternary.iffalse().type(), ternary.type()); + mv.visitLabel(end); + 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.visitTypeInsn(CHECKCAST, localVar.type().getInternalName()); + 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; + } + + throw new NotImplementedException(); + } + + private void yieldValue(State state, TargetType type) { + boxPrimitive(state, type); + state.mv.visitVarInsn(ASTORE, state.switchResultValue.peek()); + } + + private void generateClassicSwitch(State state, TargetSwitch aSwitch) { + // TODO Constant expressions are allowed, we need to evaluate them somehow... + // For now we just assume we get literals... + // TODO This always uses a lookupswitch, a tableswitch may be faster in some cases but we can't generate that every time + // TODO We can't switch on Strings yet, the idea for this (like javac does it) would be to implement the hash code at compile time + // and switch based on that, adding an equals check for every case and going to yet another tableswitch which finally decides which branch to take + var mv = state.mv; + if (aSwitch.isExpression()) + state.pushSwitch(); + + generate(state, aSwitch.expr()); + + state.enterScope(); + + var keys = new int[aSwitch.cases().stream().mapToInt(c -> c.labels().size()).sum()]; + var labels = new Label[keys.length]; + var bodyLabels = new Label[aSwitch.cases().size()]; + + var end = new Label(); + var env = new BreakEnv(); + env.endLabel = end; + state.breakStack.push(env); + + var i = 0; + var j = 0; + for (var case_ : aSwitch.cases()) { + bodyLabels[j] = new Label(); + for (var label : case_.labels()) { + if (!(label instanceof TargetLiteral literal)) + throw new CodeGenException("Labels may only be constants for now"); + keys[i] = (int) literal.value(); + labels[i] = bodyLabels[j]; + i += 1; + } + j += 1; + } + + var defaultLabel = end; + if (aSwitch.default_() != null) { + defaultLabel = new Label(); + } + + mv.visitLookupSwitchInsn(defaultLabel, keys, labels); + + for (var k = 0; k < aSwitch.cases().size(); k++) { + mv.visitLabel(bodyLabels[k]); + var cse = aSwitch.cases().get(k); + generate(state, cse.body()); + if (cse.isSingleExpression() && aSwitch.isExpression()) + yieldValue(state, cse.body().statements().get(0).type()); + if (aSwitch.isExpression()) mv.visitJumpInsn(GOTO, end); + } + + if (aSwitch.default_() != null) { + mv.visitLabel(defaultLabel); + generate(state, aSwitch.default_().body()); + if (aSwitch.default_().isSingleExpression() && aSwitch.isExpression()) + yieldValue(state, aSwitch.default_().body().statements().get(0).type()); + } + + mv.visitLabel(end); + state.breakStack.pop(); + + if (aSwitch.isExpression()) { + mv.visitVarInsn(ALOAD, state.switchResultValue.peek()); + unboxPrimitive(state, aSwitch.type()); + state.popSwitch(); + } + + state.exitScope(); + } + + private void generateEnhancedSwitch(State state, TargetSwitch aSwitch) { + var mv = state.mv; + generate(state, aSwitch.expr()); + var tmp = state.localCounter; + mv.visitInsn(DUP); + mv.visitVarInsn(ASTORE, tmp); + + state.enterScope(); + // This is the index to start the switch from + mv.visitInsn(ICONST_0); + state.pushSwitch(); + + // To be able to skip ahead to the next case + var start = new Label(); + mv.visitLabel(start); + + var end = new Label(); + var env = new BreakEnv(); + env.endLabel = end; + state.breakStack.push(env); + + var mt = MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, Object[].class); + var bootstrap = new Handle(H_INVOKESTATIC, "java/lang/runtime/SwitchBootstraps", "typeSwitch", mt.toMethodDescriptorString(), false); + + var types = new ArrayList(aSwitch.cases().size()); + for (var cse : aSwitch.cases()) for (var label : cse.labels()) { + if (label instanceof TargetTypePattern || label instanceof TargetComplexPattern) + types.add(Type.getObjectType(label.type().getInternalName())); + else if (label instanceof TargetLiteral lit) + types.add(lit.value()); + else if (label instanceof TargetGuard guard) + types.add(Type.getObjectType(guard.inner().type().getInternalName())); + // TODO Same here we need to evaluate constant; + else { + System.out.println(label); + throw new NotImplementedException(); + } + } + + mv.visitInvokeDynamicInsn("typeSwitch", "(Ljava/lang/Object;I)I", bootstrap, types.toArray()); + + var caseLabels = new Label[aSwitch.cases().size()]; + var labels = new Label[aSwitch.cases().stream().mapToInt(c -> c.labels().size()).sum()]; + var j = 0; + for (var i = 0; i < caseLabels.length; i++) { + var cse = aSwitch.cases().get(i); + var label = new Label(); + caseLabels[i] = label; + for (var k = 0; k < cse.labels().size(); k++) { + labels[j] = label; + j += 1; + } + } + + var defaultLabel = new Label(); + mv.visitTableSwitchInsn(0, labels.length - 1, defaultLabel, labels); + + for (var i = 0; i < aSwitch.cases().size(); i++) { + mv.visitLabel(caseLabels[i]); + var cse = aSwitch.cases().get(i); + + if (cse.labels().size() == 1) { + var label = cse.labels().get(0); + if (label instanceof TargetGuard gd) { + state.mv.visitVarInsn(ALOAD, tmp); + bindPattern(state, aSwitch.expr().type(), gd.inner(), start, i, 1); + } else if (label instanceof TargetPattern pat) { + state.mv.visitVarInsn(ALOAD, tmp); + bindPattern(state, aSwitch.expr().type(), pat, start, i, 1); + } + + if (label instanceof TargetGuard gd) { + generate(state, gd.expression()); + var next = new Label(); + mv.visitJumpInsn(IFNE, next); + mv.visitVarInsn(ALOAD, tmp); + // Push the offset onto the stack (this is used by the invokedynamic call) + mv.visitLdcInsn(i + 1); + mv.visitJumpInsn(GOTO, start); + mv.visitLabel(next); + } + } + + generate(state, cse.body()); + if (cse.isSingleExpression() && aSwitch.isExpression()) + yieldValue(state, cse.body().statements().get(0).type()); + if (aSwitch.isExpression()) mv.visitJumpInsn(GOTO, end); + } + + mv.visitLabel(defaultLabel); + if (aSwitch.default_() != null) { + generate(state, aSwitch.default_().body()); + if (aSwitch.default_().isSingleExpression() && aSwitch.isExpression()) + yieldValue(state, aSwitch.default_().body().statements().get(0).type()); + } else { + // throw illegal argument exception on missing default case + mv.visitTypeInsn(NEW, "java/lang/IllegalArgumentException"); + mv.visitInsn(DUP); + mv.visitLdcInsn("Unhandled case value"); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/IllegalArgumentException", "", "(Ljava/lang/String;)V", false); + mv.visitInsn(ATHROW); + } + + mv.visitLabel(end); + //mv.visitInsn(POP); + + state.breakStack.pop(); + if (aSwitch.isExpression()) { + if (aSwitch.type() != null) { + mv.visitVarInsn(ALOAD, state.switchResultValue.peek()); + unboxPrimitive(state, aSwitch.type()); + } + state.popSwitch(); + } + + state.exitScope(); + } + + private void extractField(State state, TargetType type, int i, ClassOrInterface clazz) { + if (i >= clazz.getFieldDecl().size()) + throw new CodeGenException("Couldn't find suitable field accessor for '" + type.name() + "'"); + var field = clazz.getFieldDecl().get(i); + var fieldType = converter.convert(field.getType()); + state.mv.visitMethodInsn(INVOKEVIRTUAL, type.getInternalName(), field.getName(), "()" + fieldType.toSignature(), false); + } + + private void bindPattern(State state, TargetType type, TargetPattern pat, Label start, int index, int depth) { + if (pat.type() instanceof TargetPrimitiveType) + boxPrimitive(state, pat.type()); + + if (pat.type() instanceof TargetRefType) { + state.mv.visitInsn(DUP); + state.mv.visitTypeInsn(INSTANCEOF, pat.type().getInternalName()); + + var cont = new Label(); + state.mv.visitJumpInsn(IFNE, cont); + for (var i = 0; i < depth; i++) { + state.mv.visitInsn(POP); + } + + state.mv.visitVarInsn(ALOAD, state.switchResultValue.peek()); + state.mv.visitLdcInsn(index + 1); + state.mv.visitJumpInsn(GOTO, start); + state.mv.visitLabel(cont); + + state.mv.visitTypeInsn(CHECKCAST, pat.type().getInternalName()); + } + + if (pat instanceof TargetExpressionPattern ep) { + var cur = state.createVariable(pat.type()); + state.mv.visitVarInsn(ASTORE, cur.index); + + var expr = new Equal(pat.type(), new TargetLocalVar(cur.type, cur.name), ep.expression()); + generate(state, expr); + + var cont = new Label(); + state.mv.visitJumpInsn(IFNE, cont); + for (var i = 0; i < depth - 1; i++) { + state.mv.visitInsn(POP); + } + + state.mv.visitVarInsn(ALOAD, state.switchResultValue.peek()); + state.mv.visitLdcInsn(index + 1); + state.mv.visitJumpInsn(GOTO, start); + state.mv.visitLabel(cont); + } else if (pat instanceof TargetTypePattern sp) { + var local = state.createVariable(sp.name(), sp.type()); + state.mv.visitVarInsn(ASTORE, local.index); + } else if (pat instanceof TargetComplexPattern cp) { + if (cp.name() != null) { + state.mv.visitInsn(DUP); + var local = state.createVariable(cp.name(), cp.type()); + state.mv.visitVarInsn(ASTORE, local.index); + } + + var clazz = findClass(new JavaClassName(cp.type().name())); + if (clazz == null) throw new CodeGenException("Class definition for '" + cp.type().name() + "' not found"); + // TODO Check if class is a Record + + for (var i = 0; i < cp.subPatterns().size(); i++) { + state.mv.visitInsn(DUP); + + var subPattern = cp.subPatterns().get(i); + extractField(state, cp.type(), i, clazz); + bindPattern(state, subPattern.type(), subPattern, start, index, depth + 1); + } + state.mv.visitInsn(POP); + } + } + + final Set wrapperTypes = Set.of(TargetType.Long, TargetType.Integer, TargetType.Byte, TargetType.Char, TargetType.Boolean, TargetType.Double, TargetType.Float); + + private void generateSwitch(State state, TargetSwitch aSwitch) { + if (!wrapperTypes.contains(aSwitch.expr().type())) { + generateEnhancedSwitch(state, aSwitch); + return; + } + else for (var case_ : aSwitch.cases()) { + if (case_.labels().stream().anyMatch(c -> c instanceof TargetPattern)) { + generateEnhancedSwitch(state, aSwitch); + return; + } + } + generateClassicSwitch(state, aSwitch); + } + + private void generateField(TargetField field) { + var access = field.access(); + //if ((access & ACC_PRIVATE) == 0 && (access & ACC_PROTECTED) == 0) // TODO Implement access modifiers properly + // access |= ACC_PUBLIC; + + cw.visitField(access, field.name(), field.type().toSignature(), field.type().toDescriptor(), null); + } + + private void generateStaticConstructor(TargetMethod constructor) { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "", "()V", null, null); + mv.visitCode(); + + var state = new State(null, mv, 0); + generate(state, constructor.block()); + + mv.visitInsn(RETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + + private void generateConstructor(TargetConstructor constructor) { + MethodVisitor mv = cw.visitMethod(constructor.access(), "", constructor.getDescriptor(), constructor.getSignature(), null); + if (constructor.txGenerics() != null) + mv.visitAttribute(new JavaTXSignatureAttribute(constructor.getTXSignature())); + + mv.visitCode(); + var state = new State(null, mv, 1); + for (var param : constructor.parameters()) { + var pattern = param.pattern(); + if (pattern instanceof TargetTypePattern tp) + state.createVariable(tp.name(), tp.type()); + else throw new NotImplementedException(); + } + + var stmts = constructor.block().statements(); + generate(state, stmts.get(0)); + if (constructor.fieldInitializer() != null) { + var stmts2 = constructor.fieldInitializer().statements(); + for (TargetExpression expression : stmts2) { + generate(state, expression); + } + } + for (var i = 1; i < stmts.size(); i++) + generate(state, stmts.get(i)); + + mv.visitInsn(RETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + + private void bindLocalVariables(State state, TargetComplexPattern cp, int offset) { + state.mv.visitVarInsn(ALOAD, offset); + + var clazz = findClass(new JavaClassName(cp.type().name())); + if (clazz == null) throw new CodeGenException("Class definition for '" + cp.type().name() + "' not found"); + + for (var i = 0; i < cp.subPatterns().size(); i++) { + var subPattern = cp.subPatterns().get(i); + + if (i < cp.subPatterns().size() - 1) + state.mv.visitInsn(DUP); + + extractField(state, cp.type(), i, clazz); + state.mv.visitTypeInsn(CHECKCAST, subPattern.type().getInternalName()); + offset = state.createVariable(subPattern.name(), subPattern.type()).index; + state.mv.visitVarInsn(ASTORE, offset); + if (subPattern instanceof TargetComplexPattern cp2) { + bindLocalVariables(state, cp2, offset); + } + } + } + + private void generateMethod(TargetMethod method) { + var access = method.access(); + if (method.block() == null) + access |= ACC_ABSTRACT; + if (clazz instanceof TargetInterface) + access |= ACC_PUBLIC; + + // TODO The older codegen has set ACC_PUBLIC for all methods, good for testing but bad for everything else + MethodVisitor mv = cw.visitMethod(access, method.name(), method.getDescriptor(), method.getSignature(), null); + if (method.txSignature() != null) { + mv.visitAttribute(new JavaTXSignatureAttribute(method.getTXSignature())); + } + + if (method.block() != null) { + mv.visitCode(); + var state = new State(method.signature().returnType(), mv, method.isStatic() ? 0 : 1); + var offset = 1; + for (var param : method.signature().parameters()) { + state.createVariable(param.pattern().name(), param.pattern().type()); + } + for (var param : method.signature().parameters()) { + if (param.pattern() instanceof TargetComplexPattern cp) + bindLocalVariables(state, cp, offset); + offset++; + } + generate(state, method.block()); + if (method.signature().returnType() == null) + mv.visitInsn(RETURN); + mv.visitMaxs(0, 0); + } + mv.visitEnd(); + } + + private static String generateSignature(TargetStructure clazz, Set generics) { + String ret = ""; + if (!generics.isEmpty()) { + ret += "<"; + for (var generic : generics) { + ret += generic.name() + ":" + generic.bound().toDescriptor(); + } + ret += ">"; + } + if (clazz.superType() != null) + ret += clazz.superType().toDescriptor(); + for (var intf : clazz.implementingInterfaces()) { + ret += intf.toSignature(); + } + + return ret.isEmpty() ? null : ret; + } + + public byte[] generate() { + var access = clazz.modifiers(); + //if ((access & ACC_PRIVATE) == 0 && (access & ACC_PROTECTED) == 0) // TODO Implement access modifiers properly + // access |= ACC_PUBLIC; + if (!(clazz instanceof TargetInterface)) + access |= ACC_SUPER; + + // Check sealed + for (var intf : clazz.implementingInterfaces()) { + var intfClass = compiler.getClass(new JavaClassName(intf.name())); + if (intfClass.isSealed()) { + if (intfClass.getPermittedSubtypes().stream().noneMatch(type -> type.getName().equals(new JavaClassName(className)))) { + throw new CodeGenException("Sealed interface " + intfClass.getClassName() + " doesn't permit class " + className); + } + } + } + + var signature = generateSignature(clazz, clazz.generics()); + var interfaces = clazz.implementingInterfaces().stream().map(TargetType::getInternalName).toArray(String[]::new); + var superType = clazz.superType() != null ? clazz.superType().getInternalName() : "java/lang/Object"; + + cw.visit(V1_8, access, clazz.qualifiedName().toString().replaceAll("\\.", "/"), signature, superType, interfaces); + if (clazz.txGenerics() != null && signature != null) { + var txSignature = generateSignature(clazz, clazz.txGenerics()); + if (txSignature != null) + cw.visitAttribute(new JavaTXSignatureAttribute(txSignature)); + } + + clazz.fields().forEach(this::generateField); + clazz.constructors().forEach(this::generateConstructor); + clazz.methods().forEach(this::generateMethod); + + if (clazz.staticConstructor() != null) + generateStaticConstructor(clazz.staticConstructor()); + + if (clazz instanceof TargetRecord) + generateRecordMethods(); + + // Generate wrapper classes for function types + for (var pair : funWrapperClasses.keySet()) { + var className = funWrapperClasses.get(pair); + ClassWriter cw2 = new CustomClassWriter(); + cw2.visit(V1_8, ACC_PUBLIC, className, null, "java/lang/Object", new String[] { pair.to.getInternalName() }); + cw2.visitField(ACC_PRIVATE, "wrapped", pair.from.toDescriptor(), null, null).visitEnd(); + + // Generate constructor + var ctor = cw2.visitMethod(ACC_PUBLIC, "", "(" + pair.from.toDescriptor() + ")V", null, null); + ctor.visitVarInsn(ALOAD, 0); + ctor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); + ctor.visitVarInsn(ALOAD, 0); + ctor.visitVarInsn(ALOAD, 1); + ctor.visitFieldInsn(PUTFIELD, className, "wrapped", pair.from.toDescriptor()); + ctor.visitInsn(RETURN); + ctor.visitMaxs(0, 0); + ctor.visitEnd(); + + String methodName = "apply"; + String fromDescriptor = null; + TargetType fromReturn = null; + if (!(pair.from instanceof TargetFunNType funNType)) { + var fromClass = compiler.getClass(new JavaClassName(pair.from.name())); + var fromMethod = fromClass.getMethods().stream().filter(m -> (m.modifier & ACC_ABSTRACT) != 0).findFirst().orElseThrow(); + methodName = fromMethod.name; + + fromReturn = converter.convert(fromMethod.getReturnType()); + var fromParams = converter.convert(fromMethod.getParameterList(), converter.generics.javaGenerics()).stream().map(m -> m.pattern().type()).toArray(TargetType[]::new); + fromDescriptor = TargetMethod.getDescriptor(fromReturn, fromParams); + } else { + fromReturn = funNType.returnArguments() > 0 ? TargetType.Object : null; + fromDescriptor = funNType.toMethodDescriptor(); + } + + var toClass = compiler.getClass(new JavaClassName(pair.to.name())); + var toMethod = toClass.getMethods().stream().filter(m -> (m.modifier & ACC_ABSTRACT) != 0).findFirst().orElseThrow(); + var toReturn = converter.convert(toMethod.getReturnType()); + var toParams = converter.convert(toMethod.getParameterList(), converter.generics.javaGenerics()).stream().map(m -> m.pattern().type()).toArray(TargetType[]::new); + var toDescriptor = TargetMethod.getDescriptor(toReturn, toParams); + + // Generate wrapper method + var mv = cw2.visitMethod(ACC_PUBLIC, toMethod.name, toDescriptor, null, null); + var state = new State(null, mv, 0); + + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, className, "wrapped", pair.from.toDescriptor()); + for (var i = 0; i < toParams.length; i++) { + var arg = toParams[i]; + mv.visitVarInsn(findLoadCode(arg), i + 1); + } + mv.visitMethodInsn(INVOKEINTERFACE, pair.from.getInternalName(), methodName, fromDescriptor, true); + if (fromReturn != null) { + if (toReturn instanceof TargetPrimitiveType) { + convertTo(state, fromReturn, TargetType.toWrapper(toReturn)); + } else convertTo(state, fromReturn, toReturn); + } + + if (toReturn != null) + mv.visitInsn(findReturnCode(toReturn)); + + else mv.visitInsn(RETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + + cw2.visitEnd(); + var bytes = cw2.toByteArray(); + converter.auxiliaries.put(className, bytes); + + // TODO These class loading shenanigans happen in a few places, the tests load the classes individually. + // Instead we should just look at the folder. + try { + converter.classLoader.findClass(className); + } catch (ClassNotFoundException e) { + try { + converter.classLoader.loadClass(bytes); + } catch (LinkageError ignored) {} + } + } + + cw.visitEnd(); + return cw.toByteArray(); + } + + private ClassOrInterface findClass(JavaClassName className) { + try { + for (var sf : compiler.sourceFiles.values()) { + for (var clazz : compiler.getAvailableClasses(sf)) { + if (clazz.getClassName().equals(className)) + return clazz; + } + for (var clazz : sf.KlassenVektor) { + if (clazz.getClassName().equals(className)) + return clazz; + } + } + } catch (ClassNotFoundException ignored) {} + + return null; + } + + private void generateRecordMethods() { + var mt = MethodType.methodType(Object.class, MethodHandles.Lookup.class, String.class, TypeDescriptor.class, Class.class, String.class, MethodHandle[].class); + var bootstrap = new Handle(H_INVOKESTATIC, "java/lang/runtime/ObjectMethods", "bootstrap", mt.toMethodDescriptorString(), false); + var bootstrapArgs = new Object[2 + clazz.fields().size()]; + + bootstrapArgs[0] = Type.getObjectType(clazz.getName()); + bootstrapArgs[1] = String.join(";", clazz.fields().stream().map(TargetField::name).toArray(String[]::new)); + for (var i = 0; i < clazz.fields().size(); i++) { + var field = clazz.fields().get(i); + var fieldRef = new Handle(H_GETFIELD, clazz.getName(), field.name(), field.type().toSignature(), false); + bootstrapArgs[i + 2] = fieldRef; + } + + { // hashCode + var mv = cw.visitMethod(ACC_PUBLIC, "hashCode", "()I", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitInvokeDynamicInsn("hashCode", "(L" + clazz.getName() + ";)I", bootstrap, bootstrapArgs); + mv.visitInsn(IRETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + { // equals + var mv = cw.visitMethod(ACC_PUBLIC, "equals", "(Ljava/lang/Object;)Z", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitInvokeDynamicInsn("equals", "(L" + clazz.getName() + ";Ljava/lang/Object;)Z", bootstrap, bootstrapArgs); + mv.visitInsn(IRETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + { // toString + var mv = cw.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitInvokeDynamicInsn("toString", "(L" + clazz.getName() + ";)Ljava/lang/String;", bootstrap, bootstrapArgs); + mv.visitInsn(ARETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/bytecode/FunNGenerator.java b/LanguageServer/src/main/java/de/dhbw/compiler/bytecode/FunNGenerator.java new file mode 100644 index 0000000..2c97227 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/bytecode/FunNGenerator.java @@ -0,0 +1,212 @@ +package de.dhbw.compiler.bytecode; + +import de.dhbw.compiler.syntaxtree.statement.Break; +import de.dhbw.compiler.target.tree.TargetGeneric; +import de.dhbw.compiler.target.tree.type.*; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Type; + +import java.sql.Array; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.objectweb.asm.Opcodes.*; + +/** + * //ToDo beschreiben + * + * @since Studienarbeit Type Erasure + * @author etiennezink + */ +public class FunNGenerator { + + private static final String argumentGenericBase = "T"; + private static final String returnGeneric = "R"; + private static final String methodName = "apply"; + private static final int bytecodeVersion = V1_8; + + private static final String objectSuperType = Type.getInternalName(Object.class).replace('.','/'); + private static final String objectSignature = applySignature(TargetType.Object); + + private static final String VOID = "Ljava/lang/Void;"; + + public static class GenericParameters { + int start; + public List parameters = new ArrayList<>(); + final String descriptor; + public final List inParams; + public final List realParams; + + public GenericParameters(List params, int numReturns) { + this.realParams = params; + this.inParams = flattenTypeParams(params); + var type = new TargetRefType(FunNGenerator.getSuperClassName(params.size() - 1, numReturns), params); + descriptor = applyDescriptor(type, this); + } + + private static List flattenTypeParams(List params) { + var res = new ArrayList(); + for (var param : params) { + if (param instanceof TargetSpecializedType tspec) { + res.addAll(flattenTypeParams(tspec.params())); + } else { + res.add(param); + } + } + return res; + } + + public TargetType getReturnType() { + return FunNGenerator.getReturnType(realParams); + } + + public List getArguments() { + return FunNGenerator.getArguments(realParams); + } + } + + private static String applyDescriptor(TargetType type, GenericParameters gep) { + if (type == null) return VOID; + var res = "L" + type.getInternalName(); + if (type instanceof TargetSpecializedType a) { + if (a.params().size() > 0) { + res += "<"; + for (var param : a.params()) { + if (param instanceof TargetGenericType gp) { + gep.parameters.add(param); + res += "TT" + gep.start + ";"; + gep.start += 1; + } else { + res += applyDescriptor(param, gep); + } + } + res += ">"; + } + } else { + gep.parameters.add(null); + return type.toDescriptor(); + } + res += ";"; + + return res; + } + + private static String applySignature(TargetType a) { return a.toSignature(); } + private static String applyNameDescriptor(TargetType a){ return a instanceof TargetGenericType ? "LTPH;" : String.format("%s", applySignature(a)); } + + public static String encodeType(TargetType type) { + if (type == null) return VOID; + return applyNameDescriptor(type).replace("/", "$").replace(";", "$_$"); + } + + public static byte[] generateSuperBytecode(int numberArguments, int numReturnTypes) { + StringBuilder superFunNClassSignature = new StringBuilder("<"); + StringBuilder superFunNMethodSignature = new StringBuilder("("); + StringBuilder superFunNMethodDescriptor = new StringBuilder("("); + + for (int currentParameter = 1; currentParameter <= numberArguments; currentParameter++){ + superFunNClassSignature.append(String.format("%s%d:%s", argumentGenericBase, currentParameter, objectSignature)); + superFunNMethodSignature.append(String.format("T%s;", argumentGenericBase + currentParameter)); + superFunNMethodDescriptor.append(objectSignature); + } + superFunNClassSignature.append(String.format("%s:%s>%s", returnGeneric, objectSignature, objectSignature)); + if (numReturnTypes > 0) { + superFunNMethodSignature.append(String.format(")T%s;", returnGeneric)); + superFunNMethodDescriptor.append(String.format(")%s", objectSignature)); + } else { + superFunNMethodSignature.append(")V"); + superFunNMethodDescriptor.append(")V"); + } + + System.out.println(superFunNMethodSignature); + + ClassWriter classWriter = new ClassWriter(0); + MethodVisitor methodVisitor; + classWriter.visit(bytecodeVersion, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, getSuperClassName(numberArguments, numReturnTypes), superFunNClassSignature.toString(), objectSuperType, null); + methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, methodName, superFunNMethodDescriptor.toString(), superFunNMethodSignature.toString(), null); + methodVisitor.visitEnd(); + classWriter.visitEnd(); + return classWriter.toByteArray(); + } + + public static String getSuperClassName(int numberArguments, int returnArguments) { + return returnArguments > 0 ? String.format("Fun%d$$", numberArguments) : String.format("FunVoid%d$$", numberArguments); + } + + public static byte[] generateSpecializedBytecode(GenericParameters gep, List superInterfaces) { + var argumentTypes = gep.getArguments(); + var returnType = gep.getReturnType(); + + StringBuilder funNClassSignature = new StringBuilder(objectSignature + gep.descriptor); + boolean containsGeneric = false; + + String genericSignature = "<"; + for (var i = 0; i < gep.start; i++) { + genericSignature += String.format("T%d:%s", i, objectSignature); + containsGeneric = true; + } + + genericSignature += ">"; + if (containsGeneric) funNClassSignature.insert(0, genericSignature); + + for (var superInterface : superInterfaces) { + funNClassSignature.append('L'); + funNClassSignature.append(superInterface); + funNClassSignature.append(';'); + } + + var interfaces = new ArrayList<>(superInterfaces); + interfaces.add(getSuperClassName(argumentTypes.size(), returnType != null ? 1 : 0)); + + ClassWriter classWriter = new ClassWriter(0); + classWriter.visit(bytecodeVersion, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, getSpecializedClassName(argumentTypes, returnType), funNClassSignature.toString(), objectSuperType, interfaces.toArray(String[]::new)); + classWriter.visitEnd(); + return classWriter.toByteArray(); + } + + private static void collectGenericTypeArguments(Map generics, TargetType typeArgument) { + if (typeArgument instanceof TargetSpecializedType specializedType) { + for (var arg : specializedType.params()) + collectGenericTypeArguments(generics, arg); + } else if (typeArgument instanceof TargetGenericType genericType) { + if (generics.containsKey(genericType)) + generics.put(genericType, generics.get(genericType) + 1); + else generics.put(genericType, 0); + } + } + + public static String getSpecializedClassName(GenericParameters gep) { + return getSpecializedClassName(gep.getArguments(), gep.getReturnType()); + } + + public static String getSpecializedClassName(List argumentTypes, TargetType returnType) { + var arguments = argumentTypes + .stream() + .map(FunNGenerator::encodeType) + .collect(Collectors.joining()); + + if (returnType != null) + return String.format("Fun%d$$%s%s", + argumentTypes.size(), + arguments, + encodeType(returnType)); + else return String.format("FunVoidImpl%d$$%s", + argumentTypes.size(), + arguments); + } + + public static List getArguments(List list) { + return list + .stream() + .limit(Math.max(0, list.size() - 1)) + .collect(Collectors.toList()); + } + + public static TargetType getReturnType(List list) { + if(list.isEmpty()) + throw new IndexOutOfBoundsException(); + return list.getLast(); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/bytecode/JavaTXSignatureAttribute.java b/LanguageServer/src/main/java/de/dhbw/compiler/bytecode/JavaTXSignatureAttribute.java new file mode 100644 index 0000000..a8b4383 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/bytecode/JavaTXSignatureAttribute.java @@ -0,0 +1,30 @@ +package de.dhbw.compiler.bytecode; + +import org.objectweb.asm.*; + +public class JavaTXSignatureAttribute extends Attribute { + public String signature; + + public JavaTXSignatureAttribute() { + super("JavaTXSignature"); + } + protected JavaTXSignatureAttribute(String signature) { + this(); + this.signature = signature; + } + + @Override + protected Attribute read(ClassReader classReader, int offset, int length, char[] charBuffer, int codeAttributeOffset, Label[] labels) { + var data = new byte[length]; + System.arraycopy(classReader.b, offset, data, 0, length); + var constantPoolOffset = data[0] << 8 | data[1]; + return new JavaTXSignatureAttribute((String) classReader.readConst(constantPoolOffset, charBuffer)); + } + + @Override + protected ByteVector write(ClassWriter classWriter, byte[] code, int codeLength, int maxStack, int maxLocals) { + var data = new ByteVector(); + data.putShort(classWriter.newConst(this.signature)); + return data; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/core/ConsoleInterface.java b/LanguageServer/src/main/java/de/dhbw/compiler/core/ConsoleInterface.java new file mode 100644 index 0000000..2f0f8d6 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/core/ConsoleInterface.java @@ -0,0 +1,46 @@ +package de.dhbw.compiler.core; + +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.*; +public class ConsoleInterface { + private static final String directory = System.getProperty("user.dir"); + + public static void main(String[] args) throws IOException, ClassNotFoundException { + List input = new ArrayList<>(); + List classpath = new ArrayList<>(); + String outputPath = null; + Iterator it = Arrays.asList(args).iterator(); + if(args.length == 0){ + System.out.println("No input files given. Get help with --help"); + System.exit(1); + }else if(args.length == 1 && args[0].equals("--help")){ + System.out.println("Usage: javatx [OPTION]... [FILE]...\n" + + "\t-cp\tSet Classpath\n" + + "\t-d\tSet destination directory"); + System.exit(1); + } + while(it.hasNext()){ + String arg = it.next(); + if(arg.equals("-d")){ + outputPath = it.next(); + }else if(arg.startsWith("-d")) { + outputPath = arg.substring(2); + }else if(arg.equals("-cp") || arg.equals("-classpath")){ + String[] cps = it.next().split(":"); + for(String cp : cps){ + classpath.add(new File(cp)); + } + }else{ + input.add(new File(arg)); + } + } + JavaTXCompiler compiler = new JavaTXCompiler(input, classpath, outputPath != null ? new File(outputPath) : null); + //compiler.typeInference(); + compiler.generateBytecode(); + } + + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/core/IItemWithOffset.java b/LanguageServer/src/main/java/de/dhbw/compiler/core/IItemWithOffset.java new file mode 100644 index 0000000..7bf4379 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/core/IItemWithOffset.java @@ -0,0 +1,9 @@ +package de.dhbw.compiler.core; + + +import org.antlr.v4.runtime.Token; + +public interface IItemWithOffset +{ + Token getOffset(); +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/core/JavaTXCompiler.java b/LanguageServer/src/main/java/de/dhbw/compiler/core/JavaTXCompiler.java new file mode 100644 index 0000000..107115b --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/core/JavaTXCompiler.java @@ -0,0 +1,708 @@ +//PL 2018-12-19: typeInferenceOld nach typeInference uebertragen +package de.dhbw.compiler.core; + +import de.dhbw.compiler.bytecode.Codegen; +import de.dhbw.compiler.environment.CompilationEnvironment; +import de.dhbw.compiler.environment.DirectoryClassLoader; +import de.dhbw.compiler.exceptions.DebugException; +import de.dhbw.compiler.parser.JavaTXParser; +import de.dhbw.compiler.parser.NullToken; +import de.dhbw.compiler.parser.scope.GenericsRegistry; +import de.dhbw.compiler.parser.SyntaxTreeGenerator.SyntaxTreeGenerator; +import de.dhbw.compiler.parser.scope.JavaClassName; +import de.dhbw.compiler.parser.scope.JavaClassRegistry; +import de.dhbw.compiler.syntaxtree.ClassOrInterface; +import de.dhbw.compiler.syntaxtree.GenericTypeVar; +import de.dhbw.compiler.syntaxtree.Method; +import de.dhbw.compiler.syntaxtree.ParameterList; +import de.dhbw.compiler.syntaxtree.SourceFile; +import de.dhbw.compiler.syntaxtree.GenericDeclarationList; +import de.dhbw.compiler.syntaxtree.factory.ASTFactory; +import de.dhbw.compiler.syntaxtree.factory.UnifyTypeFactory; +import de.dhbw.compiler.syntaxtree.type.ExtendsWildcardType; +import de.dhbw.compiler.syntaxtree.type.GenericRefType; +import de.dhbw.compiler.syntaxtree.type.RefType; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.syntaxtree.type.SuperWildcardType; +import de.dhbw.compiler.syntaxtree.type.TypePlaceholder; +import de.dhbw.compiler.syntaxtree.type.TypeVisitor; +import de.dhbw.compiler.syntaxtree.visual.ASTTypePrinter; +import de.dhbw.compiler.target.generate.ASTToTargetAST; +import de.dhbw.compiler.target.generate.GenericsResult; +import de.dhbw.compiler.typeinference.constraints.Constraint; +import de.dhbw.compiler.typeinference.constraints.ConstraintSet; +import de.dhbw.compiler.typeinference.constraints.Pair; +import de.dhbw.compiler.typeinference.result.ResultSet; +import de.dhbw.compiler.typeinference.typeAlgo.TYPE; +import de.dhbw.compiler.typeinference.unify.RuleSet; +import de.dhbw.compiler.typeinference.unify.TypeUnify; +import de.dhbw.compiler.typeinference.unify.distributeVariance; +import de.dhbw.compiler.typeinference.unify.interfaces.IFiniteClosure; +import de.dhbw.compiler.typeinference.unify.model.PairOperator; +import de.dhbw.compiler.typeinference.unify.model.PlaceholderType; +import de.dhbw.compiler.typeinference.unify.model.UnifyPair; +import de.dhbw.compiler.typeinference.unify.model.UnifyType; +import de.dhbw.compiler.typeinference.unify.TypeUnifyTask; +import de.dhbw.compiler.typeinference.unify.UnifyResultListener; +import de.dhbw.compiler.typeinference.unify.UnifyResultListenerImpl; +import de.dhbw.compiler.typeinference.unify.UnifyResultModel; +import de.dhbw.compiler.typeinference.unify.UnifyTaskModel; + +import java.io.*; +import java.lang.reflect.Modifier; +import java.nio.file.Path; +import java.util.*; +import java.util.Map.Entry; +import java.util.function.Function; +import java.util.stream.Collectors; + +import de.dhbw.parser.Java17Parser; +import org.apache.commons.io.output.NullOutputStream; + +public class JavaTXCompiler { + + // public static JavaTXCompiler INSTANCE; + final CompilationEnvironment environment; + Boolean resultmodel = true; + public final Map sourceFiles = new HashMap<>(); + + Boolean log = false; //gibt an ob ein Log-File nach System.getProperty("user.dir")+""/logFiles/"" geschrieben werden soll? + public volatile UnifyTaskModel usedTasks = new UnifyTaskModel(); + public final DirectoryClassLoader classLoader; + + public final List classPath; + private final File outputPath; + + public DirectoryClassLoader getClassLoader() { + return classLoader; + } + + public JavaTXCompiler(File sourceFile) throws IOException, ClassNotFoundException { + this(Arrays.asList(sourceFile), List.of(), new File(".")); + } + + public JavaTXCompiler(File sourceFile, Boolean log) throws IOException, ClassNotFoundException { + this(sourceFile); + this.log = log; + } + + public JavaTXCompiler(List sourceFiles) throws IOException, ClassNotFoundException { + this(sourceFiles, List.of(), new File(".")); + } + + public JavaTXCompiler(List sources, List contextPath, File outputPath) throws IOException, ClassNotFoundException { + var path = new ArrayList<>(contextPath); + if (contextPath.isEmpty()) { + // When no contextPaths are given, the working directory is the sources root + path.add(new File(System.getProperty("user.dir"))); + } + if (outputPath != null) path.add(outputPath); + classLoader = new DirectoryClassLoader(path, ClassLoader.getSystemClassLoader()); + environment = new CompilationEnvironment(sources, classLoader); + classPath = path; + this.outputPath = outputPath; + + for (File s : sources) { + parse(s); + } + // INSTANCE = this; + } + + private void addSourceFile(File file, SourceFile sf) { + sourceFiles.put(file, sf); + } + + public ClassOrInterface getClass(JavaClassName name) { + if (loadedClasses.containsKey(name)) return loadedClasses.get(name).cif(); + for (var sf : sourceFiles.values()) { + for (var clazz : sf.KlassenVektor) { + if (clazz.getClassName().equals(name)) return clazz; + } + } + try { + var clazz = classLoader.loadClass(name.toString()); + if (clazz != null) + return ASTFactory.createClass(clazz); + } catch (ClassNotFoundException ignored) {} + return null; + } + + public ConstraintSet getConstraints(File sourceFile) throws ClassNotFoundException, IOException { + Set allClasses = new HashSet<>();// environment.getAllAvailableClasses(); + ClassOrInterface objectClass = ASTFactory.createClass(Object.class); + var recordClass = ASTFactory.createClass(Record.class); + allClasses.add(objectClass); + allClasses.add(recordClass); + + var sf = sourceFiles.get(sourceFile); + var importedClasses = new ArrayList(); + for (JavaClassName name : sf.getImports()) { + importedClasses.addAll(getAvailableClasses(name)); + } + for (Class c : CompilationEnvironment.loadDefaultPackageClasses(sf.getPkgName(), sourceFile, this)) { + ClassOrInterface importedClass = ASTFactory.createClass(c); + importedClasses.add(importedClass); + } + sf.availableClasses.addAll(importedClasses); + + SourceFile sf_new = new SourceFile(sf.getPkgName(), sf.KlassenVektor.stream().map(cl -> new ClassOrInterface(cl)).collect(Collectors.toCollection(ArrayList::new)), sf.imports); + // sf enthaelt neues Source-File, neue Klassen-Objekte und neue + // ArrayListen-Objekte fuer Fields, Construktoren und Methoden + // Alle anderen Objekte werden nur kopiert. + var isCached = false; + for (var clazz : sf.availableClasses) { + if (loadedClasses.containsKey(clazz.getClassName())) { + allClasses.removeIf(cl -> cl.getClassName().equals(clazz.getClassName())); + var cif = loadedClasses.get(clazz.getClassName()).cif(); + allClasses.add(cif); + isCached = true; + } + } + + if (!isCached) { + sf_new.KlassenVektor.forEach(cl -> addMethods(sf_new, cl, sf.availableClasses, objectClass)); + allClasses.addAll(sf_new.getClasses()); + } + + allClasses.addAll(sf.KlassenVektor); + + TYPE ty = new TYPE(sf, allClasses); + var constraints = ty.getConstraints(); + return constraints; + } + + void addMethods(SourceFile sf, ClassOrInterface cl, List importedClasses, ClassOrInterface objectClass) { + if (!cl.areMethodsAdded()) { + ClassOrInterface superclass = null; + Optional optSuperclass = importedClasses.stream().filter(x -> x.getClassName().equals(cl.getSuperClass().getName())).findFirst(); + if (optSuperclass.isPresent()) { + superclass = optSuperclass.get(); + } else { + optSuperclass = sf.KlassenVektor.stream().filter(x -> x.getClassName().equals(cl.getSuperClass().getName())).findFirst(); + if (optSuperclass.isPresent()) { + superclass = optSuperclass.get(); + addMethods(sf, superclass, importedClasses, objectClass); + } else { + try { + var className = cl.getSuperClass().getName().toString(); + superclass = ASTFactory.createClass(classLoader.loadClass(className)); + } catch (ClassNotFoundException ignored) {} + // throw new ClassNotFoundException(""); + } + } + + Iterator paraIt = cl.getSuperClass().getParaList().iterator(); + Iterator tvarVarIt = superclass.getGenerics().iterator(); + + HashMap gtvs = new HashMap<>(); + while (paraIt.hasNext()) { + gtvs.put(tvarVarIt.next().getName(), paraIt.next()); + } + + for (Method m : superclass.getMethods()) { + if (m.isInherited || Modifier.isStatic(m.modifier)) continue; + // TODO: Add gtvs from method itself + + ParameterList newParaList = new ParameterList(m.getParameterList().getFormalparalist().stream().map(fp -> fp.withType(fp.getType().acceptTV(new TypeExchanger(gtvs)))).collect(Collectors.toCollection(ArrayList::new)), m.getParameterList().getOffset()); + cl.getMethods().add(new Method(m.modifier, m.name, m.getReturnType().acceptTV(new TypeExchanger(gtvs)), newParaList, m.block, + // new GenericDeclarationList(newGenericsList, + // ((GenericDeclarationList)m.getGenerics()).getOffset()), + (GenericDeclarationList) m.getGenerics(), m.getOffset(), true, false)); + } + + } + cl.setMethodsAdded(); + } + + private Set getAvailableClasses(JavaClassName name) throws ClassNotFoundException { + Set allClasses = new HashSet<>(); + var clazz = loadJavaTXClass(name); + if (clazz == null) { + ClassOrInterface importedClass = ASTFactory.createClass(classLoader.loadClass(name.toString())); + allClasses.add(importedClass); + } else { + allClasses.add(clazz); + } + return allClasses; + } + + public Set getAvailableClasses(SourceFile forSourceFile) throws ClassNotFoundException { + // PL 2018-09-18: List durch Set ersetzt, damit die Klassen nur einmal + // hinzugefuegt werden + // List allClasses = new + // ArrayList<>();//environment.getAllAvailableClasses(); + Set allClasses = new HashSet<>(); + + for (JavaClassName name : forSourceFile.getImports()) { + allClasses.addAll(getAvailableClasses(name)); + } + return allClasses; + } + + /* + * public List typeInferenceOld() throws ClassNotFoundException { List allClasses = new ArrayList<>();//environment.getAllAvailableClasses(); //Alle Importierten Klassen in allen geparsten Sourcefiles kommen ins FC for(SourceFile sf : this.sourceFiles.values()) { allClasses.addAll(getAvailableClasses(sf)); allClasses.addAll(sf.getClasses()); } + * + * final ConstraintSet cons = getConstraints(); + * + * FiniteClosure finiteClosure = UnifyTypeFactory.generateFC(allClasses); System.out.println(finiteClosure); ConstraintSet unifyCons = UnifyTypeFactory.convert(cons); + * + * TypeUnify unify = new TypeUnify(); Set> results = new HashSet<>(); try { File logPath = new File(System.getProperty("user.dir")+"/target/logFiles/"); logPath.mkdirs(); FileWriter logFile = new FileWriter(new File(logPath, "log")); logFile.write("FC:\\" + finiteClosure.toString()+"\n"); for(SourceFile sf : this.sourceFiles.values()) { logFile.write(ASTTypePrinter.print(sf)); } logFile.flush(); Set>> cardProd = unifyCons.cartesianProduct(); for + * (List> xCons : cardProd ){ Set xConsSet = new HashSet<>(); for (Constraint constraint : xCons) { xConsSet.addAll(constraint); } //.collect(Collectors.toCollection(ArrayList::new)))) System.out.println(xConsSet); Set methodParaTypeVarNames = allClasses.stream().map(x -> x.getMethods().stream().map(y -> y.getParameterList().getFormalparalist() .stream().filter(z -> z.getType() instanceof TypePlaceholder) .map(z -> + * ((TypePlaceholder)z.getType()).getName()).collect(Collectors.toCollection( HashSet::new))) .reduce(new HashSet(), (a,b) -> { a.addAll(b); return a;}, (a,b) -> { a.addAll(b); return a;} ) ) .reduce(new HashSet(), (a,b) -> { a.addAll(b); return a;} ); + * + * Set constructorParaTypeVarNames = allClasses.stream().map(x -> x.getConstructors().stream().map(y -> y.getParameterList().getFormalparalist() .stream().filter(z -> z.getType() instanceof TypePlaceholder) .map(z -> ((TypePlaceholder)z.getType()).getName()).collect(Collectors.toCollection( HashSet::new))) .reduce(new HashSet(), (a,b) -> { a.addAll(b); return a;}, (a,b) -> { a.addAll(b); return a;} ) ) .reduce(new HashSet(), (a,b) -> { a.addAll(b); return a;} ); + * + * Set paraTypeVarNames = methodParaTypeVarNames; paraTypeVarNames.addAll(constructorParaTypeVarNames); + * + * Set returnTypeVarNames = allClasses.stream().map(x -> x.getMethods().stream().filter(y -> y.getReturnType() instanceof TypePlaceholder) .map(z -> ((TypePlaceholder)z.getReturnType()).getName()).collect(Collectors. toCollection(HashSet::new))).reduce((a,b) -> { a.addAll(b); return a;} ).get(); + * + * Set fieldTypeVarNames = allClasses.stream().map(x -> x.getFieldDecl().stream().filter(y -> y.getReturnType() instanceof TypePlaceholder) .map(z -> ((TypePlaceholder)z.getReturnType()).getName()).collect(Collectors. toCollection(HashSet::new))).reduce((a,b) -> { a.addAll(b); return a;} ).get(); + * + * returnTypeVarNames.addAll(fieldTypeVarNames); + * + * xConsSet = xConsSet.stream().map(x -> { //Hier muss ueberlegt werden, ob //1. alle Argument- und Retuntyp-Variablen in allen UnifyPairs // mit disableWildcardtable() werden. //2. alle Typvariablen mit Argument- oder Retuntyp-Variablen //in Beziehung auch auf disableWildcardtable() gesetzt werden muessen //PL 2018-04-23 if ((x.getLhsType() instanceof PlaceholderType)) { if (paraTypeVarNames.contains(x.getLhsType().getName())) { ((PlaceholderType)x.getLhsType()).setVariance((byte)1); + * ((PlaceholderType)x.getLhsType()).disableWildcardtable(); } if (returnTypeVarNames.contains(x.getLhsType().getName())) { ((PlaceholderType)x.getLhsType()).setVariance((byte)-1); ((PlaceholderType)x.getLhsType()).disableWildcardtable(); } } if ((x.getRhsType() instanceof PlaceholderType)) { if (paraTypeVarNames.contains(x.getRhsType().getName())) { ((PlaceholderType)x.getRhsType()).setVariance((byte)1); ((PlaceholderType)x.getRhsType()).disableWildcardtable(); } if + * (returnTypeVarNames.contains(x.getRhsType().getName())) { ((PlaceholderType)x.getRhsType()).setVariance((byte)-1); ((PlaceholderType)x.getRhsType()).disableWildcardtable(); } } return x;//HIER DIE JEWEILS RECHT BZW. LINKE SEITE AUF GLEICHE VARIANZ SETZEN WIE DIE JEWEILS ANDERE SEITE }).map( y -> { if ((y.getLhsType() instanceof PlaceholderType) && (y.getRhsType() instanceof PlaceholderType)) { if (((PlaceholderType)y.getLhsType()).getVariance() != 0 && + * ((PlaceholderType)y.getRhsType()).getVariance() == 0) { ((PlaceholderType)y.getRhsType()).setVariance(((PlaceholderType)y.getLhsType( )).getVariance()); } if (((PlaceholderType)y.getLhsType()).getVariance() == 0 && ((PlaceholderType)y.getRhsType()).getVariance() != 0) { ((PlaceholderType)y.getLhsType()).setVariance(((PlaceholderType)y.getRhsType( )).getVariance()); } } return y; } ) .collect(Collectors.toCollection(HashSet::new)); varianceInheritance(xConsSet); Set> result = + * unify.unifySequential(xConsSet, finiteClosure, logFile, log); //Set> result = unify.unify(xConsSet, finiteClosure); System.out.println("RESULT: " + result); logFile.write("RES: " + result.toString()+"\n"); logFile.flush(); results.addAll(result); } + * + * results = results.stream().map(x -> { Optional> res = new RuleSet().subst(x.stream().map(y -> { if (y.getPairOp() == PairOperator.SMALLERDOTWC) y.setPairOp(PairOperator.EQUALSDOT); return y; //alle Paare a <.? b erden durch a =. b ersetzt }).collect(Collectors.toCollection(HashSet::new))); if (res.isPresent()) {//wenn subst ein Erg liefert wurde was veraendert return new TypeUnifyTask().applyTypeUnificationRules(res.get(), finiteClosure); } else return x; //wenn nichts + * veraendert wurde wird x zurueckgegeben }).collect(Collectors.toCollection(HashSet::new)); System.out.println("RESULT Final: " + results); logFile.write("RES_FINAL: " + results.toString()+"\n"); logFile.flush(); logFile.write("PLACEHOLDERS: " + PlaceholderType.EXISTING_PLACEHOLDERS); logFile.flush(); } catch (IOException e) { e.printStackTrace(); } return results.stream().map((unifyPairs -> new ResultSet(UnifyTypeFactory.convert(unifyPairs, + * generateTPHMap(cons))))).collect(Collectors.toList()); } + */ + /** + * Vererbt alle Variancen bei Paaren (a <. theta) oder (Theta <. a) wenn a eine Variance !=0 hat auf alle Typvariablen in Theta. + * + * + */ + /* + * private void varianceInheritance(Set eq) { Set usedTPH = new HashSet<>(); Set phSet = eq.stream().map(x -> { Set pair = new HashSet<>(); if (x.getLhsType() instanceof PlaceholderType) pair.add((PlaceholderType)x.getLhsType()); if (x.getRhsType() instanceof PlaceholderType) pair.add((PlaceholderType)x.getRhsType()); return pair; }).reduce(new HashSet<>(), (a,b) -> { a.addAll(b); return a;} , (c,d) -> { c.addAll(d); return c;}); + * + * ArrayList phSetVariance = new ArrayList<>(phSet); phSetVariance.removeIf(x -> (x.getVariance() == 0)); while(!phSetVariance.isEmpty()) { PlaceholderType a = phSetVariance.remove(0); usedTPH.add(a); //HashMap ht = new HashMap<>(); //ht.put(a, a.getVariance()); Set eq1 = new HashSet<>(eq); eq1.removeIf(x -> !(x.getLhsType() instanceof PlaceholderType && ((PlaceholderType)x.getLhsType()).equals(a))); eq1.stream().forEach(x -> { + * x.getRhsType().accept(new distributeVariance(), a.getVariance());}); eq1 = new HashSet<>(eq); eq1.removeIf(x -> !(x.getRhsType() instanceof PlaceholderType && ((PlaceholderType)x.getRhsType()).equals(a))); eq1.stream().forEach(x -> { x.getLhsType().accept(new distributeVariance(), a.getVariance());}); phSetVariance = new ArrayList<>(phSet); phSetVariance.removeIf(x -> (x.getVariance() == 0 || usedTPH.contains(x))); } } + */ + + public UnifyResultModel typeInferenceAsync(UnifyResultListener resultListener, Writer logFile) throws ClassNotFoundException, IOException { + List allClasses = new ArrayList<>();// environment.getAllAvailableClasses(); + // Alle Importierten Klassen in allen geparsten Sourcefiles kommen ins FC + for (Entry source : this.sourceFiles.entrySet()) { + SourceFile sf = source.getValue(); + allClasses.addAll(getAvailableClasses(sf)); + allClasses.addAll(sf.getClasses()); + allClasses.addAll(CompilationEnvironment.loadDefaultPackageClasses(sf.getPkgName(), source.getKey(), this).stream().map(ASTFactory::createClass).collect(Collectors.toList())); + } + + final ConstraintSet cons = new ConstraintSet<>(); + for (var f : this.sourceFiles.keySet()) { + cons.addAll(getConstraints(f)); + } + + Set> results = new HashSet<>(); + UnifyResultModel urm = null; + // urm.addUnifyResultListener(resultListener); + try { + logFile = logFile == null ? new FileWriter(new File("log_" + sourceFiles.keySet().iterator().next().getName())) : logFile; + IFiniteClosure finiteClosure = UnifyTypeFactory.generateFC(allClasses, logFile, getClassLoader(), this); + System.out.println(finiteClosure); + urm = new UnifyResultModel(cons, finiteClosure); + urm.addUnifyResultListener(resultListener); + ConstraintSet unifyCons = UnifyTypeFactory.convert(this, cons); + + Function distributeInnerVars = x -> { + UnifyType lhs, rhs; + if (((lhs = x.getLhsType()) instanceof PlaceholderType) && ((rhs = x.getRhsType()) instanceof PlaceholderType) && (((PlaceholderType) lhs).isInnerType() || ((PlaceholderType) rhs).isInnerType())) { + ((PlaceholderType) lhs).setInnerType(true); + ((PlaceholderType) rhs).setInnerType(true); + } + return x; + + }; + logFile.write(unifyCons.toString()); + unifyCons = unifyCons.map(distributeInnerVars); + logFile.write(unifyCons.toString()); + TypeUnify unify = new TypeUnify(); + // Set> results = new HashSet<>(); Nach vorne gezogen + logFile.write("FC:\\" + finiteClosure.toString() + "\n"); + for (SourceFile f : this.sourceFiles.values()) { + logFile.write(ASTTypePrinter.print(f)); + } + logFile.flush(); + Set varianceTPHold; + Set varianceTPH = new HashSet<>(); + varianceTPH = varianceInheritanceConstraintSet(unifyCons); + + /* + * PL 2018-11-07 wird in varianceInheritanceConstraintSet erledigt do { //PL 2018-11-05 Huellenbildung Variance auf alle TPHs der Terme auf der jeweiligen //anderen Seite übertragen varianceTPHold = new HashSet<>(varianceTPH); varianceTPH = varianceInheritanceConstraintSet(unifyCons); unifyCons.map( y -> { if ((y.getLhsType() instanceof PlaceholderType) && (y.getRhsType() instanceof PlaceholderType)) { if (((PlaceholderType)y.getLhsType()).getVariance() != 0 && + * ((PlaceholderType)y.getRhsType()).getVariance() == 0) { ((PlaceholderType)y.getRhsType()).setVariance(((PlaceholderType)y.getLhsType( )).getVariance()); } if (((PlaceholderType)y.getLhsType()).getVariance() == 0 && ((PlaceholderType)y.getRhsType()).getVariance() != 0) { ((PlaceholderType)y.getLhsType()).setVariance(((PlaceholderType)y.getRhsType( )).getVariance()); } } return y; } ); } while (!varianceTPHold.equals(varianceTPH)); + */ + + // Set> result = unify.unifySequential(xConsSet, finiteClosure, + // logFile, log); + // Set> result = unify.unify(xConsSet, finiteClosure); + List>> oderConstraints = unifyCons.getOderConstraints()/* + * .stream().map(x -> { Set> ret = new HashSet<>(); for (Constraint y : x) { ret.add(new HashSet<>(y)); } return ret; }).collect(Collectors. toCollection(ArrayList::new)) + */; + unify.unifyAsync(unifyCons.getUndConstraints(), oderConstraints, finiteClosure, logFile, log, urm, usedTasks); + } catch (IOException e) { + System.err.println("kein LogFile"); + } + return urm; + } + + public List typeInference(File file) throws ClassNotFoundException, IOException { + var sf = sourceFiles.get(file); + Set allClasses = new HashSet<>();// environment.getAllAvailableClasses(); + allClasses.addAll(getAvailableClasses(sf)); + allClasses.addAll(sf.getClasses()); + var newClasses = CompilationEnvironment.loadDefaultPackageClasses(sf.getPkgName(), file, this).stream().map(ASTFactory::createClass).collect(Collectors.toSet()); + for (var clazz : newClasses) { + // Don't load classes that get recompiled + if (sf.getClasses().stream().anyMatch(nf -> nf.getClassName().equals(clazz.getClassName()))) + continue; + if (allClasses.stream().noneMatch(old -> old.getClassName().equals(clazz.getClassName()))) + allClasses.add(clazz); + } + + final ConstraintSet cons = getConstraints(file); + Set> results = new HashSet<>(); + try { + var logFolder = new File(System.getProperty("user.dir") + "/logFiles/"); + if (log) logFolder.mkdirs(); + Writer logFile = log ? new FileWriter(new File(logFolder, "log_" + sourceFiles.keySet().iterator().next().getName())) : new OutputStreamWriter(new NullOutputStream()); + IFiniteClosure finiteClosure = UnifyTypeFactory.generateFC(allClasses.stream().toList(), logFile, classLoader, this); + System.out.println(finiteClosure); + ConstraintSet unifyCons = UnifyTypeFactory.convert(this, cons); + System.out.println("xxx1"); + Function distributeInnerVars = x -> { + UnifyType lhs, rhs; + if (((lhs = x.getLhsType()) instanceof PlaceholderType) && ((rhs = x.getRhsType()) instanceof PlaceholderType) && (((PlaceholderType) lhs).isInnerType() || ((PlaceholderType) rhs).isInnerType())) { + ((PlaceholderType) lhs).setInnerType(true); + ((PlaceholderType) rhs).setInnerType(true); + } + return x; + + }; + + logFile.write("Unify:" + unifyCons.toString()); + System.out.println("Unify:" + unifyCons.toString()); + unifyCons = unifyCons.map(distributeInnerVars); + logFile.write("\nUnify_distributeInnerVars: " + unifyCons.toString()); + TypeUnify unify = new TypeUnify(); + // Set> results = new HashSet<>(); Nach vorne gezogen + logFile.write("FC:\\" + finiteClosure.toString() + "\n"); + logFile.write(ASTTypePrinter.print(sf)); + System.out.println(ASTTypePrinter.print(sf)); + logFile.flush(); + System.out.println("Unify nach Oder-Constraints-Anpassung:" + unifyCons.toString()); + Set varianceTPHold; + Set varianceTPH = new HashSet<>(); + varianceTPH = varianceInheritanceConstraintSet(unifyCons); + + /* + * PL 2018-11-07 wird in varianceInheritanceConstraintSet erledigt do { //PL 2018-11-05 Huellenbildung Variance auf alle TPHs der Terme auf der jeweiligen //anderen Seite übertragen varianceTPHold = new HashSet<>(varianceTPH); varianceTPH = varianceInheritanceConstraintSet(unifyCons); unifyCons.map( y -> { if ((y.getLhsType() instanceof PlaceholderType) && (y.getRhsType() instanceof PlaceholderType)) { if (((PlaceholderType)y.getLhsType()).getVariance() != 0 && + * ((PlaceholderType)y.getRhsType()).getVariance() == 0) { ((PlaceholderType)y.getRhsType()).setVariance(((PlaceholderType)y.getLhsType( )).getVariance()); } if (((PlaceholderType)y.getLhsType()).getVariance() == 0 && ((PlaceholderType)y.getRhsType()).getVariance() != 0) { ((PlaceholderType)y.getLhsType()).setVariance(((PlaceholderType)y.getRhsType( )).getVariance()); } } return y; } ); } while (!varianceTPHold.equals(varianceTPH)); + */ + + // Set> result = unify.unifySequential(xConsSet, finiteClosure, + // logFile, log); + // Set> result = unify.unify(xConsSet, finiteClosure); + List>> oderConstraints = unifyCons.getOderConstraints()// .stream().map(x -> { + /* + * Set> ret = new HashSet<>(); for (Constraint y : x) { ret.add(new HashSet<>(y)); } return ret; }).collect(Collectors.toCollection(ArrayList::new)) + */; + if (resultmodel) { + /* UnifyResultModel Anfang */ + UnifyResultModel urm = new UnifyResultModel(cons, finiteClosure); + UnifyResultListenerImpl li = new UnifyResultListenerImpl(); + urm.addUnifyResultListener(li); + unify.unifyParallel(unifyCons.getUndConstraints(), oderConstraints, finiteClosure, logFile, log, urm, usedTasks); + System.out.println("RESULT Final: " + li.getResults()); + System.out.println("Constraints for Generated Generics: " + " ???"); + logFile.write("RES_FINAL: " + li.getResults().toString() + "\n"); + logFile.flush(); + return li.getResults(); + } + /* UnifyResultModel End */ + else { + // Set> result = unify.unify(unifyCons.getUndConstraints(), + // oderConstraints, finiteClosure, logFile, log, new UnifyResultModel(cons, + // finiteClosure)); + Set> result = unify.unifyOderConstraints(unifyCons.getUndConstraints(), oderConstraints, finiteClosure, logFile, log, new UnifyResultModel(cons, finiteClosure), usedTasks); + System.out.println("RESULT: " + result); + logFile.write("RES: " + result.toString() + "\n"); + logFile.flush(); + results.addAll(result); + + results = results.stream().map(x -> { + Optional> res = new RuleSet().subst(x.stream().map(y -> { + if (y.getPairOp() == PairOperator.SMALLERDOTWC) + y.setPairOp(PairOperator.EQUALSDOT); + return y; // alle Paare a <.? b erden durch a =. b ersetzt + }).collect(Collectors.toCollection(HashSet::new))); + if (res.isPresent()) {// wenn subst ein Erg liefert wurde was veraendert + return new TypeUnifyTask().applyTypeUnificationRules(res.get(), finiteClosure); + } else + return x; // wenn nichts veraendert wurde wird x zurueckgegeben + }).collect(Collectors.toCollection(HashSet::new)); + System.out.println("RESULT Final: " + results); + System.out.println("Constraints for Generated Generics: " + " ???"); + logFile.write("RES_FINAL: " + results.toString() + "\n"); + logFile.flush(); + logFile.write("PLACEHOLDERS: " + PlaceholderType.EXISTING_PLACEHOLDERS); + logFile.flush(); + } + } catch (IOException e) { + System.err.println("kein LogFile"); + } + return results.stream().map((unifyPairs -> new ResultSet(UnifyTypeFactory.convert(unifyPairs, Pair.generateTPHMap(cons))))).collect(Collectors.toList()); + } + + /** + * Vererbt alle Variancen bei Paaren (a <. theta) oder (Theta <. a) wenn a eine Variance !=0 hat auf alle Typvariablen in Theta. + * + * + */ + private Set varianceInheritanceConstraintSet(ConstraintSet cons) { + Set eq = cons.getAll(); + Set usedTPH = new HashSet<>(); + Set phSet = eq.stream().map(x -> { + Set pair = new HashSet<>(); + if (x.getLhsType() instanceof PlaceholderType) + pair.add((PlaceholderType) x.getLhsType()); + if (x.getRhsType() instanceof PlaceholderType) + pair.add((PlaceholderType) x.getRhsType()); + return pair; + }).reduce(new HashSet<>(), (a, b) -> { + a.addAll(b); + return a; + }, (c, d) -> { + c.addAll(d); + return c; + }); + + ArrayList phSetVariance = new ArrayList<>(phSet); + phSetVariance.removeIf(x -> (x.getVariance() == 0)); + while (!phSetVariance.isEmpty()) { + PlaceholderType a = phSetVariance.remove(0); + usedTPH.add(a); + // HashMap ht = new HashMap<>(); + // ht.put(a, a.getVariance()); + // ConstraintSet eq1 = cons; + // eq1.removeIf(x -> !(x.getLhsType() instanceof PlaceholderType && + // ((PlaceholderType)x.getLhsType()).equals(a))); + // durch if-Abfrage im foreach geloest + cons.forEach(x -> { + if (x.getLhsType() instanceof PlaceholderType && ((PlaceholderType) x.getLhsType()).equals(a)) { + x.getRhsType().accept(new distributeVariance(), a.getVariance()); + } + }); + // ` eq1 = new HashSet<>(eq); + // eq1.removeIf(x -> !(x.getRhsType() instanceof PlaceholderType && + // ((PlaceholderType)x.getRhsType()).equals(a))); + // durch if-Abfrage im foreach geloest + cons.forEach(x -> { + if (x.getRhsType() instanceof PlaceholderType && ((PlaceholderType) x.getRhsType()).equals(a)) { + x.getLhsType().accept(new distributeVariance(), a.getVariance()); + } + }); + phSetVariance = new ArrayList<>(phSet); // macht vermutlich keinen Sinn PL 2018-10-18, doch, es koennen neue + // TPHs mit Variancen dazugekommen sein PL 2018-11-07 + phSetVariance.removeIf(x -> (x.getVariance() == 0 || usedTPH.contains(x))); + } + return usedTPH; + } + + public final JavaClassRegistry classRegistry = new JavaClassRegistry(); + + public record ClassEntry(File classFile, ClassOrInterface cif) {} + + public final Map loadedClasses = new HashMap<>(); + + private SourceFile parse(File sourceFile) throws IOException, ClassNotFoundException { + if (sourceFiles.containsKey(sourceFile)) return sourceFiles.get(sourceFile); + Java17Parser.SourceFileContext tree = JavaTXParser.parse(sourceFile); + environment.addClassesToRegistry(classRegistry, tree, sourceFile, this); + SyntaxTreeGenerator generator = new SyntaxTreeGenerator(this, classRegistry, new GenericsRegistry(null), sourceFile.getName()); + var classes = new ArrayList(); + var sf = new SourceFile("", classes, generator.imports); + addSourceFile(sourceFile, sf); + generator.convert(classes, tree, environment.packageCrawler); + sf.setPackageName(generator.pkgName); + sf.imports.addAll(generator.imports); + return sf; + } + + /** + * When an import tries to import a JavaTX class it first looks it up in the cache and + * if it doesn't exist it's going to compile it and add it to the source files list + * @param name + */ + public ClassOrInterface loadJavaTXClass(JavaClassName name) { + var file = findFileForClass(name); + if (file != null) { + if (loadedClasses.containsKey(name)) return loadedClasses.get(name).cif(); + try { + 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), file.getName()); + var classes = new ArrayList(); + var sf = new SourceFile("", classes, generator.imports); + addSourceFile(file, sf); + generator.convert(classes, tree, environment.packageCrawler); + sf.setPackageName(generator.pkgName); + var classFiles = generateBytecode(file); + + sf.setGenerated(); + writeClassFile(classFiles, outputPath != null ? outputPath : new File("."), false); + var clazz = classLoader.loadClass(name.toString()); + var classOrInterface = ASTFactory.createClass(clazz); + loadedClasses.put(name, new ClassEntry(new File(outputPath, clazz.getName() + ".class"), classOrInterface)); + return classOrInterface; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + return null; + } + + public File findFileForClass(JavaClassName name) { + var packageName = name.getPackageName(); + var className = name.getClassName().split("\\.")[0]; + for (var cp : classPath) { + var file = new File(cp, packageName.replaceAll("\\.", "/") + "/" + className + ".jav"); + if (file.exists()) return file; + } + return null; + } + + public void generateBytecode() throws ClassNotFoundException, IOException { + for (var file : sourceFiles.keySet()) { + var sf = sourceFiles.get(file); + if (sf.isGenerated()) continue; + var classes = generateBytecode(file); + sf.setGenerated(); + writeClassFile(classes, outputPath == null ? file.getParentFile() : outputPath, outputPath == null); + } + } + + /** + * @param path - output-Directory can be null, then class file output is in the same directory as the parsed source files + * @return + */ + public Map generateBytecode(File sourceFile) throws ClassNotFoundException, IOException { + var sf = sourceFiles.get(sourceFile); + if (sf.isGenerated()) return null; + List typeinferenceResult = this.typeInference(sourceFile); + var classes = generateBytecode(sf, typeinferenceResult); + sf.setGenerated(); + return classes; + } + + private Map> generatedGenerics = new HashMap<>(); + + public Map> getGeneratedGenerics() { + return generatedGenerics; + } + + /** + * @param outputPath - can be null, then class file output is in the same directory as the parsed source files + * @param typeinferenceResult + * @throws IOException + */ + public void generateBytecode(File outputPath, List typeinferenceResult) throws IOException { + for (File f : sourceFiles.keySet()) { + HashMap classFiles = new HashMap<>(); + SourceFile sf = sourceFiles.get(f); + File path = outputPath; + if (outputPath == null) { + path = f.getParentFile(); // Set path to path of the parsed .jav file + } + + var generatedClasses = generateBytecode(sf, typeinferenceResult); + writeClassFile(generatedClasses, path, outputPath == null); + } + } + + public synchronized Map generateBytecode(SourceFile sf, List typeInferenceResult) { + var converter = new ASTToTargetAST(this, typeInferenceResult, sf, classLoader); + var generatedClasses = new HashMap(); + for (var clazz : sf.getClasses()) { + var codegen = new Codegen(converter.convert(clazz), this, converter); + var code = codegen.generate(); + generatedClasses.put(clazz.getClassName(), code); + converter.auxiliaries.forEach((name, source) -> { + generatedClasses.put(new JavaClassName(name), source); + }); + } + generatedGenerics.put(sf, converter.javaGenerics()); + converter.generateFunNTypes(); + return generatedClasses; + } + + public synchronized void writeClassFile(Map classFiles, File path, boolean preserveHierarchy) throws IOException { + FileOutputStream output; + for (JavaClassName name : classFiles.keySet()) { + byte[] bytecode = classFiles.get(name); + System.out.println("generating " + name + ".class file ..."); + var subPath = preserveHierarchy ? path : Path.of(path.toString(), name.getPackageName().split("\\.")).toFile(); + File outputFile = new File(subPath, name.getClassName() + ".class"); + outputFile.getAbsoluteFile().getParentFile().mkdirs(); + System.out.println(outputFile); + output = new FileOutputStream(outputFile); + output.write(bytecode); + output.close(); + System.out.println(name + ".class file generated"); + } + } + + /* PL 2020-03-17 mit TypeExchanger in FCGenerator.java zusammenfuehren */ + /** + * Tauscht die GTVs in einem Typ gegen die entsprechenden Typen in der übergebenen Map aus. + */ + private static class TypeExchanger implements TypeVisitor { + + private final HashMap gtvs; + + TypeExchanger(HashMap gtvs) { + this.gtvs = gtvs; + } + + @Override + public RefTypeOrTPHOrWildcardOrGeneric visit(RefType refType) { + List params = new ArrayList<>(); + for (RefTypeOrTPHOrWildcardOrGeneric param : refType.getParaList()) { + params.add(param.acceptTV(this)); + } + RefTypeOrTPHOrWildcardOrGeneric ret = new RefType(refType.getName(), params, new NullToken()); + return ret; + } + + @Override + public RefTypeOrTPHOrWildcardOrGeneric visit(SuperWildcardType superWildcardType) { + SuperWildcardType ret = new SuperWildcardType(superWildcardType.getInnerType().acceptTV(this), superWildcardType.getOffset()); + return ret; + } + + @Override + public RefTypeOrTPHOrWildcardOrGeneric visit(TypePlaceholder typePlaceholder) { + return typePlaceholder; // TypePlaceholder der vererbert wird kann bei der Vererbung nicht instanziert + // werden. + } + + @Override + public RefTypeOrTPHOrWildcardOrGeneric visit(ExtendsWildcardType extendsWildcardType) { + ExtendsWildcardType ret = new ExtendsWildcardType(extendsWildcardType.getInnerType().acceptTV(this), extendsWildcardType.getOffset()); + return ret; + } + + @Override + public RefTypeOrTPHOrWildcardOrGeneric visit(GenericRefType genericRefType) { + if (!gtvs.containsKey(genericRefType.getParsedName())) + throw new DebugException("Dieser Fall darf nicht auftreten"); + return gtvs.get(genericRefType.getParsedName()); + } + + } + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/environment/ByteArrayClassLoader.java b/LanguageServer/src/main/java/de/dhbw/compiler/environment/ByteArrayClassLoader.java new file mode 100644 index 0000000..20ea8db --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/environment/ByteArrayClassLoader.java @@ -0,0 +1,13 @@ +package de.dhbw.compiler.environment; + +public class ByteArrayClassLoader extends ClassLoader implements IByteArrayClassLoader { + @Override + public Class _defineClass(String name, byte[] code, int i, int length) throws ClassFormatError { + return defineClass(name, code, i, length); + } + + @Override + public Class findClass(String name) throws ClassNotFoundException { + return super.findClass(name); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/environment/CompilationEnvironment.java b/LanguageServer/src/main/java/de/dhbw/compiler/environment/CompilationEnvironment.java new file mode 100644 index 0000000..64caede --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/environment/CompilationEnvironment.java @@ -0,0 +1,107 @@ +package de.dhbw.compiler.environment; + +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.*; + +import com.google.common.collect.Lists; +import de.dhbw.compiler.core.JavaTXCompiler; +import de.dhbw.compiler.syntaxtree.ClassOrInterface; +import de.dhbw.compiler.syntaxtree.factory.ASTFactory; + +import de.dhbw.compiler.exceptions.DebugException; +import de.dhbw.compiler.exceptions.NotImplementedException; +import de.dhbw.compiler.parser.JavaTXParser; + +import de.dhbw.compiler.parser.scope.GatherNames; +import de.dhbw.compiler.parser.scope.JavaClassRegistry; +import de.dhbw.parser.Java17Parser; + +/** + * Stellt die Java-Environment dar und speichert alle Binarys, Librarys und Sourcefiles im zu kompilierenden Projekt Sie erstellt anhand dieser Informationen die JavaClassNameRegistry + * + * TODO: Zur Initialisierung der CompilationEnvironment sollten alle SourceFiles mit ANTLR geparst werden und alle Klassen Generics und Typen herausgefunden werden + */ +public class CompilationEnvironment { + private final List librarys; + private final List sourceFiles; + public final PackageCrawler packageCrawler; + + /** + * Imitiert die Environment beim Aufruf des JavaCompilers auf einer Menge von java-Dateien Die Environment enth�lt automatisch die Java Standard Library + * + * @param sourceFiles die zu kompilierenden Dateien + */ + public CompilationEnvironment(List sourceFiles, DirectoryClassLoader classLoader) { + /** + * Java 9 bringt einige Änderungen am Classloader So funktioniert der BootClassLoader nicht mehr. hier gibts ein paar Quellen zum nachlesen: http://java9.wtf/class-loading/ https://stackoverflow.com/questions/46494112/classloaders-hierarchy-in-java-9 + * + */ + // String bootClassPath = System.getProperty("sun.boot.class.path"); + // DirectoryClassLoader cl = DirectoryClassLoader.getPlatformClassLoader(); + String bootClassPath = System.getProperty("java.class.path"); + librarys = new ArrayList<>(); + for (String path : bootClassPath.split(File.pathSeparator)) { + try { + librarys.add(new URL("file:" + path)); + } catch (MalformedURLException e) { + new DebugException("Fehler im Classpath auf diesem System"); + } + } + // URLClassLoader loader = new URLClassLoader(new URL[0], cl); + // librarys = Arrays.asList(loader.getURLs()); + + this.sourceFiles = sourceFiles; + this.packageCrawler = new PackageCrawler(classLoader); + } + + public void addClassesToRegistry(JavaClassRegistry registry, Java17Parser.SourceFileContext tree, File sourceFile, JavaTXCompiler compiler) throws ClassNotFoundException, IOException { + Map allNames; + if (tree instanceof Java17Parser.SrcfileContext srcfile) { + allNames = GatherNames.getNames((Java17Parser.SrcfileContext) tree, packageCrawler, compiler); + for (Class c : loadDefaultPackageClasses(getPackageName(srcfile), sourceFile, compiler)) { + allNames.put(c.getName(), c.getTypeParameters().length); + } + registry.addNames(allNames); + } else { + throw new NotImplementedException(); + } + + } + + public static List loadDefaultPackageClasses(String packageName, File sourceFile, JavaTXCompiler compiler) throws IOException, ClassNotFoundException { + ClassLoader classLoader = compiler.getClassLoader(); + List ret = new ArrayList<>(); + // Set classLoader to include default package for this specific source file + File dir = sourceFile.getAbsoluteFile().getParentFile(); + String dirPath = dir.toString() + "/"; + if (!packageName.isEmpty()) + dirPath = dirPath.substring(0, dirPath.length() - packageName.length() - 1); + String path = dirPath; + ArrayList defaultPath = Lists.newArrayList(new File(path)); + classLoader = new DirectoryClassLoader(defaultPath, classLoader); + // Gather all names in the default package for this source file (classes that are imported by default) + File[] files = dir.listFiles((dir1, name) -> name.endsWith(".class")); + if (files != null) + for (File classFile : files) { + String className = classFile.getName().substring(0, classFile.getName().length() - 6); + if (className.matches("Fun\\d+\\$\\$.*")) + continue; + var name = packageName; + if (!packageName.isEmpty()) name += "."; + name += className; + ret.add(classLoader.loadClass(name)); + } + return ret; + } + + private static String getPackageName(Java17Parser.SrcfileContext forTree) { + String packageName = ""; + if (forTree.packageDeclaration() != null && !forTree.packageDeclaration().qualifiedName().identifier().isEmpty()) + packageName = forTree.packageDeclaration().qualifiedName().getText(); + return packageName; + } + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/environment/DirectoryClassLoader.java b/LanguageServer/src/main/java/de/dhbw/compiler/environment/DirectoryClassLoader.java new file mode 100644 index 0000000..bea75b2 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/environment/DirectoryClassLoader.java @@ -0,0 +1,78 @@ +package de.dhbw.compiler.environment; + +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.*; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class DirectoryClassLoader extends URLClassLoader implements IByteArrayClassLoader { +// public DirectoryClassLoader(File directory, java.lang.ClassLoader parent) { +// super(generateURLArray(dirToURL(directory)), parent); +// } + + public DirectoryClassLoader(List directory, ClassLoader parent) { + super(directory.stream().map(DirectoryClassLoader::dirToURL).flatMap(List::stream).collect(Collectors.toList()).toArray(new URL[0]), parent.getParent()); + } + + private static URL[] generateURLArray(URL url) { + return new URL[]{url}; + } + + private static List dirToURL(File file) { + //if(!url.isDirectory())throw new RuntimeException(url.toString() + " is not a directory"); + + Path dir; + if (file.isDirectory()) { + try { + return List.of(file.toURI().toURL()); // if file is a directory, use it as is + } catch (MalformedURLException e) { + e.printStackTrace(); + return List.of(); + } + } + + dir = file.toPath().getParent(); // if file is not a directory, get its parent directory + String pattern = file.toPath().getFileName().toString(); // use the file name as a glob pattern + + List urls = new ArrayList<>(); + + try { + urls = Files.walk(dir) + .filter(Files::isRegularFile) // only consider files (not directories) + .filter(path -> { + PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:" + pattern); + return matcher.matches(path.getFileName()); // match the file name against the pattern + }) + .map(path -> { + try { + return path.toUri().toURL(); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + }) // convert the path to a URL + .toList(); // print the path of each matching file + } catch (IOException | RuntimeException e) { + e.printStackTrace(); + } + return urls; + } + + @Override + public Class _defineClass(String name, byte[] code, int i, int length) throws ClassFormatError { + return defineClass(name, code, i, length); + } + + @Override + public Class findClass(String name) throws ClassNotFoundException { + return super.findClass(name); + } + + public Class _findLoadedClass(String name) throws ClassNotFoundException { + return super.findLoadedClass(name); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/environment/IByteArrayClassLoader.java b/LanguageServer/src/main/java/de/dhbw/compiler/environment/IByteArrayClassLoader.java new file mode 100644 index 0000000..965b9b4 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/environment/IByteArrayClassLoader.java @@ -0,0 +1,23 @@ +package de.dhbw.compiler.environment; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +public interface IByteArrayClassLoader { + + Class loadClass(String path) throws ClassNotFoundException; + + default Class loadClass(byte[] code) { + return this._defineClass(null, code, 0, code.length); + } + + default Class loadClass(Path path) throws IOException { + var code = Files.readAllBytes(path); + return this._defineClass(null, code, 0, code.length); + } + + public Class findClass(String name) throws ClassNotFoundException; + + Class _defineClass(String name, byte[] code, int i, int length) throws ClassFormatError; +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/environment/PackageCrawler.java b/LanguageServer/src/main/java/de/dhbw/compiler/environment/PackageCrawler.java new file mode 100644 index 0000000..7f5c715 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/environment/PackageCrawler.java @@ -0,0 +1,52 @@ +package de.dhbw.compiler.environment; + +import io.github.classgraph.ClassGraph; +import io.github.classgraph.ScanResult; + +import java.util.*; + +/** + * Hilft beim Durchsuchen von Packages + * Benutzt die Reflections-Library (https://github.com/ronmamo/reflections) + * Hilfe dazu: http://stackoverflow.com/a/9571146 + */ +public class PackageCrawler { + + final DirectoryClassLoader classLoader; + public PackageCrawler(DirectoryClassLoader classLoader) { + this.classLoader = classLoader; + } + + public Set> getClassesInPackage(String packageName) { + var res = new HashSet>(); + + try (ScanResult result = new ClassGraph() + .enableClassInfo() + .enableSystemJarsAndModules() + .addClassLoader(classLoader) + .acceptPackages(packageName) + .scan()) { + + for (var info : result.getAllClasses()) { + try { + var clazz = Class.forName(info.getName()); + res.add(clazz); + } catch (ClassNotFoundException ignored) {} + } + }; + + return res; + } + + public Map getClassNames(String packageName){ + Map nameList = new HashMap<>(); + Set> classes = getClassesInPackage(packageName); + if(packageName.equals("java.lang") && ! classes.contains(Object.class)) { + classes.add(Object.class); + } + for(Class c : classes){ + nameList.put(c.getName(), c.getTypeParameters().length); + } + return nameList; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/exceptions/DebugException.java b/LanguageServer/src/main/java/de/dhbw/compiler/exceptions/DebugException.java new file mode 100644 index 0000000..d7cf3c7 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/exceptions/DebugException.java @@ -0,0 +1,8 @@ +package de.dhbw.compiler.exceptions; + +public class DebugException extends RuntimeException { + + public DebugException(String message) { + System.err.print(message); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/exceptions/NotImplementedException.java b/LanguageServer/src/main/java/de/dhbw/compiler/exceptions/NotImplementedException.java new file mode 100644 index 0000000..1ec31b2 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/exceptions/NotImplementedException.java @@ -0,0 +1,11 @@ +package de.dhbw.compiler.exceptions; + +public class NotImplementedException extends RuntimeException { + + public NotImplementedException() { + } + + public NotImplementedException(String string) { + super(string); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/exceptions/ParserError.java b/LanguageServer/src/main/java/de/dhbw/compiler/exceptions/ParserError.java new file mode 100644 index 0000000..55005cc --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/exceptions/ParserError.java @@ -0,0 +1,10 @@ +package de.dhbw.compiler.exceptions; + +import org.antlr.v4.runtime.Token; + +public class ParserError extends TypeinferenceException{ + + public ParserError(Token offset){ + super("Fehler beim Parsen", offset); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/exceptions/TypeinferenceException.java b/LanguageServer/src/main/java/de/dhbw/compiler/exceptions/TypeinferenceException.java new file mode 100644 index 0000000..7fdcc3b --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/exceptions/TypeinferenceException.java @@ -0,0 +1,46 @@ +package de.dhbw.compiler.exceptions; + +import de.dhbw.compiler.syntaxtree.SyntaxTreeNode; +import org.antlr.v4.runtime.Token; + +/** + * Eine RuntimeException, welche bei einem Fehler während des Typinferenzalgorithmus ausgelöst wird. + * Dies wird zum Beispiel durch Programmierfehler in der Java-Eingabedatei ausgelöst. + * @author Andreas Stadelmeier, a10023 + * + */ +//TODO: Diese Klasse muss von Exception erben +public class TypeinferenceException extends RuntimeException { + + /** + * Das Offset im Quelltext bei dem das Problem aufgetaucht ist + */ + private Token offset; + private String message; + + public TypeinferenceException(String message, SyntaxTreeNode problemSource) + { + super(message); + this.message=message; + if(problemSource == null)throw new DebugException("TypinferenzException ohne Offset: "+this.message); + this.offset=problemSource.getOffset(); + } + + public TypeinferenceException(String message, Token offset){ + this.message=message; + this.offset = offset; + } + + /** + * + * @return Der Offset an dem im Quellcode der Fehler aufgetreten ist. + */ + public Token getOffset(){ + return offset; + } + + public String getMessage(){ + return this.message; + } + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/languageServerInterface/LanguageServerInterface.java b/LanguageServer/src/main/java/de/dhbw/compiler/languageServerInterface/LanguageServerInterface.java new file mode 100644 index 0000000..1678c00 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/languageServerInterface/LanguageServerInterface.java @@ -0,0 +1,25 @@ +package de.dhbw.compiler.languageServerInterface; + +import de.dhbw.compiler.typeinference.result.ResultSet; + +import java.util.List; + +/** + * Implementation of an Interface for the Language-Server to get the Resultset and abstract Syntax. + * */ +public class LanguageServerInterface { + + /** + * get final Result Set + * */ + public List getResultSet(String input) { + return null; + } + + /** + * get abstract Syntax + * */ + public List getAbstractSyntax(String input) { + return null; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/parser/JavaTXParser.java b/LanguageServer/src/main/java/de/dhbw/compiler/parser/JavaTXParser.java new file mode 100644 index 0000000..5567e30 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/parser/JavaTXParser.java @@ -0,0 +1,37 @@ +package de.dhbw.compiler.parser; + +import de.dhbw.compiler.environment.CompilationEnvironment; +import de.dhbw.compiler.parser.SyntaxTreeGenerator.SyntaxTreeGenerator; + +import de.dhbw.compiler.parser.scope.JavaClassRegistry; +import de.dhbw.compiler.syntaxtree.SourceFile; + +import de.dhbw.parser.Java17Lexer; +import de.dhbw.parser.Java17Parser; +import org.antlr.v4.runtime.CharStream; +import org.antlr.v4.runtime.CharStreams; +import org.antlr.v4.runtime.CommonTokenStream; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +public class JavaTXParser { + public static Java17Parser.SourceFileContext parse(File source) throws IOException, ClassNotFoundException { + InputStream stream = new FileInputStream(source); + // DEPRECATED: ANTLRInputStream input = new ANTLRInputStream(stream); + CharStream input = CharStreams.fromStream(stream); + Java17Lexer lexer = new Java17Lexer(input); + CommonTokenStream tokens = new CommonTokenStream(lexer); + Java17Parser parser = new Java17Parser(tokens); + return parser.sourceFile(); + /* + * SyntaxTreeGenerator generator = new SyntaxTreeGenerator(environment.getRegistry(source)); return generator.convert(tree); + */ + } + + /* + * Für das Typsystem ist es notwendig, dass sich der Source in einer Datei befindet: public SourceFile parse(String fileContent) throws IOException, java.lang.ClassNotFoundException { return this.parse(new ByteArrayInputStream(fileContent.getBytes(StandardCharsets.UTF_8))); } + */ +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/parser/NullToken.java b/LanguageServer/src/main/java/de/dhbw/compiler/parser/NullToken.java new file mode 100644 index 0000000..b9acad7 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/parser/NullToken.java @@ -0,0 +1,57 @@ +package de.dhbw.compiler.parser; + +import org.antlr.v4.runtime.CharStream; +import org.antlr.v4.runtime.Token; +import org.antlr.v4.runtime.TokenSource; + +public class NullToken implements Token { + @Override + public String getText() { + return ""; + } + + @Override + public int getType() { + return 0; + } + + @Override + public int getLine() { + return 0; + } + + @Override + public int getCharPositionInLine() { + return 0; + } + + @Override + public int getChannel() { + return 0; + } + + @Override + public int getTokenIndex() { + return 0; + } + + @Override + public int getStartIndex() { + return 0; + } + + @Override + public int getStopIndex() { + return 0; + } + + @Override + public TokenSource getTokenSource() { + return null; + } + + @Override + public CharStream getInputStream() { + return null; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/parser/SourceLoc.java b/LanguageServer/src/main/java/de/dhbw/compiler/parser/SourceLoc.java new file mode 100644 index 0000000..c8fd43a --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/parser/SourceLoc.java @@ -0,0 +1,4 @@ +package de.dhbw.compiler.parser; + +public record SourceLoc(String file, int line) { +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/parser/SyntaxTreeGenerator/AssignToLocal.java b/LanguageServer/src/main/java/de/dhbw/compiler/parser/SyntaxTreeGenerator/AssignToLocal.java new file mode 100644 index 0000000..ac971eb --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/parser/SyntaxTreeGenerator/AssignToLocal.java @@ -0,0 +1,20 @@ +package de.dhbw.compiler.parser.SyntaxTreeGenerator; + +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.statement.AssignLeftSide; +import de.dhbw.compiler.syntaxtree.statement.Expression; +import de.dhbw.compiler.syntaxtree.statement.LocalVar; + +public class AssignToLocal extends AssignLeftSide { + public final LocalVar localVar; + + public AssignToLocal(LocalVar leftSide) { + super(leftSide.getType(), leftSide.getOffset()); + localVar = leftSide; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/parser/SyntaxTreeGenerator/FCGenerator.java b/LanguageServer/src/main/java/de/dhbw/compiler/parser/SyntaxTreeGenerator/FCGenerator.java new file mode 100644 index 0000000..71167e5 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/parser/SyntaxTreeGenerator/FCGenerator.java @@ -0,0 +1,252 @@ +package de.dhbw.compiler.parser.SyntaxTreeGenerator; + +import de.dhbw.compiler.core.JavaTXCompiler; +import de.dhbw.compiler.exceptions.DebugException; +import de.dhbw.compiler.parser.NullToken; +import de.dhbw.compiler.parser.scope.JavaClassName; +import de.dhbw.compiler.syntaxtree.ClassOrInterface; +import de.dhbw.compiler.syntaxtree.GenericTypeVar; +import de.dhbw.compiler.syntaxtree.Method; +import de.dhbw.compiler.syntaxtree.Pattern; +import de.dhbw.compiler.syntaxtree.factory.ASTFactory; +import de.dhbw.compiler.syntaxtree.factory.UnifyTypeFactory; +import de.dhbw.compiler.syntaxtree.type.*; +import de.dhbw.compiler.typeinference.constraints.Pair; +import de.dhbw.compiler.typeinference.unify.model.*; + +import java.util.*; +import java.util.stream.Collectors; + +import org.antlr.v4.runtime.Token; + +public class FCGenerator { + /** + * Baut die FiniteClosure aus availableClasses. + * Klassen welche nicht in availableClasses vorkommen werden im Java Classpath nachgeschlagen. + * + * @param availableClasses - Alle geparsten Klassen + */ + public static Set toUnifyFC(JavaTXCompiler compiler, Collection availableClasses, ClassLoader classLoader) throws ClassNotFoundException { + return toFC(availableClasses, classLoader).stream().map(t -> UnifyTypeFactory.convert(compiler, t)).collect(Collectors.toSet()); + } + + public static Set toFC(Collection availableClasses, ClassLoader classLoader) throws ClassNotFoundException { + HashSet pairs = new HashSet<>(); + //PL 2018-09-18: gtvs vor die for-Schleife gezogen, damit immer die gleichen Typeplaceholder eingesetzt werden. + HashMap gtvs = new HashMap<>(); + for(ClassOrInterface cly : availableClasses){ + List newPairs = getSuperTypes(cly, availableClasses, gtvs, classLoader); + pairs.addAll(newPairs); + + //For all Functional Interfaces FI: FunN$$<... args auf dem Functional Interface ...> <. FI is added to FC + if (isFunctionalInterface(cly)) { + pairs.add(genImplFunType(cly, newPairs.get(0).TA1, gtvs)); + } + } + return pairs; + } + + + private static Boolean isFunctionalInterface(ClassOrInterface cly) { + return (cly.isInterface() && (cly.isFunctionalInterface() || cly.getMethods().size() == 1)); + } + + private static Pair genImplFunType(ClassOrInterface cly, RefTypeOrTPHOrWildcardOrGeneric fIType, HashMap gtvs) { + for(Method m : cly.getMethods()) { + if (!java.lang.reflect.Modifier.isAbstract(m.modifier)) + continue; + List tl = + (m.getParameterList().getFormalparalist() + .stream().map(p -> p.getType().acceptTV(new TypeExchanger(gtvs))) + .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, PairOperator.SMALLER); + } + return null; //kann nicht passieren, da die Methode nur aufgerufen wird wenn cl Functional Interface ist + } + + + + /** + * Bildet eine Kette vom übergebenen Typ bis hin zum höchsten bekannten Typ + * Als Generics werden TPHs benutzt, welche der Unifikationsalgorithmus korrekt interpretieren muss. + * Die verwendeten TPHs werden in der Kette nach oben gereicht, so erhält der selbe GTV immer den selben TPH + * @param forType + * @return + */ + private static List getSuperTypes(ClassOrInterface forType, Collection availableClasses, ClassLoader classLoader) throws ClassNotFoundException { + return getSuperTypes(forType, availableClasses, new HashMap<>(), classLoader); + } + + /** + * + * @param forType + * @param availableClasses + * @param gtvs + * @return + * @throws ClassNotFoundException + */ + private static List getSuperTypes(ClassOrInterface forType, Collection availableClasses, + HashMap gtvs, ClassLoader classLoader) throws ClassNotFoundException { + List params = new ArrayList<>(); + //Die GTVs, die in forType hinzukommen: + HashMap newGTVs = new HashMap<>(); + //Generics mit gleichem Namen müssen den selben TPH bekommen + for(GenericTypeVar gtv : forType.getGenerics()){ + if(!gtvs.containsKey(gtv.getName())){ + TypePlaceholder replacePlaceholder = TypePlaceholder.fresh(new NullToken()); + gtvs.put(gtv.getName(), replacePlaceholder); + newGTVs.put(gtv.getName(), replacePlaceholder); + } + params.add(gtvs.get(gtv.getName())); + } + + + List superClasses = new ArrayList<>(); + superClasses.add(forType.getSuperClass()); + superClasses.addAll(forType.getSuperInterfaces()); + + List retList = new ArrayList<>(); + for(RefType superType : superClasses){ + Optional hasSuperclass = availableClasses.stream().filter(cl -> superType.getName().equals(cl.getClassName())).findAny(); + ClassOrInterface superClass; + if(!hasSuperclass.isPresent()) //Wenn es die Klasse in den available Klasses nicht gibt wird sie im Classpath gesucht. Ansonsten Exception + { + superClass = ASTFactory.createClass(classLoader.loadClass(superType.getName().toString())); + }else{ + superClass = hasSuperclass.get(); + } + /* + Die Parameter der superklasse müssen jetzt nach den Angaben in der Subklasse + modifiziert werden + Beispie: Matrix extends Vector> + Den ersten Parameter mit Vector austauschen und dort alle Generics zu den Typplaceholdern in gtvs austauschen + */ + //Hier vermerken, welche Typen in der Superklasse ausgetauscht werden müssen + Iterator itGenParams = superClass.getGenerics().iterator(); + Iterator itSetParams = superType.getParaList().iterator(); + while(itSetParams.hasNext()){ + RefTypeOrTPHOrWildcardOrGeneric setType = itSetParams.next(); + //In diesem Typ die GTVs durch TPHs und Einsetzungen austauschen: + RefTypeOrTPHOrWildcardOrGeneric setSetType = setType.acceptTV(new TypeExchanger(gtvs)); + newGTVs.put(itGenParams.next().getName(), setSetType); + } + + //Für den superType kann man nun zum Austauschen der Generics wieder die gtvs nehmen: + //Die newGTVs sind nur für den superClass ClassOrInterface welches möglicherweise per reflection geladen wurde abgestimmt + RefTypeOrTPHOrWildcardOrGeneric superRefType = superType.acceptTV(new TypeExchanger(gtvs)); + + RefTypeOrTPHOrWildcardOrGeneric t1 = new RefType(forType.getClassName(), params, new NullToken()); + RefTypeOrTPHOrWildcardOrGeneric t2 = superRefType; + + Pair ret = new Pair(t1, t2, PairOperator.SMALLER); + + List superTypes; + //Rekursiver Aufruf. Abbruchbedingung ist Object als Superklasse: + if(superClass.getClassName().equals(ASTFactory.createObjectClass().getClassName())){ + superTypes = Arrays.asList(new Pair(ASTFactory.createObjectType(), ASTFactory.createObjectType(), PairOperator.SMALLER)); + }else{ + superTypes = getSuperTypes(superClass, availableClasses, newGTVs, classLoader); + } + + retList.add(ret); + retList.addAll(superTypes); + } + + return retList; + } + + /** + * Tauscht die GTVs in einem Typ gegen die entsprechenden Typen in der übergebenen Map aus auf der direkten Argumentebene. + * Hier sind keine Wildcards zulässig + */ + private static class TypeExchanger implements TypeVisitor{ + + private final HashMap gtvs; + + TypeExchanger(HashMap gtvs){ + this.gtvs = gtvs; + } + + @Override + public RefTypeOrTPHOrWildcardOrGeneric visit(RefType refType) { + List params = new ArrayList<>(); + for(RefTypeOrTPHOrWildcardOrGeneric param : refType.getParaList()){ + params.add(param.acceptTV(new TypeExchangerInner(gtvs))); + } + RefTypeOrTPHOrWildcardOrGeneric ret = new RefType(refType.getName(), params, new NullToken()); + return ret; + } + + @Override + public RefTypeOrTPHOrWildcardOrGeneric visit(SuperWildcardType superWildcardType) { + throw new DebugException("Dieser Fall darf nicht auftreten"); + } + + @Override + public RefTypeOrTPHOrWildcardOrGeneric visit(TypePlaceholder typePlaceholder) { + throw new DebugException("Dieser Fall darf nicht auftreten"); + } + + @Override + public RefTypeOrTPHOrWildcardOrGeneric visit(ExtendsWildcardType extendsWildcardType) { + throw new DebugException("Dieser Fall darf nicht auftreten"); + } + + @Override + public RefTypeOrTPHOrWildcardOrGeneric visit(GenericRefType genericRefType) { + if(! gtvs.containsKey(genericRefType.getParsedName())) + throw new DebugException("Dieser Fall darf nicht auftreten"); + return gtvs.get(genericRefType.getParsedName()); + } + + } + + /** + * Tauscht die GTVs in einem Typ gegen die entsprechenden Typen in der übergebenen Map aus auf den Argumenten der Argumente. + * Hier sind Wildcards zulässig + */ + private static class TypeExchangerInner implements TypeVisitor{ + + private final HashMap gtvs; + + TypeExchangerInner(HashMap gtvs){ + this.gtvs = gtvs; + } + + @Override + public RefTypeOrTPHOrWildcardOrGeneric visit(RefType refType) { + List params = new ArrayList<>(); + for(RefTypeOrTPHOrWildcardOrGeneric param : refType.getParaList()){ + params.add(param.acceptTV(this)); + } + RefTypeOrTPHOrWildcardOrGeneric ret = new RefType(refType.getName(), params, new NullToken()); + return ret; + } + + @Override + public RefTypeOrTPHOrWildcardOrGeneric visit(SuperWildcardType superWildcardType) { + return superWildcardType; + } + + @Override + public RefTypeOrTPHOrWildcardOrGeneric visit(TypePlaceholder typePlaceholder) { + throw new DebugException("Dieser Fall darf nicht auftreten"); + } + + @Override + public RefTypeOrTPHOrWildcardOrGeneric visit(ExtendsWildcardType extendsWildcardType) { + return extendsWildcardType; + } + + @Override + public RefTypeOrTPHOrWildcardOrGeneric visit(GenericRefType genericRefType) { + if(! gtvs.containsKey(genericRefType.getParsedName())) + throw new DebugException("Dieser Fall darf nicht auftreten"); + return gtvs.get(genericRefType.getParsedName()); + } + + } + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/parser/SyntaxTreeGenerator/FieldEntry.java b/LanguageServer/src/main/java/de/dhbw/compiler/parser/SyntaxTreeGenerator/FieldEntry.java new file mode 100644 index 0000000..7db3473 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/parser/SyntaxTreeGenerator/FieldEntry.java @@ -0,0 +1,6 @@ +package de.dhbw.compiler.parser.SyntaxTreeGenerator; + +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; + +public record FieldEntry(String name, RefTypeOrTPHOrWildcardOrGeneric type, int modifiers) { +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/parser/SyntaxTreeGenerator/GenericContext.java b/LanguageServer/src/main/java/de/dhbw/compiler/parser/SyntaxTreeGenerator/GenericContext.java new file mode 100644 index 0000000..d185574 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/parser/SyntaxTreeGenerator/GenericContext.java @@ -0,0 +1,14 @@ +package de.dhbw.compiler.parser.SyntaxTreeGenerator; + +import de.dhbw.compiler.parser.scope.JavaClassName; + +public class GenericContext { + private final String parentMethod; + private final JavaClassName parentClass; + + public GenericContext(JavaClassName parentClass, String parentMethod) { + if(parentMethod == null)parentMethod = ""; + this.parentClass = parentClass; + this.parentMethod = parentMethod; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/parser/SyntaxTreeGenerator/StatementGenerator.java b/LanguageServer/src/main/java/de/dhbw/compiler/parser/SyntaxTreeGenerator/StatementGenerator.java new file mode 100644 index 0000000..0b03b28 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/parser/SyntaxTreeGenerator/StatementGenerator.java @@ -0,0 +1,1036 @@ +package de.dhbw.compiler.parser.SyntaxTreeGenerator; + +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import de.dhbw.compiler.core.JavaTXCompiler; +import de.dhbw.compiler.syntaxtree.*; +import de.dhbw.compiler.syntaxtree.statement.*; +import de.dhbw.compiler.syntaxtree.type.Void; +import de.dhbw.compiler.target.tree.expression.TargetUnaryOp; +import de.dhbw.compiler.target.generate.StatementToTargetExpression; +import de.dhbw.parser.Java17Parser; +import org.antlr.v4.runtime.Token; +import de.dhbw.parser.Java17Parser.*; +import de.dhbw.compiler.exceptions.NotImplementedException; +import de.dhbw.compiler.parser.NullToken; + +import de.dhbw.compiler.parser.scope.GenericsRegistry; +import de.dhbw.compiler.parser.scope.JavaClassName; +import de.dhbw.compiler.parser.scope.JavaClassRegistry; +import de.dhbw.compiler.syntaxtree.type.RefType; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.syntaxtree.type.TypePlaceholder; + +public class StatementGenerator { + + private final JavaClassRegistry reg; + + private final Map fields; // PL 2018-11-01 fields eingefuegt, damit die fields + // immer die gleiche TPH bekommen + private final Map localVars; + private final GenericsRegistry generics; + private final JavaTXCompiler compiler; + + private final RefType superClass; + + // TODO How about instead of passing all of these types we just pass an instance of the SyntaxTreeGenerator? + public StatementGenerator(RefType superType, JavaTXCompiler compiler, JavaClassRegistry reg, GenericsRegistry generics, Map fields, Map localVars) { + this.reg = reg; + this.generics = generics; + this.fields = fields; + this.localVars = localVars; + this.compiler = compiler; + this.superClass = superType; + } + + public ParameterList convert(Java17Parser.FormalParameterListContext formalParameterListContext, boolean methodparameters) { + List ret = new ArrayList<>(); + List fps = new ArrayList<>(); + if (Objects.isNull(formalParameterListContext)) + return new ParameterList(ret, new NullToken()); // Dann ist die Parameterliste leer + if (!Objects.isNull(formalParameterListContext.lastFormalParameter())) { + /* + * Der '...' Operator wird noch nicht unterstützt, da dafür benötigte Typen (List oder Array) nicht vom Typinferenzalgo. verarbeitet werden können + */ + throw new NotImplementedException("Formale Parameter variabler Länge nicht unterstützt."); + } + + fps = formalParameterListContext.formalParameter(); + for (Java17Parser.FormalParameterContext fp : fps) { + if (fp.pattern() != null) { + ret.add(convert(fp.pattern())); + } else { + String paramName = SyntaxTreeGenerator.convert(fp.variableDeclaratorId()); + RefTypeOrTPHOrWildcardOrGeneric type; + if (fp.typeType() != null) { + type = TypeGenerator.convert(fp.typeType(), reg, generics); + } else { + type = methodparameters? + TypePlaceholder.fresh(fp.getStart(), 1, false) + : TypePlaceholder.fresh(fp.getStart()); + } + ret.add(new FormalParameter(paramName, type, fp.getStart())); + localVars.put(paramName, type); + } + } + return new ParameterList(ret, ret.get(0).getOffset()); + } + + /* + * StatementGeneration: + */ + + private Statement convert(Java17Parser.StatementContext stmt) { + switch (stmt) { + case Java17Parser.BlockstmtContext blockstmt: + return convert(blockstmt.block(), false); + case ConditionalstmtContext condition: + return convert(condition); + case WhileloopContext whileloop: + return convert(whileloop); + case DowhileloopContext dowhileloop: + return convert(dowhileloop); + case SwitchstmtContext switchstmt: + return convert(switchstmt); + case ReturnstmtContext returnstmt: + return convert(returnstmt); + case YieldstmtContext yieldstmt: + return convert(yieldstmt); + case StmtexpressionContext stmtexpression: + return convert(stmtexpression); + case AssertstmtContext assertstmt: + return convert(assertstmt); + case ForloopContext forloop: + return convert(forloop); + case TrycatchblockContext trycatchblock: + return convert(trycatchblock); + case TrycatchresourceContext trycatchresource: + return convert(trycatchresource); + case SynchronizedstmtContext synchronizedstmt: + return convert(synchronizedstmt); + case ThrowstmtContext throwstmt: + return convert(throwstmt); + case BreakstmtContext breakstmt: + return convert(breakstmt); + case ContinuestmtContext continuestmt: + return convert(continuestmt); + case SemistmtContext semistmt: + return convert(semistmt); + case LabeledstmtContext labeledstmt: + return convert(labeledstmt); + default: + throw new NotImplementedException(); + } + } + + public Block convert(Java17Parser.BlockContext block, boolean addTrailingReturn) { + List statements = new ArrayList<>(); + if (block.blockStatement().size() > 0) + for (Java17Parser.BlockStatementContext statementContext : block.blockStatement()) { + statements.addAll(convert(statementContext)); + } + if (addTrailingReturn) + statements = SyntacticSugar.addTrailingReturn(statements); + return new Block(statements, block.getStart()); + } + + private List convert(Java17Parser.BlockStatementContext statementContext) { + if (!Objects.isNull(statementContext.localVariableDeclaration())) { + return convert(statementContext.localVariableDeclaration()); + } else if (!Objects.isNull(statementContext.localTypeDeclaration())) { + throw new NotImplementedException(); + } else { + return Arrays.asList(convert(statementContext.statement())); + } + } + + private Statement convert(Java17Parser.LabeledstmtContext labeledStatementContext) { + throw new NotImplementedException(); + // return convert(labeledStatementContext.statement()); + } + + private Statement convert(Java17Parser.StmtexpressionContext stmt) { + ExpressionContext expr = stmt.statementExpression; + Token offset = stmt.getStart(); + switch (expr) { + case DottedexpressionContext dotted: + return convertToStatement(dotted, offset); + case MethodcallexpressionContext methodc: + return convert(methodc.methodCall(), offset); + case NewinstanceexpressionContext newinstance: + return convert(newinstance.creator()); + case AssignexpressionContext assignment: + Statement ret = convert(assignment); + ret.setStatement(); + return ret; + case PostfixexpressionContext postfix: + ret = convert(postfix); + ret.setStatement(); + return ret; + case PrefixexpressionContext prefix: + ret = convert(prefix); + ret.setStatement(); + return ret; + case SwitchExpression2Context switchexpr: + ret = convert(switchexpr); + ret.setStatement(); + return ret; + default: + System.out.println(stmt.getClass()); + throw new NotImplementedException(); + } + } + + private Statement convertToStatement(DottedexpressionContext expr, Token offset) { + if (!Objects.isNull(expr.methodCall())) { + return convert(expr.methodCall(), expr.expression(), offset); + } else if (!Objects.isNull(expr.NEW())) { + return convert(expr.innerCreator()); + } else { + throw new NotImplementedException(); + } + } + + private Statement convert(Java17Parser.CreatorContext creator) { + if (creator.nonWildcardTypeArguments() != null) + throw new NotImplementedException(); + + RefType newclass = convert(creator.createdName()); + + if (!Objects.isNull(creator.classCreatorRest())) { + ArgumentList args = convertArguments(creator.classCreatorRest().arguments().expressionList()); + ArrayList argTypes = args.getArguments().stream().map(x -> TypePlaceholder.fresh(creator.getStart())).collect(Collectors.toCollection(ArrayList::new)); + argTypes.add(TypePlaceholder.fresh(creator.getStart())); // return type + Statement ret = new NewClass(newclass, args, null, argTypes, creator.getStart()); + ret.setStatement(); + return ret; + } else { + return convert(creator.arrayCreatorRest()); + } + } + + private Statement convert(Java17Parser.ArrayCreatorRestContext expression) { + throw new NotImplementedException(); + } + + private RefType convert(Java17Parser.CreatedNameContext createdname) { + Java17Parser.TypeArgumentsContext genericArgs = null; + genericArgs = null; + if (createdname.typeArgumentsOrDiamond() != null) + genericArgs = createdname.typeArgumentsOrDiamond().typeArguments(); + IdentifierContext identifier = createdname.identifier(); + return (RefType) TypeGenerator.convertTypeName(identifier.getText(), genericArgs, identifier.getStart(), reg, generics); + } + + private Statement convert(Java17Parser.InnerCreatorContext innercreator) { + Java17Parser.NonWildcardTypeArgumentsContext genericArgs = null; + + if (!Objects.isNull(innercreator.nonWildcardTypeArgumentsOrDiamond())) { + genericArgs = innercreator.nonWildcardTypeArgumentsOrDiamond().nonWildcardTypeArguments(); + } + IdentifierContext identifier = innercreator.identifier(); + RefType newclass = (RefType) TypeGenerator.convertTypeName(identifier.getText(), genericArgs, identifier.getStart(), reg, generics); + ArgumentList args = convertArguments(innercreator.classCreatorRest().arguments().expressionList()); + ArrayList argTypes = args.getArguments().stream().map(x -> TypePlaceholder.fresh(innercreator.getStart())).collect(Collectors.toCollection(ArrayList::new)); + Statement ret = new NewClass(newclass, args, null, argTypes, innercreator.getStart()); + ret.setStatement(); + return ret; + + } + + private Statement convert(Java17Parser.ConditionalstmtContext stmt) { + Expression expr = convert(stmt.parExpression().expression()); + Statement thenBlock = convert(stmt.statement(0)); + Statement elseBlock = (stmt.statement().size() >= 2) ? convert(stmt.statement(1)) : null; + return new IfStmt(TypePlaceholder.fresh(stmt.getStart()), expr, thenBlock, elseBlock, stmt.getStart()); + } + + private Statement convert(Java17Parser.AssertstmtContext stmt) { + // TODO + throw new NotImplementedException(); + } + + private Statement convert(Java17Parser.SwitchstmtContext stmt) { + Expression switched = convert(stmt.parExpression().expression()); + List switchBlocks = new ArrayList<>(); + for (SwitchBlockStatementGroupContext blockstmt : stmt.switchBlockStatementGroup()) { + switchBlocks.add(convert(blockstmt)); + } + return new Switch(switched, switchBlocks, TypePlaceholder.fresh(switched.getOffset()), true, stmt.getStart()); + } + + // Um switchExpressions als Statement zu behandeln + private Statement convert(Java17Parser.SwitchExpression2Context switchexpression) { + Expression switchExpr = convert(switchexpression.switchExpression()); + if (switchExpr instanceof Switch s) { + s.setStatement(); + return s; + } else { + // sollte nie vorkommen, da convert(Java17Parser.SwitchExpressionContext switchExpression) eine Instanz von Switch zurückgibt + throw new RuntimeException(); + } + } + + private Expression convert(Java17Parser.SwitchExpressionContext switchExpression) { + Expression switched = convert(switchExpression.parExpression().expression()); + List switchBlocks = new ArrayList<>(); + Token offset = switchExpression.getStart(); + for (SwitchLabeledRuleContext labeledRule : switchExpression.switchLabeledRule()) { + switchBlocks.add(convert(labeledRule)); + } + return new Switch(switched, switchBlocks, TypePlaceholder.fresh(offset), false, offset); + } + + private SwitchBlock convert(SwitchLabeledRuleContext labeledRule) { + Boolean isDefault = false; + List labels = switch (labeledRule.switchLabelCase()) { + case LabeledRuleExprListContext exprList -> { + List labelList = exprList.expressionList().expression().stream().map((exprctx) -> { + Pattern expr = new ExpressionPattern(convert(exprctx), exprList.getStart()); + return new SwitchLabel(expr, expr.getType(), exprList.getStart()); + }).toList(); + yield labelList; + } + case LabeledRulePatternContext pattern -> { + Pattern p = convert(pattern.pattern()); + yield Arrays.asList(new SwitchLabel(p, p.getType(), pattern.getStart())); + } + case LabeledRuleDefaultContext def -> { + isDefault = true; + yield Arrays.asList(new SwitchLabel(new Void(def.getStart()), def.getStart())); + } + default -> throw new NotImplementedException(); + }; + + var isSingleExpression = false; + Token offset = labeledRule.getStart(); + SwitchRuleOutcomeContext outcome = labeledRule.switchRuleOutcome(); + Block block; + if (Objects.isNull(outcome.block())) { + List stmts = new ArrayList<>(); + stmts.add(new Yield(convert(outcome.expression()), outcome.expression().start)); + isSingleExpression = true; + block = new Block(stmts, outcome.expression().getStart()); + } else { + block = convert(outcome.block(), false); + } + return new SwitchBlock(labels, block, isDefault, isSingleExpression, offset); + } + + private Statement convert(Java17Parser.YieldstmtContext yieldstmt) { + return new Yield(convert(yieldstmt.expression()), yieldstmt.getStart()); + } + + private SwitchBlock convert(Java17Parser.SwitchBlockStatementGroupContext stmt) { + List labels = new ArrayList<>(); + stmt.switchLabel().forEach((label) -> { + labels.add(convert(label)); + }); + List block = new ArrayList<>(); + stmt.blockStatement().stream().forEach((blockStmt) -> { + block.addAll(convert(blockStmt)); + }); + return new SwitchBlock(labels, new Block(block, stmt.blockStatement(0).getStart()), false, stmt.getStart()); + } + + private SwitchLabel convert(SwitchLabelContext switchLabel) { + RefTypeOrTPHOrWildcardOrGeneric type = null; + Pattern caseExpression = switch (switchLabel) { + case SwitchLabelConstContext cons -> { + yield new ExpressionPattern(convert(cons.constantExpression), cons.getStart()); + } + case SwitchLabelPatternContext pattern -> { + yield convert(pattern.pattern()); + } + case SwitchLabelDefaultContext def -> { + type = new Void(switchLabel.getStart()); + yield null; + } + default -> throw new NotImplementedException(); + }; + Token offset = switchLabel.getStart(); + if (Objects.isNull(caseExpression)) { + if (type == null) + type = TypePlaceholder.fresh(offset); + return new SwitchLabel(type, offset); + } else { + return new SwitchLabel(caseExpression, caseExpression.getType(), offset); + } + } + + private Pattern convert(PatternContext pattern) { + + return switch (pattern) { + case PPatternContext pPattern -> { + yield convert(pPattern.primaryPattern()); + } + case GPatternContext gPattern -> { + GuardedPatternContext guarded = gPattern.guardedPattern(); + Expression condition = convert(guarded.expression()); + yield new GuardedPattern(condition, convert(guarded.primaryPattern()), guarded.getStart()); + } + default -> throw new NotImplementedException(); + }; + } + + private FormalParameter convert(PrimaryPatternContext pPattern) { + + switch (pPattern) { + case TPatternContext tPattern: + TypePatternContext typePattern = tPattern.typePattern(); + var text = typePattern.identifier().getText(); + var type = typePattern.typeType() == null ? TypePlaceholder.fresh(pPattern.getStart()) : TypeGenerator.convert(typePattern.typeType(), reg, generics); + localVars.put(text, type); + return new FormalParameter(text, type, typePattern.getStart()); + case RPatternContext rPattern: + RecordPatternContext recordPattern = rPattern.recordPattern(); + return convert(recordPattern); + case Java17Parser.LPatternContext patternContext: return new LiteralPattern(TypePlaceholder.fresh(patternContext.start), convert(patternContext.literal().get(0)), patternContext.start); + + default: + throw new NotImplementedException(); + + } + } + + private RecordPattern convert(RecordPatternContext recordPatternCtx) { + var cpl = recordPatternCtx.recordStructurePattern().recordComponentPatternList(); + List subPatternCtx = cpl == null ? List.of() : cpl.pattern(); + List subPattern = subPatternCtx.stream().map(this::convert).collect(Collectors.toList()); + IdentifierContext identifierCtx = recordPatternCtx.identifier(); + var text = (identifierCtx != null) ? identifierCtx.getText() : null; + //Hier evtl. Typ anpassen -> wenn kein Typ bekannt ist push neuen Typ auf Hashtable + var type = recordPatternCtx.typeType() == null ? TypePlaceholder.fresh(recordPatternCtx.getStart()) : TypeGenerator.convert(recordPatternCtx.typeType(), reg, generics); + if (text != null) localVars.put(text, type); + var ret = new RecordPattern(subPattern, text, type, recordPatternCtx.getStart()); + return ret; + } + + private Statement convert(Java17Parser.WhileloopContext stmt) { + Expression expr = convert(stmt.parExpression().expression()); + Statement block = convert(stmt.statement()); + return new WhileStmt(expr, block, stmt.getStart()); + } + + private Statement convert(Java17Parser.DowhileloopContext stmt) { + Statement block = convert(stmt.statement()); + Expression expr = convert(stmt.parExpression().expression()); + return new DoStmt(expr, block, stmt.getStart()); + } + + private Statement convert(Java17Parser.ForloopContext stmt) { + var control = stmt.forControl(); + 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(), + 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()) + ); + } + } + + private ArgumentList convertArguments(Java17Parser.ExpressionListContext arglist) { + if (arglist == null) + return new ArgumentList(new ArrayList<>(), new NullToken()); + Token offset = new NullToken(); + List arguments = new ArrayList(); + for (ExpressionContext arg : arglist.expression()) { + arguments.add(convert(arg)); + } + if (arguments.size() > 0) + offset = arguments.get(0).getOffset(); + return new ArgumentList(arguments, offset); + } + + private List convert(Java17Parser.LocalVariableDeclarationContext declaration) { + List ret = new ArrayList<>(); + if (declaration.variableModifier() != null && declaration.variableModifier().size() > 0) { + // TODO + throw new NotImplementedException(); + } + RefTypeOrTPHOrWildcardOrGeneric type; + if (Objects.isNull(declaration.typeType()) || !Objects.isNull(declaration.VAR())) { + type = TypePlaceholder.fresh(declaration.getStart()); + } else { + type = TypeGenerator.convert(declaration.typeType(), reg, generics); + } + if (!Objects.isNull(declaration.variableDeclarators())) + ret.addAll(generateLocalVariableAssignments(declaration.variableDeclarators().variableDeclarator(), type)); + return ret; + } + + private List generateLocalVariableAssignments(List varDeclarators, RefTypeOrTPHOrWildcardOrGeneric type) { + List ret = new ArrayList<>(); + for (Java17Parser.VariableDeclaratorContext varDecl : varDeclarators) { + IdentifierContext name = varDecl.variableDeclaratorId().identifier(); + + ret.add(new LocalVarDecl(name.getText(), type, name.getStart())); + this.localVars.put(name.getText(), type); + if (varDecl.variableInitializer() != null) { + Expression initValue; + if (varDecl.variableInitializer().arrayInitializer() != null) { + throw new NotImplementedException(); + } else { + initValue = convert(varDecl.variableInitializer().expression()); + } + ret.add(new Assign(new AssignToLocal(new LocalVar(name.getText(), type, name.getStart())), initValue, name.getStart())); + } + } + return ret; + } + + public Statement generateFieldAssignment(Java17Parser.VariableDeclaratorContext varDecl, RefTypeOrTPHOrWildcardOrGeneric type) { + IdentifierContext name = varDecl.variableDeclaratorId().identifier(); + Expression initValue; + if (varDecl.variableInitializer().arrayInitializer() != null) { + throw new NotImplementedException(); + } else { + initValue = convert(varDecl.variableInitializer().expression()); + } + var fieldEntry = fields.get(name.getText()); + return (new Assign(new AssignToField(new FieldVar(new This(varDecl.getStart()), name.getText(), type, varDecl.getStart())), initValue, name.getStart())); + } + + private Statement convert(Java17Parser.BreakstmtContext stmt) { + Token offset = stmt.getStart(); + if (!Objects.isNull(stmt.identifier())) { + return new Break(localVars.get(stmt.identifier().getText()), offset); + } else { + return new Break(TypePlaceholder.fresh(offset), offset); + } + + } + + private Statement convert(Java17Parser.ContinuestmtContext stmt) { + Token offset = stmt.getStart(); + if (!Objects.isNull(stmt.identifier())) { + return new Continue(localVars.get(stmt.identifier().getText()), offset); + } else { + return new Continue(TypePlaceholder.fresh(offset), offset); + } + } + + private Statement convert(Java17Parser.SemistmtContext stmt) { + // TODO + throw new NotImplementedException(); + } + + private Statement convert(Java17Parser.ReturnstmtContext stmt) { + if (stmt.expression() != null) { + return new Return(convert(stmt.expression()), stmt.getStart()); + } else { + return new ReturnVoid(stmt.getStart()); + } + } + + private Statement convert(Java17Parser.ThrowstmtContext stmt) { + return new Throw(convert(stmt.expression()), stmt.getStart()); + } + + private Statement convert(Java17Parser.SynchronizedstmtContext stmt) { + // TODO + throw new NotImplementedException(); + } + + private Statement convert(Java17Parser.TrycatchblockContext stmt) { + // TODO + throw new NotImplementedException(); + } + + private Statement convert(Java17Parser.TrycatchresourceContext stmt) { + // TODO + throw new NotImplementedException(); + } + + /* + *************** + Expression Conversions: + */ + private Expression convert(Java17Parser.ExpressionContext expression) { + switch (expression) { + case PrimaryExpression2Context primary: + return convert(primary.primary()); + case DottedexpressionContext dotted: + return convert(dotted, expression.getStart()); + case MethodcallexpressionContext methodcall: + return convert(methodcall.methodCall(), methodcall.getStart()); + case NewinstanceexpressionContext newinstance: + return convert(newinstance.creator()); + case CastexpressionContext castexpr: + return convert(castexpr); + case PostfixexpressionContext postfexpr: + return convert(postfexpr); + case PrefixexpressionContext prefexpr: + return convert(prefexpr); + case MathmuldivmodexpressionContext mathexpr: + return convert(mathexpr); + case MathaddsubexpressionContext mathexpr: + return convert(mathexpr); + case RelationalexpressionContext comparison: + return convert(comparison); + case InstanceofexpressionContext instanceOf: + return convert(instanceOf); + case SwitchExpression2Context switchexpression: + return convert(switchexpression.switchExpression()); + case EqualityexpressionContext equal: + return convert(equal); + case AssignexpressionContext assignment: + return convert(assignment); + case LambdaExpression2Context lambdaexpr: + return convert(lambdaexpr.lambdaExpression()); + case ArrayaccessexpressionContext arrayaccess: + return convert(arrayaccess); + case ShiftexpressionContext shiftexpr: + return convert(shiftexpr); + case BitwiseandexpressionContext bitwiseand: + return convert(bitwiseand); + case BitwisexorexpressionContext bitwisexor: + return convert(bitwisexor); + case BitwiseorexpressionContext bitwiseor: + return convert(bitwiseor); + case AndexpressionContext andexpr: + return convert(andexpr); + case OrexpressionContext orexpr: + return convert(orexpr); + case ConditionalassignexpressionContext condassign: + return convert(condassign); + default: + throw new NotImplementedException(); + } + } + + private Expression convert(DottedexpressionContext expr, Token offset) { + if (!Objects.isNull(expr.methodCall())) { + return convert(expr.methodCall(), expr.expression(), offset); + } else if (!Objects.isNull(expr.identifier())) { + return new FieldVar(convert(expr.expression()), expr.identifier().getText(), TypePlaceholder.fresh(expr.identifier().start), offset); + } else { + // Für alle anderen Optionen, wie Feldzugriff, Aufrufe von super oder explizite + // generische Invokationen + throw new NotImplementedException(); + } + } + + private MethodCall convert(MethodCallContext expr, Token offset) { + String name = "this"; + Expression receiver = new This(offset); + if (expr.identifier() != null) { + name = expr.identifier().getText(); + } else if (!Objects.isNull(expr.SUPER())) { + // if(methodInvocationContext.Identifier() != null){ + name = expr.SUPER().getText(); + } + + ArgumentList argumentList = convertArguments(expr.expressionList()); + ArrayList signature = argumentList.getArguments().stream().map(x -> TypePlaceholder.fresh(offset)).collect(Collectors.toCollection(ArrayList::new)); + signature.add(TypePlaceholder.fresh(offset)); // return type + + MethodCall ret; + if (expr.SUPER() != null) { + ret = new SuperCall(argumentList, TypePlaceholder.fresh(offset), signature, offset); + } else if(expr.THIS() != null) { + ret = new ThisCall(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; + } + + private MethodCall convert(MethodCallContext expr, ExpressionContext receiver, Token offset) { + String name = "this"; + if (expr.identifier() != null) { + name = expr.identifier().getText(); + } else if (!Objects.isNull(expr.SUPER())) { + // if(methodInvocationContext.Identifier() != null){ + name = expr.SUPER().getText(); + } + ArgumentList argumentList = convertArguments(expr.expressionList()); + ArrayList signature = argumentList.getArguments().stream().map(x -> 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); + ret.setStatement(); + return ret; + } + + public Receiver getReceiver(ExpressionContext expr) { + Expression expression = convert(expr); + /* + * if (expr instanceof PrimaryExpression2Context pc) { expression = convert(pc.primary()); } else { expression = generateLocalOrFieldVarOrClassName(expr.getText(), expr.getStart()); } + */ + return getReceiver(expression); + } + + public Receiver getReceiver(Expression expr) { + if (expr instanceof StaticClassName) { + return (Receiver) expr; + } else { + return new ExpressionReceiver(expr); + } + } + + private StaticClassName generateStaticClassName(String name, Token offset) { + var className = reg.getName(name); + var numberOfGenerics = reg.getNumberOfGenerics(name); + var refType = new RefType(className, Stream.generate(() -> (RefTypeOrTPHOrWildcardOrGeneric) TypePlaceholder.fresh(offset)).limit(numberOfGenerics).toList(), offset); + return new StaticClassName(refType, offset); + } + + /** + * Der Parser kann nicht zwischen einer lokalen Variable, einem Feldzugriff und einer Klassenangabe unterscheiden. + * + * @param expression + * @param offset + * @return + */ + private Expression generateLocalOrFieldVarOrClassName(String expression, Token offset) { + // Check for localVar: + if (localVars.get(expression) != null) { + return new LocalVar(expression, localVars.get(expression), offset); + } else if (fields.get(expression) != null) {// PL 2018-11-01 fields eingefuegt, damit die fields immer die + // gleiche TPH bekommen + return new FieldVar(new This(offset), expression, fields.get(expression).type(), offset); + } else if (reg.contains(expression)) { + return generateStaticClassName(expression, offset); + } else { + // lokale Variable wurde ohne "var"-Keyword deklariert und direkt mit Wert versehen + localVars.put(expression, TypePlaceholder.fresh(offset)); + return new LocalVar(expression, localVars.get(expression), offset); + } + } + + private Expression convert(Java17Parser.ArrayaccessexpressionContext arrayaccess) { + throw new NotImplementedException(); + } + + private Expression convert(Java17Parser.ConditionalassignexpressionContext expression) { + return new Ternary(TypePlaceholder.fresh( + expression.getStart()), + convert(expression.expression(0)), + convert(expression.expression(1)), + convert(expression.expression(2)), + expression.getStart() + ); + } + + private Expression convert(Java17Parser.OrexpressionContext expression) { + if (expression.expression().size() != 2) { + throw new NotImplementedException(); + } else { + return new BoolExpression(BoolExpression.Operator.OR, new RefType(new JavaClassName("java.lang.Boolean"), expression.getStart()), convert(expression.expression(0)), convert(expression.expression(1)), expression.getStart()); + } + } + + private Expression convert(Java17Parser.AndexpressionContext expression) { + if (expression.expression().size() != 2) { + throw new NotImplementedException(); + } else { + return new BoolExpression(BoolExpression.Operator.AND, new RefType(new JavaClassName("java.lang.Boolean"), expression.getStart()), convert(expression.expression(0)), convert(expression.expression(1)), expression.getStart()); + } + } + + private Statement convert(AssignexpressionContext expr) { + switch (expr.bop.getText()) { + case "=": + AssignLeftSide leftHandSide = convertAssignLHS(convert(expr.expression(0))); + return new Assign(leftHandSide, convert(expr.expression(1)), expr.getStart()); + case "+=": + case "-=": + case "*=": + case "/=": + case "&=": + case "|=": + case "^=": + case ">>=": + case ">>>=": + case "<<=": + case "%=": + default: + throw new NotImplementedException(); + } + } + + private AssignLeftSide convertAssignLHS(Expression expr) { + Expression leftSide = expr; + if (leftSide instanceof FieldVar) + return new AssignToField((FieldVar) leftSide); + else if (leftSide instanceof LocalVar) + return new AssignToLocal((LocalVar) leftSide); + else + throw new NotImplementedException(); + } + + private Expression convert(Java17Parser.BitwiseorexpressionContext expression) { + return new BinaryExpr(BinaryExpr.Operator.OR, TypePlaceholder.fresh(expression.getStart()), convert(expression.expression(0)), convert(expression.expression(1)), expression.getStart()); + } + + private Expression convert(Java17Parser.BitwisexorexpressionContext expression) { + return new BinaryExpr(BinaryExpr.Operator.XOR, TypePlaceholder.fresh(expression.getStart()), convert(expression.expression(0)), convert(expression.expression(1)), expression.getStart()); + } + + private Expression convert(Java17Parser.BitwiseandexpressionContext expression) { + return new BinaryExpr(BinaryExpr.Operator.AND, TypePlaceholder.fresh(expression.getStart()), convert(expression.expression(0)), convert(expression.expression(1)), expression.getStart()); + } + + private Expression convert(Java17Parser.EqualityexpressionContext expression) { + String operator = expression.bop.getText(); + Expression leftSide = convert(expression.expression(0)); + Expression rightSide = convert(expression.expression(1)); + return new BinaryExpr(convertBinaryOperator(operator), TypePlaceholder.fresh(expression.getStart()), leftSide, rightSide, expression.getStart()); + } + + private Expression convert(Java17Parser.RelationalexpressionContext expression) { + String operator = expression.bop.getText(); + return new BinaryExpr(convertBinaryOperator(operator), TypePlaceholder.fresh(expression.getStart()), convert(expression.expression(0)), convert(expression.expression(1)), expression.getStart()); + } + + private Expression convert(Java17Parser.InstanceofexpressionContext expression) { + Expression left = convert(expression.expression()); + Token offset = expression.getStart(); + if (Objects.isNull(expression.pattern())) {; + return new InstanceOf(left, new RefType(reg.getName("java.lang.Boolean"), expression.getStart()), TypeGenerator.convert(expression.typeType(), reg, generics), offset); + } else { + switch (expression.pattern()) { + case PPatternContext primaryPattern: + switch (primaryPattern.primaryPattern()) { + case TPatternContext typePattern: + TypePatternContext typePatternCtx = typePattern.typePattern(); + String localVarName = typePatternCtx.identifier().getText(); + RefTypeOrTPHOrWildcardOrGeneric localVarType = TypeGenerator.convert(typePatternCtx.typeType(), reg, generics); + localVars.put(localVarName, localVarType); + return new InstanceOf(left, new RefType(reg.getName("java.lang.Boolean"), expression.getStart()), new FormalParameter(localVarName, localVarType, typePatternCtx.getStart()), offset); + default: + throw new NotImplementedException(); + } + default: + throw new NotImplementedException(); + } + } + } + + private BinaryExpr.Operator convertBinaryOperator(String operator) { + // return BinaryExpr.Operator.ADD; + if (operator.equals("+")) { + return BinaryExpr.Operator.ADD; + } else if (operator.equals("-")) { + return BinaryExpr.Operator.SUB; + } else if (operator.equals("*")) { + return BinaryExpr.Operator.MUL; + } else if (operator.equals("&")) { + return BinaryExpr.Operator.AND; + } else if (operator.equals("|")) { + return BinaryExpr.Operator.OR; + } else if (operator.equals("/")) { + return BinaryExpr.Operator.DIV; + } else if (operator.equals("<")) { + return BinaryExpr.Operator.LESSTHAN; + } else if (operator.equals(">")) { + return BinaryExpr.Operator.BIGGERTHAN; + } else if (operator.equals(">=")) { + return BinaryExpr.Operator.BIGGEREQUAL; + } else if (operator.equals("<=")) { + return BinaryExpr.Operator.LESSEQUAL; + } else if (operator.equals("==")) { + return BinaryExpr.Operator.EQUAL; + } else if (operator.equals("!=")) { + return BinaryExpr.Operator.NOTEQUAL; + } else if (operator.equals("%")) { + return BinaryExpr.Operator.MOD; + } else { + throw new NotImplementedException(); + } + // throw new NotImplementedException(); + } + + private Expression convert(Java17Parser.ShiftexpressionContext expression) { + throw new NotImplementedException(); + } + + private Expression convert(Java17Parser.MathaddsubexpressionContext expression) { + Expression leftSide = convert(expression.expression(0)); + Expression rightSide = convert(expression.expression(1)); + BinaryExpr.Operator op = convertBinaryOperator(expression.bop.getText()); + Token offset = expression.getStart(); + return new BinaryExpr(op, TypePlaceholder.fresh(expression.getStart()), leftSide, rightSide, offset); + } + + private Expression convert(Java17Parser.MathmuldivmodexpressionContext expression) { + Expression leftSide = convert(expression.expression(0)); + Expression rightSide = convert(expression.expression(1)); + BinaryExpr.Operator op = convertBinaryOperator(expression.bop.getText()); + Token offset = expression.getStart(); + return new BinaryExpr(op, TypePlaceholder.fresh(offset), leftSide, rightSide, offset); + } + + private Statement convert(PrefixexpressionContext prefixexpr) { + Expression expr = convert(prefixexpr.expression()); + Token op = prefixexpr.prefix; + Statement ret; + if (op.getText().equals("++")) { + ret = new UnaryExpr(UnaryExpr.Operation.PREINCREMENT, expr, TypePlaceholder.fresh(op), op); + ret.setStatement(); + return ret; + } else if (op.getText().equals("--")) { + ret = new UnaryExpr(UnaryExpr.Operation.PREDECREMENT, expr, TypePlaceholder.fresh(op), op); + ret.setStatement(); + return ret; + } else if (op.getText().equals("!")) { + ret = new UnaryExpr(UnaryExpr.Operation.NOT, expr, TypePlaceholder.fresh(op), op); + return ret; + } else { + throw new NotImplementedException(); + } + } + + private Statement convert(Java17Parser.PostfixexpressionContext postfixexpr) { + Expression expr = convert(postfixexpr.expression()); + Token op = postfixexpr.postfix; + switch (op.getText()) { + case "++": + return new UnaryExpr(UnaryExpr.Operation.POSTINCREMENT, expr, TypePlaceholder.fresh(op), op); + case "--": + return new UnaryExpr(UnaryExpr.Operation.POSTDECREMENT, expr, TypePlaceholder.fresh(op), op); + default: + throw new NotImplementedException(); + } + } + + private Expression convert(Java17Parser.CastexpressionContext castexpr) { + ExpressionContext expr = castexpr.expression(); + if (expr instanceof PrefixexpressionContext pfe) { + throw new NotImplementedException(); + } + return new CastExpr(TypeGenerator.convert(castexpr.typeType(0), reg, generics), convert(expr), expr.getStart()); + } + + private Expression convert(Java17Parser.PrimaryContext primary) { + switch (primary) { + case PrimaryExpressionContext primexpression: + return convert(primexpression.expression()); + case PrimaryThisContext primthis: + return new This(primthis.getStart()); + case PrimarySuperContext primsuper: + return new Super(primsuper.getStart()); + case PrimaryLiteralContext primliteral: + return convert(primliteral.literal()); + case PrimaryIdentifierContext primidentifier: + return generateLocalOrFieldVarOrClassName(primidentifier.getText(), primidentifier.getStart()); + case PrimaryClassrefContext primclassref: + throw new NotImplementedException(); + default: + throw new NotImplementedException(); + } + } + + private Expression convert(Java17Parser.LiteralContext literal) { + switch (literal) { + case IntLiteralContext intliteral: + Number value; + if (intliteral.getText().endsWith("l") || intliteral.getText().endsWith("L")) + value = Long.parseLong(intliteral.getText().substring(0, intliteral.getText().length() - 1)); + else value = Integer.parseInt(intliteral.getText()); + return new Literal(TypePlaceholder.fresh(literal.getStart()), value, intliteral.getStart()); + case FltLiteralContext floatliteral: + if (floatliteral.getText().endsWith("f") || floatliteral.getText().endsWith("F")) + value = Float.parseFloat(floatliteral.getText().substring(0, floatliteral.getText().length() - 1)); + else if (floatliteral.getText().endsWith("d") || floatliteral.getText().endsWith("D")) + value = Double.parseDouble(floatliteral.getText().substring(0, floatliteral.getText().length() - 1)); + else value = Double.parseDouble(floatliteral.getText()); + return new Literal(TypePlaceholder.fresh(literal.getStart()), value, floatliteral.getStart()); + case CharLiteralContext charliteral: + RefType type = new RefType(reg.getName("java.lang.Character"), charliteral.getStart()); + return new Literal(type, charliteral.getText().charAt(1), charliteral.getStart()); + case StringLiteralContext stringliteral: + type = new RefType(reg.getName("java.lang.String"), stringliteral.getStart()); + return new Literal(type, stringliteral.getText().substring(1, stringliteral.getText().length() - 1), stringliteral.getStart()); + case BoolLiteralContext boolliteral: + type = new RefType(reg.getName("java.lang.Boolean"), boolliteral.getStart()); + return new Literal(type, Boolean.parseBoolean(boolliteral.getText()), boolliteral.getStart()); + case NullLiteralContext nullliteral: + return new Literal(TypePlaceholder.fresh(nullliteral.getStart()), null, nullliteral.getStart()); + default: + throw new NotImplementedException(); + } + } + + private Expression convert(Java17Parser.LambdaExpressionContext expression) { + Java17Parser.LambdaParametersContext lambdaParams = expression.lambdaParameters(); + ParameterList params; + if (lambdaParams.identifier().size() > 0) { + List parameterList = new ArrayList<>(); + for (IdentifierContext identifier : lambdaParams.identifier()) { + Token offset = identifier.getStart(); + parameterList.add(new FormalParameter(identifier.getText(), TypePlaceholder.fresh(offset), offset)); + } + params = new ParameterList(parameterList, lambdaParams.getStart()); + } else if (lambdaParams.formalParameterList() != null) { + params = convert(lambdaParams.formalParameterList(), false); + // }else if( lambdaParams.inferredFormalParameterList != null){ + } else if (!Objects.isNull(lambdaParams.lambdaLVTIList())) { + List parameterList = new ArrayList<>(); + for (LambdaLVTIParameterContext param : lambdaParams.lambdaLVTIList().lambdaLVTIParameter()) { + Token offset = param.getStart(); + parameterList.add(new FormalParameter(param.identifier().getText(), TypePlaceholder.fresh(offset), offset)); + } + params = new ParameterList(parameterList, lambdaParams.getStart()); + } else { + params = new ParameterList(new ArrayList<>(), expression.getStart()); + } + + HashMap lambdaLocals = new HashMap<>(); + lambdaLocals.putAll(localVars); + for (Pattern param : params.getFormalparalist()) { + if (!(param instanceof FormalParameter fp)) throw new IllegalArgumentException(); + lambdaLocals.put(fp.getName(), fp.getType()); + } + StatementGenerator lambdaGenerator = new StatementGenerator(superClass, compiler, reg, generics, fields, lambdaLocals); + + Block block; + if (expression.lambdaBody().expression() != null) { + List statements = new ArrayList<>(); + statements.add(new Return(lambdaGenerator.convert(expression.lambdaBody().expression()), expression.lambdaBody().expression().getStart())); + block = new Block(statements, expression.lambdaBody().getStart()); + } else { + block = lambdaGenerator.convert(expression.lambdaBody().block(), true); + } + List funNParams = new ArrayList<>(); + funNParams.add(TypePlaceholder.fresh(expression.getStart()));// ret-Type + params.getFormalparalist().forEach(formalParameter -> // Für jeden Parameter einen TPH anfügen: + funNParams.add(TypePlaceholder.fresh(expression.getStart()))); + RefTypeOrTPHOrWildcardOrGeneric lambdaType = TypePlaceholder.fresh(expression.getStart()); + // RefType lambdaType = new + // RefType(reg.getName("Fun"+params.getFormalparalist().size()), + // funNParams, name.getStart()); + return new LambdaExpression(lambdaType, params, block, expression.getStart()); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/parser/SyntaxTreeGenerator/SyntacticSugar.java b/LanguageServer/src/main/java/de/dhbw/compiler/parser/SyntaxTreeGenerator/SyntacticSugar.java new file mode 100644 index 0000000..3f8c632 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/parser/SyntaxTreeGenerator/SyntacticSugar.java @@ -0,0 +1,51 @@ +package de.dhbw.compiler.parser.SyntaxTreeGenerator; + +import de.dhbw.compiler.exceptions.NotImplementedException; +import de.dhbw.compiler.parser.NullToken; +import de.dhbw.compiler.syntaxtree.AbstractASTWalker; +import de.dhbw.compiler.syntaxtree.Constructor; +import de.dhbw.compiler.syntaxtree.statement.*; + +import java.util.List; + +public class SyntacticSugar { + + public static List addTrailingReturn(List statements) { + if (statements.size() != 0) { + Statement lastStmt = statements.get(statements.size() - 1); + ReturnFinder hasReturn = new ReturnFinder(); + lastStmt.accept(hasReturn); + if (hasReturn.hasReturn) + return statements; + } + statements.add(new ReturnVoid(new NullToken())); + return statements; + } + + private static class ReturnFinder extends AbstractASTWalker { + public boolean hasReturn = false; + + @Override + public void visit(Return aReturn) { + hasReturn = true; + } + + @Override + public void visit(ReturnVoid aReturn) { + hasReturn = true; + } + + @Override + public void visit(LambdaExpression le) { + //PL 2024-04-09 Do nothing, as in a LambdaExpression a return could be + } + } + + private static boolean hasReturn(Block block) { + for (Statement s : block.getStatements()) + if (s instanceof Return) + return true; + return false; + } + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/parser/SyntaxTreeGenerator/SyntaxTreeGenerator.java b/LanguageServer/src/main/java/de/dhbw/compiler/parser/SyntaxTreeGenerator/SyntaxTreeGenerator.java new file mode 100644 index 0000000..ff679a9 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/parser/SyntaxTreeGenerator/SyntaxTreeGenerator.java @@ -0,0 +1,604 @@ +package de.dhbw.compiler.parser.SyntaxTreeGenerator; + +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import de.dhbw.compiler.core.JavaTXCompiler; +import de.dhbw.compiler.parser.NullToken; +import de.dhbw.compiler.syntaxtree.*; +import de.dhbw.compiler.syntaxtree.Record; +import de.dhbw.compiler.syntaxtree.statement.*; +import de.dhbw.parser.Java17Parser; +import de.dhbw.parser.Java17Parser.*; +import org.antlr.v4.runtime.CommonToken; +import org.antlr.v4.runtime.Token; + +import com.google.common.graph.ElementOrder.Type; + +import de.dhbw.compiler.environment.PackageCrawler; +import de.dhbw.compiler.exceptions.NotImplementedException; +import de.dhbw.compiler.exceptions.TypeinferenceException; +import de.dhbw.compiler.parser.scope.GatherNames; +import de.dhbw.compiler.parser.scope.GenericsRegistry; +import de.dhbw.compiler.parser.scope.JavaClassName; +import de.dhbw.compiler.parser.scope.JavaClassRegistry; +import de.dhbw.compiler.syntaxtree.factory.ASTFactory; +import de.dhbw.compiler.syntaxtree.type.RefType; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.syntaxtree.type.TypePlaceholder; +import de.dhbw.compiler.syntaxtree.type.Void; + +public class SyntaxTreeGenerator { + private JavaClassRegistry reg; + private final GenericsRegistry globalGenerics; + public String pkgName = ""; + public Set imports = new HashSet<>(); + HashMap allmodifiers = new HashMap<>(); + // PL 2018-11-01 fields eingefuegt, damit die fields immer die gleiche TPH + // bekommen + private final Map fields = new HashMap<>(); + // PL 2019-10-23: Muss für jede Klasse neu initilisiert werden + List fieldInitializations = new ArrayList<>(); + List staticFieldInitializations = new ArrayList<>(); + + private final JavaTXCompiler compiler; + private RefType superClass; + + 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 + // globalen Datenbank benötigt. + this.globalGenerics = globalGenerics; + this.reg = reg; + this.allmodifiers.put(Modifier.toString(Modifier.PUBLIC), Modifier.PUBLIC); + this.allmodifiers.put(Modifier.toString(Modifier.PRIVATE), Modifier.PRIVATE); + this.allmodifiers.put(Modifier.toString(Modifier.PROTECTED), Modifier.PROTECTED); + this.allmodifiers.put(Modifier.toString(Modifier.ABSTRACT), Modifier.ABSTRACT); + this.allmodifiers.put(Modifier.toString(Modifier.STATIC), Modifier.STATIC); + this.allmodifiers.put(Modifier.toString(Modifier.STRICT), Modifier.STRICT); + this.allmodifiers.put(Modifier.toString(Modifier.FINAL), Modifier.FINAL); + this.allmodifiers.put(Modifier.toString(Modifier.TRANSIENT), Modifier.TRANSIENT); + this.allmodifiers.put(Modifier.toString(Modifier.VOLATILE), Modifier.VOLATILE); + this.allmodifiers.put(Modifier.toString(Modifier.SYNCHRONIZED), Modifier.SYNCHRONIZED); + this.allmodifiers.put(Modifier.toString(Modifier.NATIVE), Modifier.NATIVE); + this.allmodifiers.put(Modifier.toString(Modifier.INTERFACE), Modifier.INTERFACE); + this.allmodifiers.put("sealed", 4096); + this.allmodifiers.put("non-sealed", 8192); + this.allmodifiers.put("default", 16384); + this.allmodifiers.put("strictfp", 32768); + + this.compiler = compiler; + this.fileName = fileName; + } + + public JavaClassRegistry getReg() { + return this.reg; + } + + public String convertQualifiedName(Java17Parser.QualifiedNameContext ctx) { + /* + * String ret = ""; for (Java17Parser.IdentifierContext ident : ctx.identifier()) { ret += ident.getText(); if (ctx.identifier().iterator().hasNext()) { ret += '.'; } } + */ + return ctx.getText(); + } + + public void convert(List classes, Java17Parser.SourceFileContext ctx, PackageCrawler packageCrawler) throws ClassNotFoundException, NotImplementedException { + SrcfileContext srcfile; + if (ctx instanceof Java17Parser.SrcfileContext) { + srcfile = (SrcfileContext) ctx; + } else { + return; + } + if (srcfile.packageDeclaration() != null) + this.pkgName = convert(srcfile.packageDeclaration()); + Map imports = GatherNames.getImports(srcfile, packageCrawler, compiler); + this.imports.addAll(imports.keySet().stream().map(name -> reg.getName(name)).collect(Collectors.toSet())); + + for (Java17Parser.ClassOrInterfaceContext type : srcfile.classOrInterface()) { + ClassorinterfacedeclContext clsoif; + if (type instanceof NoclassorinterfaceContext) { + continue; + } else { + clsoif = (ClassorinterfacedeclContext) type; + } + ClassOrInterface newClass; + int modifiers = 0; + if (!clsoif.classOrInterfaceModifier().isEmpty()) { + for (Java17Parser.ClassOrInterfaceModifierContext mod : clsoif.classOrInterfaceModifier()) { + modifiers += allmodifiers.get(mod.getText()); + } + } + fieldInitializations = new ArrayList<>(); // PL 2019-10-22: muss für jede Klasse neu initilisiert werden + staticFieldInitializations = new ArrayList<>(); + if (!Objects.isNull(clsoif.classDeclaration())) { + newClass = convertClass(clsoif.classDeclaration(), modifiers); + } else if (!Objects.isNull(clsoif.interfaceDeclaration())) { + newClass = convertInterface(clsoif.interfaceDeclaration(), modifiers); + } else if (!Objects.isNull(clsoif.recordDeclaration())) { + newClass = convertRecord(clsoif.recordDeclaration(), modifiers); + } else { + throw new NotImplementedException(); + } + classes.add(newClass); + } + if (classes.isEmpty()) { + throw new NotImplementedException("SourceFile enthält keine Klassen"); + } + } + + private String convert(Java17Parser.PackageDeclarationContext ctx) { + return convertQualifiedName(ctx.qualifiedName()); + } + + private ClassOrInterface convertClass(Java17Parser.ClassDeclarationContext ctx, int modifiers) { + String className = this.pkgName + (this.pkgName.length() > 0 ? "." : "") + ctx.identifier().getText(); + JavaClassName name = reg.getName(className); // Holt den Package Namen mit dazu + if (!name.toString().equals(className)) { // Kommt die Klasse schon in einem anderen Package vor? + throw new TypeinferenceException("Name " + className + " bereits vorhanden in " + reg.getName(className).toString(), ctx.getStart()); + } + GenericsRegistry generics = createGenerics(ctx.genericDeclarationList(), name, "", reg, new GenericsRegistry(globalGenerics)); + Token offset = ctx.getStart(); + GenericDeclarationList genericClassParameters; + if (ctx.genericDeclarationList() == null) { + genericClassParameters = new GenericDeclarationList(new ArrayList<>(), ctx.classBody().getStart()); + } else { + genericClassParameters = TypeGenerator.convert(ctx.genericDeclarationList(), name, "", reg, generics); + } + RefType superClass; + if (ctx.EXTENDS() != null) { + superClass = convertSuperType(ctx.typeType()); + } else { + superClass = new RefType(ASTFactory.createObjectClass().getClassName(), ctx.getStart()); + } + this.superClass = superClass; + List fielddecl = new ArrayList<>(); + List methods = new ArrayList<>(); + List constructors = new ArrayList<>(); + Boolean isInterface = false; + Boolean isFunctionalInterface = false; + List implementedInterfaces = new ArrayList<>(); + List permittedSubtypes = new ArrayList<>(); + for (ClassBodyDeclarationContext clsbodydecl : ctx.classBody().classBodyDeclaration()) { + convert(clsbodydecl, fielddecl, constructors, methods, name, superClass, generics); + } + if (constructors.isEmpty()) { + constructors.add(generateStandardConstructor(ctx.identifier().getText(), name, superClass, genericClassParameters, offset)); + } + if (ctx.IMPLEMENTS() != null) { + implementedInterfaces.addAll(convert(ctx.typeList(0), generics)); + } + // Ist Bit für 'sealed'-Modifier gesetzt + if ((modifiers & 4096) != 0) { + if (!Objects.isNull(ctx.PERMITS())) { + // permitted subtypes sind letzte typeList (siehe Grammatikregel 'classDeclaration') + permittedSubtypes.addAll(convert(ctx.typeList(ctx.typeList().size() - 1), generics)); + } else { + // falls sealed modifier ohne 'permits'-List oder umgekehrt + throw new NotImplementedException("Invalid sealed class declaration"); + } + } + 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, fileName); + + } + + private Record convertRecord(RecordDeclarationContext recordDeclaration, int modifiers) { + this.superClass = new RefType(new JavaClassName("java.lang.Record"), new NullToken()); + String identifier = recordDeclaration.identifier().getText(); + String className = this.pkgName + (this.pkgName.length() > 0 ? "." : "") + identifier; + JavaClassName name = reg.getName(className); // Holt den Package Namen mit dazu + Token offset = recordDeclaration.getStart(); + GenericsRegistry generics = createGenerics(recordDeclaration.genericDeclarationList(), name, "", reg, new GenericsRegistry(globalGenerics)); + if (!name.toString().equals(className)) { // Kommt die Klasse schon in einem anderen Package vor? + throw new TypeinferenceException("Name " + className + " bereits vorhanden in " + reg.getName(className).toString(), recordDeclaration.getStart()); + } + GenericDeclarationList genericClassParameters; + if (recordDeclaration.genericDeclarationList() == null) { + genericClassParameters = new GenericDeclarationList(new ArrayList<>(), recordDeclaration.recordBody().getStart()); + } else { + genericClassParameters = TypeGenerator.convert(recordDeclaration.genericDeclarationList(), name, "", reg, generics); + } + RefType superClass = new RefType(ASTFactory.createClass(java.lang.Record.class).getClassName(), offset); + List fielddecl = new ArrayList<>(); + List methods = new ArrayList<>(); + List constructors = new ArrayList<>(); + Boolean isInterface = false; + List implementedInterfaces = new ArrayList<>(); + List constructorParameters = new ArrayList<>(); + List constructorStatements = new ArrayList<>(); + + List components = recordDeclaration.recordHeader().recordComponentList() != null ? + recordDeclaration.recordHeader().recordComponentList().recordComponent(): List.of(); + for (RecordComponentContext component : components) { + int fieldmodifiers = allmodifiers.get("private") + allmodifiers.get("final"); + String fieldname = component.identifier().getText(); + Token fieldoffset = component.getStart(); + RefTypeOrTPHOrWildcardOrGeneric fieldtype = null; + if (Objects.isNull(component.typeType())) { + fieldtype = TypePlaceholder.fresh(offset); + } else { + fieldtype = TypeGenerator.convert(component.typeType(), reg, generics); + } + fielddecl.add(new Field(fieldname, fieldtype, fieldmodifiers, fieldoffset)); + constructorParameters.add(new FormalParameter(fieldname, fieldtype, fieldoffset)); + FieldVar fieldvar = new FieldVar(new This(offset), fieldname, fieldtype, fieldoffset); + constructorStatements.add(new Assign(new AssignToField(fieldvar), new LocalVar(fieldname, fieldtype, fieldoffset), offset)); + Statement returnStatement = new Return(fieldvar, offset); + 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), prepareBlock(new Block(constructorStatements, offset), superClass), genericClassParameters, offset); + //Optional initializations = Optional.of(implicitConstructor); + constructors.add(implicitConstructor); + for (ClassBodyDeclarationContext bodyDeclaration : recordDeclaration.recordBody().classBodyDeclaration()) { + convert(bodyDeclaration, fielddecl, constructors, methods, name, superClass, generics); + } + if (!Objects.isNull(recordDeclaration.IMPLEMENTS())) { + implementedInterfaces.addAll(convert(recordDeclaration.typeList(), generics)); + } + var staticCtor = Optional.of(this.generateStaticConstructor(recordDeclaration.identifier().getText(), staticFieldInitializations, genericClassParameters, offset)); + return new Record(modifiers, name, fielddecl, Optional.empty(), staticCtor, methods, constructors, genericClassParameters, superClass, isInterface, implementedInterfaces, offset, fileName); + } + + private void convert(ClassBodyDeclarationContext classBody, List fields, List constructors, List methods, JavaClassName name, RefType superClass, GenericsRegistry generics) { + MemberdeclContext member; + if (classBody instanceof MemberdeclContext) { + member = (MemberdeclContext) classBody; + Integer membermodifiers = 0; + for (ModifierContext mod : member.modifier()) { + if (mod.classOrInterfaceModifier() != null && mod.classOrInterfaceModifier().annotation() != null) + continue; // TODO don't eat annotations + membermodifiers += allmodifiers.get(mod.getText()); + } + switch (member.memberDeclaration()) { + case MemberclassorinterfaceContext memberclsoif: { + break; + } + case MemberfieldContext memberfield: { + fields.addAll(convert(memberfield.fieldDeclaration(), membermodifiers, generics)); + break; + } + case MembermethodContext membermethod: { + Method convertedMethod = convert(membermodifiers, membermethod.method(), name, superClass, generics); + if (convertedMethod instanceof Constructor constructor) { + constructors.add(constructor); + } else { + methods.add(convertedMethod); + } + break; + } + case MemberconstructorContext memberconstructor: { + constructors.add(convert(membermodifiers, memberconstructor.constructor(), name, superClass, generics)); + break; + } + default: + break; + } + } else if (classBody instanceof Java17Parser.ClassblockContext ctx && ctx.STATIC() != null) { + // Static blocks + var stmtgen = new StatementGenerator(superClass, compiler, reg, generics, this.fields, new HashMap<>()); + var block = stmtgen.convert(((Java17Parser.ClassblockContext) classBody).block(), false); + staticFieldInitializations.addAll(block.statements); + } + } + + private ClassOrInterface convertInterface(Java17Parser.InterfaceDeclarationContext ctx, int modifiers) { + this.superClass = new RefType(new JavaClassName("java.lang.Object"), new NullToken()); + String className = (this.pkgName.length() > 0 ? this.pkgName + "." : "") + ctx.identifier().getText(); + JavaClassName name = reg.getName(className); // Holt den Package Namen mit dazu + if (!name.toString().equals(className)) { // Kommt die Klasse schon in einem anderen Package vor? + throw new TypeinferenceException("Name " + className + " bereits vorhanden in " + reg.getName(className).toString(), ctx.getStart()); + } + if (!Modifier.isInterface(modifiers)) + modifiers += Modifier.INTERFACE; + + GenericsRegistry generics = createGenerics(ctx.genericDeclarationList(), name, "", reg, new GenericsRegistry(globalGenerics)); + + GenericDeclarationList genericParams; + if (!Objects.isNull(ctx.genericDeclarationList())) { + genericParams = TypeGenerator.convert(ctx.genericDeclarationList(), name, "", reg, generics); + } else { + genericParams = createEmptyGenericDeclarationList(ctx.identifier().getStart()); + } + RefType superClass = ASTFactory.createObjectType(); + + List fields = new ArrayList<>(); + List methods = new ArrayList<>(); + for (InterfaceBodyDeclarationContext interfacebody : ctx.interfaceBody().interfaceBodyDeclaration()) { + if (interfacebody instanceof Java17Parser.EmptyinterfaceContext) { + continue; + } else { + InterfacememberContext interfacemember = (InterfacememberContext) interfacebody; + int membermodifiers = 0; + for (ModifierContext mod : interfacemember.modifier()) { + membermodifiers += allmodifiers.get(mod.getText()); + } + int methodmodifiers = membermodifiers; + switch (interfacemember.interfaceMemberDeclaration()) { + case InterfaceconstContext constant: + fields.add(convert(constant)); + break; + case InterfacemethodContext method: + InterfaceMethodDeclarationContext declaration = method.interfaceMethodDeclaration(); + for (InterfaceMethodModifierContext mod : declaration.interfaceMethodModifier()) { + methodmodifiers += allmodifiers.get(mod.getText()); + } + InterfaceCommonBodyDeclarationContext commonbody = declaration.interfaceCommonBodyDeclaration(); + methods.add(convert(methodmodifiers, commonbody, new GenericDeclarationList(new ArrayList<>(), commonbody.getStart()), generics)); + break; + case GenericinterfacemethodContext genericmethod: + GenericInterfaceMethodDeclarationContext genericdeclaration = genericmethod.genericInterfaceMethodDeclaration(); + int genericmethodmodifiers = 0; + for (InterfaceMethodModifierContext mod : genericdeclaration.interfaceMethodModifier()) { + genericmethodmodifiers += allmodifiers.get(mod.getText()); + } + commonbody = genericdeclaration.interfaceCommonBodyDeclaration(); + GenericDeclarationList gtv = TypeGenerator.convert(genericdeclaration.genericDeclarationList(), name, commonbody.identifier().getText(), reg, generics); + methods.add(convert(genericmethodmodifiers, commonbody, gtv, generics)); + break; + default: + throw new NotImplementedException(); + } + } + } + List extendedInterfaces = new ArrayList<>(); + if (!Objects.isNull(ctx.EXTENDS())) { + extendedInterfaces.addAll(convert(ctx.typeList(0), generics)); + } + List permittedSubtypes = null; + // Ist Bit für 'sealed'-Modifier gesetzt + if ((modifiers & 4096) != 0) { + if (!Objects.isNull(ctx.PERMITS())) { + // permitted subtypes sind letzte typeList (siehe Grammatikregel 'classDeclaration') + permittedSubtypes = new ArrayList<>(convert(ctx.typeList(ctx.typeList().size() - 1), generics)); + } else { + // falls sealed modifier ohne 'permits'-List oder umgekehrt + throw new NotImplementedException("Invalid sealed class declaration"); + } + } + + 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(), fileName); + } + + private GenericDeclarationList createEmptyGenericDeclarationList(Token classNameIdentifier) { + CommonToken gtvOffset = new CommonToken(classNameIdentifier); + gtvOffset.setCharPositionInLine(gtvOffset.getCharPositionInLine() + classNameIdentifier.getText().length()); + gtvOffset.setStartIndex(gtvOffset.getStopIndex() + 1); + return new GenericDeclarationList(new ArrayList<>(), gtvOffset); + } + + private Field convert(InterfaceconstContext constant) { + // TODO: Erstelle hier ein Feld! + throw new NotImplementedException(); + } + + private Method convert(int modifiers, InterfaceCommonBodyDeclarationContext bodydeclaration, GenericDeclarationList gtvDeclarations, GenericsRegistry generics) { + String name = bodydeclaration.identifier().getText(); + + RefTypeOrTPHOrWildcardOrGeneric retType; + if (Objects.isNull(bodydeclaration.refType())) { + retType = TypePlaceholder.fresh(bodydeclaration.getStart()); + } else { + if (bodydeclaration.refType() instanceof RefType2Context reftype) { + retType = TypeGenerator.convert(reftype.typeType(), reg, generics); + } else { + retType = new Void(bodydeclaration.refType().getStart()); + } + } + StatementGenerator stmtgen = new StatementGenerator(superClass, compiler, reg, generics, fields, new HashMap<>()); + ParameterList paramlist = stmtgen.convert(bodydeclaration.formalParameters().formalParameterList(), true); + MethodBodyContext body = bodydeclaration.methodBody(); + Block block = null; + if (!(body instanceof EmptymethodContext)) { + MethodblockContext methodblock = (MethodblockContext) body; + block = stmtgen.convert(methodblock.block(), true); + } + else { + modifiers += Modifier.ABSTRACT; + } + return new Method(modifiers, name, retType, paramlist, block, gtvDeclarations, bodydeclaration.getStart()); + } + + protected static Block prepareBlock(Block constructorBlock, RefType superClass) { + List statements = constructorBlock.getStatements(); + if (statements.isEmpty() || !(statements.get(0) instanceof SuperCall || statements.get(0) instanceof ThisCall)) { + var signature = new ArrayList(); + signature.add(TypePlaceholder.fresh(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); + return new Constructor(Modifier.PUBLIC, className, classType, params, prepareBlock(new Block(new ArrayList<>(), offset), superClass), classGenerics, offset); // fieldInitializations // 2018-11-24 + } + + /* + * fieldInitializations werden in einem Psedokonstruktor in der abstrakten Syntax gespeichert + */ + private Constructor generatePseudoConstructor(String className, List initializations, GenericDeclarationList classGenerics, Token offset) { + RefType classType = ClassOrInterface.generateTypeOfClass(reg.getName(className), classGenerics, offset); + ParameterList params = new ParameterList(new ArrayList<>(), offset); + return new Constructor(Modifier.PUBLIC, className, classType, params, new Block(new ArrayList<>(initializations), offset), classGenerics, offset); + } + + private Method generateStaticConstructor(String className, List 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 Method(Modifier.PUBLIC, className, classType, params, block, classGenerics, offset); + } + + private RefType convertSuperType(Java17Parser.TypeTypeContext typeType) { + ClassOrInterfaceTypeContext supertypecontext = typeType.classOrInterfaceType(); + if (supertypecontext != null && supertypecontext.DOT().size() > 0) { + throw new NotImplementedException(); + } else { + TypeArgumentsContext typeArguments = (typeType.classOrInterfaceType().typeArguments().size() > 0) ? typeType.classOrInterfaceType().typeArguments().get(typeType.classOrInterfaceType().typeArguments().size() - 1) : null; + RefTypeOrTPHOrWildcardOrGeneric ret = TypeGenerator.convertTypeName(typeType.classOrInterfaceType().typeIdentifier().getText(), typeArguments, typeType.getStart(), reg, globalGenerics); + if (ret instanceof RefType) { + return (RefType) ret; + } else { + throw new TypeinferenceException(typeType.getText() + " ist kein gültiger Supertyp", typeType.getStart()); + } + } + } + + private List convert(Java17Parser.TypeListContext ctx, GenericsRegistry generics) { + List ret = new ArrayList<>(); + for (Java17Parser.TypeTypeContext type : ctx.typeType()) { + ret.add((RefType) TypeGenerator.convert(type, reg, generics)); + } + return ret; + } + + public Method convert(int modifiers, Java17Parser.MethodContext methodContext, JavaClassName parentClass, RefType superClass, GenericsRegistry generics) { + GenericsRegistry localgenerics = generics; + MethodDeclarationContext methoddeclaration; + GenericDeclarationListContext genericdeclarations; + GenericDeclarationList gtvDeclarations; + MethodHeaderContext header; + String name; + if (methodContext instanceof GenericmethodContext) { + GenericmethodContext gmc = (GenericmethodContext) methodContext; + genericdeclarations = gmc.genericMethodDeclaration().genericDeclarationList(); + methoddeclaration = gmc.genericMethodDeclaration().methodDeclaration(); + header = methoddeclaration.methodHeader(); + name = header.identifier().getText(); + localgenerics.putAll(createGenerics(genericdeclarations, parentClass, name, reg, generics)); + gtvDeclarations = TypeGenerator.convert(genericdeclarations, parentClass, name, reg, localgenerics); + } else { + MethoddeclContext mdc = (MethoddeclContext) methodContext; + methoddeclaration = mdc.methodDeclaration(); + header = methoddeclaration.methodHeader(); + gtvDeclarations = new GenericDeclarationList(new ArrayList<>(), header.getStart()); + name = header.identifier().getText(); + } + + RefTypeOrTPHOrWildcardOrGeneric retType; + if (Objects.isNull(header.refType())) { + retType = TypePlaceholder.fresh(header.getStart(), -1, false); + } else { + if (header.refType() instanceof RefType2Context reftype) { + retType = TypeGenerator.convert(reftype.typeType(), reg, generics); + } else { + retType = new Void(header.refType().getStart()); + } + } + StatementGenerator stmtgen = new StatementGenerator(superClass, compiler, reg, localgenerics, fields, new HashMap<>()); + ParameterList paramlist = stmtgen.convert(header.formalParameters().formalParameterList(), true); + MethodBodyContext body = methoddeclaration.methodBody(); + Block block = null; + if (body instanceof EmptymethodContext emptymethod) { + if (!Modifier.isAbstract(modifiers)) { + // TODO: Error! Abstrakte Methode ohne abstrakt Keyword + } + } else { + MethodblockContext methodblock = (MethodblockContext) body; + block = stmtgen.convert(methodblock.block(), true); + } + if (name.equals(parentClass.getClassName())) { + 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()); + } + } + + public Constructor convert(int modifiers, Java17Parser.ConstructorContext constructorContext, JavaClassName parentClass, RefType superClass, GenericsRegistry generics) { + GenericsRegistry localgenerics = generics; + GenericDeclarationListContext genericdeclarations; + GenericDeclarationList gtvDeclarations; + ConstructorDeclarationContext constructordeclaration; + String name; + if (constructorContext instanceof GenericconstructorContext) { + GenericconstructorContext genericconstructor = (GenericconstructorContext) constructorContext; + GenericConstructorDeclarationContext gcdeclaration = genericconstructor.genericConstructorDeclaration(); + name = gcdeclaration.constructorDeclaration().identifier().getText(); + genericdeclarations = gcdeclaration.genericDeclarationList(); + constructordeclaration = gcdeclaration.constructorDeclaration(); + localgenerics.putAll(createGenerics(genericdeclarations, parentClass, name, reg, generics)); + gtvDeclarations = TypeGenerator.convert(genericdeclarations, parentClass, name, reg, localgenerics); + } else { + ConstructordeclContext constructordeclarationcontext = (ConstructordeclContext) constructorContext; + constructordeclaration = constructordeclarationcontext.constructorDeclaration(); + name = constructordeclaration.identifier().getText(); + gtvDeclarations = new GenericDeclarationList(new ArrayList<>(), constructordeclaration.getStart()); + } + 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(), true); + Block block = prepareBlock(stmtgen.convert(constructordeclaration.constructorBody, true), superClass); + return new Constructor(modifiers, name, retType, paramlist, block, gtvDeclarations, constructordeclaration.getStart()); + } + + List convert(Java17Parser.FieldDeclarationContext fieldDeclContext, int modifiers, GenericsRegistry generics) { + List ret = new ArrayList<>(); + RefTypeOrTPHOrWildcardOrGeneric fieldType; + if (fieldDeclContext.typeType() != null) { + fieldType = TypeGenerator.convert(fieldDeclContext.typeType(), reg, generics); + } else { + // PL 2019-12-06: variableDeclaratorList() eingefuegt, um als Token nicht die + // Modifier zu bekommen + fieldType = TypePlaceholder.fresh(fieldDeclContext.variableDeclarators().getStart(), -1, false); + } + for (Java17Parser.VariableDeclaratorContext varDecl : fieldDeclContext.variableDeclarators().variableDeclarator()) { + String fieldName = varDecl.variableDeclaratorId().getText(); + this.fields.put(fieldName, new FieldEntry(fieldName, fieldType, modifiers)); + if (varDecl.variableInitializer() != null) { + initializeField(varDecl, Modifier.isStatic(modifiers), fieldType, generics); + } + ret.add(new Field(fieldName, fieldType, modifiers, varDecl.getStart())); + } + return ret; + } + + public static String convert(Java17Parser.VariableDeclaratorIdContext variableDeclaratorIdContext) { + return variableDeclaratorIdContext.getText(); + } + + // Initialize a field by creating implicit constructor. + private void initializeField(Java17Parser.VariableDeclaratorContext ctx, boolean isStatic, RefTypeOrTPHOrWildcardOrGeneric typeOfField, GenericsRegistry generics) { + StatementGenerator statementGenerator = new StatementGenerator(superClass, compiler, reg, generics, fields, new HashMap<>()); + var assignment = statementGenerator.generateFieldAssignment(ctx, typeOfField); + if (isStatic) { + staticFieldInitializations.add(assignment); + } + else fieldInitializations.add(assignment); + } + + public int convertModifier(String modifier) { + return allmodifiers.get(modifier); + } + + private GenericsRegistry createGenerics(Java17Parser.GenericDeclarationListContext ctx, JavaClassName parentClass, String parentMethod, JavaClassRegistry reg, GenericsRegistry generics) { + GenericsRegistry ret = new GenericsRegistry(this.globalGenerics); + ret.putAll(generics); + if (ctx == null) + return ret; + for (Java17Parser.GenericTypeVarContext tp : ctx.genericTypeVar()) { + ret.put(tp.identifier().getText(), new GenericContext(parentClass, parentMethod)); + TypeGenerator.convert(tp, parentClass, parentMethod, reg, ret); + } + return ret; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/parser/SyntaxTreeGenerator/TypeGenerator.java b/LanguageServer/src/main/java/de/dhbw/compiler/parser/SyntaxTreeGenerator/TypeGenerator.java new file mode 100644 index 0000000..95f196a --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/parser/SyntaxTreeGenerator/TypeGenerator.java @@ -0,0 +1,209 @@ +package de.dhbw.compiler.parser.SyntaxTreeGenerator; + +import de.dhbw.compiler.exceptions.NotImplementedException; +import de.dhbw.compiler.exceptions.TypeinferenceException; +import de.dhbw.compiler.parser.NullToken; + +import de.dhbw.compiler.parser.scope.GenericsRegistry; +import de.dhbw.compiler.parser.scope.JavaClassName; +import de.dhbw.compiler.parser.scope.JavaClassRegistry; +import de.dhbw.compiler.syntaxtree.GenericDeclarationList; +import de.dhbw.compiler.syntaxtree.GenericTypeVar; +import de.dhbw.compiler.syntaxtree.factory.ASTFactory; +import de.dhbw.compiler.syntaxtree.type.ExtendsWildcardType; +import de.dhbw.compiler.syntaxtree.type.GenericRefType; +import de.dhbw.compiler.syntaxtree.type.RefType; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.syntaxtree.type.SuperWildcardType; +import de.dhbw.compiler.syntaxtree.type.TypePlaceholder; +import de.dhbw.parser.Java17Parser; +import de.dhbw.parser.Java17Parser.*; +import org.antlr.v4.runtime.Token; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class TypeGenerator { + + public static RefTypeOrTPHOrWildcardOrGeneric convert(Java17Parser.ClassOrInterfaceTypeContext classOrInterfaceTypeContext, JavaClassRegistry reg, GenericsRegistry generics) { + Java17Parser.TypeArgumentsContext arguments = null; + /* + * PL 2019-03-19 auskommentiert ANFANG if(unannClassOrInterfaceTypeContext. unannClassType_lfno_unannClassOrInterfaceType() != null){ arguments = unannClassOrInterfaceTypeContext. unannClassType_lfno_unannClassOrInterfaceType().typeArguments(); }else{// if(unannClassOrInterfaceTypeContext. unannInterfaceType_lfno_unannClassOrInterfaceType() != null){ arguments = unannClassOrInterfaceTypeContext. unannInterfaceType_lfno_unannClassOrInterfaceType(). + * unannClassType_lfno_unannClassOrInterfaceType().typeArguments(); } PL 2019-03-19 auskommentiert ENDE + */ + /** + * Problem sind hier die verschachtelten Typen mit verschachtelten Typargumenten Beispiel: Typ.InnererTyp + */ + if (classOrInterfaceTypeContext.typeArguments().size() > 1) + throw new NotImplementedException(); + + String name = ""; + for (IdentifierContext id : classOrInterfaceTypeContext.identifier()) { + name += id.getText() + '.'; + } + name += classOrInterfaceTypeContext.typeIdentifier().getText(); + if (classOrInterfaceTypeContext.getStop().getText().equals(">")) { + /* + * Fuer Debug-Zwecke unannClassOrInterfaceTypeContext. unannInterfaceType_lfno_unannClassOrInterfaceType(); unannClassOrInterfaceTypeContext. unannClassType_lfno_unannClassOrInterfaceType().getText(); //unannClassOrInterfaceTypeContext. unannInterfaceType_lfno_unannClassOrInterfaceType(). unannClassType_lfno_unannClassOrInterfaceType().typeArguments(); //UnannClassType_lfno_unannClassOrInterfaceTypeContext unannClassOrInterfaceTypeContext.unannClassType_lf_unannClassOrInterfaceType( 0); + * unannClassOrInterfaceTypeContext.unannClassType_lf_unannClassOrInterfaceType( 0).getText(); unannClassOrInterfaceTypeContext.unannClassType_lf_unannClassOrInterfaceType( 1); unannClassOrInterfaceTypeContext.unannClassType_lf_unannClassOrInterfaceType( 1).getText(); unannClassOrInterfaceTypeContext. unannClassType_lfno_unannClassOrInterfaceType().getText(); //unannClassOrInterfaceTypeContext. unannInterfaceType_lf_unannClassOrInterfaceType(); //unannClassOrInterfaceTypeContext. + * unannInterfaceType_lf_unannClassOrInterfaceType(0).getText(); //unannClassOrInterfaceTypeContext. unannInterfaceType_lf_unannClassOrInterfaceType(1).getText(); //unannClassOrInterfaceTypeContext. unannInterfaceType_lfno_unannClassOrInterfaceType().getText(); + */ + List typeargs = classOrInterfaceTypeContext.typeArguments(); + arguments = typeargs.size() != 0 ? classOrInterfaceTypeContext.typeArguments(0) : null; + } + return convertTypeName(name, arguments, classOrInterfaceTypeContext.getStart(), reg, generics); + } + + public static RefTypeOrTPHOrWildcardOrGeneric convert(Java17Parser.TypeTypeContext typeContext, JavaClassRegistry reg, GenericsRegistry genericsRegistry) { + if (typeContext.primitiveType() != null) { + switch (typeContext.primitiveType().getText()) { + case "boolean": + return new RefType(ASTFactory.createClass(Boolean.class).getClassName(), typeContext.getStart()); + case "int": + return new RefType(ASTFactory.createClass(Integer.class).getClassName(), typeContext.getStart()); + case "double": + return new RefType(ASTFactory.createClass(Double.class).getClassName(), typeContext.getStart()); + case "float": + return new RefType(ASTFactory.createClass(Float.class).getClassName(), typeContext.getStart()); + default: + throw new NotImplementedException(); + } + } else if (!typeContext.LBRACK().isEmpty()) { // ArrayType über eckige Klammer prüfen + // System.out.println(unannTypeContext.getText()); + throw new NotImplementedException(); + } + /* + * else if (typeContext.classOrInterfaceType() != null) { JavaClassName name = reg .getName(typeContext.classOrInterfaceType().typeIdentifier().getText()); return new RefType(name, typeContext.getStart()); } + */ + return TypeGenerator.convert(typeContext.classOrInterfaceType(), reg, genericsRegistry); + } + + public static GenericDeclarationList convert(Java17Parser.GenericDeclarationListContext typeParametersContext, JavaClassName parentClass, String parentMethod, JavaClassRegistry reg, GenericsRegistry generics) { + Token endOffset = typeParametersContext.getStop(); + List typeVars = new ArrayList<>(); + for (Java17Parser.GenericTypeVarContext typeParameter : typeParametersContext.genericTypeVar()) { + typeVars.add(convert(typeParameter, parentClass, parentMethod, reg, generics)); + endOffset = typeParameter.getStop(); + } + return new GenericDeclarationList(typeVars, endOffset); + } + + public static GenericTypeVar convert(Java17Parser.GenericTypeVarContext typeVar, JavaClassName parentClass, String parentMethod, JavaClassRegistry reg, GenericsRegistry generics) { + String name = typeVar.identifier().getText(); + // TODO: Es müssen erst alle GenericTypeVars generiert werden, dann können die + // bounds dieser Generics ermittelt werden + // Problem ist erlaubt, würde aber bei den Bounds von A den + // Generic B nicht als solchen erkennen + List bounds = TypeGenerator.convert(typeVar.typeBound(), reg, generics); + + GenericTypeVar ret = new GenericTypeVar(name, bounds, typeVar.getStart(), typeVar.getStop()); + return ret; + } + + public static List convert(Java17Parser.TypeBoundContext typeBoundContext, JavaClassRegistry reg, GenericsRegistry generics) { + List ret = new ArrayList<>(); + if (Objects.isNull(typeBoundContext)) { + ret.add(ASTFactory.createObjectType()); + return ret; + } + if (typeBoundContext.typeType().size() > 0) { + for (TypeTypeContext tt : typeBoundContext.typeType()) { + ret.add(convert(tt, reg, generics)); + } + return ret; + } + throw new NotImplementedException(); + } + + public static RefTypeOrTPHOrWildcardOrGeneric convert(Java17Parser.WildcardTypeContext wildcardContext, JavaClassRegistry reg, GenericsRegistry generics) { + if (wildcardContext.getChildCount() < 3) { + if (!Objects.isNull(wildcardContext.extendsWildcardType())) { + return new ExtendsWildcardType(convert(wildcardContext.extendsWildcardType().typeType(), reg, generics), wildcardContext.getStart()); + } else if (!Objects.isNull(wildcardContext.superWildcardType())) { + return new SuperWildcardType(convert(wildcardContext.superWildcardType().typeType(), reg, generics), wildcardContext.getStart()); + } else { + return new ExtendsWildcardType(new RefType(new JavaClassName("java.lang.Object"), new NullToken()), wildcardContext.getStart()); + } + } else { + throw new NotImplementedException(); // Wildcard ohne Bound + } + } + + public static RefTypeOrTPHOrWildcardOrGeneric convertTypeName(String name, Token offset, JavaClassRegistry reg, GenericsRegistry generics) { + return convertTypeName(name, (Java17Parser.TypeArgumentsContext) null, offset, reg, generics); + } + + public static RefTypeOrTPHOrWildcardOrGeneric convertTypeName(String name, Java17Parser.TypeArgumentsContext typeArguments, Token offset, JavaClassRegistry reg, GenericsRegistry generics) { + if (!reg.contains(name)) { // Dann könnte es ein generischer Type oder ein FunN$$-Type sein + if (generics.contains(name)) { + return new GenericRefType(name, offset); + } else { + Pattern p = Pattern.compile("Fun(\\d+)[$][$]"); + Matcher m = p.matcher(name); + if (m.matches()) {// es ist FunN$$-Type + return new RefType(new JavaClassName(name), convert(typeArguments, reg, generics), offset); + } else { + throw new TypeinferenceException("Der Typ " + name + " ist nicht vorhanden", offset); + } + } + } + if (typeArguments == null) { + List params = new ArrayList<>(); + for (int i = 0; i < reg.getNumberOfGenerics(name); i++) { + params.add(TypePlaceholder.fresh(offset)); + } + return new RefType(reg.getName(name), params, offset); + } else { + return new RefType(reg.getName(name), convert(typeArguments, reg, generics), offset); + } + } + + public static RefTypeOrTPHOrWildcardOrGeneric convertTypeName(String name, Java17Parser.NonWildcardTypeArgumentsContext typeArguments, Token offset, JavaClassRegistry reg, GenericsRegistry generics) { + if (!reg.contains(name)) { // Dann könnte es ein generischer Type oder ein FunN$$-Type sein + if (generics.contains(name)) { + return new GenericRefType(name, offset); + } else { + Pattern p = Pattern.compile("Fun(\\d+)[$][$]"); + Matcher m = p.matcher(name); + if (m.matches()) {// es ist FunN$$-Type + return new RefType(new JavaClassName(name), convert(typeArguments, reg, generics), offset); + } else { + throw new TypeinferenceException("Der Typ " + name + " ist nicht vorhanden", offset); + } + } + } + if (typeArguments == null) { + List params = new ArrayList<>(); + for (int i = 0; i < reg.getNumberOfGenerics(name); i++) { + params.add(TypePlaceholder.fresh(offset)); + } + return new RefType(reg.getName(name), params, offset); + } else { + return new RefType(reg.getName(name), convert(typeArguments, reg, generics), offset); + } + } + + public static List convert(Java17Parser.TypeArgumentsContext typeArguments, JavaClassRegistry reg, GenericsRegistry generics) { + List ret = new ArrayList<>(); + for (Java17Parser.TypeArgumentContext arg : typeArguments.typeArgument()) { + WildcardTypeContext wc = arg.wildcardType(); + if (!Objects.isNull(wc)) { + ret.add(convert(wc, reg, generics)); + } else { + ret.add(convert(arg.typeType(), reg, generics)); + } + } + return ret; + } + + public static List convert(Java17Parser.NonWildcardTypeArgumentsContext typeArguments, JavaClassRegistry reg, GenericsRegistry generics) { + List ret = new ArrayList<>(); + for (Java17Parser.TypeTypeContext arg : typeArguments.typeList().typeType()) { + ret.add(convert(arg, reg, generics)); + } + return ret; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/parser/TODO b/LanguageServer/src/main/java/de/dhbw/compiler/parser/TODO new file mode 100644 index 0000000..165cb56 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/parser/TODO @@ -0,0 +1,5 @@ += Grammatik = + +* Core-Problem: Typinferenz vs. Konstruktoren +* möglicherweise Problem: falsche Return-Expressions + diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/parser/notes/GetNames b/LanguageServer/src/main/java/de/dhbw/compiler/parser/notes/GetNames new file mode 100644 index 0000000..2c59e3b --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/parser/notes/GetNames @@ -0,0 +1,15 @@ +* Methode als statische Klasse +* Methode gibt eine JavaClassRegistry zurück (für mehr als 1 S0ourcefile). +* Suchmuster: \n rule +* Generell: lieber leere Listen und wenig null verwenden (Spezialfälle ausgenommen). + +== Fehler/Exceptions == + +* Eigene wie z.B. TypeCheckExceptions +* Fehler sollen an Semantikchecker usw. weiter gegeben werden. + +== Offset == + +* Evtl. Zeichen im File/in der Klasse durch Antlr ermitteln. +* z.B. ParserRuleContext.getStart() +* Anstatt offset: Instanz des entsprechenden ParserRuleContext (liefert evtl. noch mehr Infos) diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/parser/notes/TODO b/LanguageServer/src/main/java/de/dhbw/compiler/parser/notes/TODO new file mode 100644 index 0000000..8d04f71 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/parser/notes/TODO @@ -0,0 +1,3 @@ +* fieldDeclarations +* Imports +* (Q)Generics diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/parser/notes/questions b/LanguageServer/src/main/java/de/dhbw/compiler/parser/notes/questions new file mode 100644 index 0000000..61a725a --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/parser/notes/questions @@ -0,0 +1,2 @@ +* Ablegen der Type Parameter: kompletter Name? +* Typen (unannType etc.) diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/parser/parse_tree b/LanguageServer/src/main/java/de/dhbw/compiler/parser/parse_tree new file mode 100644 index 0000000..13078b5 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/parser/parse_tree @@ -0,0 +1,18 @@ +* Listener-Pattern für das Projekt eher ungeeignet. + += Herangehensweise/Format = + +* CompilatunUnit (Rot) wird zu Source-File (Root) +* Im Paket Syntaxtree finden sich die Klassen, die ich letztendlich erzeugen muss. +* Kann hier auch Veränderungen vornehmen (Pull Request) +* Wichtig! Typnamen müssen aufgelöst werden können (also z.B. java.lang.util.ArrayList (JavaClassRegistry). + += Idee bei mehreren Files = +* Zunächst alle Files anschauen und Pakate/Klassen für die spätere Verwendung "registrieren". +* Danach erst das komplette Package/alle Klassen imselben Verzeichnis parsen. + +== Fragen/PProbleme SyntaxTreeGenerator == + +* ClassRegistry: Unklar, woher diese kommen soll. +* Konstruktor für Class fehlt. +* Namenskonflikt Class vs. Class in Java? diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/parser/scope/GatherNames.java b/LanguageServer/src/main/java/de/dhbw/compiler/parser/scope/GatherNames.java new file mode 100644 index 0000000..492f715 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/parser/scope/GatherNames.java @@ -0,0 +1,154 @@ +package de.dhbw.compiler.parser.scope; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import com.google.common.collect.Iterables; +import de.dhbw.compiler.core.JavaTXCompiler; +import de.dhbw.compiler.environment.PackageCrawler; +import de.dhbw.compiler.exceptions.NotImplementedException; +import de.dhbw.parser.Java17Parser; + + +public class GatherNames { + + public static Map getNames(Java17Parser.SrcfileContext ctx, PackageCrawler packages, JavaTXCompiler compiler) throws ClassNotFoundException { + Map ret = new HashMap<>(); + for (Java17Parser.ClassOrInterfaceContext clsoifctx : ctx.classOrInterface()) { + if (clsoifctx instanceof Java17Parser.NoclassorinterfaceContext) { + continue; + } + ret.putAll(getNames(clsoifctx, getPackageName(ctx), packages, compiler)); + } + ret.putAll(getImports(ctx, packages, compiler)); + return ret; + } + + public static Map getNames(Java17Parser.ClassOrInterfaceContext clsoifctx, String pkgName, PackageCrawler packages, JavaTXCompiler compiler) throws ClassNotFoundException { + Map ret = new HashMap<>(); + Java17Parser.ClassorinterfacedeclContext clsoif = (Java17Parser.ClassorinterfacedeclContext) clsoifctx; + String nameString = ""; + String fullname = clsoif.getChild(clsoif.getChildCount() - 1).getClass().getName(); + String classname = fullname.substring(fullname.indexOf("$") + 1); + int numGenerics = 0; + /* + * Es werden alle Namen gesammelt, die syntaktisch von Java-TX (sprich der Grammatik) erkannt werden. Auch wenn z.B. Annotationen oder Enumerationen noch nicht im Compiler implementiert sind. Die "NotImplementedException" wird dann im "SyntaxTreeGenerator" geworfen. Das Statement soll als Vorbereitung dienen, für den Fall, dass weitere Sprachkonstrukte in den Compiler aufgenommen werden. + */ + switch (classname) { + case "ClassDeclarationContext": + if (!pkgName.isEmpty()) { + nameString = pkgName + "." + clsoif.classDeclaration().identifier().getText(); + } else { + nameString = clsoif.classDeclaration().identifier().getText(); + } + numGenerics = clsoif.classDeclaration().genericDeclarationList() != null ? clsoif.classDeclaration().genericDeclarationList().genericTypeVar().size() : 0; + ret.put(nameString, numGenerics); + ret.putAll(getNames(clsoif.classDeclaration().classBody().classBodyDeclaration(), pkgName, packages, compiler)); + break; + case "EnumDeclarationContext": + if (!pkgName.isEmpty()) { + nameString = pkgName + "." + clsoif.enumDeclaration().identifier().getText(); + } else { + nameString = clsoif.enumDeclaration().identifier().getText(); + } + numGenerics = 0; + ret.put(nameString, numGenerics); + Java17Parser.EnumConstantsContext enumConstants = clsoif.enumDeclaration().enumConstants(); + if (!Objects.isNull(enumConstants)) { + for (Java17Parser.EnumConstantContext enumConstant : enumConstants.enumConstant()) { + Java17Parser.ClassBodyContext enumConstClassBody = enumConstant.classBody(); + if (!Objects.isNull(enumConstClassBody)) { + ret.putAll(getNames(enumConstClassBody.classBodyDeclaration(), pkgName, packages, compiler)); + } + } + } + break; + case "InterfaceDeclarationContext": + if (pkgName != "") { + nameString = pkgName + "." + clsoif.interfaceDeclaration().identifier().getText(); + } else { + nameString = clsoif.interfaceDeclaration().identifier().getText(); + } + numGenerics = clsoif.interfaceDeclaration().genericDeclarationList() != null ? clsoif.interfaceDeclaration().genericDeclarationList().genericTypeVar().size() : 0; + ret.put(nameString, numGenerics); + for (Java17Parser.InterfaceBodyDeclarationContext ifbody : clsoif.interfaceDeclaration().interfaceBody().interfaceBodyDeclaration()) { + if (ifbody instanceof Java17Parser.InterfacememberContext member && member.interfaceMemberDeclaration() instanceof Java17Parser.SubclassorinterfaceContext sub) { + ret.putAll(getNames(sub.classOrInterface(), pkgName, packages, compiler)); + } + } + break; + case "AnnotationTypeDeclarationContext": + if (pkgName != "") { + nameString = pkgName + "." + clsoif.annotationTypeDeclaration().identifier().getText(); + } else { + nameString = clsoif.annotationTypeDeclaration().identifier().getText(); + } + numGenerics = 0; + ret.put(nameString, numGenerics); + for (Java17Parser.AnnotationTypeElementDeclarationContext anTypeElem : clsoif.annotationTypeDeclaration().annotationTypeBody().annotationTypeElementDeclaration()) { + Java17Parser.ClassOrInterfaceContext anClsoifctx = anTypeElem.annotationTypeElementRest().classOrInterface(); + if (!Objects.isNull(anClsoifctx)) { + ret.putAll(getNames(anClsoifctx, pkgName, packages, compiler)); + } + } + break; + case "RecordDeclarationContext": + if (pkgName != "") { + nameString = pkgName + "." + clsoif.recordDeclaration().identifier().getText(); + } else { + nameString = clsoif.recordDeclaration().identifier().getText(); + } + numGenerics = clsoif.recordDeclaration().genericDeclarationList() != null ? clsoif.recordDeclaration().genericDeclarationList().genericTypeVar().size() : 0; + ret.put(nameString, numGenerics); + ret.putAll(getNames(clsoif.recordDeclaration().recordBody().classBodyDeclaration(), pkgName, packages, compiler)); + break; + default: + throw new NotImplementedException(); + } + return ret; + } + + public static Map getNames(List clsBodyDecl, String pkgName, PackageCrawler packages, JavaTXCompiler compiler) throws ClassNotFoundException { + Map ret = new HashMap<>(); + for (Java17Parser.ClassBodyDeclarationContext clsbody : clsBodyDecl) { + if (clsbody instanceof Java17Parser.MemberdeclContext member && member.memberDeclaration() instanceof Java17Parser.MemberclassorinterfaceContext memberclsoifctx) { + ret.putAll(getNames(memberclsoifctx.classOrInterface(), pkgName, packages, compiler)); + } + } + return ret; + } + + public static Map getImports(Java17Parser.SrcfileContext ctx, PackageCrawler packages, JavaTXCompiler compiler) throws ClassNotFoundException { + Map ret = new HashMap<>(); + // ret.putAll(packages.getClassNames("java.lang")); + for (Java17Parser.ImportDeclarationContext importDeclCtx : ctx.importDeclaration()) { + if (importDeclCtx.MUL() == null) { + var name = importDeclCtx.qualifiedName().getText(); + var className = new JavaClassName(name); + var clazz = compiler.loadJavaTXClass(className); + if (clazz != null) { + ret.put(name, compiler.classRegistry.getNumberOfGenerics(name)); + } else { + Class cl = compiler.getClassLoader().loadClass(name); + ret.put(cl.getName(), cl.getTypeParameters().length); + } + } else if (importDeclCtx.MUL() != null) { + // TODO Find stuff in user defined packages + ret.putAll(packages.getClassNames(importDeclCtx.qualifiedName().getText())); + } + // Die Unterscheidungen für 'static imports' wurden herausgenommen, da sie den + // auszuführenden Code nicht beeinflussen + } + return ret; + } + + private static String getPackageName(Java17Parser.SrcfileContext ctx) { + String pkgName = ""; + if (ctx.packageDeclaration() != null) { + pkgName = ctx.packageDeclaration().qualifiedName().getText(); + } + return pkgName; + } +} \ No newline at end of file diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/parser/scope/GenericsRegistry.java b/LanguageServer/src/main/java/de/dhbw/compiler/parser/scope/GenericsRegistry.java new file mode 100644 index 0000000..3af82cc --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/parser/scope/GenericsRegistry.java @@ -0,0 +1,50 @@ +package de.dhbw.compiler.parser.scope; + +import de.dhbw.compiler.parser.SyntaxTreeGenerator.GenericContext; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +public class GenericsRegistry { + private final List registry = new ArrayList<>(); + public final GenericsRegistry globalRegistry; + + public GenericsRegistry(GenericsRegistry globalRegistry){ + this.globalRegistry = globalRegistry; + } + + public void put(String name, GenericContext genericContext){ + registry.add(new GenericVariable(genericContext,name)); + if(globalRegistry != null)globalRegistry.put(name, genericContext); + } + + public boolean contains(String name) { + Optional ret = registry.stream().map(((GenericVariable genericVariable) -> genericVariable.name.equals(name))) + .reduce(((a, b) -> a || b)); + if(ret.isPresent()) + return ret.get(); + return false; + } + + public GenericContext get(String name) { + return registry.stream() + .filter((genericVariable -> genericVariable.name.equals(name))).findAny().get().context; + } + + public void putAll(GenericsRegistry generics) { + for(GenericVariable generic : generics.registry){ + this.put(generic.name, generic.context); + } + } +} + +class GenericVariable{ + final GenericContext context; + final String name; + + GenericVariable(GenericContext context, String name){ + this.context = context; + this.name = name; + } +} \ No newline at end of file diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/parser/scope/JavaClassName.java b/LanguageServer/src/main/java/de/dhbw/compiler/parser/scope/JavaClassName.java new file mode 100644 index 0000000..85ef28d --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/parser/scope/JavaClassName.java @@ -0,0 +1,159 @@ +package de.dhbw.compiler.parser.scope; + +import java.util.ArrayList; +import java.util.List; + +/** + * Stellt den Namen einer Java Klasse dar. + * Dieser kann auch den Packagenamen mit beinhalten: + * de.dhbwstuttgart.typeinference.Menge + * + * @author Andreas Stadelmeier + */ +public class JavaClassName { + + // FIXME It's very much possible to have imports to inner classes + // In that case a.package.Foo.Bar, a.package is the Package and Foo.Bar the class name + // Its impossible to decide what's the package based solely on the name of the class + + public static final JavaClassName Void = new JavaClassName("void"); + private String name; + private PackageName packageName; + + public JavaClassName(String name) { + if (name == null) + throw new NullPointerException(); + + String[] names = name.split("[.]"); + boolean match = true; + if (names.length == 1) { + // packageName = new PackageName(); + this.name = name; + } else { + name = names[names.length - 1]; + List packageNames = new ArrayList(); + for (int i = 0; i < names.length - 1; i++) { + packageNames.add(names[i]); + } + packageName = new PackageName(packageNames); + this.name = names[names.length - 1]; + } + } + + /** + * Gibt von einem Klassennamen nur den Namen der Klasse zur�ck + * Beispiel: + * java.lang.Object wird zu: Object + */ + public static String stripClassName(String className) { + return new JavaClassName(className).name; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + /* + * result = prime * result + * + ((packageName == null) ? 0 : packageName.hashCode()); //PackageName does + * not infect hashCode + */ + return result; + } + + /** + * Namen sind nur gleich, wenn bei den beiden zu vergleichenden JavaClassNames + * auch das Package angegeben ist + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (obj instanceof String) + return this.toString().equals(obj) || (this.name != null && this.name.equals(obj)); // Auch mit Strings als + // Klassennamen kompatibel + // TODO: sollte bald obsolet + // sein + if (getClass() != obj.getClass()) + return false; + JavaClassName other = (JavaClassName) obj; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + if (packageName != null && other.packageName != null) { + if (!packageName.equals(other.packageName)) + return false;// Spezialfall, nicht beide Typen müssen eindeutig mit Packagenamen angegeben + // werden + } + return true; + } + + @Override + public String toString() { + return (packageName != null ? packageName.toString() + "." : "") + name; + } + + public String getPackageName() { + return (packageName != null ? packageName.toString() : ""); + } + + public String getClassName() { + return name; + } +} + +class PackageName { + + List names = new ArrayList<>(); + + public PackageName(List packageNames) { + names = packageNames; + } + + public PackageName() { + // Do nothing + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((names == null) ? 0 : names.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + PackageName other = (PackageName) obj; + if (names == null) { + if (other.names != null) + return false; + } else if (!names.equals(other.names)) + return false; + return true; + } + + @Override + public String toString() { + String ret = ""; + if (names == null) + return ""; + for (String n : names) + ret += n + "."; + if (ret != null && ret.length() > 0 && ret.charAt(ret.length() - 1) == '.') { + ret = ret.substring(0, ret.length() - 1); + } + return ret; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/parser/scope/JavaClassRegistry.java b/LanguageServer/src/main/java/de/dhbw/compiler/parser/scope/JavaClassRegistry.java new file mode 100644 index 0000000..18b688a --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/parser/scope/JavaClassRegistry.java @@ -0,0 +1,65 @@ +package de.dhbw.compiler.parser.scope; + +import de.dhbw.compiler.exceptions.NotImplementedException; + +import java.util.*; + +/** + * Speichert die Klassen f�r einen bestimmten Projektscope + */ +public class JavaClassRegistry { + final Map existingClasses = new HashMap<>(); + + public JavaClassRegistry(Map initialNames) { + addNames(initialNames); + } + + public JavaClassRegistry() {} + + public void addNames(Map names) { + for (String name : names.keySet()) { + existingClasses.put(new JavaClassName(name), names.get(name)); + } + } + + public void addName(String className, int numberOfGenerics) { + existingClasses.put(new JavaClassName(className), numberOfGenerics); + } + + public JavaClassName getName(String className) { + for (JavaClassName name : existingClasses.keySet()) { + if (name.equals(new JavaClassName(className))) + return name; + } + throw new RuntimeException("Class " + className + " not found!"); + } + + @Override + public String toString() { + return existingClasses.toString(); + } + + public List getAllFromPackage(String packageName) { + List ret = new ArrayList<>(); + for (JavaClassName className : this.existingClasses.keySet()) { + JavaClassName toCompare = new JavaClassName( + packageName + "." + JavaClassName.stripClassName(className.toString())); + if (toCompare.toString().equals(className.toString())) { + ret.add(className); + } + } + return ret; + } + + public boolean contains(String whole) { + return existingClasses.containsKey(new JavaClassName(whole)); + } + + public boolean contains(JavaClassName name) { + return existingClasses.containsKey(name); + } + + public int getNumberOfGenerics(String name) { + return existingClasses.get(new JavaClassName(name)); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/ASTVisitor.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/ASTVisitor.java new file mode 100644 index 0000000..38c668f --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/ASTVisitor.java @@ -0,0 +1,43 @@ +package de.dhbw.compiler.syntaxtree; + +import de.dhbw.compiler.syntaxtree.type.*; + +public interface ASTVisitor extends StatementVisitor{ + + void visit(SourceFile sourceFile); + + void visit(GenericTypeVar genericTypeVar); + + void visit(FormalParameter formalParameter); + + void visit(LiteralPattern literalPattern); + + void visit(GenericDeclarationList genericTypeVars); + + void visit(Field field); + + void visit(Method field); + + void visit(Constructor field); + + void visit(ParameterList formalParameters); + + void visit(ClassOrInterface classOrInterface); + + void visit(RefType refType); + + void visit(SuperWildcardType superWildcardType); + + void visit(TypePlaceholder typePlaceholder); + + void visit(ExtendsWildcardType extendsWildcardType); + + void visit(GenericRefType genericRefType); + + void visit(ExpressionPattern aPattern); + + void visit(RecordPattern aRecordPattern); + + void visit(GuardedPattern aGuardedPattern); + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/AbstractASTWalker.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/AbstractASTWalker.java new file mode 100644 index 0000000..f951fe6 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/AbstractASTWalker.java @@ -0,0 +1,352 @@ +package de.dhbw.compiler.syntaxtree; + +import de.dhbw.compiler.parser.SyntaxTreeGenerator.AssignToLocal; +import de.dhbw.compiler.syntaxtree.statement.*; +import de.dhbw.compiler.syntaxtree.type.*; + +import java.util.Iterator; +import java.util.Objects; + +public abstract class AbstractASTWalker implements ASTVisitor { + @Override + public void visit(Constructor cons) { + visitMethod(cons); + } + + @Override + public void visit(SourceFile sourceFile) { + for (ClassOrInterface cl : sourceFile.getClasses()) { + cl.accept(this); + } + } + + @Override + public void visit(ArgumentList argumentList) { + for (Expression expr : argumentList.getArguments()) { + expr.accept(this); + } + } + + @Override + public void visit(GenericTypeVar genericTypeVar) { + + } + + @Override + public void visit(FormalParameter formalParameter) { + formalParameter.getType().accept((ASTVisitor) this); + } + + @Override + public void visit(LiteralPattern literalPattern) { + + } + + @Override + public void visit(GenericDeclarationList genericTypeVars) { + Iterator genericIterator = genericTypeVars.iterator(); + if (genericIterator.hasNext()) { + while (genericIterator.hasNext()) { + genericIterator.next().accept(this); + } + } + } + + @Override + public void visit(Field field) { + field.getType().accept(this); + } + + @Override + public void visit(Method method) { + visitMethod(method); + } + + private void visitMethod(Method method) { + method.getReturnType().accept(this); + method.getParameterList().accept(this); + if (method.block != null) + method.block.accept(this); + } + + @Override + public void visit(ParameterList formalParameters) { + Iterator it = formalParameters.getFormalparalist().iterator(); + if (it.hasNext()) { + while (it.hasNext()) { + it.next().accept(this); + } + } + } + + @Override + public void visit(ClassOrInterface classOrInterface) { + classOrInterface.getGenerics().accept(this); + for (Field f : classOrInterface.getFieldDecl()) { + f.accept(this); + } + for (Constructor c : classOrInterface.getConstructors()) { + c.accept(this); + } + for (Method m : classOrInterface.getMethods()) { + m.accept(this); + } + } + + @Override + public void visit(RefType refType) { + Iterator genericIterator = refType.getParaList().iterator(); + if (genericIterator.hasNext()) { + while (genericIterator.hasNext()) { + genericIterator.next().accept(this); + } + } + } + + @Override + public void visit(SuperWildcardType superWildcardType) { + superWildcardType.getInnerType().accept(this); + } + + @Override + public void visit(TypePlaceholder typePlaceholder) { + } + + @Override + public void visit(ExtendsWildcardType extendsWildcardType) { + extendsWildcardType.getInnerType().accept(this); + } + + @Override + public void visit(GenericRefType genericRefType) { + } + + @Override + public void visit(LambdaExpression lambdaExpression) { + lambdaExpression.params.accept(this); + lambdaExpression.methodBody.accept(this); + } + + @Override + public void visit(Assign assign) { + assign.lefSide.accept(this); + assign.rightSide.accept(this); + assign.rightSide.getType().accept((ASTVisitor) this); + } + + @Override + public void visit(BinaryExpr binary) { + + } + + @Override + public void visit(BoolExpression logical) { + + } + + @Override + public void visit(Block block) { + for (Statement stmt : block.getStatements()) { + stmt.accept(this); + } + } + + @Override + public void visit(CastExpr castExpr) { + + } + + @Override + public void visit(EmptyStmt emptyStmt) { + + } + + @Override + public void visit(FieldVar fieldVar) { + fieldVar.receiver.accept(this); + } + + @Override + public void visit(ForStmt forStmt) { + 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); + if (!Objects.isNull(ifStmt.else_block)) + ifStmt.else_block.accept(this); + } + + @Override + public void visit(InstanceOf instanceOf) { + + } + + @Override + public void visit(LocalVar localVar) { + + } + + @Override + public void visit(LocalVarDecl localVarDecl) { + localVarDecl.getType().accept(this); + } + + @Override + public void visit(MethodCall methodCall) { + methodCall.receiver.accept(this); + methodCall.getArgumentList().accept(this); + methodCall.getArgumentList().getArguments().forEach(a -> a.getType().accept((ASTVisitor) this)); + } + + @Override + public void visit(NewClass methodCall) { + visit((MethodCall) methodCall); + } + + @Override + public void visit(NewArray newArray) { + + } + + @Override + public void visit(ExpressionReceiver receiver) { + receiver.expr.accept(this); + } + + @Override + public void visit(UnaryExpr unaryExpr) { + unaryExpr.expr.accept(this); + } + + @Override + public void visit(Return aReturn) { + aReturn.retexpr.accept(this); + aReturn.getType().accept((ASTVisitor) this); + } + + @Override + public void visit(ReturnVoid aReturn) { + + } + + @Override + public void visit(Break aBreak) { + aBreak.accept(this); + } + + @Override + public void visit(Continue aContinue) { + aContinue.accept(this); + } + + @Override + public void visit(StaticClassName staticClassName) { + + } + + @Override + public void visit(Super aSuper) { + + } + + @Override + public void visit(This aThis) { + + } + + @Override + public void visit(WhileStmt whileStmt) { + whileStmt.loopBlock.accept(this); + } + + @Override + public void visit(DoStmt whileStmt) { + whileStmt.loopBlock.accept(this); + } + + @Override + public void visit(Literal literal) { + + } + + @Override + public void visit(Throw aThrow) { + + } + + @Override + public void visit(AssignToField assignLeftSide) { + assignLeftSide.field.accept(this); + } + + @Override + public void visit(AssignToLocal assignLeftSide) { + assignLeftSide.localVar.accept(this); + } + + @Override + public void visit(SuperCall superCall) { + this.visit((MethodCall) superCall); + } + + @Override + public void visit(ThisCall thisCall) { + + } + + @Override + public void visit(Switch switchStmt) { + switchStmt.getSwitch().accept(this); + switchStmt.getBlocks().stream().forEach((switchBlock) -> { + switchBlock.accept(this); + }); + } + + @Override + public void visit(SwitchBlock switchBlock) { + switchBlock.getLabels().stream().forEach((label) -> { + label.accept(this); + }); + switchBlock.getStatements().stream().forEach((stmt) -> { + stmt.accept(this); + }); + } + + @Override + public void visit(SwitchLabel switchLabel) { + + } + + @Override + public void visit(Yield aYield) { + } + + @Override + public void visit(ExpressionPattern aPattern) { + + } + + @Override + public void visit(RecordPattern aRecordPattern) { + + } + + @Override + public void visit(GuardedPattern aGuardedPattern) { + + } + + @Override + public void visit(Ternary ternary) { + ternary.cond.accept(this); + ternary.iftrue.accept(this); + ternary.iffalse.accept(this); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/ClassOrInterface.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/ClassOrInterface.java new file mode 100644 index 0000000..e8fa60c --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/ClassOrInterface.java @@ -0,0 +1,202 @@ +package de.dhbw.compiler.syntaxtree; + +import de.dhbw.compiler.parser.NullToken; +import de.dhbw.compiler.parser.scope.JavaClassName; +import de.dhbw.compiler.syntaxtree.type.GenericRefType; +import de.dhbw.compiler.syntaxtree.type.RefType; +import de.dhbw.compiler.syntaxtree.type.TypePlaceholder; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import org.antlr.v4.runtime.Token; + +import java.lang.reflect.Modifier; +import java.util.*; + +/** + * Stellt jede Art von Klasse dar. Auch abstrakte Klassen und Interfaces + */ +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 fields = new ArrayList<>(); + private Optional fieldInitializations; // PL 2018-11-24: Noetig, um Bytecode fuer initializators nur einmal zu erzeugen + private Optional staticInitializer; + private List methods = new ArrayList<>(); + private GenericDeclarationList genericClassParameters; + private RefType superClass; + protected boolean isInterface; + protected boolean isFunctionalInterface; + private List implementedInterfaces; + private List permittedSubtypes; + private List constructors; + + public ClassOrInterface(int modifiers, JavaClassName name, List fielddecl, Optional fieldInitializations, Optional staticInitializer, List methods, List constructors, GenericDeclarationList genericClassParameters, RefType superClass, Boolean isInterface, Boolean isFunctionalInterface, List implementedInterfaces, List permittedSubtypes, Token offset, String fileName) { + super(offset); + if (isInterface) { + modifiers |= Modifier.INTERFACE | Modifier.ABSTRACT; + } + this.modifiers = modifiers; + this.name = name; + this.fields = fielddecl; + this.fieldInitializations = fieldInitializations; + this.staticInitializer = staticInitializer; + this.genericClassParameters = genericClassParameters; + this.superClass = superClass; + this.isInterface = isInterface; + this.isFunctionalInterface= isFunctionalInterface; + this.implementedInterfaces = implementedInterfaces; + this.permittedSubtypes = permittedSubtypes; + this.methods = methods; + this.constructors = constructors; + this.fileName = fileName; + } + + /* + * erzeugt fuer Fields, Konstruktoren und Methoden neue ArrayList-Objekte alle anderen Datenobjekte werden nur kopiert. + */ + public ClassOrInterface(ClassOrInterface cl) { + super(cl.getOffset()); + this.modifiers = cl.modifiers; + this.name = cl.name; + this.fields = new ArrayList<>(cl.fields); + this.fieldInitializations = cl.fieldInitializations; + this.staticInitializer = cl.staticInitializer; + this.genericClassParameters = cl.genericClassParameters; + this.superClass = cl.superClass; + this.isInterface = cl.isInterface; + this.isFunctionalInterface= cl.isFunctionalInterface; + 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 getField(String name) { + // TODO This should be a map + return fields.stream().filter(field -> field.getName().equals(name)).findFirst(); + } + + public Optional getStaticInitializer() { + return staticInitializer; + } + + public boolean isSealed() { return permittedSubtypes != null; } + public List getPermittedSubtypes() { return permittedSubtypes != null ? permittedSubtypes : List.of(); } + + public boolean isInterface() { + return (Modifier.INTERFACE & this.getModifiers()) != 0; + } + + public boolean isFunctionalInterface() { + return this.isFunctionalInterface; + } + + // Gets if it is added + public Boolean areMethodsAdded() { + return methodAdded; + } + + // Sets that it is added + public void setMethodsAdded() { + methodAdded = true; + } + + // Gets class name + public JavaClassName getClassName() { + return this.name; + } + + // Get modifiers + public int getModifiers() { + return this.modifiers; + } + + public List getFieldDecl() { + return this.fields; + } + + public Optional getfieldInitializations() { + return this.fieldInitializations; + } + + public List getMethods() { + return this.methods; + } + /* + * public RefType getType() { return generateTypeOfClass(this.getClassName(), this.getGenerics(), this.getOffset()); } + */ + // TODO: Das hier ist ein Problem. Je nach Kontext wird hier ein anderer Typ benötigt + public static RefType generateTypeOfClass(JavaClassName name, GenericDeclarationList genericsOfClass, Token offset) { + // Hier wird immer ein generischer Typ generiert, also mit Type placeholdern + List params = new ArrayList<>(); + for (GenericTypeVar genericTypeVar : genericsOfClass) { + // params.add(genericTypeVar.getTypePlaceholder()); + params.add(TypePlaceholder.fresh(offset)); + } + return new RefType(name, params, offset); + } + + /** + * + * @return die aktuelle Klasse als RefType + */ + public RefType generateTypeOfThisClass() { + List params = new ArrayList<>(); + for (GenericTypeVar genericTypeVar : this.getGenerics()) { + // params.add(genericTypeVar.getTypePlaceholder()); + params.add(new GenericRefType(genericTypeVar.getName(), new NullToken())); + } + return new RefType(name, params, new NullToken()); + } + + /** + * Die Superklasse im Kontext dieser ClassOrInterface Das bedeutet, dass generische Variablen als GenericRefTypes dargestellt sind + */ + public RefType getSuperClass() { + return superClass; + } + + public GenericDeclarationList getGenerics() { + return this.genericClassParameters; + } + + @Override + public RefTypeOrTPHOrWildcardOrGeneric getReturnType() { + return null; + } + + public List getConstructors() { + return constructors; + } + + @Override + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } + + public Collection getSuperInterfaces() { + return implementedInterfaces; + } + + public String toString() { + return this.name.toString() + this.genericClassParameters.toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ClassOrInterface other)) return false; + return Objects.equals(name, other.name); + } + + @Override + public int hashCode() { + return Objects.hash(name); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/Constructor.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/Constructor.java new file mode 100644 index 0000000..e4c6708 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/Constructor.java @@ -0,0 +1,29 @@ +package de.dhbw.compiler.syntaxtree; + +import de.dhbw.compiler.parser.NullToken; +import de.dhbw.compiler.syntaxtree.statement.Statement; +import de.dhbw.compiler.syntaxtree.statement.Super; +import de.dhbw.compiler.syntaxtree.statement.SuperCall; +import de.dhbw.compiler.syntaxtree.type.RefType; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.syntaxtree.type.Void; +import org.antlr.v4.runtime.Token; + +import de.dhbw.compiler.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) { + super(modifier, name, returnType, parameterList, codeInsideConstructor, gtvDeclarations, offset); + } + + @Override + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/ExceptionList.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/ExceptionList.java new file mode 100644 index 0000000..4ad17e7 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/ExceptionList.java @@ -0,0 +1,14 @@ +package de.dhbw.compiler.syntaxtree; + +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; + +import java.util.List; + +public class ExceptionList +{ + private List exceptions; + + public ExceptionList(List exceptions){ + this.exceptions = exceptions; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/ExpressionPattern.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/ExpressionPattern.java new file mode 100644 index 0000000..3abc3d0 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/ExpressionPattern.java @@ -0,0 +1,28 @@ +package de.dhbw.compiler.syntaxtree; + +import de.dhbw.compiler.syntaxtree.statement.Expression; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import org.antlr.v4.runtime.Token; + +public class ExpressionPattern extends Pattern { + private final Expression expression; + + public ExpressionPattern(Expression expression, Token offset) { + super(expression.getType(), offset); + this.expression = expression; + } + + public Expression getExpression() { + return expression; + } + + @Override + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } + + @Override + public ExpressionPattern withType(RefTypeOrTPHOrWildcardOrGeneric type) { + return new ExpressionPattern(expression, getOffset()); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/Field.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/Field.java new file mode 100644 index 0000000..ceb1460 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/Field.java @@ -0,0 +1,43 @@ +package de.dhbw.compiler.syntaxtree; + +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import org.antlr.v4.runtime.Token; + +import java.util.ArrayList; + +public class Field extends SyntaxTreeNode implements TypeScope { + + public final int modifier; + private String name; + private RefTypeOrTPHOrWildcardOrGeneric type; + + public Field(String name, RefTypeOrTPHOrWildcardOrGeneric type, int modifier, Token offset) { + super(offset); + this.name = name; + this.type = type; + this.modifier = modifier; + } + + public String getName() { + return this.name; + } + + public RefTypeOrTPHOrWildcardOrGeneric getType() { + return type; + } + + @Override + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } + + @Override + public Iterable getGenerics() { + return new ArrayList<>(); + } + + @Override + public RefTypeOrTPHOrWildcardOrGeneric getReturnType() { + return type; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/FieldDeclaration.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/FieldDeclaration.java new file mode 100644 index 0000000..abe6113 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/FieldDeclaration.java @@ -0,0 +1,28 @@ +package de.dhbw.compiler.syntaxtree; + +import de.dhbw.compiler.syntaxtree.statement.Expression; +import org.antlr.v4.runtime.Token; + +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; + +/** + * Eine Feldinitialisation steht für eine Felddeklaration mit gleichzeitiger Wertzuweisung + * Beispiel: 'public Feld FeldVar = FeldWert;' + * @author janulrich + * + */ +public class FieldDeclaration extends Field{ + + private Expression wert; + + /** + * Dieser Konstruktor der FieldDeclaration erstellt den Syntaxknoten vollständig. + * Kein nachträgliches hinzfügen von Informationen oder aufrufen von parserPostProcessing ist notwendig. + */ + public FieldDeclaration(String name, RefTypeOrTPHOrWildcardOrGeneric typ, int modifier, Expression value, Token offset){ + super(name, typ, modifier, offset);//Dieser Deklarator wird nicht vom Parser aufgerufen. Dadurch gibt es auch keinen Offset + this.wert = value; + } + + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/FormalParameter.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/FormalParameter.java new file mode 100644 index 0000000..7e7678f --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/FormalParameter.java @@ -0,0 +1,27 @@ +package de.dhbw.compiler.syntaxtree; + +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import org.antlr.v4.runtime.Token; + +public class FormalParameter extends Pattern { + private String name; + + public FormalParameter(String name, RefTypeOrTPHOrWildcardOrGeneric type, Token offset) { + super(type, offset); + this.name = name; + } + + public String getName() { + return name; + } + + @Override + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } + + @Override + public FormalParameter withType(RefTypeOrTPHOrWildcardOrGeneric type) { + return new FormalParameter(name, type, getOffset()); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/GenericDeclarationList.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/GenericDeclarationList.java new file mode 100644 index 0000000..55c30af --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/GenericDeclarationList.java @@ -0,0 +1,65 @@ +package de.dhbw.compiler.syntaxtree; + +import org.antlr.v4.runtime.Token; + +import com.google.common.collect.Lists; + +import de.dhbw.compiler.parser.NullToken; + +import java.util.*; + + +/** + * Stellt eine Deklarations-Liste von Generischen Variablen dar. + * Kann vor Methoden und Klassen auftauchen. (<....>) + * @author janulrich + * + */ +public class GenericDeclarationList extends SyntaxTreeNode implements Iterable{ + + private Token offsetOfLastElement; + private List gtvs = new ArrayList<>(); + + @SuppressWarnings("unchecked") + public GenericDeclarationList(Iterable values, Token endOffset) { + super(endOffset); + gtvs = isListOfGenericTypeVar(values) ? (List)values : Lists.newArrayList(values); + this.offsetOfLastElement = endOffset; + } + + public GenericDeclarationList(ArrayList values, Token endOffset) { + super(endOffset); + gtvs = values; + this.offsetOfLastElement = endOffset; } + + private boolean isListOfGenericTypeVar(Iterable values) { + return values instanceof List && ((List)values).size() > 0 && ((List)values).get(0) instanceof GenericTypeVar; + } + + @Override + public Iterator iterator() { + return gtvs.iterator(); + } + + @Override + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } + + public String toString() { + return this.gtvs.toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + GenericDeclarationList that = (GenericDeclarationList) o; + return gtvs.equals(that.gtvs); + } + + @Override + public int hashCode() { + return Objects.hash(gtvs); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/GenericTypeVar.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/GenericTypeVar.java new file mode 100644 index 0000000..b106cc2 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/GenericTypeVar.java @@ -0,0 +1,78 @@ +package de.dhbw.compiler.syntaxtree; + +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; + +import org.antlr.v4.runtime.Token; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * Entspricht einem GenericTypeVar, jedoch mit Bounds + * (d.h. vorgaben, von welchem Typ die Typevar sein darf + * => extends Class x + * => implements Interface y + * ... + * @author hoti 4.5.06 + * + */ +public class GenericTypeVar extends SyntaxTreeNode +{ + + /** + * Hier sind die Bounds in Form von Type-Objekten abgespeichert + */ + List bounds=new ArrayList(); + private Token endOffset; + private String name; + + public GenericTypeVar(String s, List bounds, Token offset, Token endOffset) + { + super(offset); + name = s; + if(bounds != null)for(RefTypeOrTPHOrWildcardOrGeneric t : bounds){ + //if(t!=null)this.extendVars.add(t); + } + //this.genericTypeVar = new RefType(s,offset); + this.bounds = bounds; + this.endOffset = endOffset; + } + + public List getBounds() + { + return bounds; + } + + public String toString() + { + return "BoGTV " + this.name + " " + this.bounds; + } + + public String getName(){ + return name.toString(); + } + + /* + public JavaClassName definingClass(){ + return name.getParentClass(); + } +*/ + @Override + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + GenericTypeVar that = (GenericTypeVar) o; + return bounds.equals(that.bounds) && name.equals(that.name); + } + + @Override + public int hashCode() { + return Objects.hash(bounds, name); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/GuardedPattern.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/GuardedPattern.java new file mode 100644 index 0000000..ac802aa --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/GuardedPattern.java @@ -0,0 +1,35 @@ +package de.dhbw.compiler.syntaxtree; + +import de.dhbw.compiler.syntaxtree.statement.Expression; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import org.antlr.v4.runtime.Token; + +public class GuardedPattern extends Pattern { + + private final Expression condition; + private final Pattern nested; + + public GuardedPattern(Expression condition, Pattern nested, Token offset) { + super(nested.getType(), offset); + this.condition = condition; + this.nested = nested; + } + + public Expression getCondition() { + return condition; + } + + public Pattern getNestedPattern() { + return nested; + } + + @Override + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } + + @Override + public GuardedPattern withType(RefTypeOrTPHOrWildcardOrGeneric type) { + return new GuardedPattern(condition, nested, getOffset()); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/LiteralPattern.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/LiteralPattern.java new file mode 100644 index 0000000..f40b3e8 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/LiteralPattern.java @@ -0,0 +1,29 @@ +package de.dhbw.compiler.syntaxtree; + + +import de.dhbw.compiler.syntaxtree.ASTVisitor; +import de.dhbw.compiler.syntaxtree.Pattern; +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.statement.Expression; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.typeinference.assumptions.TypeInferenceBlockInformation; +import de.dhbw.compiler.typeinference.constraints.ConstraintSet; +import org.antlr.v4.runtime.Token; + +public class LiteralPattern extends FormalParameter +{ + public final Expression value; + public LiteralPattern(RefTypeOrTPHOrWildcardOrGeneric type, Expression value, Token offset) { + super(null, type, offset); + + this.value = value; + } + @Override + public FormalParameter withType(RefTypeOrTPHOrWildcardOrGeneric type) { + return new LiteralPattern(type, value, getOffset()); + } + @Override + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/Method.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/Method.java new file mode 100644 index 0000000..decd8ed --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/Method.java @@ -0,0 +1,119 @@ +package de.dhbw.compiler.syntaxtree; + +import java.util.ArrayList; +import java.util.Objects; + +import de.dhbw.compiler.parser.NullToken; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.typeinference.assumptions.TypeInferenceBlockInformation; +import de.dhbw.compiler.typeinference.constraints.ConstraintSet; +import de.dhbw.compiler.typeinference.assumptions.TypeInferenceInformation; +import de.dhbw.compiler.typeinference.typeAlgo.TYPE; +import de.dhbw.compiler.typeinference.typeAlgo.TYPEStmt; +import org.antlr.v4.runtime.Token; + +import de.dhbw.compiler.core.IItemWithOffset; +import de.dhbw.compiler.syntaxtree.statement.Block; + +/** + * Stellt eine Methode dar. Problem: Parser kann nicht zwischen Methode und + * Konstruktor unterscheiden. Daher kann diese Klasse beides sein. Dies wird mit + * dem ParserPostProcessing behoben. + * + * @author janulrich + * + */ +public class Method extends SyntaxTreeNode implements IItemWithOffset, TypeScope +{ + public final Block block; + public final int modifier; + public final String name; + private ParameterList parameterlist = new ParameterList(new ArrayList<>(), new NullToken()); + private ExceptionList exceptionlist; + private GenericDeclarationList generics; + private final RefTypeOrTPHOrWildcardOrGeneric returnType; + public final Boolean isInherited; + public final Boolean isImplemented; + + /* + * its Constraints + * eingefuegt PL 2021-02-15 + */ + public final ConstraintSet constraints = new ConstraintSet(); + + public Method(int modifier, String name, RefTypeOrTPHOrWildcardOrGeneric returnType, ParameterList parameterList, Block block, + GenericDeclarationList gtvDeclarations, Token offset) { + super(offset); + this.name = name; + this.modifier = modifier; + this.returnType = returnType; + this.parameterlist = parameterList; + this.block = block; + this.generics = gtvDeclarations; + this.isInherited = false; + this.isImplemented = false; + } + + public Method(int modifier, String name, RefTypeOrTPHOrWildcardOrGeneric returnType, ParameterList parameterList, Block block, + GenericDeclarationList gtvDeclarations, Token offset, Boolean isInherited, Boolean isOverridden) { + super(offset); + this.name = name; + this.modifier = modifier; + this.returnType = returnType; + this.parameterlist = parameterList; + this.block = block; + this.generics = gtvDeclarations; + this.isInherited = isInherited; + this.isImplemented = isOverridden; + } + + public ParameterList getParameterList() { + return parameterlist; + } + + public GenericDeclarationList getGenerics() { + return generics; + } + + @Override + public RefTypeOrTPHOrWildcardOrGeneric getReturnType() { + return this.returnType; + } + + public ConstraintSet getConstraints() { + return this.constraints; + } + + @Override + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } + + @Override + public Token getOffset() { + return super.getOffset(); + } + + public String getName() { + return name; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Method method = (Method) o; + return Objects.equals(name, method.name) && Objects.equals(parameterlist, method.parameterlist) && Objects.equals(returnType, method.returnType); + } + + @Override + public int hashCode() { + return Objects.hash(name, parameterlist, returnType); + } + + @Override + public String toString() { + return name; + + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/ParameterList.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/ParameterList.java new file mode 100644 index 0000000..d013e76 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/ParameterList.java @@ -0,0 +1,36 @@ +package de.dhbw.compiler.syntaxtree; + +import org.antlr.v4.runtime.Token; + +import java.util.Iterator; +import java.util.List; + +public class ParameterList extends SyntaxTreeNode implements Iterable { + private List formalparameter; + + public ParameterList(List params, Token offset) { + super(offset); + this.formalparameter = params; + } + + public Pattern getParameterAt(int i) { + if (i >= formalparameter.size()) + return null; + + return formalparameter.get(i); + } + + public List getFormalparalist() { + return formalparameter; + } + + @Override + public Iterator iterator() { + return formalparameter.iterator(); + } + + @Override + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/Pattern.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/Pattern.java new file mode 100644 index 0000000..896226a --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/Pattern.java @@ -0,0 +1,19 @@ +package de.dhbw.compiler.syntaxtree; + +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import org.antlr.v4.runtime.Token; + +public abstract class Pattern extends SyntaxTreeNode { + private final RefTypeOrTPHOrWildcardOrGeneric type; + + public Pattern(RefTypeOrTPHOrWildcardOrGeneric type, Token offset) { + super(offset); + this.type = type; + } + + public RefTypeOrTPHOrWildcardOrGeneric getType(){ + return type; + } + + public abstract Pattern withType(RefTypeOrTPHOrWildcardOrGeneric type); +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/Record.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/Record.java new file mode 100644 index 0000000..f428fca --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/Record.java @@ -0,0 +1,19 @@ +package de.dhbw.compiler.syntaxtree; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import org.antlr.v4.runtime.Token; + +import de.dhbw.compiler.parser.scope.JavaClassName; +import de.dhbw.compiler.syntaxtree.type.RefType; + +import javax.swing.text.html.Option; + +public class Record extends ClassOrInterface { + + public Record(int modifiers, JavaClassName name, List fielddecl, Optional fieldInitializations, Optional staticInitializer, List methods, List constructors, GenericDeclarationList genericClassParameters, RefType superClass, Boolean isInterface, List 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); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/RecordPattern.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/RecordPattern.java new file mode 100644 index 0000000..6b360f3 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/RecordPattern.java @@ -0,0 +1,33 @@ +package de.dhbw.compiler.syntaxtree; + +import java.util.ArrayList; +import java.util.List; + +import org.antlr.v4.runtime.Token; + +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; + +public class RecordPattern extends FormalParameter { + + private final List subPattern; + + public RecordPattern(String name, RefTypeOrTPHOrWildcardOrGeneric type, Token offset) { + super(name, type, offset); + subPattern = new ArrayList<>(); + } + + public RecordPattern(List subPattern, String name, RefTypeOrTPHOrWildcardOrGeneric type, Token offset) { + super(name, type, offset); + this.subPattern = subPattern; + } + + public List getSubPattern() { + return this.subPattern; + } + + @Override + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } + +} \ No newline at end of file diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/SourceFile.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/SourceFile.java new file mode 100644 index 0000000..e7268f3 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/SourceFile.java @@ -0,0 +1,78 @@ +package de.dhbw.compiler.syntaxtree; + +import java.io.File; +import java.util.*; + +import de.dhbw.compiler.parser.NullToken; +import de.dhbw.compiler.parser.scope.JavaClassName; +import de.dhbw.compiler.typeinference.constraints.ConstraintSet; +import de.dhbw.compiler.typeinference.assumptions.TypeInferenceInformation; +//import sun.security.x509.X509CertInfo; + +public class SourceFile extends SyntaxTreeNode { + private String pkgName; + + public final List KlassenVektor; + public final Set imports; + + private boolean isGenerated; + + public List availableClasses = new ArrayList<>(); + + /** + * Die SourceFile repräsntiert eine zu einem Syntaxbaum eingelesene Java-Datei. + * SourceFile stellt dabei den Wurzelknoten des Syntaxbaumes dar. + */ + public SourceFile(String pkgName, List classDefinitions, Set imports) { + super(new NullToken()); + //if (classDefinitions.size() > 0) { // Enthält die Liste Klassen? + this.KlassenVektor = classDefinitions; // Klassen werden übernommen + //} else { + // this.KlassenVektor = null; // es handelt sich um ein "Java Module" + //} + this.pkgName = pkgName; + this.imports = imports; + } + + public SourceFile(SourceFile sf) { + super(new NullToken()); + this.KlassenVektor = new ArrayList<>(sf.KlassenVektor); + this.imports = new HashSet<>(sf.imports); + } + + public void setPackageName(String packageName) { + this.pkgName = packageName; + } + + public void setGenerated() { + this.isGenerated = true; + } + + public boolean isGenerated() { + return this.isGenerated; + } + + public String getPkgName() { + return this.pkgName; + } + + // Get imports (to test implementation) + public Set getImports() { + return this.imports; + } + + public List getClasses() { + return KlassenVektor; + } + + public List getAllMethods() { + List ret = new ArrayList<>(); + getClasses().forEach(cl -> ret.addAll(cl.getMethods())); + return ret; + } + + @Override + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/StatementVisitor.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/StatementVisitor.java new file mode 100644 index 0000000..72bcf68 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/StatementVisitor.java @@ -0,0 +1,88 @@ +package de.dhbw.compiler.syntaxtree; + +import de.dhbw.compiler.parser.SyntaxTreeGenerator.AssignToLocal; +import de.dhbw.compiler.syntaxtree.statement.*; + + +public interface StatementVisitor { + + void visit(ArgumentList argumentList); + + void visit(LambdaExpression lambdaExpression); + + void visit(Assign assign); + + void visit(BinaryExpr binary); + + void visit(BoolExpression logical); + + void visit(Block block); + + void visit(CastExpr castExpr); + + void visit(EmptyStmt emptyStmt); + + void visit(FieldVar fieldVar); + + void visit(ForStmt forStmt); + + void visit(ForEachStmt forEachStmt); + + void visit(IfStmt ifStmt); + + void visit(InstanceOf instanceOf); + + void visit(LocalVar localVar); + + void visit(LocalVarDecl localVarDecl); + + void visit(MethodCall methodCall); + + void visit(NewClass methodCall); + + void visit(NewArray newArray); + + void visit(Return aReturn); + + void visit(ReturnVoid aReturn); + + void visit(Switch switchStmt); + + void visit(SwitchBlock switchBlock); + + void visit(SwitchLabel switchLabel); + + void visit(Break aBreak); + + void visit(Continue aContinue); + + void visit(Yield aYield); + + void visit(StaticClassName staticClassName); + + void visit(Super aSuper); + + void visit(This aThis); + + void visit(WhileStmt whileStmt); + + void visit(DoStmt whileStmt); + + void visit(AssignToField assignLeftSide); + + void visit(AssignToLocal assignLeftSide); + + void visit(SuperCall superCall); + + void visit(ThisCall thisCall); + + void visit(ExpressionReceiver expressionReceiver); + + void visit(UnaryExpr unaryExpr); + + void visit(Literal literal); + + void visit(Throw aThrow); + + void visit(Ternary ternary); +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/SyntaxTreeNode.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/SyntaxTreeNode.java new file mode 100644 index 0000000..cff8a70 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/SyntaxTreeNode.java @@ -0,0 +1,24 @@ +package de.dhbw.compiler.syntaxtree; + +import java.util.ArrayList; +import java.util.List; + +import de.dhbw.compiler.core.IItemWithOffset; +import de.dhbw.compiler.typeinference.assumptions.TypeInferenceInformation; +import de.dhbw.compiler.core.IItemWithOffset; +import org.antlr.v4.runtime.Token; +//import org.antlr.v4.runtime.misc.Pair; + +public abstract class SyntaxTreeNode implements IItemWithOffset { + private final Token offset; + + public SyntaxTreeNode(Token offset){ + this.offset = offset; + } + + public Token getOffset(){ + return offset; + } + + public abstract void accept(ASTVisitor visitor); +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/TypeScope.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/TypeScope.java new file mode 100644 index 0000000..51b7d54 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/TypeScope.java @@ -0,0 +1,12 @@ +package de.dhbw.compiler.syntaxtree; + +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; + +import java.util.Collection; + + +public interface TypeScope { + Iterable getGenerics(); + + RefTypeOrTPHOrWildcardOrGeneric getReturnType(); +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/factory/ASTFactory.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/factory/ASTFactory.java new file mode 100644 index 0000000..afe30ea --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/factory/ASTFactory.java @@ -0,0 +1,487 @@ +package de.dhbw.compiler.syntaxtree.factory; + +import java.io.File; +import java.io.IOException; +import java.lang.annotation.Annotation; +import java.lang.reflect.*; +import java.lang.reflect.Constructor; +import java.lang.reflect.Type; +import java.util.*; + +import de.dhbw.compiler.bytecode.JavaTXSignatureAttribute; +import de.dhbw.compiler.parser.NullToken; +import de.dhbw.compiler.parser.scope.JavaClassName; +import de.dhbw.compiler.syntaxtree.*; +import de.dhbw.compiler.syntaxtree.Field; +import de.dhbw.compiler.syntaxtree.Method; +import de.dhbw.compiler.syntaxtree.type.*; +import de.dhbw.compiler.syntaxtree.type.Void; +import de.dhbw.compiler.syntaxtree.statement.Block; +import de.dhbw.compiler.syntaxtree.statement.Statement; +import de.dhbw.compiler.syntaxtree.type.WildcardType; +import de.dhbw.compiler.util.Pair; +import org.antlr.v4.runtime.Token; +import org.apache.commons.io.IOUtils; +import org.objectweb.asm.*; +import org.objectweb.asm.signature.SignatureReader; +import org.objectweb.asm.signature.SignatureVisitor; + +/** + * Anmerkung: Die ASTFactory Methoden, welche ASTBäume aus java.lang.Class Objekten generieren, können davon ausgehen, dass alle Imports und Typnamen korrekt sind und müssen diese nicht überprüfen. + */ +public class ASTFactory { + + private static final HashMap cache = new HashMap<>(); + + public static ClassOrInterface createClass(Class jreClass) { + if (cache.containsKey(jreClass)) + return cache.get(jreClass); + + // TODO Inner classes + + var methodSignatures = new HashMap, String>(); + String classSignature = null; + + // Load class with asm to figure out if there's a JavaTX signature + try { + var path = jreClass.getName().replace('.', '/') + ".class"; + var classLoader = jreClass.getClassLoader(); + if (classLoader != null && new File(path).exists()) { + var bytes = IOUtils.toByteArray(Objects.requireNonNull(classLoader.getResourceAsStream(path))); + var classReader = new ClassReader(bytes); + var classVisitor = new ClassVisitor(Opcodes.ASM7) { + String classSignature; + + @Override + public void visitAttribute(Attribute attribute) { + if (attribute.type.equals("JavaTXSignature")) { + classSignature = ((JavaTXSignatureAttribute) attribute).signature; + } + super.visitAttribute(attribute); + } + + @Override + public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { + classSignature = signature; + super.visit(version, access, name, signature, superName, interfaces); + } + + @Override + public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { + + methodSignatures.put(new Pair<>(name, descriptor), signature); + return new MethodVisitor(Opcodes.ASM7) { + @Override + public void visitAttribute(Attribute attribute) { + if (attribute.type.equals("JavaTXSignature")) { + methodSignatures.put(new Pair<>(name, descriptor), ((JavaTXSignatureAttribute) attribute).signature); + } + super.visitAttribute(attribute); + } + }; + } + }; + + classReader.accept(classVisitor, new Attribute[] { new JavaTXSignatureAttribute() }, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); + classSignature = classVisitor.classSignature; + } + } catch (IOException e) { + // Skip + } + JavaClassName name = new JavaClassName(jreClass.getName()); + List methoden = new ArrayList<>(); + List konstruktoren = new ArrayList<>(); + for (Constructor constructor : jreClass.getConstructors()) { + var signature = methodSignatures.get(new Pair<>(constructor.getName(), org.objectweb.asm.Type.getConstructorDescriptor(constructor))); + createConstructor(constructor, signature, jreClass).map(c -> konstruktoren.add(c)); + } + + Set allMethods = new HashSet<>(Arrays.asList(jreClass.getMethods())); + if (jreClass.isInterface()) + allMethods.addAll(Arrays.asList(Object.class.getMethods())); // For some reason interfaces don't inherit from Object + + Set allDeclaredMethods = new HashSet<>(Arrays.asList(jreClass.getDeclaredMethods())); + Set allInheritedMethods = new HashSet<>(allMethods); + allInheritedMethods.removeAll(allDeclaredMethods); + for (java.lang.reflect.Method method : allDeclaredMethods) { + var signature = methodSignatures.get(new Pair<>(method.getName(), org.objectweb.asm.Type.getMethodDescriptor(method))); + if (jreClass.getSuperclass()==null) { + methoden.add(createMethod(method, signature, jreClass, false, false)); + } + else { + Boolean isImplemented = false; + isImplemented = Arrays.stream(jreClass.getInterfaces()). + reduce(false, + (x,y) -> { + try { + y.getDeclaredMethod(method.getName(), method.getParameterTypes()); + return true; + } + catch (NoSuchMethodException e) { + return false; + }}, + (x,y) -> (x || y) + ); + + if (isImplemented) { + methoden.add(createMethod(method, signature, jreClass, false, true)); + } + else { + if (Modifier.isAbstract(jreClass.getSuperclass().getModifiers())) { + try { + jreClass.getSuperclass().getDeclaredMethod(method.getName(), method.getParameterTypes()); + methoden.add(createMethod(method, signature, jreClass, false, true)); + } + catch (NoSuchMethodException e) { + methoden.add(createMethod(method, signature, jreClass, false, false)); + } + } + else { + methoden.add(createMethod(method, signature, jreClass, false, false)); + } + + } + }} + for (java.lang.reflect.Method method : allInheritedMethods) { + var signature = methodSignatures.get(new Pair<>(method.getName(), org.objectweb.asm.Type.getMethodDescriptor(method))); + methoden.add(createMethod(method, signature, jreClass, true, false)); + } + List felder = new ArrayList<>(); + for (java.lang.reflect.Field field : jreClass.getDeclaredFields()) { + felder.add(createField(field, name)); + } + int modifier = jreClass.getModifiers(); + boolean isInterface = jreClass.isInterface(); + List aLA; + boolean isFunctionalInterface = + (aLA = Arrays.asList(jreClass.getAnnotations())).size() > 0 && + aLA.get(0) instanceof FunctionalInterface ? + true : + false; + // see: https://stackoverflow.com/questions/9934774/getting-generic-parameter-from-supertype-class + ParameterizedType parameterSuperClass = null; + Type tempSuperClass = jreClass.getGenericSuperclass(); + if (tempSuperClass != null && tempSuperClass instanceof ParameterizedType) + parameterSuperClass = (ParameterizedType) tempSuperClass; + Class superjreClass = jreClass.getSuperclass(); + RefType superClass; + if (parameterSuperClass != null) { + superClass = (RefType) createType(parameterSuperClass); + } else if (superjreClass != null) { + superClass = (RefType) createType(superjreClass); + } else {// Jede Klasse und jedes Interface erbt von Object: (auch Object selbst!) + superClass = (RefType) createType(Object.class); + } + List implementedInterfaces = new ArrayList<>(); + for (Type jreInterface : jreClass.getGenericInterfaces()) { + implementedInterfaces.add((RefType) createType(jreInterface)); + } + List permittedSubtypes = new ArrayList<>(); + if (jreClass.isSealed()) { + for (Class subclass : jreClass.getPermittedSubclasses()) { + permittedSubtypes.add((RefType) createType(subclass)); + } + } + + GenericDeclarationList genericDeclarationList = createGenerics(jreClass.getTypeParameters(), jreClass, null, classSignature); + + 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, null); + cache.put(jreClass, cinf); + return cinf; + } + + private static Field createField(java.lang.reflect.Field field, JavaClassName jreClass) { + return new Field(field.getName(), createType(field.getGenericType()), field.getModifiers(), new NullToken()); + } + + // private static RefType createType(Class classType) { + // return createClass(classType).getType(); + // } + + private static Optional createConstructor(Constructor constructor, String signature, Class inClass) { + String name = constructor.getName(); + RefTypeOrTPHOrWildcardOrGeneric returnType = createType(inClass); + Parameter[] jreParams = constructor.getParameters(); + Type[] jreGenericParams = constructor.getGenericParameterTypes(); + List params = new ArrayList<>(); + int i = 0; + for (Type jreParam : jreGenericParams) { + if (jreParam == null) + continue; + RefTypeOrTPHOrWildcardOrGeneric paramType = createType(jreParam); + params.add(new FormalParameter(jreParams[i].getName(), paramType, new NullToken())); + i++; + } + ParameterList parameterList = new ParameterList(params, new NullToken()); + Block block = new Block(new ArrayList(), new NullToken()); + GenericDeclarationList gtvDeclarations = createGenerics(constructor.getTypeParameters(), inClass, constructor.getName(), signature); + Token offset = new NullToken(); + int modifier = constructor.getModifiers(); + + if (inClass.equals(Object.class)) { + return Optional.empty(); + } + + return Optional.of(new de.dhbw.compiler.syntaxtree.Constructor(modifier, name, returnType, parameterList, block, gtvDeclarations, offset /* , new ArrayList<>() geloescht PL 2018-11-24 */)); + } + + public static Method createMethod(java.lang.reflect.Method jreMethod, String signature, Class inClass, Boolean isInherited, Boolean isImplemented) { + String name = jreMethod.getName(); + RefTypeOrTPHOrWildcardOrGeneric returnType; + Type jreRetType; + if (jreMethod.getGenericReturnType() != null) { + jreRetType = jreMethod.getGenericReturnType(); + } else { + jreRetType = jreMethod.getReturnType(); + } + returnType = createType(jreRetType); + Parameter[] jreParams = jreMethod.getParameters(); + Type[] jreGenericParams = jreMethod.getGenericParameterTypes(); + List params = new ArrayList<>(); + int i = 0; + for (Type jreParam : jreGenericParams) { + if (jreParam == null) + continue; + RefTypeOrTPHOrWildcardOrGeneric paramType = createType(jreParam); + params.add(new FormalParameter(jreParams[i].getName(), paramType, new NullToken())); + i++; + } + ParameterList parameterList = new ParameterList(params, new NullToken()); + Block block = new Block(new ArrayList(), new NullToken()); + GenericDeclarationList gtvDeclarations = createGenerics(jreMethod.getTypeParameters(), inClass, jreMethod.getName(), signature); + Token offset = new NullToken(); + + return new Method(jreMethod.getModifiers(), name, returnType, parameterList, block, gtvDeclarations, offset, isInherited, isImplemented); + } + + public static GenericDeclarationList createGenerics(TypeVariable[] typeParameters, Class context, String methodName, String signature) { + if (signature == null) { + List gtvs = new ArrayList<>(); + for (TypeVariable jreTV : typeParameters) { + de.dhbw.compiler.syntaxtree.GenericTypeVar gtv = createGeneric(jreTV, jreTV.getName(), context, methodName); + gtvs.add(gtv); + } + return new GenericDeclarationList(gtvs, new NullToken()); + } else { + var res = createGenerics(signature); + return res; + } + } + + public static GenericDeclarationList createGenerics(String signature) { + if (signature == null) + return new GenericDeclarationList(new ArrayList<>(), new NullToken()); + + var gtvs = new ArrayList(); + var signatureVisitor = new SignatureVisitor(Opcodes.ASM7) { + List bounds = new ArrayList<>(); + final Stack bound = new Stack<>(); + final Stack classTypes = new Stack<>(); + + // All hail the mighty visitor pattern + final SignatureVisitor doNothing = new SignatureVisitor(Opcodes.ASM7) { + }; + + char wildcard = '='; + + @Override + public SignatureVisitor visitSuperclass() { + return doNothing; + } + + @Override + public SignatureVisitor visitParameterType() { + return doNothing; + } + + @Override + public SignatureVisitor visitReturnType() { + return doNothing; + } + + @Override + public SignatureVisitor visitExceptionType() { + return doNothing; + } + + @Override + public void visitFormalTypeParameter(String name) { + bounds = new ArrayList<>(); + gtvs.add(new GenericTypeVar(name, bounds, new NullToken(), new NullToken())); + } + + @Override + public void visitTypeVariable(String name) { + var refType = new GenericRefType(name, new NullToken()); + if (classTypes.isEmpty()) { + ((List) gtvs.get(gtvs.size() - 1).getBounds()).add(refType); + } else { + pushType(refType); + } + } + + @Override + public void visitClassType(String name) { + var refType = new RefType(new JavaClassName(name.replaceAll("/", ".")), new ArrayList<>(), new NullToken()); + classTypes.push(refType); + pushType(refType); + } + + void pushType(RefTypeOrTPHOrWildcardOrGeneric refType) { + if (wildcard == SignatureVisitor.SUPER) { + bound.push(new SuperWildcardType(refType, new NullToken())); + } else if (wildcard == SignatureVisitor.EXTENDS) { + bound.push(new ExtendsWildcardType(refType, new NullToken())); + } else { + bound.push(refType); + } + } + + @Override + public SignatureVisitor visitTypeArgument(char wildcard) { + this.wildcard = wildcard; + return this; + } + + boolean equals(RefTypeOrTPHOrWildcardOrGeneric a, RefTypeOrTPHOrWildcardOrGeneric b) { + if (b instanceof SuperWildcardType wc) + return equals(a, wc.getInnerType()); + else if (b instanceof ExtendsWildcardType wc) + return equals(a, wc.getInnerType()); + return a == b; + } + + @Override + public void visitEnd() { + wildcard = '='; + var classType = (RefType) classTypes.pop(); + if (!classTypes.isEmpty()) { + var next = classTypes.peek(); + var par = bound.pop(); + var toAdd = new ArrayList(); + while (!equals(next, par)) { + toAdd.add(par); + par = bound.pop(); + } + var element = par; + if (par instanceof WildcardType wc) { + element = wc.getInnerType(); + } + Collections.reverse(toAdd); + ((RefType) element).getParaList().addAll(toAdd); + + bound.push(par); + } else { + if (bound.peek() != classType) { + classType.getParaList().add(bound.pop()); + bounds.add(classType); + } else { + bounds.add(bound.pop()); + } + } + } + }; + + var sr = new SignatureReader(signature); + sr.accept(signatureVisitor); + + return new GenericDeclarationList(gtvs, new NullToken()); + } + + private static RefTypeOrTPHOrWildcardOrGeneric createType(Type type) { + if (type == null || type.getTypeName().equals("void")) { + return new Void(new NullToken()); + } else if (type.getTypeName().equals("int")) { + return new RefType(new JavaClassName("java.lang.Integer"), new ArrayList<>(), new NullToken(), true); + } else if (type.getTypeName().equals("byte")) { + return new RefType(new JavaClassName("java.lang.Byte"), new ArrayList<>(), new NullToken(), true); + } 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.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("float")) { + return new RefType(new JavaClassName("java.lang.Float"), new ArrayList<>(), new NullToken(), true); + } else if (type.getTypeName().equals("double")) { + return new RefType(new JavaClassName("java.lang.Double"), new ArrayList<>(), new NullToken(), true); + } else if (type.getTypeName().equals("long")) { + return new RefType(new JavaClassName("java.lang.Long"), new ArrayList<>(), new NullToken(), true); + } else { + if (type instanceof TypeVariable) { + // GTVDeclarationContext via "(TypeVariable) type).getGenericDeclaration()" + return new GenericRefType(type.getTypeName(), new NullToken()); + } + List params = new ArrayList<>(); + if (type instanceof ParameterizedType) { + for (Type t : ((ParameterizedType) type).getActualTypeArguments()) { + params.add(createType(t)); + } + } + String name = type.getTypeName(); + if (name.contains("<")) { // Komischer fix. Type von Generischen Typen kann die Generics im Namen enthalten Type + // Diese entfernen: + name = name.split("<")[0]; + } + if (type instanceof java.lang.reflect.WildcardType) { + java.lang.reflect.WildcardType wildcardType = (java.lang.reflect.WildcardType) type; + if (wildcardType.getLowerBounds().length > 0) { + return new SuperWildcardType(createType(wildcardType.getLowerBounds()[0]), new NullToken()); + } else if (wildcardType.getUpperBounds().length > 0) { + return new ExtendsWildcardType(createType(wildcardType.getUpperBounds()[0]), new NullToken()); + } else {// Es handelt sich um den '?'-Typ: + return new ExtendsWildcardType(createObjectType(), new NullToken()); + } + } else { + RefType ret = new RefType(new JavaClassName(name), params, new NullToken()); + return ret; + } + } + } + + public static de.dhbw.compiler.syntaxtree.GenericTypeVar createGeneric(TypeVariable jreTypeVar, String jreTVName, Class context, String parentMethod) { + JavaClassName parentClass = new JavaClassName(context.getName()); + List genericBounds = new ArrayList<>(); + Type[] bounds = jreTypeVar.getBounds(); + if (bounds.length > 0) { + for (Type bound : bounds) { + genericBounds.add(createType(bound)); + } + } + return new de.dhbw.compiler.syntaxtree.GenericTypeVar(jreTVName, genericBounds, new NullToken(), new NullToken()); + } + + public static ClassOrInterface createObjectClass() { + return createClass(Object.class); + } + + public static RefType createObjectType() { + return new RefType(createClass(Object.class).getClassName(), new NullToken()); + } + + /* + * public Constructor createEmptyConstructor(Class parent){ Block block = new Block(); block.setType(new de.dhbwstuttgart.syntaxtree.type.Void(block, 0)); block.statements.add(new SuperCall(block)); + * + * return ASTFactory.createConstructor(parent, new ParameterList(), block); } + * + * public static Constructor createConstructor(Class superClass, ParameterList paralist, Block block){ block.parserPostProcessing(superClass); + * + * Method method = ASTFactory.createMethod("", paralist, block, superClass); method.setType(new de.dhbwstuttgart.syntaxtree.type.Void(block, 0)); + * + * return new Constructor(method, superClass); } + * + * public static Class createClass(String className, RefType type, Modifiers modifiers, Menge supertypeGenPara, SourceFile parent) { // TODO bytecode createClass //String name, RefType superClass, Modifiers modifiers, Menge supertypeGenPara Class generatedClass = new Class(className, type, modifiers, supertypeGenPara); generatedClass.addField(ASTFactory.createEmptyConstructor(generatedClass)); + * + * generatedClass.parserPostProcessing(parent); + * + * return generatedClass; } + * + * public static Class createObject(){ return createClass(java.lang.Object.class); } + * + * public static Class createInterface(String className, RefType superClass, Modifiers modifiers, Menge supertypeGenPara, SourceFile parent){ Class generatedClass = new Class(new JavaClassName(className), new ArrayList(), new ArrayList(), modifiers, true, superClass, new ArrayList(), new GenericDeclarationList(), -1); generatedClass.parserPostProcessing(parent); return generatedClass; } + * + * public static RefType createObjectType(){ return createObjectClass().getType(); } + */ +} \ No newline at end of file diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/factory/NameGenerator.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/factory/NameGenerator.java new file mode 100644 index 0000000..07942d1 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/factory/NameGenerator.java @@ -0,0 +1,91 @@ +package de.dhbw.compiler.syntaxtree.factory; + +public class NameGenerator { + + private static String strNextName = "A"; + + /** + * Setzt den zu Beginn der Typinferenz auf "A" zurueck. + * Dies ist bei JUnit-Test noetig + * TypePlaceholder.
Author: Martin Pluemicke + * @return void + */ + public static void reset() { + strNextName = "A"; + } + + /** + * Berechnet einen neuen, eindeutigen Namen f�r eine neue + * TypePlaceholder.
Author: J�rg B�uerle + * @return Der Name + */ + public static String makeNewName() + { + // otth: Funktion berechnet einen neuen Namen anhand eines alten gespeicherten + String strReturn = strNextName; + + // n�chster Name berechnen und in strNextName speichern + inc( strNextName.length() - 1 ); + + return strReturn; + } + + /** + * Hilfsfunktion zur Berechnung eines neuen Namens + *
Author: J�rg B�uerle + * @param i + */ + private static void inc(int i) + { + // otth: Hilfsfunktion zur Berechnung eines neuen Namens + // otth: Erh�hung des Buchstabens an der Stelle i im String strNextName + // otth: Nach �berlauf: rekursiver Aufruf + + // falls i = -1 --> neuer Buchstabe vorne anf�gen + if ( i == -1 ) + { + strNextName = "A" + strNextName; + return; + } + + char cBuchstabe = (char)(strNextName.charAt( i )); + cBuchstabe++; + if ( cBuchstabe - 65 > 25 ) + { + // aktuelle Stelle: auf A zuruecksetzen + manipulate( i, 'A' ); + + // vorherige Stelle erh�hen + inc( i - 1 ); + } + else + { + // aktueller Buchstabe �ndern + manipulate( i, cBuchstabe ); + } + + } + + /** + * Hilfsfunktion zur Berechnung eines neuen Namens. + *
Author: J�rg B�uerle + * @param nStelle + * @param nWert + */ + private static void manipulate( int nStelle, char nWert ) + { + // otth: Hilfsfunktion zur Berechnung eines neuen Namens + // otth: Ersetzt im String 'strNextName' an der Position 'nStelle' den Buchstaben durch 'nWert' + + String strTemp = ""; + for( int i = 0; i < strNextName.length(); i++) + { + if ( i == nStelle ) + strTemp = strTemp + nWert; + else + strTemp = strTemp + strNextName.charAt( i ); + } + strNextName = strTemp; + } + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/factory/PrimitiveMethodsGenerator.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/factory/PrimitiveMethodsGenerator.java new file mode 100644 index 0000000..8fac00f --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/factory/PrimitiveMethodsGenerator.java @@ -0,0 +1,9 @@ +package de.dhbw.compiler.syntaxtree.factory; + +/** + * Generiert Hilfsmethoden für die Unary und Binary Operatoren + * Diese Methoden stellen die möglichen Operationen +,-,++, etc dar + */ +public class PrimitiveMethodsGenerator { + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/factory/UnifyTypeFactory.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/factory/UnifyTypeFactory.java new file mode 100644 index 0000000..b1e2b53 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/factory/UnifyTypeFactory.java @@ -0,0 +1,297 @@ +package de.dhbw.compiler.syntaxtree.factory; + +import java.io.Writer; +import java.lang.reflect.Modifier; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +import de.dhbw.compiler.core.JavaTXCompiler; +import de.dhbw.compiler.exceptions.NotImplementedException; +import de.dhbw.compiler.parser.NullToken; +import de.dhbw.compiler.parser.SourceLoc; +import de.dhbw.compiler.parser.SyntaxTreeGenerator.FCGenerator; +import de.dhbw.compiler.parser.scope.JavaClassName; +import de.dhbw.compiler.syntaxtree.ClassOrInterface; +import de.dhbw.compiler.syntaxtree.GenericTypeVar; +import de.dhbw.compiler.syntaxtree.type.*; +import de.dhbw.compiler.syntaxtree.type.Void; +import de.dhbw.compiler.syntaxtree.type.WildcardType; +import de.dhbw.compiler.typeinference.constraints.ConstraintSet; +import de.dhbw.compiler.typeinference.constraints.Pair; +import de.dhbw.compiler.typeinference.result.PairNoResult; +import de.dhbw.compiler.typeinference.result.PairTPHEqualTPH; +import de.dhbw.compiler.typeinference.result.PairTPHequalRefTypeOrWildcardType; +import de.dhbw.compiler.typeinference.result.PairTPHsmallerTPH; +import de.dhbw.compiler.typeinference.result.ResultPair; +import de.dhbw.compiler.typeinference.unify.model.*; +import org.antlr.v4.runtime.Token; + +public class UnifyTypeFactory { + + private static ArrayList PLACEHOLDERS = new ArrayList<>(); + + public static FiniteClosure generateFC(List fromClasses, Writer logFile, ClassLoader classLoader, JavaTXCompiler compiler) throws ClassNotFoundException { + /* + Die transitive Hülle muss funktionieren. + Man darf schreiben List
extends AL + und Vector extends List + hier muss dann aber dennoch die Vererbung V < L < AL + hergestellt werden. + In einem solchen Vererbungsbaum dürfen die TPH auch die gleichen Namen haben. + Generell dürfen sie immer die gleichen Namen haben. + TODO: die transitive Hülle bilden + */ + return new FiniteClosure(FCGenerator.toUnifyFC(compiler, fromClasses, classLoader), logFile, compiler); + } + + 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, SourceLoc location){ + return new UnifyPair(tl, tr, PairOperator.SMALLERDOT, location); + } + + 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, SourceLoc location){ + return new UnifyPair(tl, tr, PairOperator.EQUALSDOT, location); + } + + /** + * Convert from + * ASTType -> UnifyType + */ + public static UnifyType convert(JavaTXCompiler compiler, RefTypeOrTPHOrWildcardOrGeneric t, Boolean innerType){ + if (t instanceof GenericRefType){ + return UnifyTypeFactory.convert(compiler, (GenericRefType)t, innerType); + } else if (t instanceof TypePlaceholder){ + return UnifyTypeFactory.convert(compiler, (TypePlaceholder)t, innerType); + } else if (t instanceof ExtendsWildcardType){ + return UnifyTypeFactory.convert(compiler, (ExtendsWildcardType)t, innerType); + } else if (t instanceof SuperWildcardType) { + return UnifyTypeFactory.convert(compiler, (SuperWildcardType) t, innerType); + } else if (t instanceof RefType){ + return UnifyTypeFactory.convert(compiler, (RefType)t, innerType); + } + //Es wurde versucht ein Typ umzuwandeln, welcher noch nicht von der Factory abgedeckt ist + throw new NotImplementedException("Der Typ "+t+" kann nicht umgewandelt werden"); + } + + public static UnifyType convert(JavaTXCompiler compiler, RefType t, Boolean innerType){ + //Check if it is a FunN Type: + Pattern p = Pattern.compile("Fun(\\d+)[$][$]"); + Matcher m = p.matcher(t.getName().toString()); + boolean b = m.matches(); + if(b){ + Integer N = Integer.valueOf(m.group(1)); + if((N + 1) == t.getParaList().size()){ + return convertFunN(compiler, t.getParaList(), false); + } + } + UnifyType ret; + List params = new ArrayList<>(); + if (t.getParaList() != null) { + for (RefTypeOrTPHOrWildcardOrGeneric pT : t.getParaList()) { + params.add(UnifyTypeFactory.convert(compiler, pT, true)); + } + } + + var clazz = compiler.getClass(t.getName()); + if (clazz != null && clazz.isInterface() && clazz.isFunctionalInterface()) { + var method = clazz.getMethods().stream().filter(x -> Modifier.isAbstract(x.modifier)).findFirst().orElseThrow(); + var methodParams = method.getParameterList().getFormalparalist().stream().map(x -> convert(compiler, x.getType(), true)).toList(); + var generics = StreamSupport.stream(clazz.getGenerics().spliterator(), false).map(GenericTypeVar::getName).toList(); + return new FunInterfaceType(t.getName().toString(), new TypeParams(params), methodParams, convert(compiler, method.getReturnType(), true), generics); + } + + return new ReferenceType(t.getName().toString(),new TypeParams(params)); + } + + public static UnifyType convertFunN(JavaTXCompiler compiler, List paraList, Boolean innerType){ + UnifyType ret; + List params = new ArrayList<>(); + if(paraList != null && paraList.size() > 0){ + for(RefTypeOrTPHOrWildcardOrGeneric pT : paraList){ + params.add(UnifyTypeFactory.convert(compiler, pT, false)); + } + } + ret = FunNType.getFunNType(new TypeParams(params)); + return ret; + } + + public static UnifyType convert(JavaTXCompiler compiler, TypePlaceholder tph, Boolean innerType){ + if (tph.getName().equals("AFR")) { + System.out.println("XXX"+innerType); + } + PlaceholderType ntph = new PlaceholderType(tph.getName(), tph.getVariance()); + ntph.setVariance(tph.getVariance()); + ntph.setOrCons(tph.getOrCons()); + ntph.setWildcardtable(tph.getWildcardtable()); + int in = PLACEHOLDERS.indexOf(ntph); + if (in == -1) { + PLACEHOLDERS.add(ntph); + ntph.setInnerType(innerType); + return ntph; + } + else { + PlaceholderType oldpht = PLACEHOLDERS.get(in); + oldpht.setInnerType(oldpht.isInnerType() || innerType); + return oldpht; + } + } + + public static UnifyType convert(JavaTXCompiler compiler, GenericRefType t, Boolean innerType){ + return new ReferenceType(t.getParsedName(), true); + } + + public static UnifyType convert(JavaTXCompiler compiler, WildcardType t, Boolean innerType){ + if(t.isExtends()) + return new ExtendsType(UnifyTypeFactory.convert(compiler, t.getInnerType(), false)); + else if(t.isSuper()) + return new SuperType(UnifyTypeFactory.convert(compiler, t.getInnerType(), false)); + else throw new NotImplementedException(); + } + + + public static ConstraintSet convert(JavaTXCompiler compiler, ConstraintSet constraints) { + return constraints.map(c -> UnifyTypeFactory.convert(compiler, c)); + } + + //NEVER USED + //public static Constraint convert(Constraint constraint){ + // Constraint unifyPairConstraint = constraint.stream() + // .map(UnifyTypeFactory::convert) + // .collect(Collectors.toCollection( () -> new Constraint (constraint.isInherited(), convert(constraint.getExtendConstraint())))); + // return unifyPairConstraint; + //} + + public static UnifyPair convert(JavaTXCompiler compiler, Pair p) { + UnifyPair ret = null; + if(p.GetOperator().equals(PairOperator.SMALLERDOT)) { + ret = generateSmallerDotPair(UnifyTypeFactory.convert(compiler, p.TA1, false) + , UnifyTypeFactory.convert(compiler, p.TA2, false), p.getLocation()); + //return ret; + }else if(p.GetOperator().equals(PairOperator.SMALLERNEQDOT)) { + ret = generateSmallNotEqualDotPair(UnifyTypeFactory.convert(compiler, p.TA1, false) + , UnifyTypeFactory.convert(compiler, p.TA2, false), p.getLocation()); + //return ret; + }else if(p.GetOperator().equals(PairOperator.EQUALSDOT)) { + ret = generateEqualDotPair(UnifyTypeFactory.convert(compiler, p.TA1, false) + , UnifyTypeFactory.convert(compiler, p.TA2, false), p.getLocation()); + //return ret; + }else if(p.GetOperator().equals(PairOperator.SMALLER)){ + ret = generateSmallerPair(UnifyTypeFactory.convert(compiler, p.TA1, false), + UnifyTypeFactory.convert(compiler, p.TA2, false), p.getLocation()); + }else throw new NotImplementedException(); + UnifyType lhs, rhs; + if (((lhs = ret.getLhsType()) instanceof PlaceholderType) + && ((PlaceholderType)lhs).isWildcardable() + && (rhs = ret.getLhsType()) instanceof PlaceholderType) { + if (lhs.getName().equals("AQ")) { + System.out.println(""); + } + ((PlaceholderType)rhs).enableWildcardtable(); + } + + if (((rhs = ret.getLhsType()) instanceof PlaceholderType) + && ((PlaceholderType)rhs).isWildcardable() + && (lhs = ret.getLhsType()) instanceof PlaceholderType) { + if (rhs.getName().equals("AQ")) { + System.out.println(""); + } + ((PlaceholderType)lhs).enableWildcardtable(); + } + return ret; + } + + /** + * Convert from + * UnifyType -> ASTType + */ + public static Set convert(Set unifyPairSet, Map tphs) { + return unifyPairSet.stream().map( + unifyPair -> convert(unifyPair, tphs)) + .collect(Collectors.toSet()); + } + + public static ResultPair convert(UnifyPair mp, Map tphs) { + if (mp == null) { return null;} //kann bei basePairs passieren + RefTypeOrTPHOrWildcardOrGeneric tl = UnifyTypeFactory.convert(mp.getLhsType(), tphs); + RefTypeOrTPHOrWildcardOrGeneric tr = UnifyTypeFactory.convert(mp.getRhsType(), tphs); + if(tl instanceof TypePlaceholder){ + if(tr instanceof TypePlaceholder) { + + if(mp.getPairOp().equals(PairOperator.EQUALSDOT)) { + return new PairTPHEqualTPH((TypePlaceholder)tl, (TypePlaceholder)tr); + //Einfach ignorieren TODO: Das hier muss ausgebessert werden: + //return new PairTPHequalRefTypeOrWildcardType((TypePlaceholder)tl, ASTFactory.createObjectType()); + }else{ + return new PairTPHsmallerTPH((TypePlaceholder)tl, (TypePlaceholder)tr, convert(mp.getBasePair(), tphs)); + } + }else if(tr instanceof RefType){ + return new PairTPHequalRefTypeOrWildcardType((TypePlaceholder)tl, (RefType) tr); + }else if(tr instanceof WildcardType){ + return new PairTPHequalRefTypeOrWildcardType((TypePlaceholder)tl, (WildcardType) tr); + }else if(tr instanceof GenericRefType){ + return new PairTPHequalRefTypeOrWildcardType((TypePlaceholder)tl, (GenericRefType) tr); + }else throw new NotImplementedException(); + }else return new PairNoResult(tl, tr);//throw new NotImplementedException(); + } + + public static RefTypeOrTPHOrWildcardOrGeneric convert(ReferenceType t, Map tphs) { + if(JavaClassName.Void.equals(t.getName()))return new Void(new NullToken()); + if (t.isGenTypeVar()) return new GenericRefType(t.getName(),new NullToken()); + RefType ret = new RefType(new JavaClassName(t.getName()),convert(t.getTypeParams(), tphs),new NullToken()); + return ret; + } + + public static RefTypeOrTPHOrWildcardOrGeneric convert(FunNType t, Map tphs) { + RefType ret = new RefType(new JavaClassName(t.getName()), convert(t.getTypeParams(), tphs), new NullToken()); + return ret; + } + + public static RefTypeOrTPHOrWildcardOrGeneric convert(SuperType t, Map tphs) { + RefTypeOrTPHOrWildcardOrGeneric innerType = convert(t.getSuperedType(), tphs); + return new SuperWildcardType(innerType, new NullToken()); + } + + public static RefTypeOrTPHOrWildcardOrGeneric convert(ExtendsType t, Map tphs) { + RefTypeOrTPHOrWildcardOrGeneric innerType = convert(t.getExtendedType(), tphs); + return new ExtendsWildcardType(innerType, new NullToken()); + } + + public static RefTypeOrTPHOrWildcardOrGeneric convert(PlaceholderType t, Map tphs) { + TypePlaceholder ret = tphs.get(t.getName()); + if(ret == null){ //Dieser TPH wurde vom Unifikationsalgorithmus erstellt + ret = TypePlaceholder.fresh(new NullToken()); + tphs.put(t.getName(), ret); + } + ret.setVariance(t.getVariance()); + return ret; + } + + public static RefTypeOrTPHOrWildcardOrGeneric convert(UnifyType t, Map tphs) { + if(t instanceof FunNType)return convert((FunNType) t, tphs); + if(t instanceof ReferenceType)return convert((ReferenceType) t, tphs); + if(t instanceof SuperType)return convert((SuperType) t, tphs); + if(t instanceof ExtendsType)return convert((ExtendsType) t, tphs); + if(t instanceof PlaceholderType)return convert((PlaceholderType) t, tphs); + throw new NotImplementedException("Der Typ "+t+" kann nicht umgewandelt werden"); + } + + private static List convert(TypeParams typeParams, Map tphs) { + List ret = new ArrayList<>(); + for(UnifyType uT : typeParams){ + RefTypeOrTPHOrWildcardOrGeneric toAdd = convert(uT, tphs); + ret.add(toAdd); + } + return ret; + } + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/ArgumentList.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/ArgumentList.java new file mode 100644 index 0000000..a08722e --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/ArgumentList.java @@ -0,0 +1,33 @@ +package de.dhbw.compiler.syntaxtree.statement; + + +import de.dhbw.compiler.syntaxtree.ASTVisitor; +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.SyntaxTreeNode; +import org.antlr.v4.runtime.Token; + +import java.util.List; + +public class ArgumentList extends SyntaxTreeNode +{ + public ArgumentList(List expr, Token offset) { + super(offset); + this.expr = expr; + } + + private List expr; + + public List getArguments(){ + return expr; + } + + + @Override + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } + + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Assign.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Assign.java new file mode 100644 index 0000000..433bb39 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Assign.java @@ -0,0 +1,28 @@ + +package de.dhbw.compiler.syntaxtree.statement; + +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.typeinference.assumptions.TypeInferenceBlockInformation; +import de.dhbw.compiler.typeinference.constraints.ConstraintSet; +import de.dhbw.compiler.typeinference.unify.model.PairOperator; +import org.antlr.v4.runtime.Token; + +/* +Aufbau: +rightSide = leftSide + */ +public class Assign extends Statement { + public final Expression rightSide; + public final AssignLeftSide lefSide; + + public Assign(AssignLeftSide leftHandSide, Expression value, Token offset) { + super(leftHandSide.getType(), offset); + this.rightSide = value; + this.lefSide = leftHandSide; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/AssignLeftSide.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/AssignLeftSide.java new file mode 100644 index 0000000..7698df7 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/AssignLeftSide.java @@ -0,0 +1,12 @@ +package de.dhbw.compiler.syntaxtree.statement; + +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import org.antlr.v4.runtime.Token; + +public abstract class AssignLeftSide extends TypableStatement{ + + public AssignLeftSide(RefTypeOrTPHOrWildcardOrGeneric type, Token offset) { + super(type, offset); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/AssignToField.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/AssignToField.java new file mode 100644 index 0000000..81f6c4b --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/AssignToField.java @@ -0,0 +1,17 @@ +package de.dhbw.compiler.syntaxtree.statement; + +import de.dhbw.compiler.syntaxtree.StatementVisitor; + +public class AssignToField extends AssignLeftSide { + public final FieldVar field; + + public AssignToField(FieldVar fieldVar) { + super(fieldVar.getType(), fieldVar.getOffset()); + field = fieldVar; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/BinaryExpr.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/BinaryExpr.java new file mode 100644 index 0000000..d9e16d9 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/BinaryExpr.java @@ -0,0 +1,42 @@ +package de.dhbw.compiler.syntaxtree.statement; + +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import org.antlr.v4.runtime.Token; + +public class BinaryExpr extends Expression { + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } + + public enum Operator { + ADD, // + + SUB, // - + MUL, // * + MOD, // Modulo Operator % + AND, // & + OR, // | + XOR, // ^ + DIV, // / + LESSTHAN, // < + BIGGERTHAN, // > + LESSEQUAL, // <= + BIGGEREQUAL, // >= + EQUAL, // == + NOTEQUAL // != + } + + public final Operator operation; + public final Expression lexpr; + public final Expression rexpr; + + public BinaryExpr(Operator operation, RefTypeOrTPHOrWildcardOrGeneric type, Expression lexpr, Expression rexpr, Token offset) { + super(type, offset); + + this.operation = operation; + this.lexpr = lexpr; + this.rexpr = rexpr; + } + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Block.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Block.java new file mode 100644 index 0000000..2f92479 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Block.java @@ -0,0 +1,27 @@ +package de.dhbw.compiler.syntaxtree.statement; + +import java.util.ArrayList; +import java.util.List; + +import org.antlr.v4.runtime.Token; + +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.type.TypePlaceholder; + +public class Block extends Statement { + public Block(List statements, Token offset) { + super(TypePlaceholder.fresh(offset), offset); + this.statements = statements; + } + + public List statements = new ArrayList<>(); + + public List getStatements() { + return statements; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/BoolExpression.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/BoolExpression.java new file mode 100644 index 0000000..5993bb6 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/BoolExpression.java @@ -0,0 +1,31 @@ +package de.dhbw.compiler.syntaxtree.statement; + +import org.antlr.v4.runtime.Token; + +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; + +public class BoolExpression extends Expression { + + public enum Operator { + AND, // && + OR, // || + } + + public final Operator operation; + public final Expression lexpr; + public final Expression rexpr; + + public BoolExpression(Operator operation, RefTypeOrTPHOrWildcardOrGeneric type, Expression lexpr, Expression rexpr, Token offset) { + super(type, offset); + this.operation = operation; + this.lexpr = lexpr; + this.rexpr = rexpr; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Break.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Break.java new file mode 100644 index 0000000..d1133ec --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Break.java @@ -0,0 +1,19 @@ +package de.dhbw.compiler.syntaxtree.statement; + +import org.antlr.v4.runtime.Token; + +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; + +public class Break extends Statement { + + public Break(RefTypeOrTPHOrWildcardOrGeneric type, Token offset) { + super(type, offset); + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/CastExpr.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/CastExpr.java new file mode 100644 index 0000000..b84b987 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/CastExpr.java @@ -0,0 +1,25 @@ +package de.dhbw.compiler.syntaxtree.statement; + +import de.dhbw.compiler.exceptions.NotImplementedException; +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.typeinference.assumptions.TypeInferenceBlockInformation; +import de.dhbw.compiler.typeinference.constraints.ConstraintSet; +import org.antlr.v4.runtime.Token; + + +public class CastExpr extends Expression +{ + public CastExpr(RefTypeOrTPHOrWildcardOrGeneric castType, Expression expr, Token offset) + { + super(castType, offset); + this.expr = expr; + } + + public Expression expr; + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Continue.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Continue.java new file mode 100644 index 0000000..0b63f02 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Continue.java @@ -0,0 +1,18 @@ +package de.dhbw.compiler.syntaxtree.statement; + +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import org.antlr.v4.runtime.Token; + +public class Continue extends Statement { + + public Continue(RefTypeOrTPHOrWildcardOrGeneric type, Token offset) { + super(type, offset); + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/DoStmt.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/DoStmt.java new file mode 100644 index 0000000..af9ec8c --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/DoStmt.java @@ -0,0 +1,18 @@ +package de.dhbw.compiler.syntaxtree.statement; + +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.type.TypePlaceholder; +import org.antlr.v4.runtime.Token; + +public class DoStmt extends WhileStmt +{ + public DoStmt(Expression expr, Statement loopBlock, Token offset) + { + super(expr, loopBlock, offset); + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/EmptyStmt.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/EmptyStmt.java new file mode 100644 index 0000000..d2e76eb --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/EmptyStmt.java @@ -0,0 +1,22 @@ +package de.dhbw.compiler.syntaxtree.statement; + +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.type.Void; +import de.dhbw.compiler.typeinference.assumptions.TypeInferenceBlockInformation; +import de.dhbw.compiler.typeinference.constraints.ConstraintSet; +import de.dhbw.compiler.typeinference.assumptions.TypeInferenceInformation; +import org.antlr.v4.runtime.Token; + + +public class EmptyStmt extends Statement +{ + public EmptyStmt(Token offset) + { + super(new Void(offset),offset); + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Expression.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Expression.java new file mode 100644 index 0000000..fc5f787 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Expression.java @@ -0,0 +1,16 @@ + +package de.dhbw.compiler.syntaxtree.statement; + +import de.dhbw.compiler.syntaxtree.ASTVisitor; +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.SyntaxTreeNode; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.typeinference.assumptions.TypeInferenceBlockInformation; +import de.dhbw.compiler.typeinference.constraints.ConstraintSet; +import org.antlr.v4.runtime.Token; + +public abstract class Expression extends TypableStatement { + public Expression(RefTypeOrTPHOrWildcardOrGeneric type, Token offset) { + super(type, offset); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/ExpressionReceiver.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/ExpressionReceiver.java new file mode 100644 index 0000000..5f77e3b --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/ExpressionReceiver.java @@ -0,0 +1,21 @@ +package de.dhbw.compiler.syntaxtree.statement; + +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import org.antlr.v4.runtime.Token; + +public class ExpressionReceiver extends Receiver +{ + public final Expression expr; + + public ExpressionReceiver(Expression expr) + { + super(expr.getType(), expr.getOffset()); + this.expr = expr; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/FieldVar.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/FieldVar.java new file mode 100644 index 0000000..cfab538 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/FieldVar.java @@ -0,0 +1,31 @@ +package de.dhbw.compiler.syntaxtree.statement; + +import de.dhbw.compiler.exceptions.TypeinferenceException; +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.typeinference.assumptions.FieldAssumption; +import de.dhbw.compiler.typeinference.assumptions.TypeInferenceBlockInformation; +import de.dhbw.compiler.typeinference.constraints.Constraint; +import de.dhbw.compiler.typeinference.constraints.ConstraintSet; +import de.dhbw.compiler.typeinference.unify.model.PairOperator; +import org.antlr.v4.runtime.Token; + +import java.util.HashSet; +import java.util.Set; + +public class FieldVar extends Expression { + + public final String fieldVarName; + public final Expression receiver; + + public FieldVar(Expression receiver, String fieldVarName, RefTypeOrTPHOrWildcardOrGeneric type, Token offset) { + super(type, offset); + this.fieldVarName = fieldVarName; + this.receiver = receiver; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/ForEachStmt.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/ForEachStmt.java new file mode 100644 index 0000000..03dadc0 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/ForEachStmt.java @@ -0,0 +1,26 @@ +package de.dhbw.compiler.syntaxtree.statement; + +import de.dhbw.compiler.parser.NullToken; +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.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); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/ForStmt.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/ForStmt.java new file mode 100644 index 0000000..ba5533b --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/ForStmt.java @@ -0,0 +1,34 @@ + +package de.dhbw.compiler.syntaxtree.statement; + +import de.dhbw.compiler.exceptions.NotImplementedException; +import de.dhbw.compiler.parser.NullToken; +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.type.Void; +import de.dhbw.compiler.typeinference.assumptions.TypeInferenceBlockInformation; +import de.dhbw.compiler.typeinference.constraints.ConstraintSet; +import org.antlr.v4.runtime.Token; + +import java.util.List; + +public class ForStmt extends Statement +{ + public final List initializer; + public final Expression condition; + public final List loopExpr; + public final Statement block; + + public ForStmt(Token offset, List initializer, Expression condition, List loopExpr, Statement block) + { + super(new Void(new NullToken()), offset); + this.initializer = initializer; + this.condition = condition; + this.loopExpr = loopExpr; + this.block = block; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } +} \ No newline at end of file diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/IfStmt.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/IfStmt.java new file mode 100644 index 0000000..25fdee2 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/IfStmt.java @@ -0,0 +1,26 @@ +package de.dhbw.compiler.syntaxtree.statement; + +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.typeinference.assumptions.TypeInferenceBlockInformation; +import de.dhbw.compiler.typeinference.constraints.ConstraintSet; +import de.dhbw.compiler.typeinference.assumptions.TypeInferenceInformation; +import org.antlr.v4.runtime.Token; + +public class IfStmt extends Statement { + public final Expression expr; + public final Statement then_block; + public final Statement else_block; + + public IfStmt(RefTypeOrTPHOrWildcardOrGeneric type, Expression expr, Statement thenBlock, Statement elseBlock, Token offset) { + super(type, offset); + this.expr = expr; + this.then_block = thenBlock; + this.else_block = elseBlock; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/InstanceOf.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/InstanceOf.java new file mode 100644 index 0000000..105874f --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/InstanceOf.java @@ -0,0 +1,38 @@ +package de.dhbw.compiler.syntaxtree.statement; + +import de.dhbw.compiler.syntaxtree.FormalParameter; +import de.dhbw.compiler.syntaxtree.Pattern; +import org.antlr.v4.runtime.Token; + +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; + +public class InstanceOf extends Expression { + private final Pattern pattern; + private final Expression expr; + + public InstanceOf(Expression expr, RefTypeOrTPHOrWildcardOrGeneric type, RefTypeOrTPHOrWildcardOrGeneric reftype, Token offset) { + super(type, offset); + this.pattern = new FormalParameter(null, reftype, offset); + this.expr = expr; + } + + public InstanceOf(Expression expr, RefTypeOrTPHOrWildcardOrGeneric type, Pattern pattern, Token offset) { + super(type, offset); + this.pattern = pattern; + this.expr = expr; + } + + public Pattern getPattern() { + return pattern; + } + + public Expression getExpression() { + return expr; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/JavaInternalExpression.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/JavaInternalExpression.java new file mode 100644 index 0000000..bd0c332 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/JavaInternalExpression.java @@ -0,0 +1,12 @@ +package de.dhbw.compiler.syntaxtree.statement; + +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import org.antlr.v4.runtime.Token; + +import java.nio.charset.StandardCharsets; + +public abstract class JavaInternalExpression extends Statement{ + public JavaInternalExpression(RefTypeOrTPHOrWildcardOrGeneric retType, Token offset){ + super(retType, offset); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/LambdaExpression.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/LambdaExpression.java new file mode 100644 index 0000000..4314b5f --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/LambdaExpression.java @@ -0,0 +1,42 @@ +package de.dhbw.compiler.syntaxtree.statement; + +import de.dhbw.compiler.syntaxtree.*; +import de.dhbw.compiler.syntaxtree.type.RefType; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.typeinference.assumptions.TypeInferenceBlockInformation; +import de.dhbw.compiler.typeinference.constraints.Constraint; +import de.dhbw.compiler.typeinference.constraints.ConstraintSet; +import de.dhbw.compiler.typeinference.constraints.Pair; +import org.antlr.v4.runtime.Token; +//import sun.reflect.generics.reflectiveObjects.NotImplementedException; + +import java.util.ArrayList; + +public class LambdaExpression extends Expression implements TypeScope { + public final Block methodBody; + public final ParameterList params; + + public LambdaExpression(RefTypeOrTPHOrWildcardOrGeneric type, ParameterList params, Block methodBody, Token offset) { + super(type,offset); + this.methodBody = methodBody; + this.params = params; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } + + @Override + public Iterable getGenerics() { + //Lambda-Ausdrücke haben keine Generics + return new ArrayList<>(); + } + + @Override + public RefTypeOrTPHOrWildcardOrGeneric getReturnType() { + //RefType type = (RefType) this.getType(); + //return type.getParaList().get(0); + return methodBody.getType(); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Literal.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Literal.java new file mode 100644 index 0000000..31fb6c2 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Literal.java @@ -0,0 +1,24 @@ +package de.dhbw.compiler.syntaxtree.statement; + + +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.statement.Expression; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.typeinference.assumptions.TypeInferenceBlockInformation; +import de.dhbw.compiler.typeinference.constraints.ConstraintSet; +import org.antlr.v4.runtime.Token; + +public class Literal extends Expression +{ + public final Object value; + + public Literal(RefTypeOrTPHOrWildcardOrGeneric type, Object value, Token offset) { + super(type, offset); + this.value = value; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/LocalVar.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/LocalVar.java new file mode 100644 index 0000000..3ddd2d8 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/LocalVar.java @@ -0,0 +1,25 @@ +package de.dhbw.compiler.syntaxtree.statement; + +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import org.antlr.v4.runtime.Token; + +public class LocalVar extends Statement { + + public final String name; + + public LocalVar(String n, RefTypeOrTPHOrWildcardOrGeneric type, Token offset) { + super(type, offset); + this.name = n; + } + + public LocalVar(Expression e1, RefTypeOrTPHOrWildcardOrGeneric type, String access) { + super(type, e1.getOffset()); + this.name = access; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/LocalVarDecl.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/LocalVarDecl.java new file mode 100644 index 0000000..27ef914 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/LocalVarDecl.java @@ -0,0 +1,31 @@ +package de.dhbw.compiler.syntaxtree.statement; + + +import de.dhbw.compiler.exceptions.NotImplementedException; +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.typeinference.assumptions.TypeInferenceBlockInformation; +import de.dhbw.compiler.typeinference.constraints.ConstraintSet; +import org.antlr.v4.runtime.Token; + + +public class LocalVarDecl extends Statement +{ + + private String name; + + public LocalVarDecl(String name, RefTypeOrTPHOrWildcardOrGeneric type, Token offset) + { + super(type, offset); + this.name = name; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } + + public String getName() { + return name; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/MethodCall.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/MethodCall.java new file mode 100644 index 0000000..4a61237 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/MethodCall.java @@ -0,0 +1,56 @@ +package de.dhbw.compiler.syntaxtree.statement; + +import de.dhbw.compiler.exceptions.TypeinferenceException; +import de.dhbw.compiler.syntaxtree.*; +import de.dhbw.compiler.syntaxtree.type.RefType; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.typeinference.assumptions.TypeInferenceBlockInformation; +import de.dhbw.compiler.typeinference.constraints.Constraint; +import de.dhbw.compiler.typeinference.constraints.ConstraintSet; +import de.dhbw.compiler.typeinference.assumptions.MethodAssumption; +import de.dhbw.compiler.typeinference.constraints.Pair; +import de.dhbw.compiler.typeinference.unify.model.PairOperator; +import org.antlr.v4.runtime.Token; + +import de.dhbw.compiler.syntaxtree.type.TypePlaceholder; + +import java.util.*; + + +public class MethodCall extends Statement +{ + public final String name; + public final Receiver receiver; + + public final ArgumentList arglist; + + public RefTypeOrTPHOrWildcardOrGeneric receiverType; + + //sind Tphs, repraesentieren im Resultset die Signatur der aufgerufenen Methoden, letztes Element ist der Returntyp + public final ArrayList signature; + + public MethodCall(RefTypeOrTPHOrWildcardOrGeneric retType, Receiver receiver, String methodName, ArgumentList argumentList, + RefTypeOrTPHOrWildcardOrGeneric receiverType, ArrayList signature, Token offset){ + super(retType,offset); + this.arglist = argumentList; + this.name = methodName; + this.receiver = receiver; + this.receiverType = receiverType; + this.signature = signature; + if (signature == null) throw new NullPointerException(); + } + + public List signatureArguments() { + return signature.subList(0, signature.size() - 1); + } + + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } + + public ArgumentList getArgumentList() { + return arglist; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/NewArray.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/NewArray.java new file mode 100644 index 0000000..1fc5866 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/NewArray.java @@ -0,0 +1,24 @@ +package de.dhbw.compiler.syntaxtree.statement; +import java.util.List; + +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.typeinference.assumptions.TypeInferenceBlockInformation; +import de.dhbw.compiler.typeinference.constraints.ConstraintSet; +import de.dhbw.compiler.exceptions.NotImplementedException; + + +public class NewArray extends Expression +{ + public NewArray(int offset,int variableLength) + { + super(null,null); + } + private RefTypeOrTPHOrWildcardOrGeneric type; + public List expr; + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/NewClass.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/NewClass.java new file mode 100644 index 0000000..ba9d3dd --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/NewClass.java @@ -0,0 +1,43 @@ +package de.dhbw.compiler.syntaxtree.statement; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import de.dhbw.compiler.exceptions.TypeinferenceException; +import de.dhbw.compiler.parser.NullToken; +import de.dhbw.compiler.syntaxtree.ClassOrInterface; +import de.dhbw.compiler.syntaxtree.Method; +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.type.RefType; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.syntaxtree.type.TypePlaceholder; +import de.dhbw.compiler.typeinference.assumptions.MethodAssumption; +import de.dhbw.compiler.typeinference.assumptions.TypeInferenceBlockInformation; +import de.dhbw.compiler.typeinference.constraints.Constraint; +import de.dhbw.compiler.typeinference.constraints.ConstraintSet; +import de.dhbw.compiler.typeinference.constraints.Pair; +import de.dhbw.compiler.typeinference.unify.model.PairOperator; +import org.antlr.v4.runtime.Token; +import de.dhbw.compiler.exceptions.NotImplementedException; + + +public class NewClass extends MethodCall +{ + /** + * + * @param newClass Typ der Instanzierten Klasse + * @param args Argumente mit denen der New-Call aufgerufen wurde + * @param start + */ + public NewClass(RefType newClass, ArgumentList args, RefTypeOrTPHOrWildcardOrGeneric receiverType, + ArrayList signature, Token start) { + super(newClass, new ExpressionReceiver(new EmptyStmt(start)), newClass.getName().toString(), + args, receiverType, signature, start); + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Receiver.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Receiver.java new file mode 100644 index 0000000..dac3024 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Receiver.java @@ -0,0 +1,12 @@ +package de.dhbw.compiler.syntaxtree.statement; + +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import org.antlr.v4.runtime.Token; + +public abstract class Receiver extends Expression +{ + public Receiver(RefTypeOrTPHOrWildcardOrGeneric type, Token offset) + { + super(type, offset); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Return.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Return.java new file mode 100644 index 0000000..ffe5329 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Return.java @@ -0,0 +1,18 @@ +package de.dhbw.compiler.syntaxtree.statement; + +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import org.antlr.v4.runtime.Token; + +public class Return extends Statement { + public final Expression retexpr; + + public Return(Expression retExpr, Token offset) { + super(retExpr.getType(), offset); + this.retexpr = retExpr; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/ReturnVoid.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/ReturnVoid.java new file mode 100644 index 0000000..0cfc9be --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/ReturnVoid.java @@ -0,0 +1,15 @@ +package de.dhbw.compiler.syntaxtree.statement; + +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import org.antlr.v4.runtime.Token; + +public class ReturnVoid extends Return{ + public ReturnVoid(Token offset) { + super(new EmptyStmt(offset), offset); + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Statement.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Statement.java new file mode 100644 index 0000000..7f4e06f --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Statement.java @@ -0,0 +1,25 @@ +package de.dhbw.compiler.syntaxtree.statement; + +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import org.antlr.v4.runtime.Token; + + +public abstract class Statement extends Expression +{ + /* zeigt an, dass eine StatementExpression als Statement benutzt wird + */ + private boolean isStatement = false; + + public Statement(RefTypeOrTPHOrWildcardOrGeneric type, Token offset) + { + super(type, offset); + } + + public void setStatement() { + isStatement=true; + } + + public boolean getStatement() { + return isStatement; + } +} \ No newline at end of file diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/StaticClassName.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/StaticClassName.java new file mode 100644 index 0000000..d84ff11 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/StaticClassName.java @@ -0,0 +1,21 @@ +package de.dhbw.compiler.syntaxtree.statement; + +import de.dhbw.compiler.parser.scope.JavaClassName; +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.type.RefType; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.typeinference.assumptions.TypeInferenceBlockInformation; +import de.dhbw.compiler.typeinference.constraints.ConstraintSet; +import de.dhbw.compiler.typeinference.assumptions.TypeInferenceInformation; +import org.antlr.v4.runtime.Token; + +public class StaticClassName extends Receiver { + public StaticClassName(RefTypeOrTPHOrWildcardOrGeneric type, Token offset) { + super(type, offset); + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Super.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Super.java new file mode 100644 index 0000000..0125fdd --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Super.java @@ -0,0 +1,29 @@ +package de.dhbw.compiler.syntaxtree.statement; + +import de.dhbw.compiler.parser.NullToken; +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.syntaxtree.type.TypePlaceholder; +import de.dhbw.compiler.syntaxtree.type.Void; +import de.dhbw.compiler.typeinference.assumptions.TypeInferenceBlockInformation; +import de.dhbw.compiler.typeinference.constraints.ConstraintSet; +import de.dhbw.compiler.typeinference.assumptions.TypeInferenceInformation; +import org.antlr.v4.runtime.Token; +import de.dhbw.compiler.exceptions.NotImplementedException; + +public class Super extends Expression { + + public Super(Token offset) { + super(TypePlaceholder.fresh(offset), offset); + } + + public Super(RefTypeOrTPHOrWildcardOrGeneric type, Token offset) + { + super(type, offset); + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/SuperCall.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/SuperCall.java new file mode 100644 index 0000000..dea103b --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/SuperCall.java @@ -0,0 +1,34 @@ +package de.dhbw.compiler.syntaxtree.statement; + +import de.dhbw.compiler.parser.NullToken; +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.type.RefType; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.syntaxtree.type.TypePlaceholder; +import de.dhbw.compiler.syntaxtree.type.Void; +import org.antlr.v4.runtime.Token; + +import de.dhbw.compiler.syntaxtree.SyntaxTreeNode; + +import java.util.ArrayList; +import java.util.List; + + +public class SuperCall extends MethodCall +{ + public SuperCall(RefTypeOrTPHOrWildcardOrGeneric receiverType, + ArrayList argTypes, Token offset){ + this(new ArgumentList(new ArrayList(), offset), receiverType, argTypes, offset); + } + + public SuperCall(ArgumentList argumentList, RefTypeOrTPHOrWildcardOrGeneric receiverType, + ArrayList argTypes, Token offset){ + super(new Void(offset), new ExpressionReceiver(new Super(receiverType, offset)), "", argumentList, receiverType, argTypes, offset); + } + + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Switch.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Switch.java new file mode 100644 index 0000000..3f92ed9 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Switch.java @@ -0,0 +1,37 @@ +package de.dhbw.compiler.syntaxtree.statement; + +import java.util.ArrayList; +import java.util.List; + +import org.antlr.v4.runtime.Token; + +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; + +public class Switch extends Statement { + + private Expression switchedExpression; + private List blocks = new ArrayList<>(); + + public Switch(Expression switched, List blocks, RefTypeOrTPHOrWildcardOrGeneric type, Boolean isStatement, Token offset) { + super(type, offset); + if (isStatement) + setStatement(); + this.switchedExpression = switched; + this.blocks = blocks; + } + + public Expression getSwitch() { + return switchedExpression; + } + + public List getBlocks() { + return blocks; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/SwitchBlock.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/SwitchBlock.java new file mode 100644 index 0000000..4462c0e --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/SwitchBlock.java @@ -0,0 +1,43 @@ +package de.dhbw.compiler.syntaxtree.statement; + +import java.util.ArrayList; +import java.util.List; + +import org.antlr.v4.runtime.Token; + +import de.dhbw.compiler.syntaxtree.StatementVisitor; + +public class SwitchBlock extends Block { + + private List labels = new ArrayList<>(); + + private boolean defaultBlock = false; + public final boolean isExpression; // This is for single expressions that yield a value + + public SwitchBlock(List labels, Block statements, boolean isExpression, Token offset) { + super(statements.getStatements(), offset); + this.labels = labels; + this.isExpression = isExpression; + } + + public SwitchBlock(List labels, Block statements, boolean isDefault, boolean isExpression, Token offset) { + super(statements.getStatements(), offset); + this.labels = labels; + this.defaultBlock = isDefault; + this.isExpression = isExpression; + } + + public boolean isDefault() { + return defaultBlock; + } + + public List getLabels() { + return labels; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/SwitchLabel.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/SwitchLabel.java new file mode 100644 index 0000000..3156d5a --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/SwitchLabel.java @@ -0,0 +1,37 @@ +package de.dhbw.compiler.syntaxtree.statement; + +import de.dhbw.compiler.syntaxtree.Pattern; +import org.antlr.v4.runtime.Token; + +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; + +public class SwitchLabel extends Expression { + + private Pattern pattern; + private Boolean defaultCase = false; + + public SwitchLabel(Pattern pattern, RefTypeOrTPHOrWildcardOrGeneric type, Token offset) { + super(type, offset); + this.pattern = pattern; + } + + public SwitchLabel(RefTypeOrTPHOrWildcardOrGeneric type, Token offset) { + super(type, offset); + this.defaultCase = true; + } + + public Pattern getPattern() { + return pattern; + } + + public Boolean isDefault() { + return this.defaultCase; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Ternary.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Ternary.java new file mode 100644 index 0000000..1c975a0 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Ternary.java @@ -0,0 +1,24 @@ +package de.dhbw.compiler.syntaxtree.statement; + +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import org.antlr.v4.runtime.Token; + +public class Ternary extends Expression { + + public final Expression cond; + public final Expression iftrue; + public final Expression iffalse; + + public Ternary(RefTypeOrTPHOrWildcardOrGeneric type, Expression cond, Expression iftrue, Expression iffalse, Token offset) { + super(type, offset); + this.cond = cond; + this.iftrue = iftrue; + this.iffalse = iffalse; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/This.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/This.java new file mode 100644 index 0000000..0b884b9 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/This.java @@ -0,0 +1,25 @@ +package de.dhbw.compiler.syntaxtree.statement; + +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.type.RefType; +import de.dhbw.compiler.syntaxtree.type.TypePlaceholder; +import org.antlr.v4.runtime.Token; +import de.dhbw.compiler.exceptions.NotImplementedException; + +public class This extends Expression +{ + public This(Token offset) { + super(TypePlaceholder.fresh(offset), offset); + } + + public ArgumentList arglist; + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } + + public String toString() { + return "this: "+ this.getType(); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/ThisCall.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/ThisCall.java new file mode 100644 index 0000000..71c974f --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/ThisCall.java @@ -0,0 +1,25 @@ +package de.dhbw.compiler.syntaxtree.statement; + +import de.dhbw.compiler.syntaxtree.Constructor; +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.syntaxtree.type.TypePlaceholder; +import de.dhbw.compiler.syntaxtree.type.Void; +import org.antlr.v4.runtime.Token; + +import java.util.ArrayList; + + +public class ThisCall extends MethodCall +{ + public ThisCall(ArgumentList argumentList, RefTypeOrTPHOrWildcardOrGeneric receiverType, ArrayList argTypes, Token offset) { + super(new Void(offset), new ExpressionReceiver(new This(offset)), "", argumentList, receiverType, argTypes, offset); + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } +} + + diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Throw.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Throw.java new file mode 100644 index 0000000..7eb30d4 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Throw.java @@ -0,0 +1,21 @@ +package de.dhbw.compiler.syntaxtree.statement; + +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.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); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/TypableStatement.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/TypableStatement.java new file mode 100644 index 0000000..1d02de7 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/TypableStatement.java @@ -0,0 +1,28 @@ +package de.dhbw.compiler.syntaxtree.statement; + +import de.dhbw.compiler.syntaxtree.ASTVisitor; +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.SyntaxTreeNode; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import org.antlr.v4.runtime.Token; + +public abstract class TypableStatement extends SyntaxTreeNode{ + private RefTypeOrTPHOrWildcardOrGeneric type; + + public TypableStatement(RefTypeOrTPHOrWildcardOrGeneric type, Token offset){ + super(offset); + if(type == null)throw new NullPointerException(); + this.type = type; + } + + public RefTypeOrTPHOrWildcardOrGeneric getType(){ + return type; + } + + public abstract void accept(StatementVisitor visitor); + + @Override + public void accept(ASTVisitor visitor) { + this.accept((StatementVisitor)visitor); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/UnaryExpr.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/UnaryExpr.java new file mode 100644 index 0000000..34d350b --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/UnaryExpr.java @@ -0,0 +1,37 @@ +package de.dhbw.compiler.syntaxtree.statement; + + +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.statement.Expression; +import de.dhbw.compiler.syntaxtree.statement.JavaInternalExpression; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import org.antlr.v4.runtime.Token; + +public class UnaryExpr extends JavaInternalExpression +{ + public enum Operation{ + NOT, + MINUS, + PREINCREMENT, + PREDECREMENT, + POSTINCREMENT, + PLUS, POSTDECREMENT + } + + + public final Operation operation; + public Expression expr; + + public UnaryExpr(Operation operation, Expression argument, RefTypeOrTPHOrWildcardOrGeneric retType, Token offset) + { + super(retType, offset); + this.expr = argument; + this.operation = operation; + } + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } + + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/WhileStmt.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/WhileStmt.java new file mode 100644 index 0000000..b3b292b --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/WhileStmt.java @@ -0,0 +1,28 @@ +package de.dhbw.compiler.syntaxtree.statement; + + +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.type.TypePlaceholder; +import de.dhbw.compiler.typeinference.assumptions.TypeInferenceBlockInformation; +import de.dhbw.compiler.typeinference.constraints.ConstraintSet; +import de.dhbw.compiler.typeinference.assumptions.TypeInferenceInformation; +import de.dhbw.compiler.exceptions.NotImplementedException; +import org.antlr.v4.runtime.Token; + +public class WhileStmt extends Statement +{ + public final Expression expr; + public final Statement loopBlock; + + public WhileStmt(Expression expr, Statement loopBlock, Token offset) + { + super(TypePlaceholder.fresh(offset), offset); + this.expr = expr; + this.loopBlock = loopBlock; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Yield.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Yield.java new file mode 100644 index 0000000..46c5acb --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/statement/Yield.java @@ -0,0 +1,18 @@ +package de.dhbw.compiler.syntaxtree.statement; + +import org.antlr.v4.runtime.Token; + +import de.dhbw.compiler.syntaxtree.StatementVisitor; + +public class Yield extends Return { + + public Yield(Expression retExpr, Token offset) { + super(retExpr, offset); + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/type/ExtendsWildcardType.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/type/ExtendsWildcardType.java new file mode 100644 index 0000000..9b9edc3 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/type/ExtendsWildcardType.java @@ -0,0 +1,71 @@ +package de.dhbw.compiler.syntaxtree.type; + + +import de.dhbw.compiler.syntaxtree.ASTVisitor; +import de.dhbw.compiler.typeinference.result.ResultSetVisitor; +import org.antlr.v4.runtime.Token; + +import java.util.Objects; + +/** + * Stellt eine Wildcard mit oberer Grenze dar. + * z.B. void test(? extends Number var){..} + * ... + * @author luar 2.12.06 + * + */ + +public class ExtendsWildcardType extends WildcardType{ + + /** + * Author: Arne Lüdtke
+ * Standard Konstruktor für eine ExtendsWildcard + */ + public ExtendsWildcardType (RefTypeOrTPHOrWildcardOrGeneric extendsType, Token offset) + { + super(extendsType, offset); + } + + @Override + public boolean isExtends() { + return true; + } + + @Override + public boolean isSuper() { + return false; + } + + @Override + public String toString() { + return "? extends "+innerType.toString(); + } + + @Override + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } + + @Override + public
A acceptTV(TypeVisitor visitor) { + return visitor.visit(this); + } + + @Override + public void accept(ResultSetVisitor visitor) { + visitor.visit(this); + } + + @Override + public int hashCode() { + return Objects.hashCode(this.innerType); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ExtendsWildcardType that = (ExtendsWildcardType) o; + return that.innerType.equals(this.innerType); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/type/GenericRefType.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/type/GenericRefType.java new file mode 100644 index 0000000..9fd4c93 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/type/GenericRefType.java @@ -0,0 +1,57 @@ +package de.dhbw.compiler.syntaxtree.type; + +import de.dhbw.compiler.syntaxtree.ASTVisitor; +import de.dhbw.compiler.typeinference.result.ResultSetVisitor; +import org.antlr.v4.runtime.Token; + +import java.util.Objects; + +public class GenericRefType extends RefTypeOrTPHOrWildcardOrGeneric +{ + private String name; + + public GenericRefType(String name, Token offset) + { + super(offset); + this.name = name; + } + + public String getParsedName(){ + return name.toString(); + } + + @Override + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } + + @Override + public A acceptTV(TypeVisitor visitor) { + return visitor.visit(this); + } + + @Override + public void accept(ResultSetVisitor visitor) { + visitor.visit(this); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + GenericRefType that = (GenericRefType) o; + return name.equals(that.name); + } + + @Override + public int hashCode() { + return Objects.hash(name); + } + + @Override + public String toString() + { + return "GTV " + this.name; + } +} + diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/type/RefType.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/type/RefType.java new file mode 100644 index 0000000..dc8209c --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/type/RefType.java @@ -0,0 +1,132 @@ +package de.dhbw.compiler.syntaxtree.type; + +import de.dhbw.compiler.parser.scope.JavaClassName; +import de.dhbw.compiler.syntaxtree.ASTVisitor; +import de.dhbw.compiler.typeinference.result.ResultSetVisitor; +import org.antlr.v4.runtime.Token; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; + + +public class RefType extends RefTypeOrTPHOrWildcardOrGeneric +{ + protected final JavaClassName name; + protected final List parameter; + /** + * Ist primitiveFlag auf true, muss beim Codegen dieser Reftype durch + * den primitiven Datentyp ersetzt werden + * + * Bsp: java.lang.Integer mit Flag wird dann zu [int] + */ + boolean primitiveFlag = false; // TODO Should be final + + public RefType(JavaClassName fullyQualifiedName, Token offset) + { + this(fullyQualifiedName, new ArrayList<>(), offset); + } + + public boolean isPrimitive() { + return primitiveFlag; + } + + @Override + public String toString(){ + String params = ""; + if(parameter.size()>0){ + params += "<"; + Iterator it = parameter.iterator(); + while(it.hasNext()){ + RefTypeOrTPHOrWildcardOrGeneric param = it.next(); + params += param.toString(); + if(it.hasNext())params += ", "; + } + params += ">"; + } + return this.name.toString() + params; + } + + @Override + public int hashCode() { + return this.name.hashCode();//Nur den Name hashen. Sorgt für langsame, aber funktionierende HashMaps + } + + public RefType(JavaClassName fullyQualifiedName, List parameter, Token offset) { + this(fullyQualifiedName, parameter, offset, false); + } + + public RefType(JavaClassName fullyQualifiedName, List parameter, Token offset, boolean primitiveFlag) { + super(offset); + this.name = (fullyQualifiedName); + this.parameter = parameter; + this.primitiveFlag = primitiveFlag; + } + + public JavaClassName getName() + { + return name; + } + + public List getParaList(){ + if(this.parameter==null)return new ArrayList<>(); + return this.parameter; + } + + /** + * Author: Jrg Buerle
+ * @return + */ + public boolean equals(Object obj) + { + if(obj instanceof RefType){ + if (!Objects.equals(this.name, ((RefType) obj).name)) return false; + boolean ret = true; + + //if(!(super.equals(obj))) PL 2020-03-12 muss vll. einkommentiert werden + // return false; + + if(parameter==null || parameter.size()==0){ + ret &= (((RefType)obj).getParaList()==null || ((RefType)obj).getParaList().size()==0); + } + else{ + if(((RefType)obj).getParaList()==null){ + ret = false; + } + else if(parameter.size() != ((RefType)obj).getParaList().size()) + { + ret = false; + } + else + { + for(int i = 0; i A acceptTV(TypeVisitor
visitor) { + return visitor.visit(this); + } + + @Override + public void accept(ResultSetVisitor visitor) { + visitor.visit(this); + } +} + diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/type/RefTypeOrTPHOrWildcardOrGeneric.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/type/RefTypeOrTPHOrWildcardOrGeneric.java new file mode 100644 index 0000000..ce7574d --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/type/RefTypeOrTPHOrWildcardOrGeneric.java @@ -0,0 +1,22 @@ +package de.dhbw.compiler.syntaxtree.type; + +import de.dhbw.compiler.syntaxtree.ASTVisitor; +import de.dhbw.compiler.syntaxtree.SyntaxTreeNode; +import de.dhbw.compiler.typeinference.result.ResultSetVisitor; +import org.antlr.v4.runtime.Token; + +public abstract class RefTypeOrTPHOrWildcardOrGeneric extends SyntaxTreeNode{ + public RefTypeOrTPHOrWildcardOrGeneric(Token offset) { + super(offset); + } + + @Override + public abstract void accept(ASTVisitor visitor); + + public abstract A acceptTV(TypeVisitor visitor); + public abstract void accept(ResultSetVisitor visitor); + + @Override + public abstract boolean equals(Object o); + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/type/SuperWildcardType.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/type/SuperWildcardType.java new file mode 100644 index 0000000..850410c --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/type/SuperWildcardType.java @@ -0,0 +1,83 @@ +package de.dhbw.compiler.syntaxtree.type; + + +import de.dhbw.compiler.syntaxtree.ASTVisitor; +import de.dhbw.compiler.syntaxtree.GenericTypeVar; +import de.dhbw.compiler.typeinference.result.ResultSetVisitor; +import org.antlr.v4.runtime.Token; + +import java.util.Objects; + +/** + * Stellt eine Wildcard mit unterer Grenze dar. + * z.B. void test(? super Integer var){..} + * ... + * @author luar 2.12.06 + * + */ + +public class SuperWildcardType extends WildcardType{ + + /** + * Author: Arne Lüdtke
+ * Standard Konstruktor für eine SuperWildcard + */ + public SuperWildcardType( RefTypeOrTPHOrWildcardOrGeneric innerType, Token offset) + { + super(innerType, offset); + } + + /** + * Author: Arne Lüdtke
+ * Gibt den Typen in der Wildcard zurück. + * Beispiel: ? super Integer. + * Integer wird zurückgegeben. + */ + public RefTypeOrTPHOrWildcardOrGeneric getInnerType() + { + return this.innerType; + } + + @Override + public String toString() { + return "? super "+innerType.toString(); + } + + @Override + public boolean isExtends() { + return false; + } + + @Override + public boolean isSuper() { + return true; + } + + @Override + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } + + @Override + public
A acceptTV(TypeVisitor visitor) { + return visitor.visit(this); + } + + @Override + public void accept(ResultSetVisitor visitor) { + visitor.visit(this); + } + + @Override + public int hashCode() { + return Objects.hashCode(this.innerType); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + SuperWildcardType that = (SuperWildcardType) o; + return that.innerType.equals(this.innerType); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/type/TypePlaceholder.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/type/TypePlaceholder.java new file mode 100644 index 0000000..04eac4e --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/type/TypePlaceholder.java @@ -0,0 +1,142 @@ +package de.dhbw.compiler.syntaxtree.type; +import java.util.Hashtable; + +import de.dhbw.compiler.parser.NullToken; +import de.dhbw.compiler.syntaxtree.ASTVisitor; +import de.dhbw.compiler.syntaxtree.SyntaxTreeNode; +import de.dhbw.compiler.syntaxtree.factory.NameGenerator; +import de.dhbw.compiler.typeinference.result.ResultSetVisitor; +import org.antlr.v4.runtime.Token; + +/** + * Repr�sentiert einen Typparameter f�r einen vom Programmierer nicht angegeben + * Typ. Jede TypePlaceholder besitzt einen eindeutigen Namen aus einem Namenspool + * und + * ist in einer zentralen Registry, d.h. einer Hashtable abgelegt. + * @author J�rg B�uerle + * @version $Date: 2013/06/19 12:45:37 $ + */ +public class TypePlaceholder extends RefTypeOrTPHOrWildcardOrGeneric +{ + private final String name; + + /** + * variance shows the variance of the pair + * 1: contravariant + * -1 covariant + * 0 invariant + */ + private int variance = 0; + + /** + * isWildcardable gibt an, ob ein Wildcardtyp dem PlaceholderType zugeordnet werden darf + */ + private boolean wildcardable = true; + + /* + * Fuer Oder-Constraints: + * orCons = 1: Receiver + * orCons = 0: Argument oder kein Oder-Constraint + * orCons = -1: RetType + */ + private byte orCons = 0; + + + /** + * Privater Konstruktor - Eine TypePlaceholder-Variable wird �ber die + * Factory-Methode fresh() erzeugt. + *
Author: J�rg B�uerle + */ + private TypePlaceholder(String name, Token offset, int variance, boolean wildcardable) + { + super(offset); + this.name = name; + this.variance = variance; + this.wildcardable = wildcardable; + } + + + /** + * @author Andreas Stadelmeier, a10023 + * Ruft die TypePlaceholder.fresh()-Methode auf. + * Fügt zusätzlich einen Replacementlistener hinzu. + * @return + */ + public static TypePlaceholder fresh(Token position){ + return new TypePlaceholder(NameGenerator.makeNewName(), position, 0, true); + } + + public static TypePlaceholder fresh(Token position, int variance, boolean wildcardable){ + return new TypePlaceholder(NameGenerator.makeNewName(), position, variance, wildcardable); + } + + public static RefTypeOrTPHOrWildcardOrGeneric of(String name) { + return new TypePlaceholder(name, new NullToken(),0, true); + } + + + /** + * Author: J�rg B�uerle
+ * @return + */ + public boolean equals(Object obj) + { + if(obj instanceof TypePlaceholder){ + return this.toString().equals(((TypePlaceholder)obj).toString()); + //return super.equals(obj); + } + else{ + return false; + } + } + + @Override + public int hashCode() { + return this.getName().hashCode(); + } + + public String toString() + { + return "TPH " + this.name; + } + + public String getName() { + return name; + } + + public void setVariance(int variance) { + this.variance= variance; + } + + public int getVariance() { + return this.variance; + } + + @Override + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } + + @Override + public
A acceptTV(TypeVisitor visitor) { + return visitor.visit(this); + } + + @Override + public void accept(ResultSetVisitor visitor) { + visitor.visit(this); + } + + public void setOrCons(byte i) { + orCons = i; + } + + public byte getOrCons() { + return orCons; + } + + + public Boolean getWildcardtable() { + return wildcardable; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/type/TypeVisitor.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/type/TypeVisitor.java new file mode 100644 index 0000000..7584f39 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/type/TypeVisitor.java @@ -0,0 +1,13 @@ +package de.dhbw.compiler.syntaxtree.type; + +public interface TypeVisitor { + A visit(RefType refType); + + A visit(SuperWildcardType superWildcardType); + + A visit(TypePlaceholder typePlaceholder); + + A visit(ExtendsWildcardType extendsWildcardType); + + A visit(GenericRefType genericRefType); +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/type/Void.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/type/Void.java new file mode 100644 index 0000000..24c5b5b --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/type/Void.java @@ -0,0 +1,14 @@ +package de.dhbw.compiler.syntaxtree.type; + +import org.antlr.v4.runtime.Token; + +import de.dhbw.compiler.parser.scope.JavaClassName; + + +public class Void extends RefType +{ + public Void(Token offset) { + super(JavaClassName.Void, offset); + } +} + diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/type/WildcardType.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/type/WildcardType.java new file mode 100644 index 0000000..1caf3a1 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/type/WildcardType.java @@ -0,0 +1,42 @@ +package de.dhbw.compiler.syntaxtree.type; + +import org.antlr.v4.runtime.Token; + +/** + * Stellt eine Wildcard in Java dar. + * z.B. void Test(? var){..} + * @author luar 2.12.06 + * + */ + +public abstract class WildcardType extends RefTypeOrTPHOrWildcardOrGeneric { + + protected RefTypeOrTPHOrWildcardOrGeneric innerType = null; + + /** + * Author: Arne Lüdtke
+ * Standard Konstruktor für eine Wildcard + */ + public WildcardType(RefTypeOrTPHOrWildcardOrGeneric innerType, Token offset) + { + super(offset); + this.innerType = innerType; + } + + public RefTypeOrTPHOrWildcardOrGeneric getInnerType(){ + return innerType; + } + + /** + * Author: Arne Lüdtke
+ * Gibt String Entsprechung zurück. + */ + public String toString() + { + return "?"; + } + + + public abstract boolean isExtends(); + public abstract boolean isSuper(); +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/visual/ASTPrinter.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/visual/ASTPrinter.java new file mode 100644 index 0000000..4b8b4d7 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/visual/ASTPrinter.java @@ -0,0 +1,13 @@ +package de.dhbw.compiler.syntaxtree.visual; + +import de.dhbw.compiler.syntaxtree.*; + +public class ASTPrinter { + + public static String print(SourceFile toPrint) { + StringBuilder output = new StringBuilder(); + new OutputGenerator(output).visit(toPrint); + return output.toString(); + } + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/visual/ASTTypePrinter.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/visual/ASTTypePrinter.java new file mode 100644 index 0000000..0172b62 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/visual/ASTTypePrinter.java @@ -0,0 +1,13 @@ +package de.dhbw.compiler.syntaxtree.visual; + +import de.dhbw.compiler.syntaxtree.*; + +public class ASTTypePrinter extends ASTPrinter{ + + public static String print(SourceFile toPrint){ + StringBuilder output = new StringBuilder(); + new TypeOutputGenerator(output).visit(toPrint); + return output.toString(); + } + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/visual/OutputGenerator.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/visual/OutputGenerator.java new file mode 100644 index 0000000..5dc623e --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/visual/OutputGenerator.java @@ -0,0 +1,533 @@ +package de.dhbw.compiler.syntaxtree.visual; + +import de.dhbw.compiler.parser.SyntaxTreeGenerator.AssignToLocal; +import de.dhbw.compiler.syntaxtree.*; +import de.dhbw.compiler.syntaxtree.statement.*; +import de.dhbw.compiler.syntaxtree.type.*; + +import java.lang.reflect.Modifier; +import java.util.Iterator; +import java.util.List; + +public class OutputGenerator implements ASTVisitor { + private static final String TAB = " "; + String tabs = ""; + protected final StringBuilder out; + + public OutputGenerator(StringBuilder out) { + this.out = out; + } + + public void tab() { + tabs += TAB; + } + + public void untab() { + tabs = tabs.substring(0, tabs.length() - TAB.length()); + } + + @Override + public void visit(SourceFile sourceFile) { + for (ClassOrInterface cl : sourceFile.getClasses()) { + cl.accept(this); + } + } + + @Override + public void visit(ArgumentList argumentList) { + out.append("("); + Iterator expressionIterator = argumentList.getArguments().iterator(); + while (expressionIterator.hasNext()) { + expressionIterator.next().accept(this); + if (expressionIterator.hasNext()) + out.append(", "); + } + out.append(")"); + } + + @Override + public void visit(GenericTypeVar genericTypeVar) { + out.append(genericTypeVar.getName().toString()); + } + + @Override + public void visit(FormalParameter formalParameter) { + formalParameter.getType().accept(this); + out.append(" "); + out.append(formalParameter.getName()); + } + + @Override + public void visit(LiteralPattern literalPattern) { + literalPattern.value.accept(this); + } + + @Override + public void visit(GenericDeclarationList genericTypeVars) { + Iterator genericIterator = genericTypeVars.iterator(); + if (genericIterator.hasNext()) { + out.append("<"); + while (genericIterator.hasNext()) { + genericIterator.next().accept(this); + if (genericIterator.hasNext()) + out.append(", "); + } + out.append(">"); + } + } + + @Override + public void visit(Field field) { + field.getType().accept(this); + out.append(" "); + out.append(field.getName()); + out.append(";"); + } + + @Override + public void visit(Method method) { + method.getReturnType().accept(this); + out.append(" " + method.getName()); + method.getParameterList().accept(this); + if (method.block != null) + method.block.accept(this); + out.append("\n"); + } + + @Override + public void visit(Constructor method) { + out.append(method.getName()); + method.getParameterList().accept(this); + method.block.accept(this); + out.append("\n"); + } + + @Override + public void visit(ParameterList formalParameters) { + out.append("("); + Iterator genericIterator = formalParameters.getFormalparalist().iterator(); + if (genericIterator.hasNext()) { + while (genericIterator.hasNext()) { + genericIterator.next().accept(this); + if (genericIterator.hasNext()) + out.append(", "); + } + } + out.append(")"); + } + + @Override + public void visit(ClassOrInterface classOrInterface) { + if (classOrInterface.isInterface()) { + out.append("interface "); + } else { + out.append("class "); + } + out.append(classOrInterface.getClassName().toString()); + classOrInterface.getGenerics().accept(this); + out.append(" {\n\n"); + tab(); + for (Field f : classOrInterface.getFieldDecl()) { + out.append(tabs); + f.accept(this); + out.append("\n"); + } + if (classOrInterface.getfieldInitializations().isPresent()) {// PL 2019-11-28: Zum Ausdrucken der Fieldinitializer + classOrInterface.getfieldInitializations().get().accept(this); + } + for (Method m : classOrInterface.getMethods()) { + out.append(tabs); + m.accept(this); + out.append("\n"); + } + for (Constructor m : classOrInterface.getConstructors()) { + out.append(tabs); + m.accept(this); + out.append("\n"); + } + untab(); + out.append("}"); + } + + @Override + public void visit(RefType refType) { + out.append(refType.getName().toString()); + Iterator genericIterator = refType.getParaList().iterator(); + if (genericIterator.hasNext()) { + out.append("<"); + while (genericIterator.hasNext()) { + genericIterator.next().accept(this); + if (genericIterator.hasNext()) + out.append(", "); + } + out.append(">"); + } + } + + @Override + public void visit(SuperWildcardType superWildcardType) { + out.append("? super "); + superWildcardType.getInnerType().accept(this); + } + + @Override + public void visit(TypePlaceholder typePlaceholder) { + out.append("TPH " + typePlaceholder.getName()); + } + + @Override + public void visit(ExtendsWildcardType extendsWildcardType) { + out.append("? extends "); + extendsWildcardType.getInnerType().accept(this); + } + + @Override + public void visit(GenericRefType genericRefType) { + out.append(genericRefType.getParsedName().toString()); + } + + @Override + public void visit(LambdaExpression lambdaExpression) { + lambdaExpression.params.accept(this); + out.append(" -> "); + lambdaExpression.methodBody.accept(this); + } + + @Override + public void visit(Assign assign) { + assign.lefSide.accept(this); + out.append(" = "); + assign.rightSide.accept(this); + } + + @Override + public void visit(BinaryExpr binary) { + binary.lexpr.accept(this); + out.append(" op "); + binary.rexpr.accept(this); + } + + @Override + public void visit(BoolExpression logical) { + logical.lexpr.accept(this); + out.append(" op "); + logical.rexpr.accept(this); + } + + @Override + public void visit(Block block) { + tab(); + out.append("{\n"); + for (Statement stmt : block.getStatements()) { + out.append(tabs); + stmt.accept(this); + out.append(";\n"); + } + untab(); + out.append(tabs); + out.append("}"); + } + + @Override + public void visit(CastExpr castExpr) { + + } + + @Override + public void visit(EmptyStmt emptyStmt) { + + } + + @Override + public void visit(FieldVar fieldVar) { + fieldVar.receiver.accept(this); + out.append("." + fieldVar.fieldVarName); + } + + @Override + public void visit(ForStmt forStmt) { + + } + + @Override + public void visit(ForEachStmt forEachStmt) { + out.append("for("); + forEachStmt.statement.accept(this); + out.append(" : "); + forEachStmt.expression.accept(this); + out.append(")\n"); + tab(); + out.append(tabs); + forEachStmt.block.accept(this); + untab(); + } + + @Override + public void visit(IfStmt ifStmt) { + out.append("if("); + ifStmt.expr.accept(this); + out.append(")\n"); + tab(); + out.append(tabs); + ifStmt.then_block.accept(this); + untab(); + if (ifStmt.else_block != null) { + out.append("\n" + tabs + "else\n"); + tab(); + out.append(tabs); + ifStmt.else_block.accept(this); + untab(); + } + } + + @Override + public void visit(InstanceOf instanceOf) { + instanceOf.getExpression().accept(this); + out.append(" instanceof "); + instanceOf.getPattern().accept(this); + } + + @Override + public void visit(LocalVar localVar) { + if (localVar.name.isEmpty()) { + localVar.getType().accept(this); + } else { + out.append(localVar.name); + } + } + + @Override + public void visit(LocalVarDecl localVarDecl) { + localVarDecl.getType().accept(this); + out.append(" " + localVarDecl.getName()); + } + + @Override + public void visit(MethodCall methodCall) { + methodCall.receiver.accept(this); + out.append("." + methodCall.name); + out.append(" Signature: " + methodCall.signature); + methodCall.getArgumentList().accept(this); + } + + @Override + public void visit(NewClass methodCall) { + out.append("new "); + out.append(methodCall.name); + methodCall.getArgumentList().accept(this); + } + + @Override + public void visit(NewArray newArray) { + + } + + @Override + public void visit(Return aReturn) { + out.append("return "); + aReturn.retexpr.accept(this); + } + + @Override + public void visit(ReturnVoid aReturn) { + out.append("return"); + } + + @Override + public void visit(Break aBreak) { + out.append("break"); + } + + @Override + public void visit(Continue aContinue) { + out.append("continue"); + } + + @Override + public void visit(StaticClassName staticClassName) { + + } + + @Override + public void visit(Super aSuper) { + + } + + @Override + public void visit(This aThis) { + out.append("this"); + } + + @Override + public void visit(WhileStmt whileStmt) { + out.append("while("); + whileStmt.expr.accept(this); + out.append(")"); + whileStmt.loopBlock.accept(this); + } + + @Override + public void visit(DoStmt whileStmt) { + out.append("do "); + whileStmt.loopBlock.accept(this); + out.append("while("); + whileStmt.expr.accept(this); + out.append(");"); + } + + @Override + public void visit(AssignToField assignLeftSide) { + assignLeftSide.field.accept(this); + } + + @Override + public void visit(AssignToLocal assignLeftSide) { + assignLeftSide.localVar.accept(this); + } + + @Override + public void visit(SuperCall superCall) { + out.append("super("); + superCall.arglist.accept(this); + out.append(")"); + out.append(" Signature: " + superCall.signature); + } + + @Override + public void visit(ThisCall thisCall) { + out.append("this("); + thisCall.arglist.accept(this); + out.append(")"); + out.append(" Signature: " + thisCall.signature); + } + + @Override + public void visit(ExpressionReceiver receiver) { + receiver.expr.accept(this); + } + + @Override + public void visit(UnaryExpr unaryExpr) { + if (unaryExpr.operation == UnaryExpr.Operation.MINUS) { + out.append("-"); + } + if (unaryExpr.operation == UnaryExpr.Operation.PLUS) { + out.append("+"); + } + if (unaryExpr.operation == UnaryExpr.Operation.PREDECREMENT) { + out.append("--"); + } + if (unaryExpr.operation == UnaryExpr.Operation.PREINCREMENT) { + out.append("++"); + } + unaryExpr.expr.accept(this); + if (unaryExpr.operation == UnaryExpr.Operation.POSTDECREMENT) { + out.append("--"); + } + if (unaryExpr.operation == UnaryExpr.Operation.POSTINCREMENT) { + out.append("++"); + } + } + + @Override + public void visit(de.dhbw.compiler.syntaxtree.statement.Literal literal) { + out.append(literal.value); + } + + @Override + public void visit(Throw aThrow) { + // TODO implement + } + + @Override + public void visit(Ternary ternary) { + out.append("("); + ternary.cond.accept(this); + out.append(" ? "); + ternary.iftrue.accept(this); + out.append(" : "); + ternary.iffalse.accept(this); + out.append(")::"); + ternary.getType().accept(this); + } + + @Override + public void visit(Switch switchStmt) { + out.append("switch("); + switchStmt.getSwitch().accept(this); + out.append("){\n"); + tab(); + for (SwitchBlock switchBlock : switchStmt.getBlocks()) { + switchBlock.accept(this); + } + untab(); + out.append(tabs); + out.append("}::"); + switchStmt.getType().accept(this); + } + + @Override + public void visit(SwitchBlock switchBlock) { + switchBlock.getLabels().stream().forEach((label) -> { + out.append(tabs); + label.accept(this); + }); + tab(); + switchBlock.getStatements().stream().forEach((stmt) -> { + out.append(tabs); + stmt.accept(this); + out.append(";\n"); + }); + out.append("\n"); + untab(); + } + + @Override + public void visit(SwitchLabel switchLabel) { + if (switchLabel.isDefault()) { + out.append("default"); + } else { + out.append("case "); + switchLabel.getPattern().accept(this); + } + out.append(":\n"); + } + + @Override + public void visit(Yield aYield) { + out.append("yield ("); + aYield.retexpr.accept(this); + out.append(")::"); + aYield.getType().accept(this); + } + + @Override + public void visit(ExpressionPattern aPattern) { + aPattern.getType().accept(this); + out.append(" "); + aPattern.getExpression().accept(this); + } + + @Override + public void visit(RecordPattern aRecordPattern) { + aRecordPattern.getType().accept(this); + out.append("("); + List subPatterns = aRecordPattern.getSubPattern(); + for (var i = 0; i < subPatterns.size(); i++) { + subPatterns.get(i).accept(this); + if (i < subPatterns.size() - 1) + out.append(", "); + } + String name; + if ((name = aRecordPattern.getName()) != null) + out.append(name); + out.append(")"); + } + + @Override + public void visit(GuardedPattern aGuardedPattern) { + aGuardedPattern.getNestedPattern().accept(this); + out.append(" with "); + aGuardedPattern.getCondition().accept(this); + } +} \ No newline at end of file diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/visual/ResultSetOutputGenerator.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/visual/ResultSetOutputGenerator.java new file mode 100644 index 0000000..474a524 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/visual/ResultSetOutputGenerator.java @@ -0,0 +1,34 @@ +package de.dhbw.compiler.syntaxtree.visual; + +import de.dhbw.compiler.syntaxtree.type.*; +import de.dhbw.compiler.typeinference.result.*; + +public class ResultSetOutputGenerator extends OutputGenerator implements ResultSetVisitor{ + + public ResultSetOutputGenerator(StringBuilder out) { + super(out); + } + + @Override + public void visit(PairTPHsmallerTPH p) { + print(p, "<"); + } + + @Override + public void visit(PairTPHequalRefTypeOrWildcardType p) { + print(p, "=."); + } + + @Override + public void visit(PairTPHEqualTPH p) { + print(p, "=."); + } + + private void print(ResultPair p , String operator){ + out.append("("); + p.getLeft().accept((ResultSetVisitor) this); + out.append(" "+operator+" "); + p.getRight().accept((ResultSetVisitor) this); + out.append(")"); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/visual/ResultSetPrinter.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/visual/ResultSetPrinter.java new file mode 100644 index 0000000..7022a01 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/visual/ResultSetPrinter.java @@ -0,0 +1,20 @@ +package de.dhbw.compiler.syntaxtree.visual; + +import de.dhbw.compiler.syntaxtree.SourceFile; +import de.dhbw.compiler.typeinference.result.ResultPair; +import de.dhbw.compiler.typeinference.result.ResultSet; + +import java.util.Set; + +public class ResultSetPrinter { + + public static String print(ResultSet toPrint){ + StringBuilder output = new StringBuilder(); + for(ResultPair p : toPrint.results){ + p.accept(new ResultSetOutputGenerator(output)); + output.append("\n"); + } + return output.toString(); + } + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/visual/TypeOutputGenerator.java b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/visual/TypeOutputGenerator.java new file mode 100644 index 0000000..dbbed58 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/syntaxtree/visual/TypeOutputGenerator.java @@ -0,0 +1,224 @@ +package de.dhbw.compiler.syntaxtree.visual; + +import de.dhbw.compiler.syntaxtree.*; +import de.dhbw.compiler.syntaxtree.statement.*; +import de.dhbw.compiler.syntaxtree.statement.Literal; +import de.dhbw.compiler.syntaxtree.type.*; + +public class TypeOutputGenerator extends OutputGenerator { + + TypeOutputGenerator(StringBuilder out){ + super(out); + } + + @Override + public void visit(SourceFile sourceFile) { + super.visit(sourceFile); + } + + @Override + public void visit(ArgumentList argumentList) { + super.visit(argumentList); + } + + @Override + public void visit(GenericTypeVar genericTypeVar) { + super.visit(genericTypeVar); + } + + @Override + public void visit(FormalParameter formalParameter) { + super.visit(formalParameter); + } + + @Override + public void visit(GenericDeclarationList genericTypeVars) { + super.visit(genericTypeVars); + } + + @Override + public void visit(Field field) { + super.visit(field); + } + + @Override + public void visit(Method method) { + super.visit(method); + } + + @Override + public void visit(ParameterList formalParameters) { + super.visit(formalParameters); + } + + @Override + public void visit(ClassOrInterface classOrInterface) { + super.visit(classOrInterface); + } + + @Override + public void visit(RefType refType) { + super.visit(refType); + } + + @Override + public void visit(SuperWildcardType superWildcardType) { + super.visit(superWildcardType); + } + + @Override + public void visit(TypePlaceholder typePlaceholder) { + super.visit(typePlaceholder); + } + + @Override + public void visit(ExtendsWildcardType extendsWildcardType) { + super.visit(extendsWildcardType); + } + + @Override + public void visit(GenericRefType genericRefType) { + super.visit(genericRefType); + } + + @Override + public void visit(LambdaExpression lambdaExpression) { + out.append("("); + super.visit(lambdaExpression); + out.append(")"); + this.out.append("::"); + lambdaExpression.getType().accept(this); + } + + @Override + public void visit(Assign assign) { + super.visit(assign); + } + + @Override + public void visit(BinaryExpr binary) { + binary.lexpr.accept(this); + out.append(" | "); + binary.rexpr.accept(this); + } + + @Override + public void visit(Block block) { + out.append("("); + super.visit(block); + out.append(")"); + this.out.append("::"); + block.getType().accept(this); + } + + @Override + public void visit(CastExpr castExpr) { + super.visit(castExpr); + } + + @Override + public void visit(EmptyStmt emptyStmt) { + super.visit(emptyStmt); + } + + @Override + public void visit(FieldVar fieldVar) { + out.append("("); + super.visit(fieldVar); + out.append(")"); + this.out.append("::"); + fieldVar.getType().accept(this); + } + + @Override + public void visit(ForStmt forStmt) { + super.visit(forStmt); + } + + @Override + public void visit(IfStmt ifStmt) { + super.visit(ifStmt); + } + + @Override + public void visit(InstanceOf instanceOf) { + super.visit(instanceOf); + } + + @Override + public void visit(LocalVar localVar) { + out.append("("); + super.visit(localVar); + out.append(")"); + this.out.append("::"); + localVar.getType().accept(this); + } + + @Override + public void visit(LocalVarDecl localVarDecl) { + super.visit(localVarDecl); + } + + @Override + public void visit(MethodCall methodCall) { + out.append("("); + super.visit(methodCall); + out.append(")"); + this.out.append("::"); + methodCall.getType().accept(this); + } + + @Override + public void visit(NewClass methodCall) { + super.visit(methodCall); + } + + @Override + public void visit(NewArray newArray) { + super.visit(newArray); + } + + @Override + public void visit(ExpressionReceiver receiver) { + super.visit(receiver); + } + + @Override + public void visit(Return aReturn) { + super.visit(aReturn); + } + + @Override + public void visit(ReturnVoid aReturn) { + super.visit(aReturn); + } + + @Override + public void visit(StaticClassName staticClassName) { + super.visit(staticClassName); + } + + @Override + public void visit(Super aSuper) { + super.visit(aSuper); + } + + @Override + public void visit(This aThis) { + out.append("("); + super.visit(aThis); + out.append(")"); + this.out.append("::"); + aThis.getType().accept(this); + } + + @Override + public void visit(WhileStmt whileStmt) { + super.visit(whileStmt); + } + + @Override + public void visit(Literal literal) { + super.visit(literal); + } +} \ No newline at end of file diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/generate/ASTToTargetAST.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/generate/ASTToTargetAST.java new file mode 100644 index 0000000..227dba7 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/generate/ASTToTargetAST.java @@ -0,0 +1,713 @@ +package de.dhbw.compiler.target.generate; + +import de.dhbw.compiler.bytecode.CodeGenException; +import de.dhbw.compiler.bytecode.FunNGenerator; +import de.dhbw.compiler.core.JavaTXCompiler; +import de.dhbw.compiler.environment.ByteArrayClassLoader; +import de.dhbw.compiler.environment.IByteArrayClassLoader; +import de.dhbw.compiler.exceptions.DebugException; +import de.dhbw.compiler.parser.NullToken; +import de.dhbw.compiler.parser.scope.JavaClassName; +import de.dhbw.compiler.syntaxtree.*; +import de.dhbw.compiler.syntaxtree.Record; +import de.dhbw.compiler.syntaxtree.factory.ASTFactory; +import de.dhbw.compiler.syntaxtree.statement.*; +import de.dhbw.compiler.syntaxtree.type.*; +import de.dhbw.compiler.target.tree.*; +import de.dhbw.compiler.target.tree.expression.*; +import de.dhbw.compiler.target.tree.type.*; +import de.dhbw.compiler.typeinference.result.*; + +import java.sql.Array; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * @author dholle + */ +public class ASTToTargetAST { + + record SignaturePair(TypePlaceholder signature, RefTypeOrTPHOrWildcardOrGeneric parameter) {}; + record SignaturePairTarget(TargetType signature, TargetType parameter) {} + + public static RefType OBJECT = ASTFactory.createObjectType(); // TODO It would be better if I could call this directly but the hashcode seems to change + + protected List all; + public Generics generics; + public List currentMethodOverloads; + + final Map> userDefinedGenerics = new HashMap<>(); + final Map> tphsInMethods = new HashMap<>(); + private Method currentMethod; + + public final JavaTXCompiler compiler; + + public List findAllVariants(RefTypeOrTPHOrWildcardOrGeneric type) { + return javaGenerics().stream().map(generics -> generics.resolve(type)).distinct().toList(); + } + + public List txGenerics() { + return all.stream().map(generics -> new GenericsResult(generics.txGenerics)).toList(); + } + + public List javaGenerics() { + return all.stream().map(generics -> new GenericsResult(generics.javaGenerics)).toList(); + } + + public TargetExpression convert(Pattern pattern) { + var converter = new StatementToTargetExpression(this); + pattern.accept(converter); + return converter.result; + } + + public record Generics(JavaGenerics javaGenerics, TxGenerics txGenerics) { + } + + + public IByteArrayClassLoader classLoader; + protected SourceFile sourceFile; + + public ASTToTargetAST(List resultSets) { + this(null, resultSets); + } + public ASTToTargetAST(JavaTXCompiler compiler, List resultSets) { + this(compiler, resultSets, null, new ByteArrayClassLoader()); + } + + public ASTToTargetAST(JavaTXCompiler compiler, List resultSets, SourceFile sourceFile, IByteArrayClassLoader classLoader) { + this.compiler = compiler; + this.classLoader = classLoader; + this.sourceFile = sourceFile; + + all = new ArrayList<>(); + for (var set : resultSets) { + all.add(new Generics(new JavaGenerics(this, set), new TxGenerics(this, set))); + } + this.generics = all.get(0); + } + + public void addSignaturePair(TypePlaceholder signature, RefTypeOrTPHOrWildcardOrGeneric parameter) { + var set = tphsInMethods.getOrDefault(currentMethod, new HashSet<>()); + set.add(new SignaturePair(signature, parameter)); + tphsInMethods.put(currentMethod, set); + } + + Optional findMethod(ClassOrInterface owner, String name, List argumentList) { + Optional method = Optional.empty(); + while (method.isEmpty()) { + method = owner.getMethods().stream().filter(m -> m.name.equals(name) && parameterEquals(m.getParameterList(), argumentList)).findFirst(); + if (owner.getClassName().toString().equals("java.lang.Object")) break; + owner = compiler.getClass(owner.getSuperClass().getName()); + } + return method; + } + + Optional findConstructor(ClassOrInterface owner, List argumentList) { + return owner.getConstructors().stream().filter(c -> parameterEquals(c.getParameterList(), argumentList)).findFirst(); + } + + boolean parameterEquals(ParameterList parameterList, List arguments) { + var pars = parameterList.getFormalparalist(); + if (pars.size() != arguments.size()) + return false; + + for (var i = 0; i < pars.size(); i++) { + var type1 = convert(pars.get(i).getType(), generics.javaGenerics); + var type2 = arguments.get(i); + if (type1 instanceof TargetGenericType) + return true; + if (TargetType.toPrimitive(type2).equals(type1)) + return true; + if (!type1.equals(type2)) + return false; + } + + return true; + } + + Set convert(Set result, GenerateGenerics generics) { + return result.stream().map(p -> { + if (p instanceof GenerateGenerics.PairLT pair) { + return new TargetGeneric(pair.left.resolve().getName(), convert(pair.right.resolve(), generics)); + } else if (p instanceof GenerateGenerics.PairEQ pair) { + return new TargetGeneric(pair.left.resolve().getName(), convert(pair.right, generics)); + } else { + throw new IllegalArgumentException(); + } + }).collect(Collectors.toSet()); + } + + public List convert(GenericTypeVar typeVar, GenerateGenerics generics) { + var ret = new ArrayList(); + for (var bound : typeVar.getBounds()) { + ret.add(new TargetGeneric(typeVar.getName(), generics.getTargetType(bound))); + } + return ret; + } + + // This is used to serve as a custom equality to signature that performs a weak check without going into record patterns. + // The two signatures are considered equal if all the argument types match. + record WeakSignature(TargetMethod.Signature signature) { + @Override + public boolean equals(Object o) { + if (!(o instanceof WeakSignature other)) return false; + if (other.signature.parameters().size() != signature.parameters().size()) return false; + for (var i = 0; i < signature.parameters().size(); i++) { + var p1 = signature.parameters().get(i).pattern().type(); + var p2 = other.signature.parameters().get(i).pattern().type(); + if (!p1.equals(p2)) return false; + } + return true; + } + + @Override + public int hashCode() { + return Objects.hash(signature.parameters().stream().map(p -> p.pattern().type()).toArray()); + } + } + + public List> groupOverloads(ClassOrInterface input, List methods) { + var res = new ArrayList>(); + var mapOfSignatures = new HashMap>(); + for (var method : methods) { + // Convert all methods + var methodsWithTphs = convert(input, method); + // Then check for methods with the same signature + for (var m : methodsWithTphs) { + var signature = new WeakSignature(m.method.signature()); + var methodsWithSameSignature = mapOfSignatures.getOrDefault(signature, new ArrayList<>()); + methodsWithSameSignature.add(m); + mapOfSignatures.put(signature, methodsWithSameSignature); + } + } + + for (var methodsWithSignature : mapOfSignatures.values()) { + var resMethods = new HashSet(); + outer: for (var m1 : methodsWithSignature) { + for (var m2 : methodsWithSignature) { + for (var i = 0; i < m1.args.size(); i++) { + var arg1 = m1.args.get(i); + var arg2 = m2.args.get(i); + if (arg1.parameter.equals(arg2.parameter)) { + if (isSupertype(arg1.signature, arg2.signature) && + !arg1.signature.equals(arg2.signature)) continue outer; + } + } + } + resMethods.add(m1.method); + } + res.add(resMethods.stream().toList()); + } + + return res; + } + + public TargetStructure convert(ClassOrInterface input) { + Set javaGenerics = new HashSet<>(); + Set txGenerics = new HashSet<>(); + + var genericsIter = input.getGenerics().iterator(); + if (genericsIter.hasNext()) { + // Add empty set of generics to cache so that it doesn't try to calculate it later + var userDefinedGenerics = new HashSet(); + this.userDefinedGenerics.put(input, userDefinedGenerics); + while (genericsIter.hasNext()) { + var next = genericsIter.next(); + userDefinedGenerics.add(next); + // TODO Support multiple bounds + javaGenerics.add(new TargetGeneric(next.getName(), convert(next.getBounds().get(0)))); + } + } else { + this.userDefinedGenerics.put(input, new HashSet<>()); + // Generate generics only if there are no user defined ones + javaGenerics = convert(generics.javaGenerics.generics(input), generics.javaGenerics); + txGenerics = convert(generics.txGenerics.generics(input), generics.txGenerics); + } + + TargetBlock fieldInitializer = null; + if (input.getfieldInitializations().isPresent()) + fieldInitializer = convert(input.getfieldInitializations().get().block); + TargetBlock finalFieldInitializer = fieldInitializer; + + var superInterfaces = input.getSuperInterfaces().stream().map(clazz -> convert(clazz, generics.javaGenerics)).toList(); + var constructors = input.getConstructors().stream().map(constructor -> this.convert(input, constructor, finalFieldInitializer)).flatMap(List::stream).toList(); + var fields = input.getFieldDecl().stream().map(this::convert).toList(); + var methods = groupOverloads(input, input.getMethods()).stream().map(m -> generatePatternOverloads(input, m)).flatMap(List::stream).toList(); + + TargetMethod staticConstructor = null; + if (input.getStaticInitializer().isPresent()) + staticConstructor = this.convert(input, input.getStaticInitializer().get()).stream().findFirst().orElseThrow().method; + + if (input instanceof Record) + return new TargetRecord(input.getModifiers(), input.getClassName(), javaGenerics, txGenerics, superInterfaces, constructors, staticConstructor, fields, methods); + else if (input.isInterface()) + return new TargetInterface(input.getModifiers(), input.getClassName(), javaGenerics, txGenerics, methods, superInterfaces, staticConstructor); + else return new TargetClass(input.getModifiers(), input.getClassName(), convert(input.getSuperClass(), generics.javaGenerics), javaGenerics, txGenerics, superInterfaces, constructors, staticConstructor, fields, methods); + } + + public List convert(ParameterList input, GenerateGenerics generics) { + var res = new ArrayList(); + for (var i = 0; i < input.getFormalparalist().size(); i++) { + var param = input.getFormalparalist().get(i); + var pattern = (TargetPattern) convert(param); + if (pattern instanceof TargetComplexPattern) pattern = pattern.withName("__var" + i); + res.add(new MethodParameter(pattern)); + } + return res; + } + + private boolean hasGeneric(Set generics, GenericRefType type) { + return generics.stream().anyMatch(g -> g.name().equals(type.getParsedName())); + } + + private Set collectMethodGenerics(ClassOrInterface clazz, GenerateGenerics generateGenerics, Set generics, Method input) { + var convertedGenerics = new HashSet<>(convert(generics, generateGenerics)); + outer: for (GenericTypeVar typeVar : input.getGenerics()) { + for (var classGeneric : clazz.getGenerics()) { + if (classGeneric.equals(typeVar)) { + continue outer; + } + } + convertedGenerics.addAll(convert(typeVar, generateGenerics)); + } + /* + * var returnType = sigma.getType(input.getReturnType(), equality); if ((returnType instanceof GenericRefType refType) && !hasGeneric(convertedGenerics, refType)) { convertedGenerics.add(new TargetGeneric(refType.getParsedName(), convert(OBJECT))); } for (var param : input.getParameterList()) { var type = sigma.getType(param.getType(), equality); if (type instanceof GenericRefType refType && !hasGeneric(convertedGenerics, refType)) { convertedGenerics.add(new + * TargetGeneric(refType.getParsedName(), convert(OBJECT))); } } + */ + + return convertedGenerics; + } + + private List convert(ClassOrInterface currentClass, Constructor input, TargetBlock fieldInitializer) { + generics = all.get(0); + List result = new ArrayList<>(); + Set> parameterSet = new HashSet<>(); + this.currentMethod = input; + + for (var s : all) { + generics = s; + var javaGenerics = this.generics.javaGenerics.generics(currentClass, input); + var txGenerics = this.generics.txGenerics.generics(currentClass, input); + List params = convert(input.getParameterList(), this.generics.javaGenerics); + if (parameterSet.stream().noneMatch(p -> p.equals(params))) { + List txParams = convert(input.getParameterList(), this.generics.txGenerics); + var javaMethodGenerics = collectMethodGenerics(currentClass, generics.javaGenerics(), javaGenerics, input); + var txMethodGenerics = collectMethodGenerics(currentClass, generics.txGenerics(), txGenerics, input); + + result.add(new TargetConstructor(input.modifier, javaMethodGenerics, txMethodGenerics, params, txParams, convert(input.block), fieldInitializer)); + parameterSet.add(params); + } + } + + return result; + } + + private String encodeName(String name, TargetMethod.Signature params) { + var res = new StringBuilder(); + res.append(name); + res.append('$'); + for (var param : params.parameters()) { + encodeName(param.pattern(), res); + } + return res.toString(); + } + + private void encodeName(TargetPattern pattern, StringBuilder res) { + if (pattern instanceof TargetComplexPattern cp) { + res.append(FunNGenerator.encodeType(cp.type())); + for (var pat : cp.subPatterns()) { + encodeName(pat, res); + } + } else { + res.append(FunNGenerator.encodeType(pattern.type())); + } + } + + private TargetExpression generatePatternOverloadsRec(int offset, TargetExpression switchExpr, List params, List patterns, List methods, TargetType classType) { + if (methods.isEmpty()) throw new DebugException("Couldn't find a candidate for switch overloading"); + if (methods.size() == 1) { + var method = methods.getFirst(); + TargetExpression caseBody = new TargetMethodCall( + method.signature().returnType(), + new TargetThis(classType), + params, + classType, + method.name(), + false, false, method.isPrivate() + ); + if (method.signature().returnType() != null) { + caseBody = new TargetReturn(caseBody); + } + return caseBody; + } + + var cases = new ArrayList(); + var usedPatterns = new HashSet(); + + for (var method : methods) { + var patternsRec = new ArrayList<>(patterns); + + TargetExpression expr = null; + var i = 0; + for (var param : method.signature().parameters()) { + if (param.pattern() instanceof TargetComplexPattern pat) { + if (i == offset) { + patternsRec.add(pat); + } + if (i > offset) { + // Find next pattern + var pattern = param.pattern(); + expr = new TargetLocalVar(pattern.type(), pattern.name()); + break; + } + i++; + } + } + + var lastPattern = patternsRec.getLast(); + if (usedPatterns.contains(lastPattern)) continue; + usedPatterns.add(lastPattern); + + var candidates = methods.stream().filter(m -> { + var j = 0; + for (var param : m.signature().parameters()) { + if (j >= patternsRec.size()) return true; + if (param.pattern() instanceof TargetComplexPattern) { + if (!patternsRec.get(j).equals(param.pattern())) return false; + j++; + } + } + return true; + }).toList(); + + var caseBody = generatePatternOverloadsRec(offset + 1, expr, params, patternsRec, candidates, classType); + var body = new TargetBlock(List.of(caseBody)); + var case_ = new TargetSwitch.Case(List.of(lastPattern), body); + + cases.add(case_); + } + + return new TargetSwitch(switchExpr, cases, null, true); + } + + private List generatePatternOverloads(ClassOrInterface clazz, List overloadedMethods) { + if (overloadedMethods.size() <= 1) return overloadedMethods; + // Check if we have a pattern as a parameter + var firstMethod = overloadedMethods.getFirst(); + if (firstMethod.signature().parameters().stream().noneMatch(mp -> mp.pattern() instanceof TargetComplexPattern)) return overloadedMethods; + // Rename existing methods + + var res = new ArrayList(); + for (var method : overloadedMethods) { + var name = encodeName(method.name(), method.signature()); + res.add(new TargetMethod(method.access(), name, method.block(), method.signature(), method.txSignature())); + } + + var signatureParams = firstMethod.signature().parameters().stream().map(p -> { + if (p.pattern() instanceof TargetComplexPattern pat) { + return new MethodParameter(pat.type(), pat.name()); + } + return p; + }).toList(); + var parameters = firstMethod.signature().parameters().stream().map( p -> (TargetExpression) new TargetLocalVar(p.pattern().type(), p.pattern().name())).toList(); + //var patterns = List.of((TargetComplexPattern) firstMethod.signature().parameters().stream() + // .filter(p -> p.pattern() instanceof TargetComplexPattern).findFirst().orElseThrow().pattern()); + var firstPattern = firstMethod.signature().parameters().stream().filter(p -> p.pattern() instanceof TargetComplexPattern).findFirst().orElseThrow().pattern(); + + // Generate dispatch method + var classType = new TargetRefType(clazz.getClassName().getClassName()); + var stmt = generatePatternOverloadsRec(0, new TargetLocalVar(firstPattern.type(), firstPattern.name()), parameters, List.of(), res, classType); + var block = new TargetBlock(List.of(stmt)); + + var signature = new TargetMethod.Signature(firstMethod.signature().generics(), signatureParams, firstMethod.signature().returnType()); + var bridgeMethod = new TargetMethod(firstMethod.access(), firstMethod.name(), block, signature, firstMethod.txSignature()); + + res.add(bridgeMethod); + return res; + } + + private Expression makeRecordSwitch(RefTypeOrTPHOrWildcardOrGeneric returnType, ParameterList params, List overloadedMethods) { + var param = params.getFormalparalist().get(0); + assert param instanceof RecordPattern; // TODO + + var cases = new ArrayList(); + for (var method : overloadedMethods) { + var statements = new ArrayList(); + /*statements.add(new MethodCall( + method.getReturnType(), new ExpressionReceiver(new This(new NullToken())), method.name, + params, + ));*/ + + var block = new Block(statements, new NullToken()); + var labels = new ArrayList(); + cases.add(new SwitchBlock(labels, block, true, new NullToken())); + } + var swtch = new Switch(new LocalVar("par0", param.getType(), new NullToken()), cases, returnType, false, new NullToken()); + + return swtch; + } + + private Optional findSuperMethodToOverride(ClassOrInterface currentClass, String name, List params) { + var superClass = compiler.getClass(currentClass.getSuperClass().getName()); + var methodStream = superClass.getMethods().stream(); + for (var superInterface : currentClass.getSuperInterfaces()) { + methodStream = Stream.concat(methodStream, compiler.getClass(superInterface.getName()).getMethods().stream()); + } + + return methodStream.filter(m -> { + if (!m.name.equals(name)) return false; + var sParams = m.getParameterList(); + if (sParams.getFormalparalist().size() != params.size()) return false; + for (var i = 0; i < params.size(); i++) { + var a = TargetType.toPrimitive(params.get(i).pattern().type()); + var b = convert(sParams.getFormalparalist().get(i).getType()); + if (!Objects.equals(a, b)) return false; + } + return true; + }).findFirst(); + } + + record MethodWithTphs(TargetMethod method, List args) {} + + record Signature(TargetMethod.Signature java, TargetMethod.Signature tx, Generics generics) {} + + private List convert(ClassOrInterface currentClass, Method method) { + generics = all.getFirst(); + List result = new ArrayList<>(); + this.currentMethod = method; + + List signatures = new ArrayList<>(); + HashMap> collectedGenerics = new HashMap<>(); + + for (var s : all) { + generics = s; + var javaGenerics = this.generics.javaGenerics.generics(currentClass, method); + var txGenerics = this.generics.txGenerics.generics(currentClass, method); + List params = convert(method.getParameterList(), this.generics.javaGenerics); + var returnType = convert(method.getReturnType(), this.generics.javaGenerics); + var superMethod = findSuperMethodToOverride(currentClass, method.getName(), params); + if (superMethod.isPresent()) { + // If we find a super method to override, use its parameters and return types + var newReturnType = convert(superMethod.get().getReturnType(), this.generics.javaGenerics); + if (newReturnType instanceof TargetPrimitiveType && TargetType.toPrimitive(returnType).equals(newReturnType)) { + returnType = newReturnType; + params = convert(superMethod.get().getParameterList(), method.getParameterList(), this.generics.javaGenerics); + } + } + + List txParams = convert(method.getParameterList(), this.generics.txGenerics); + + var javaMethodGenerics = collectMethodGenerics(currentClass, generics.javaGenerics(), javaGenerics, method); + var txMethodGenerics = collectMethodGenerics(currentClass, generics.txGenerics(), txGenerics, method); + + var javaSignature = new TargetMethod.Signature(javaMethodGenerics, params, returnType); + var txSignature = new TargetMethod.Signature(txMethodGenerics, txParams, convert(method.getReturnType(), this.generics.txGenerics)); + + signatures.add(new Signature(javaSignature, txSignature, generics)); + var listOfGenerics = collectedGenerics.getOrDefault(javaSignature, new ArrayList<>()); + listOfGenerics.add(generics); + collectedGenerics.put(javaSignature, listOfGenerics); + } + + for (var signature : signatures) { + generics = signature.generics; + currentMethodOverloads = collectedGenerics.get(signature.java); + + var newMethod = new TargetMethod(method.modifier, method.name, convert(method.block), signature.java, signature.tx); + var concreteParams = tphsInMethods.getOrDefault(method, new HashSet<>()).stream().map(sig -> new SignaturePairTarget(convert(sig.signature), convert(sig.parameter))).toList(); + + result.add(new MethodWithTphs(newMethod, concreteParams)); + } + + return result; + } + + private List convert(ParameterList superList, ParameterList paraList, JavaGenerics generics) { + var list = new ArrayList(); + for (var i = 0; i < paraList.getFormalparalist().size(); i++) { + var param = paraList.getParameterAt(i); + var pattern = (TargetPattern) convert(param); + if (pattern instanceof TargetComplexPattern) pattern = pattern.withName("__var" + i); + list.add(new MethodParameter(pattern).withType(convert(superList.getParameterAt(i).getType(), generics))); + } + return list; + } + + protected TargetSwitch.Case convert(SwitchBlock block) { + return new TargetSwitch.Case(block.getLabels().stream().map(this::convert).toList(), convert((Block) block), block.isExpression); + } + + protected TargetBlock convert(Block block) { + if (block == null) return null; + 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); + return converter.result; + } + + private TargetField convert(Field input) { + return new TargetField(input.modifier, convert(input.getType(), generics.javaGenerics), input.getName()); + } + + private final Map usedFunN = new HashMap<>(); + private final Set usedFunNSuperTypes = new HashSet<>(); + + public Map auxiliaries = new HashMap<>(); + + public TargetType convert(RefTypeOrTPHOrWildcardOrGeneric input) { + return convert(input, generics.javaGenerics); + } + + private static void collectArguments(TargetSpecializedType tspec, List newParams) { + for (var i = 0; i < tspec.params().size(); i++) { + var param = tspec.params().get(i); + if (param instanceof TargetSpecializedType fn) { + collectArguments(tspec, newParams); + } else { + newParams.add(param); + } + } + } + + static TargetType flattenFunNType(List params, FunNGenerator.GenericParameters gep) { + var newParams = new ArrayList(); + for (TargetType param : params) { + if (param instanceof TargetSpecializedType fn) { + collectArguments(fn, newParams); + } else { + newParams.add(param); + } + } + var filteredParams = new ArrayList(); + for (var i = 0; i < newParams.size(); i++) { + if (i < gep.inParams.size() && gep.inParams.get(i) != null) + filteredParams.add(newParams.get(i)); + } + return TargetFunNType.fromParams(params, filteredParams, gep.getReturnType() != null ? 1 : 0); + } + + private boolean isSubtype(TargetType test, TargetType other) { + var testClass = compiler.getClass(new JavaClassName(test.name())); + var otherClass = compiler.getClass(new JavaClassName(other.name())); + if (testClass == null) return false; + while (testClass != null) { + if (testClass.equals(otherClass)) return true; + if (testClass.getClassName().equals(new JavaClassName("java.lang.Object"))) break; + testClass = compiler.getClass(testClass.getSuperClass().getName()); + } + return false; + } + + private boolean isSupertype(TargetType test, TargetType other) { + return isSubtype(other, test); + } + + private boolean isSubtype(FunNGenerator.GenericParameters test, FunNGenerator.GenericParameters other) { + if (test.getArguments().size() != other.getArguments().size()) return false; + if (!isSubtype(test.getReturnType(), other.getReturnType())) return false; + for (int i = 0; i < test.getArguments().size(); i++) { + var arg1 = test.getArguments().get(i); + var arg2 = other.getArguments().get(i); + if (!isSupertype(arg1, arg2)) return false; + } + return true; + } + + public void generateFunNTypes() { + for (var entry : usedFunN.entrySet()) { + var gep = entry.getValue(); + var superInterfaces = usedFunN.values().stream() + .filter(g -> !g.equals(gep)) + .filter(genericParameters -> isSubtype(gep, genericParameters)) + .map(FunNGenerator::getSpecializedClassName) + .toList(); + + var code = FunNGenerator.generateSpecializedBytecode(gep, superInterfaces); + + try { + classLoader.findClass(entry.getKey()); + } catch (ClassNotFoundException e) { + try { + classLoader.loadClass(code); + } catch (LinkageError ignored) {} + } + auxiliaries.put(entry.getKey(), code); + } + } + + protected TargetType convert(RefTypeOrTPHOrWildcardOrGeneric input, GenerateGenerics generics) { + return input.acceptTV(new TypeVisitor<>() { + @Override + public TargetType visit(RefType refType) { + var name = refType.getName().toString(); + if (name.equals("void")) + return null; + if (refType.isPrimitive()) { + return TargetType.toPrimitive(refType); + } + + var params = refType.getParaList().stream().map(type -> { + return convert(type, generics); + }).toList(); + + if (name.matches("Fun\\d+\\$\\$")) { // TODO This seems like a bad idea + var returnType = FunNGenerator.getReturnType(params); + var className = FunNGenerator.getSpecializedClassName(FunNGenerator.getArguments(params), returnType); + if (!usedFunNSuperTypes.contains(params.size())) { + usedFunNSuperTypes.add(params.size()); + var code = FunNGenerator.generateSuperBytecode(params.size() - 1, returnType != null ? 1 : 0); + var superClassName = FunNGenerator.getSuperClassName(params.size() - 1, returnType != null ? 1 : 0); + try { + classLoader.findClass(superClassName); + } catch (ClassNotFoundException e) { + try { + classLoader.loadClass(code); + } catch (LinkageError ignored) {} + } + auxiliaries.put(superClassName, code); + } + FunNGenerator.GenericParameters gep = null; + if (!usedFunN.containsKey(className)) { + gep = new FunNGenerator.GenericParameters(params, returnType != null ? 1 : 0); + usedFunN.put(className, gep); + } else { + gep = usedFunN.get(className); + } + return flattenFunNType(params, gep); + } + return new TargetRefType(name, params); + } + + @Override + public TargetType visit(SuperWildcardType superWildcardType) { + return new TargetSuperWildcard(convert(superWildcardType.getInnerType(), generics)); + } + + @Override + public TargetType visit(TypePlaceholder typePlaceholder) { + return generics.getTargetType(typePlaceholder); + } + + @Override + public TargetType visit(ExtendsWildcardType extendsWildcardType) { + return new TargetExtendsWildcard(convert(extendsWildcardType.getInnerType(), generics)); + } + + @Override + public TargetType visit(GenericRefType genericRefType) { + return new TargetGenericType(genericRefType.getParsedName()); + } + }); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/generate/Bound.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/generate/Bound.java new file mode 100644 index 0000000..027bd27 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/generate/Bound.java @@ -0,0 +1,24 @@ +package de.dhbw.compiler.target.generate; + +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.syntaxtree.type.TypePlaceholder; + +import java.util.List; + +public record Bound(boolean isOnMethod, RefTypeOrTPHOrWildcardOrGeneric bound) { + public static Bound onMethod(String tph) { + return new Bound(true, TypePlaceholder.of(tph)); + } + + public static Bound onMethod(RefTypeOrTPHOrWildcardOrGeneric bound) { + return new Bound(true, bound); + } + + public static Bound onClass(String tph) { + return new Bound(false, TypePlaceholder.of(tph)); + } + + public static Bound onClass(RefTypeOrTPHOrWildcardOrGeneric bound) { + return new Bound(false, bound); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/generate/BoundsList.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/generate/BoundsList.java new file mode 100644 index 0000000..092bf03 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/generate/BoundsList.java @@ -0,0 +1,52 @@ +package de.dhbw.compiler.target.generate; + +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.syntaxtree.type.TypePlaceholder; + +import java.util.AbstractList; +import java.util.List; + +public class BoundsList extends AbstractList { + private final List bounds; + public final RefTypeOrTPHOrWildcardOrGeneric base; + + public BoundsList(RefTypeOrTPHOrWildcardOrGeneric base, List bounds) { + this.base = base; + this.bounds = bounds; + } + + public BoundsList(List bounds) { + this(null, bounds); + } + + public BoundsList(Bound... bounds) { + this(null, List.of(bounds)); + } + + @Override + public Bound get(int index) { + return bounds.get(index); + } + + @Override + public int size() { + return bounds.size(); + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof BoundsList right)) return false; + if (size() != right.size()) return false; + for (var i = 0; i < size(); i++) { + var l = get(i); + var r = right.get(i); + if (l.isOnMethod() != r.isOnMethod()) return false; + if (i == size() - 1) { + if (!(l.bound() instanceof TypePlaceholder)) { + if (!(l.bound().equals(r.bound()))) return false; + } + } + } + return true; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/generate/CycleFinder.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/generate/CycleFinder.java new file mode 100644 index 0000000..81dd35a --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/generate/CycleFinder.java @@ -0,0 +1,104 @@ +package de.dhbw.compiler.target.generate; + +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class CycleFinder { + private CycleFinder() {} + + static Set allNodes(Set input) { + return input.stream() + .filter(GenerateGenerics.PairLT.class::isInstance) + .map(GenerateGenerics.PairLT.class::cast) + .flatMap(pair -> Stream.of(pair.left, pair.right)).collect(Collectors.toSet()); + } + + static Set outgoingEdgesOf(GenerateGenerics.TPH tph, Set input) { + return input.stream() + .filter(GenerateGenerics.PairLT.class::isInstance) + .map(GenerateGenerics.PairLT.class::cast) + .filter(pair -> pair.left.equals(tph)) + .map(pair -> pair.right).collect(Collectors.toSet()); + } + + static boolean containsEdge(GenerateGenerics.TPH a, GenerateGenerics.TPH b, Set input) { + return input.stream() + .filter(GenerateGenerics.PairLT.class::isInstance) + .map(GenerateGenerics.PairLT.class::cast) + .anyMatch(pair -> pair.left.equals(a) && pair.right.equals(b)); + } + + // Tiernan simple cycles algorithm + // Adapted from https://github.com/jgrapht/jgrapht/blob/master/jgrapht-core/src/main/java/org/jgrapht/alg/cycle/TiernanSimpleCycles.java + static Set> findCycles(Set input) { + Map indices = new HashMap<>(); + List path = new ArrayList<>(); + Set pathSet = new HashSet<>(); + Map> blocked = new HashMap<>(); + Set> cycles = new HashSet<>(); + + int index = 0; + for (var tph : allNodes(input)) { + blocked.put(tph, new HashSet<>()); + indices.put(tph, index++); + } + + var vertexIterator = allNodes(input).iterator(); + if (!vertexIterator.hasNext()) return cycles; + + GenerateGenerics.TPH startOfPath = null; + GenerateGenerics.TPH endOfPath = vertexIterator.next(); + GenerateGenerics.TPH temp = null; + int endIndex = 0; + boolean extensionFound = false; + path.add(endOfPath); + pathSet.add(endOfPath); + + while (true) { + do { + extensionFound = false; + for (GenerateGenerics.TPH n : outgoingEdgesOf(endOfPath, input)) { + int cmp = indices.get(n).compareTo(indices.get(path.get(0))); + if ((cmp > 0) && !pathSet.contains(n) && !blocked.get(endOfPath).contains(n)) { + path.add(n); + pathSet.add(n); + endOfPath = n; + extensionFound = true; + break; + } + } + } while (extensionFound); + + startOfPath = path.get(0); + if (containsEdge(endOfPath, startOfPath, input)) { + List cycle = new ArrayList<>(path); + cycles.add(cycle); + } + if (path.size() > 1) { + blocked.get(endOfPath).clear(); + endIndex = path.size() - 1; + path.remove(endIndex); + pathSet.remove(endOfPath); + --endIndex; + temp = endOfPath; + endOfPath = path.get(endIndex); + blocked.get(endOfPath).add(temp); + continue; + } + if (vertexIterator.hasNext()) { + path.clear(); + pathSet.clear(); + endOfPath = vertexIterator.next(); + path.add(endOfPath); + pathSet.add(endOfPath); + for (GenerateGenerics.TPH tph : blocked.keySet()) { + blocked.get(tph).clear(); + } + continue; + } + break; + } + return cycles; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/generate/GenerateGenerics.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/generate/GenerateGenerics.java new file mode 100644 index 0000000..d801d20 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/generate/GenerateGenerics.java @@ -0,0 +1,990 @@ +package de.dhbw.compiler.target.generate; + +import de.dhbw.compiler.parser.NullToken; +import de.dhbw.compiler.syntaxtree.ClassOrInterface; +import de.dhbw.compiler.syntaxtree.Constructor; +import de.dhbw.compiler.syntaxtree.GenericTypeVar; +import de.dhbw.compiler.syntaxtree.Method; +import de.dhbw.compiler.syntaxtree.statement.*; +import de.dhbw.compiler.syntaxtree.type.*; +import de.dhbw.compiler.syntaxtree.type.Void; +import de.dhbw.compiler.target.tree.type.TargetGenericType; +import de.dhbw.compiler.target.tree.type.TargetType; +import de.dhbw.compiler.typeinference.result.PairTPHEqualTPH; +import de.dhbw.compiler.typeinference.result.PairTPHequalRefTypeOrWildcardType; +import de.dhbw.compiler.typeinference.result.PairTPHsmallerTPH; +import de.dhbw.compiler.typeinference.result.ResultSet; + +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public abstract class GenerateGenerics { + + private final ASTToTargetAST astToTargetAST; + + public class TPH { + private final TypePlaceholder wrap; + + TPH(TypePlaceholder wrap) { + this.wrap = wrap; + } + + public TypePlaceholder resolve() { + return equality.getOrDefault(wrap, wrap); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TPH tph = (TPH) o; + return Objects.equals(resolve(), tph.resolve()); + } + + @Override + public int hashCode() { + return Objects.hash(resolve()); + } + + @Override + public String toString() { + return resolve().getName(); + } + } + + public abstract class Pair { + public final TPH left; + + Pair(TPH left) { + this.left = left; + } + + public abstract RefTypeOrTPHOrWildcardOrGeneric resolveRight(); + } + + public class PairLT extends Pair { + public final TPH right; + + PairLT(TPH left, TPH right) { + super(left); + this.right = right; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PairLT pairLT = (PairLT) o; + return Objects.equals(right, pairLT.right) && Objects.equals(left, pairLT.left); + } + + @Override + public int hashCode() { + return Objects.hash(right, left); + } + + @Override + public RefTypeOrTPHOrWildcardOrGeneric resolveRight() { + return right.resolve(); + } + + @Override + public String toString() { + return "(" + left + " < " + right + ")"; + } + } + + public class PairEQ extends Pair { + public final RefType right; + + PairEQ(TPH left, RefType right) { + super(left); + this.right = right; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PairEQ pairLT = (PairEQ) o; + return Objects.equals(right, pairLT.right) && Objects.equals(left, pairLT.left); + } + + @Override + public int hashCode() { + return Objects.hash(right, left); + } + + @Override + public RefTypeOrTPHOrWildcardOrGeneric resolveRight() { + return right; + } + + @Override + public String toString() { + return "(" + left + " = " + right + ")"; + } + } + + final Map> computedGenericsOfMethods = new HashMap<>(); + final Map> computedGenericsOfClasses = new HashMap<>(); + + final Map> usedTPHsOfMethods = new HashMap<>(); + final Map> familyOfMethods = new HashMap<>(); + + final Set simplifiedConstraints = new HashSet<>(); + Map concreteTypes = new HashMap<>(); + Map equality = new HashMap<>(); + + GenerateGenerics(ASTToTargetAST astToTargetAST, ResultSet constraints) { + this.astToTargetAST = astToTargetAST; + for (var constraint : constraints.results) { + if (constraint instanceof PairTPHsmallerTPH p) { + System.out.println(p.left + " " + p.left.getVariance()); + simplifiedConstraints.add(new PairLT(new TPH(p.left), new TPH(p.right))); + } else if (constraint instanceof PairTPHEqualTPH p) { + equality.put(p.getLeft(), p.getRight()); + } else if (constraint instanceof PairTPHequalRefTypeOrWildcardType p) { + System.out.println(p.left + " = " + p.right); + concreteTypes.put(new TPH(p.left), p.right); + } + } + + System.out.println("Simplified constraints: " + simplifiedConstraints); + } + + /*public record GenericsState(Map concreteTypes, Map equality) {} + + public GenericsState store() { + return new GenericsState(new HashMap<>(concreteTypes), new HashMap<>(equality)); + } + + public void restore(GenericsState state) { + this.concreteTypes = state.concreteTypes; + this.equality = state.equality; + } + + public void addOverlay(TypePlaceholder from, RefTypeOrTPHOrWildcardOrGeneric to) { + if (to instanceof TypePlaceholder t) equality.put(from, t); + else if (to instanceof RefType t) concreteTypes.put(new TPH(from), t); + }*/ + + Set findTypeVariables(RefTypeOrTPHOrWildcardOrGeneric type) { + var result = new HashSet(); + if (type instanceof TypePlaceholder tph) { + var nTph = new TPH(tph); + if (concreteTypes.containsKey(nTph)) { + result.addAll(findTypeVariables(concreteTypes.get(nTph))); + return result; + } + result.add(nTph); + } else if (type instanceof RefType refType) { + for (var t : refType.getParaList()) + result.addAll(findTypeVariables(t)); + } else if (type instanceof ExtendsWildcardType wildcardType) { + result.addAll(findTypeVariables(wildcardType.getInnerType())); + } else if (type instanceof SuperWildcardType wildcardType) { + result.addAll(findTypeVariables(wildcardType.getInnerType())); + } + return result; + } + + boolean containsRelation(Set result, PairLT pair) { + // Check if both the right and the left are already part of a relation + var containsLeft = false; + for (var pair2 : result) { + if (pair2.left.equals(pair.left)) { + containsLeft = true; + break; + } + } + var containsRight = false; + for (var pair2 : result) + if (pair2 instanceof PairLT plt) { + if (plt.right.equals(pair.right)) { + containsRight = true; + break; + } + } + return containsLeft && containsRight; + } + + void addToPairs(Set input, Pair pair) { + if (pair instanceof PairLT plt) { + input.removeIf(pair2 -> { + if (pair2 instanceof PairEQ peq) { + return peq.left.equals(plt.left) && peq.right.equals(ASTToTargetAST.OBJECT); + } + return false; + }); + } else if (input.stream().anyMatch(p -> p.left.equals(pair.left))) { + return; + } + + input.add(pair); + } + + void addToEquality(TypePlaceholder from, TypePlaceholder to, Set referenced) { + for (var entry : new HashSet<>(equality.entrySet())) { + if (entry.getValue().equals(from)) { + equality.remove(entry.getKey()); + equality.put(entry.getKey(), to); + } + } + System.out.println(from + " -> " + to + " " + from.getVariance()); + //from.setVariance(to.getVariance()); + equality.put(from, to); + referenced.remove(new TPH(from)); + referenced.add(new TPH(to)); + } + + Set transitiveClosure(Set generics) { + Set all = new HashSet<>(generics); + Set toAdd = new HashSet<>(); + int sizeBefore; + do { + sizeBefore = all.size(); + toAdd.clear(); + for (var g1 : all) { + for (var g2 : all) { + if (g1 instanceof PairLT pair && g2 instanceof PairLT pair2) { + if (pair2.left.equals(pair.right)) + toAdd.add(new PairLT(pair.left, pair2.right)); + } + } + } + all.addAll(toAdd); + } while (sizeBefore < all.size()); + return all; + } + + private void methodFindConstraints( + ClassOrInterface owner, Method method, + Set typeVariables, + Set typeVariablesOfClass, + Set result + ) { + var userDefinedGenericsOfClass = astToTargetAST.userDefinedGenerics.get(owner); + + // Type variables with bounds that are also type variables of the method + for (var typeVariable : new HashSet<>(typeVariables)) { + if (classHasGeneric(userDefinedGenericsOfClass, typeVariablesOfClass, typeVariable)) + continue; + for (var pair : simplifiedConstraints) { + if (pair.left.equals(typeVariable) && typeVariables.contains(pair.right)) { + addToPairs(result, new PairLT(pair.left, pair.right)); + } + } + } + + if (method.block != null) + method.block.accept(new TracingStatementVisitor() { + + private RefTypeOrTPHOrWildcardOrGeneric superType = new de.dhbw.compiler.syntaxtree.type.Void(new NullToken()); + + @Override + public void visit(MethodCall methodCall) { + //Anfang es werden Paare von TPHs gespeichert, die bei den Generated Generics ueber die Methodengrenzen hinweg + //betrachtet werden muessen + //Definition 7.2 (Family of generated generics). T1 <. R1 <.^∗ R2 <. T2 + Set T1s = + methodCall.getArgumentList() + .getArguments() + .stream() + .map(TypableStatement::getType) + .collect(Collectors.toCollection(HashSet::new)) + .stream().filter(TypePlaceholder.class::isInstance) + .map(TypePlaceholder.class::cast) + .map(TPH::new) + .collect(Collectors.toCollection(HashSet::new)); + Set T2s = new HashSet<>(); + findTphs(superType, T2s); + + System.out.println("T1s: " + T1s + " T2s: " + T2s); + //Ende + + superType = methodCall.receiverType; + methodCall.receiver.accept(this); + for (int i = 0; i < methodCall.arglist.getArguments().size(); i++) { + superType = methodCall.arglist.getArguments().get(i).getType(); + methodCall.arglist.getArguments().get(i).accept(this); + } + + if (methodCall.receiver instanceof ExpressionReceiver expressionReceiver) { + if (expressionReceiver.expr instanceof This) { + var optMethod = astToTargetAST.findMethod(owner, methodCall.name, methodCall.signatureArguments().stream().map(astToTargetAST::convert).toList()); + if (optMethod.isEmpty()) return; + var method2 = optMethod.get(); + System.out.println("In: " + method.getName() + " Method: " + method2.getName()); + var generics = family(owner, method2); + + // transitive and + var all = transitiveClosure(generics); + // reflexive + var toAdd = new HashSet(); + for (var generic : all) { + toAdd.add(new PairLT(generic.left, generic.left)); + } + all.addAll(toAdd); + + HashSet newPairs = new HashSet<>(); + + // Loop from hell + outer: + for (var R1 : typeVariables) { + if (typeVariablesOfClass.contains(R1)) continue; + for (var generic : all) + if (generic instanceof PairLT ptph) { + for (var pair : simplifiedConstraints) { + if (!(pair.left.equals(R1) && pair.right.equals(ptph.left))) + continue; + + for (var R2 : typeVariables) { + for (var pair2 : simplifiedConstraints) { + + if (!(pair2.right.equals(R2) && pair2.left.equals(ptph.right))) + continue; + if (R1.equals(R2)) continue; + if (!T1s.contains(R1) || !T2s.contains(R2)) continue; + + var newPair = new PairLT(R1, R2); + System.out.println("New pair: " + newPair); + newPairs.add(newPair); + + if (!containsRelation(result, newPair)) + addToPairs(result, newPair); + continue outer; + } + } + } + } + } + simplifiedConstraints.addAll(newPairs); + } + } + } + + @Override + public void visit(LambdaExpression lambdaExpression) { + superType = new Void(new NullToken()); + lambdaExpression.methodBody.accept(this); + } + + @Override + public void visit(Assign assign) { + superType = assign.rightSide.getType(); + assign.rightSide.accept(this); + } + + @Override + public void visit(BinaryExpr binary) { + superType = new Void(new NullToken()); + binary.lexpr.accept(this); + superType = new Void(new NullToken()); + binary.rexpr.accept(this); + } + + @Override + public void visit(Block block) { + for (var expr : block.statements) { + superType = new de.dhbw.compiler.syntaxtree.type.Void(new NullToken()); + expr.accept(this); + } + } + + @Override + public void visit(IfStmt ifStmt) { + superType = new Void(new NullToken()); + ifStmt.expr.accept(this); + superType = new Void(new NullToken()); + ifStmt.then_block.accept(this); + superType = new Void(new NullToken()); + if (ifStmt.else_block != null) + ifStmt.else_block.accept(this); + } + + @Override + public void visit(Return aReturn) { + superType = aReturn.getType(); + aReturn.retexpr.accept(this); + } + + @Override + public void visit(WhileStmt whileStmt) { + superType = new Void(new NullToken()); + whileStmt.expr.accept(this); + superType = new Void(new NullToken()); + whileStmt.loopBlock.accept(this); + } + + @Override + public void visit(ArgumentList arglist) { + for (int i = 0; i < arglist.getArguments().size(); i++) { + superType = arglist.getArguments().get(i).getType(); + arglist.getArguments().get(i).accept(this); + } + } + }); + + var closure = transitiveClosure(simplifiedConstraints); + // Type variables with bounds that are also type variables of the class + for (var typeVariable : new HashSet<>(typeVariables)) { + if (typeVariablesOfClass.contains(typeVariable)) continue; + + var pairs = new HashSet(); + for (var pair : closure) { + if (!(pair instanceof PairLT ptph)) continue; + if (ptph.left.equals(typeVariable) && typeVariablesOfClass.contains(ptph.right)) { + pairs.add(new PairLT(ptph.left, ptph.right)); + } + } + + // Find the closest pair with the minimum amount of steps + PairLT minimalPair = null; + var minSteps = Integer.MAX_VALUE; + for (var pair : pairs) { + var left = pair.left; + var visited = new HashSet(); + var steps = 0; + while (!left.equals(pair.right)) { + visited.add(left); + var found = false; + for (var pair2 : simplifiedConstraints) { + if (left.equals(pair2.left) && !visited.contains(pair2.right)) { + left = pair2.right; + steps += 1; + found = true; + break; + } + } + if (!found) break; + } + if (steps < minSteps) { + minSteps = steps; + minimalPair = pair; + } + } + + if (minimalPair != null) + addToPairs(result, minimalPair); + } + + // All unbounded type variables (bounds not in method) + outer: + for (var typeVariable : typeVariables) { + if (classHasGeneric(userDefinedGenericsOfClass, typeVariablesOfClass, typeVariable)) + continue; + for (var pair : result) { + if (pair.left.equals(typeVariable)) + continue outer; + } + addToPairs(result, new PairEQ(typeVariable, ASTToTargetAST.OBJECT)); + } + + // All unbounded bounds + outer: + for (var pair : simplifiedConstraints) { + for (var pair2 : simplifiedConstraints) { + if (pair.right.equals(pair2.left)) + continue outer; + } + if (!classHasGeneric(userDefinedGenericsOfClass, typeVariablesOfClass, pair.right) && typeVariables.contains(pair.right)) { + addToPairs(result, new PairEQ(pair.right, ASTToTargetAST.OBJECT)); + } + } + } + + private boolean classHasGeneric(Set userDefinedGenericsOfClass, Set typeVariablesOfClass, TPH typeVariable) { + return typeVariablesOfClass.contains(typeVariable) || userDefinedGenericsOfClass.stream().anyMatch(g -> g.getName().equals(typeVariable.resolve().getName())); + } + + private void methodFindTypeVariables( + Method method, + Set typeVariables + ) { + + if (!(method instanceof Constructor)) + typeVariables.addAll(findTypeVariables(method.getReturnType())); + for (var arg : method.getParameterList().getFormalparalist()) { + typeVariables.addAll(findTypeVariables(arg.getType())); + } + + if (method.block != null) + method.block.accept(new TracingStatementVisitor() { + @Override + public void visit(LocalVarDecl localVarDecl) { + typeVariables.addAll(findTypeVariables(localVarDecl.getType())); + } + + @Override + public void visit(MethodCall methodCall) { + super.visit(methodCall); + typeVariables.addAll(findTypeVariables(methodCall.getType())); + } + }); + } + + abstract void generics(ClassOrInterface owner, Method method, Set result, Set javaTypeVariablesOfClass); + + Set family(ClassOrInterface owner, Method method) { + Set result = new HashSet<>(); + if (familyOfMethods.containsKey(method)) + return familyOfMethods.get(method); + + familyOfMethods.put(method, result); + + var classGenerics = generics(owner); + HashSet typeVariablesOfClass = new HashSet<>(); + + for (var pair : classGenerics) { + typeVariablesOfClass.add(pair.left); + } + + HashSet javaTypeVariables = new HashSet<>(); + + methodFindTypeVariables(method, javaTypeVariables); + methodFindConstraints(owner, method, javaTypeVariables, typeVariablesOfClass, result); + eliminateTransitives(result); + + return result; + } + + Set generics(ClassOrInterface owner, Method method) { + if (computedGenericsOfMethods.containsKey(method)) { + var cached = computedGenericsOfMethods.get(method); + System.out.println("Cached " + method.getName() + ": " + cached); + return cached; + } + + var result = new HashSet(); + computedGenericsOfMethods.put(method, result); + + var classGenerics = generics(owner); + HashSet typeVariablesOfClass = new HashSet<>(); + for (var pair : classGenerics) { + typeVariablesOfClass.add(pair.left); + } + + result.addAll(family(owner, method)); + + var referenced = new HashSet(); + + var usedTphs = new HashSet(); + // For eliminating inner type variables we need to figure out which ones are actually used + for (var param : method.getParameterList().getFormalparalist()) { + usedTphs.addAll(findTypeVariables(param.getType())); + } + usedTphs.addAll(findTypeVariables(method.getReturnType())); + referenced.addAll(usedTphs); + referenced.addAll(typeVariablesOfClass); + + generics(owner, method, result, referenced); + usedTPHsOfMethods.put(method, usedTphs); + + normalize(result, classGenerics, usedTphs); + + System.out.println(this.getClass().getSimpleName() + " " + method.name + ": " + result); + return result; + } + + private void eliminateChain(Set result, List chain) { + for (var pair : new HashSet<>(result)) { + if (pair instanceof PairLT ptph && chain.get(chain.size() - 1).equals(ptph.left)) { + if (chain.contains(ptph.right)) return; + var copy = new ArrayList<>(chain); + copy.add(ptph.right); + if (copy.size() > 2) + result.remove(new PairLT(chain.get(0), ptph.right)); + eliminateChain(result, copy); + } + } + } + + void eliminateTransitives(Set result) { + for (var pair : new HashSet<>(result)) + if (pair instanceof PairLT ptph) { + var first = ptph.left; + var chain = new ArrayList(); + chain.add(ptph.left); + chain.add(ptph.right); + eliminateChain(result, chain); + } + } + + void findAllBounds(RefTypeOrTPHOrWildcardOrGeneric type, Set generics) { + if (type instanceof TypePlaceholder tph) { + var nTph = new TPH(tph); + var concreteType = concreteTypes.get(nTph); + if (concreteType != null) { + findAllBounds(concreteType, generics); + return; + } + + var found = false; + for (var rsp : simplifiedConstraints) { + if (rsp.left.equals(nTph)) { + var pair = new PairLT(new TPH(tph), rsp.right); + if (!generics.contains(pair)) { + addToPairs(generics, pair); + findAllBounds(rsp.right.resolve(), generics); + found = true; + } + } + } + if (!found) + addToPairs(generics, new PairEQ(nTph, ASTToTargetAST.OBJECT)); + } else if (type instanceof RefType refType) { + refType.getParaList().forEach(t -> findAllBounds(t, generics)); + } + } + + abstract void generics(ClassOrInterface classOrInterface, Set result, Set referenced); + + Set generics(ClassOrInterface classOrInterface) { + if (computedGenericsOfClasses.containsKey(classOrInterface)) + return computedGenericsOfClasses.get(classOrInterface); + + Set javaResult = new HashSet<>(); + computedGenericsOfClasses.put(classOrInterface, javaResult); + + for (var field : classOrInterface.getFieldDecl()) { + findAllBounds(field.getType(), javaResult); + } + + var referenced = new HashSet(); + eliminateTransitives(javaResult); + generics(classOrInterface, javaResult, referenced); + + var referencedByClass = new HashSet(); + for (var field : classOrInterface.getFieldDecl()) { + findTphs(field.getType(), referencedByClass); + } + + normalize(javaResult, null, referencedByClass); + + System.out.println(this.getClass().getSimpleName() + " Class " + classOrInterface.getClassName().getClassName() + ": " + javaResult); + return javaResult; + } + + void normalize(Set result, Set classGenerics, Set usedTphs) { + for (var p1 : new HashSet<>(result)) { + if (p1 instanceof PairLT ptph && ptph.left.resolve().equals(ptph.right.resolve())) + result.remove(p1); // TODO This is a bit strange + } + + for (var tph : usedTphs) { + if (classGenerics == null || classGenerics.stream().noneMatch((pair) -> pair.left.equals(tph))) + addToPairs(result, new PairEQ(tph, ASTToTargetAST.OBJECT)); + } + } + + private record ToAdd(TypePlaceholder left, TypePlaceholder right) {} + + void equalizeTypeVariables(Set input, Set referenced) { + + var elementsToAddToEquality = new ArrayList(); + + for (var pair : new HashSet<>(input)) { + if (pair instanceof PairLT ptph && referenced.contains(ptph.left)) { + var chain = new ArrayList(); + chain.add(ptph.left); + chain.add(ptph.right); + + outer: + while (true) { + var added = false; + for (var pair2 : input) { + if (pair2 instanceof PairLT ptph2 && ptph2.left.equals(chain.get(chain.size() - 1))) { + if (chain.contains(ptph2.right)) break outer; + chain.add(ptph2.right); + added = true; + } + } + if (!added) break; + } + + System.out.println(chain + " " + chain.stream().map(e -> e.resolve().getVariance()).toList()); + var variance = chain.get(0).resolve().getVariance(); + if (variance != 1) continue; + var index = 0; + for (var tph : chain) { + if (variance == 1 && tph.resolve().getVariance() == -1) { + variance = -1; + } + if (variance == -1 && tph.resolve().getVariance() == 1 && referenced.contains(tph)) { + break; + } + index++; + } + if (variance == 1) continue; + + + var start = chain.get(0); + var prev = start; + for (var i = 1; i < index; i++) { + var cur = chain.get(i); + if (!referenced.contains(cur)) continue; + elementsToAddToEquality.add(new ToAdd(cur.resolve(), start.resolve())); + //addToEquality(cur.resolve(), start.resolve(), referenced); + TPH finalPrev = prev; + input.removeIf(p -> p.equals(new PairLT(finalPrev, cur))); + for (var pair2 : new HashSet<>(input)) { + // TODO Maybe this would be unnecessary if we were to add the = constraints later on + if (pair2 instanceof PairEQ peq && pair.left.equals(cur)) { + input.remove(pair2); + input.add(new PairEQ(start, peq.right)); + } + } + prev = chain.get(i); + } + } + } + + for (var pair : elementsToAddToEquality) { + System.out.println(pair); + addToEquality(pair.left, pair.right, referenced); + } + } + + void findTphs(RefTypeOrTPHOrWildcardOrGeneric type, Set tphs) { + if (type instanceof RefType refType) { + refType.getParaList().forEach(t -> findTphs(t, tphs)); + } else if (type instanceof TypePlaceholder tph) { + tph = equality.getOrDefault(tph, tph); + var concreteType = concreteTypes.get(new TPH(tph)); + if (concreteType != null) { + findTphs(concreteType, tphs); + return; + } + tphs.add(new TPH(tph)); + } + } + + void eliminateInnerTypeVariablesOfClass(ClassOrInterface classOrInterface, Set input, Set referenced) { + for (var field : classOrInterface.getFieldDecl()) { + findTphs(field.getType(), referenced); + } + doIterationForMethods(classOrInterface); + for (var method : classOrInterface.getMethods()) { + var usedTPHs = usedTPHsOfMethods.get(method); + if (usedTPHs != null) + referenced.addAll(usedTPHs); + } + eliminateInnerTypeVariables(referenced, input); + } + + void doIterationForMethods(ClassOrInterface classOrInterface) { + familyOfMethods.clear(); + + var oldFamily = new HashMap>(); + do { + oldFamily.clear(); + oldFamily.putAll(familyOfMethods); + familyOfMethods.clear(); + Stream.concat(classOrInterface.getMethods().stream(), classOrInterface.getConstructors().stream()).forEach(method -> { + family(classOrInterface, method); + }); + } while(!oldFamily.equals(familyOfMethods)); + + Stream.concat(classOrInterface.getMethods().stream(), classOrInterface.getConstructors().stream()).forEach(method -> { + generics(classOrInterface, method); + }); + } + + private void findChain(Set referenced, Set input, Set output, TPH start, TPH end, Set chain) { + if (referenced.contains(end)) { + var pair = new PairLT(start, end); + output.add(pair); + return; + } + var foundNext = false; + for (var pair : input) { + if (pair instanceof PairLT ptph && ptph.left.equals(end)) { + if (chain.contains(ptph.right)) return; + chain = new HashSet<>(chain); + chain.add(ptph.right); + findChain(referenced, input, output, start, ptph.right, chain); + foundNext = true; + } + } + if (!foundNext) { + output.add(new PairEQ(start, ASTToTargetAST.OBJECT)); + } + } + + void eliminateInnerTypeVariables(Set referenced, Set input) { + var output = new HashSet(); + for (var tph : referenced) { + for (var pair : input) { + if (pair instanceof PairLT pthp && pthp.left.equals(tph)) { + var chain = new HashSet(); + chain.add(tph); + findChain(referenced, input, output, tph, pthp.right, chain); + } + } + } + for (var pair : input) { + if (pair instanceof PairEQ rtph) { + if (referenced.contains(rtph.left)) + output.add(rtph); + } + } + + input.clear(); + input.addAll(output); + } + + void eliminateCycles(Set input, Set referenced) { + var cycles = CycleFinder.findCycles(input); + for (var cycle : cycles) { + var newTph = TypePlaceholder.fresh(new NullToken()); + var variance = cycle.get(0).resolve().getVariance(); + for (var tph : cycle) { + if (tph.resolve().getVariance() != variance) { + variance = 0; + break; + } + } + newTph.setVariance(variance); + + referenced.add(new TPH(newTph)); + addToPairs(input, new PairEQ(new TPH(newTph), ASTToTargetAST.OBJECT)); + cycle.add(cycle.get(0)); // Make it a complete cycle + for (var i = 0; i < cycle.size() - 1; i++) { + var left = cycle.get(i); + var right = cycle.get(i + 1); + var pair = new PairLT(left, right); + input.remove(pair); + addToEquality(left.resolve(), newTph, referenced); + } + } + } + + Set findConnectionToReturnType(Set returnTypes, Set input, Set visited, TPH tph) { + if (returnTypes.contains(tph)) { + var res = new HashSet(); + res.add(tph); + return res; + } else { + for (var pair : input) if (pair instanceof PairLT ptph) { + if (ptph.left.equals(tph) && !visited.contains(ptph.right)) { + visited.add(ptph.right); + var result = findConnectionToReturnType(returnTypes, input, visited, ptph.right); + if (result.size() > 0) { + result.add(ptph.right); + return result; + }; + } + } + } + return new HashSet<>(); + } + + void eliminateInfimaConnectedToReturnType(Method method, Set input, Set referenced) { + var foundInfima = false; + do { + foundInfima = false; + for (var constraint : new HashSet<>(input)) { + var left = constraint.left; + Set infima = new HashSet<>(); + for (var pair : input) { + if (pair instanceof PairLT stph) { + if (pair.left.equals(constraint.left)) + infima.add(stph); + } + } + if (infima.size() > 1) { + System.out.println(infima); + for (var pair : infima) { + var returnTypes = findTypeVariables(method.getReturnType()); + var chain = findConnectionToReturnType(returnTypes, input, new HashSet<>(), pair.left); + System.out.println("Find: " + pair.left + " " + chain); + chain.remove(pair.left); + if (chain.size() > 0) { + for (var tph : chain) + addToEquality(pair.left.resolve(), tph.resolve(), referenced); + foundInfima = true; + } + } + } + } + } while (foundInfima); + input.removeIf((i) -> (i instanceof PairLT lt) && lt.left.equals(lt.right)); + } + + void eliminateInfima(Set input, Set referenced) { + var foundInfima = false; + do { + foundInfima = false; + for (var constraint : new HashSet<>(input)) { + var left = constraint.left; + Set infima = new HashSet<>(); + for (var pair : input) { + if (pair instanceof PairLT stph) { + if (pair.left.equals(constraint.left)) + infima.add(stph); + } + } + if (infima.size() > 1) { + foundInfima = true; + var newTph = TypePlaceholder.fresh(new NullToken()); + var variance = infima.stream().findFirst().get().right.resolve().getVariance(); + for (var pair : infima) { + if (pair.right.resolve().getVariance() != variance) { + variance = 0; + break; + } + } + newTph.setVariance(variance); + System.out.println(infima + " " + infima.stream().map(i -> i.right.resolve().getVariance()).toList()); + System.out.println("Infima new TPH " + newTph + " variance " + variance); + + //referenced.add(newTph); + addToPairs(input, new PairLT(left, new TPH(newTph))); + input.removeAll(infima); + for (var infimum : infima) { + addToEquality(infimum.right.resolve(), newTph, referenced); + new HashSet<>(input).forEach(pair -> { + if (pair.left.equals(infimum.right)) { + input.remove(pair); + if (pair instanceof PairLT stph) { + if (!newTph.equals(stph.right.resolve())) + addToPairs(input, new PairLT(new TPH(newTph), stph.right)); + } else if (pair instanceof PairEQ rtph) { + addToPairs(input, new PairEQ(new TPH(newTph), rtph.right)); + } + } else if (pair instanceof PairLT stph && stph.right.equals(infimum.right)) { + input.remove(pair); + if (!newTph.equals(stph.left.resolve())) + addToPairs(input, new PairLT(stph.left, new TPH(newTph))); + } + }); + } + } + } + } while (foundInfima); + } + + RefTypeOrTPHOrWildcardOrGeneric getType(RefTypeOrTPHOrWildcardOrGeneric type) { + if (type instanceof TypePlaceholder tph) { + if (equality.containsKey(tph)) { + return getType(equality.get(tph)); + } + return concreteTypes.getOrDefault(new TPH(tph), tph); + } + return type; + } + + TargetType getTargetType(RefTypeOrTPHOrWildcardOrGeneric in) { + if (in instanceof TypePlaceholder tph) { + if (equality.containsKey(tph)) { + return getTargetType(equality.get(tph)); + } + var type = concreteTypes.get(new TPH(tph)); + if (type == null) return new TargetGenericType(tph.getName()); + return astToTargetAST.convert(type, this); + } + return astToTargetAST.convert(in, this); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/generate/GenericsResult.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/generate/GenericsResult.java new file mode 100644 index 0000000..81022ff --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/generate/GenericsResult.java @@ -0,0 +1,76 @@ +package de.dhbw.compiler.target.generate; + +import de.dhbw.compiler.syntaxtree.ClassOrInterface; +import de.dhbw.compiler.syntaxtree.Method; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.syntaxtree.type.TypePlaceholder; +import de.dhbw.compiler.target.tree.type.TargetType; + +import java.util.*; + +public class GenericsResult { + private final GenerateGenerics generics; + + GenericsResult(GenerateGenerics generics) { + this.generics = generics; + } + + public GenericsResultSet get(ClassOrInterface clazz) { + var generics = this.generics.computedGenericsOfClasses.get(clazz); + return new GenericsResultSet(generics, this.generics.equality); + } + + // TODO Compute generics if not present? + public GenericsResultSet get(Method method) { + var generics = this.generics.computedGenericsOfMethods.get(method); + return new GenericsResultSet(generics, this.generics.equality); + } + + public BoundsList getBounds(RefTypeOrTPHOrWildcardOrGeneric type, ClassOrInterface clazz) { + return getBounds(type, clazz, null); + } + + public BoundsList getBounds(RefTypeOrTPHOrWildcardOrGeneric type, ClassOrInterface clazz, Method method) { + var resolvedType = resolve(type); + type = resolvedType; + if (type instanceof TypePlaceholder) { + var methodGenerics = get(method); + var classGenerics = get(clazz); + List result = new ArrayList<>(); + + Optional bound = Optional.empty(); + do { + bound = Optional.empty(); + for (var pair : methodGenerics) { + if (pair.left.resolve().equals(type)) { + type = pair.resolveRight(); + bound = Optional.of(new Bound(true, type)); + break; + } + } + if (bound.isEmpty()) { + for (var pair : classGenerics) { + if (pair.left.resolve().equals(type)) { + type = pair.resolveRight(); + bound = Optional.of(new Bound(false, type)); + break; + } + } + } + bound.ifPresent(result::add); + } while (bound.isPresent()); + return new BoundsList(resolvedType, result); + } + return new BoundsList(resolvedType, List.of()); + } + + public RefTypeOrTPHOrWildcardOrGeneric resolve(RefTypeOrTPHOrWildcardOrGeneric type) { + if (type instanceof TypePlaceholder tph) + return this.generics.getType(tph); + return type; + } + + public TargetType resolveTarget(RefTypeOrTPHOrWildcardOrGeneric type) { + return this.generics.getTargetType(type); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/generate/GenericsResultSet.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/generate/GenericsResultSet.java new file mode 100644 index 0000000..2839a23 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/generate/GenericsResultSet.java @@ -0,0 +1,43 @@ +package de.dhbw.compiler.target.generate; + +import de.dhbw.compiler.syntaxtree.type.TypePlaceholder; +import de.dhbw.compiler.typeinference.result.PairTPHequalRefTypeOrWildcardType; +import de.dhbw.compiler.typeinference.result.PairTPHsmallerTPH; +import de.dhbw.compiler.typeinference.result.ResultPair; + +import java.util.*; + +public class GenericsResultSet extends AbstractSet { + + final Set backing; + final Map equality; + + public GenericsResultSet(Set backing, Map equality) { + this.backing = backing == null ? new HashSet<>() : new HashSet<>(backing); + this.equality = equality; + } + + @Override + public Iterator iterator() { + return backing.iterator(); + } + + @Override + public int size() { + return backing.size(); + } + + public Optional> getResultPairFor(TypePlaceholder tph) { + var tph2 = equality.getOrDefault(tph, tph); + return this.stream().filter(pair -> { + return pair.left.resolve().equals(tph2); + }).findFirst().map(pair -> { + ResultPair res = null; + if (pair instanceof GenerateGenerics.PairLT lt) + res = new PairTPHsmallerTPH(lt.left.resolve(), lt.right.resolve()); + else if (pair instanceof GenerateGenerics.PairEQ eq) + res = new PairTPHequalRefTypeOrWildcardType(eq.left.resolve(), eq.right); + return res; + }); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/generate/JavaGenerics.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/generate/JavaGenerics.java new file mode 100644 index 0000000..eb3e5d0 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/generate/JavaGenerics.java @@ -0,0 +1,30 @@ +package de.dhbw.compiler.target.generate; + +import de.dhbw.compiler.syntaxtree.ClassOrInterface; +import de.dhbw.compiler.syntaxtree.Method; +import de.dhbw.compiler.typeinference.result.ResultSet; + +import java.util.Set; + +final class JavaGenerics extends GenerateGenerics { + JavaGenerics(ASTToTargetAST astToTargetAST, ResultSet constraints) { + super(astToTargetAST, constraints); + } + + @Override + void generics(ClassOrInterface owner, Method method, Set result, Set referenced) { + eliminateCycles(result, referenced); + eliminateInfimaConnectedToReturnType(method, result, referenced); + eliminateInfima(result, referenced); + equalizeTypeVariables(result, referenced); + eliminateInnerTypeVariables(referenced, result); + } + + @Override + void generics(ClassOrInterface classOrInterface, Set result, Set referenced) { + eliminateCycles(result, referenced); + eliminateInfima(result, referenced); + eliminateInnerTypeVariablesOfClass(classOrInterface, result, referenced); + equalizeTypeVariables(result, referenced); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/generate/StatementToTargetExpression.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/generate/StatementToTargetExpression.java new file mode 100644 index 0000000..4e4c8b9 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/generate/StatementToTargetExpression.java @@ -0,0 +1,594 @@ +package de.dhbw.compiler.target.generate; + +import de.dhbw.compiler.core.JavaTXCompiler; +import de.dhbw.compiler.exceptions.DebugException; +import de.dhbw.compiler.exceptions.NotImplementedException; +import de.dhbw.compiler.parser.SyntaxTreeGenerator.AssignToLocal; +import de.dhbw.compiler.parser.scope.JavaClassName; +import de.dhbw.compiler.syntaxtree.*; +import de.dhbw.compiler.syntaxtree.statement.*; +import de.dhbw.compiler.syntaxtree.type.*; +import de.dhbw.compiler.target.tree.MethodParameter; +import de.dhbw.compiler.target.tree.TargetMethod; +import de.dhbw.compiler.target.tree.expression.*; +import de.dhbw.compiler.target.tree.type.*; + +import java.lang.reflect.Modifier; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +public class StatementToTargetExpression implements ASTVisitor { + + public StatementToTargetExpression(ASTToTargetAST converter) { + this.converter = converter; + } + + public TargetExpression result; + private final ASTToTargetAST converter; + + @Override + public void visit(ArgumentList argumentList) { + throw new NotImplementedException(); + } + + @Override + public void visit(LambdaExpression lambdaExpression) { + var parameters = StreamSupport.stream(lambdaExpression.params.spliterator(), false) + .map(p -> (FormalParameter) p) + .map(p -> new MethodParameter(new TargetTypePattern(converter.convert(p.getType()), p.getName()))) + .toList(); + + List captures = new ArrayList<>(); + lambdaExpression.methodBody.accept(new TracingStatementVisitor() { + // TODO The same mechanism is implemented in Codegen, maybe use it from there? + final Stack> localVariables = new Stack<>(); + { + localVariables.push(new HashSet<>()); + } + + boolean hasLocalVar(String name) { + for (var localVariables : this.localVariables) { + if (localVariables.contains(name)) + return true; + } + return false; + } + + @Override + public void visit(Block block) { + localVariables.push(new HashSet<>()); + super.visit(block); + localVariables.pop(); + } + + @Override + public void visit(LocalVar localVar) { + super.visit(localVar); + var capture = new MethodParameter(new TargetTypePattern(converter.convert(localVar.getType()), localVar.name)); + if (!hasLocalVar(localVar.name) && !parameters.contains(capture) && !captures.contains(capture)) + captures.add(capture); + } + + @Override + public void visit(LocalVarDecl varDecl) { + var localVariables = this.localVariables.peek(); + localVariables.add(varDecl.getName()); + } + + @Override + public void visit(LambdaExpression lambda) { + } // Don't look at lambda expressions + }); + + 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) { + var isStatic = false; + var type = converter.convert(fieldVar.receiver.getType()); + var clazz = converter.compiler.getClass(new JavaClassName(type.name())); + var field = clazz.getField(fieldVar.fieldVarName).orElseThrow(); + result = new TargetFieldVar(converter.convert(fieldVar.getType()), type, Modifier.isStatic(field.modifier), 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 findMethod(JavaClassName className, String name, List args) { + return converter.findMethod(converter.compiler.getClass(className), name, args); + } + + @Override + public void visit(MethodCall methodCall) { + var receiverType = converter.convert(methodCall.receiver.getType()); + var isFunNType = receiverType instanceof TargetFunNType; + + var returnType = isFunNType ? TargetType.Object : converter.convert(methodCall.signature.get(methodCall.signature.size() - 1)); + var receiverName = new JavaClassName(converter.convert(methodCall.receiver.getType()).name()); + var argList = methodCall.signature.stream().map(converter::convert).toList(); + argList = argList.subList(0, argList.size() - 1); + + Method foundMethod = null; + var isStatic = false; + var isInterface = true; + var isPrivate = false; + var signature = methodCall.signatureArguments().stream().map(converter::convert).toList(); + + // Add used TPHs to containing method + for (var i = 0; i < methodCall.signatureArguments().size(); i++) { + converter.addSignaturePair(methodCall.signatureArguments().get(i), methodCall.arglist.getArguments().get(i).getType()); + } + + 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(); + } + + System.out.println(argList); + 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(Continue aContinue) { + result = new TargetContinue(); + } + + @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) { + result = new TargetDo(converter.convert(whileStmt.expr), converter.convert(whileStmt.loopBlock)); + } + + // 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 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)); + } + + record TypeVariants(RefTypeOrTPHOrWildcardOrGeneric in, List types) {} + + private List extractAllPatterns(Pattern pattern) { + return switch (pattern) { + case GuardedPattern guarded -> extractAllPatterns(guarded.getNestedPattern()); + case RecordPattern recordPattern -> recordPattern.getSubPattern().stream() + .map(this::extractAllPatterns) + .flatMap(List::stream).toList(); + case FormalParameter param -> List.of(new TypeVariants(param.getType(), converter.findAllVariants(param.getType()))); + default -> List.of(); + }; + } + + record TypePair(RefTypeOrTPHOrWildcardOrGeneric in, RefTypeOrTPHOrWildcardOrGeneric out) {} + + private void cartesianProduct( + List variants, int index, + List current, + List> result) { + + if (index == variants.size()) { + result.add(new ArrayList<>(current)); + return; + } + var currentSet = variants.get(index).types; + for (var element: currentSet) { + current.add(element); + cartesianProduct(variants, index + 1, current, result); + current.removeLast(); + } + } + + private List> cartesianProduct(List variants) { + var prod = new ArrayList>(); + cartesianProduct(variants, 0, new ArrayList<>(), prod); + + var res = new ArrayList>(); + for (var list : prod) { + var l = new ArrayList(); + for (var i = 0; i < list.size(); i++) { + l.add(new TypePair(variants.get(i).in, list.get(i))); + } + res.add(l); + } + return res; + } + + @Override + public void visit(Switch switchStmt) { + var variants = converter.findAllVariants(switchStmt.getSwitch().getType()); + var returns = converter.findAllVariants(switchStmt.getType()); + var canBeOverloaded = variants.size() == 1 && returns.size() == 1; + + var cases = switchStmt.getBlocks().stream().filter(s -> !s.isDefault()).map(case_ -> { + var overloads = new ArrayList(); + + if (canBeOverloaded) { + for (var label: case_.getLabels()) { + var product = cartesianProduct(extractAllPatterns(label.getPattern())); + + for (var l : product) { + var oldGenerics = converter.generics; + + // Set the generics to matching result set + for (var generics : converter.currentMethodOverloads) { + var java = generics.javaGenerics(); + var equals = true; + for (var pair : l) { + if (!java.getType(pair.in).equals(pair.out)) { + equals = false; break; + } + } + if (equals) { + converter.generics = generics; + break; + } + } + + overloads.add(converter.convert(case_)); + converter.generics = oldGenerics; + } + } + } else { + overloads.add(converter.convert(case_)); + } + + return overloads; + }).flatMap(List::stream).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.dhbw.compiler.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(LiteralPattern literalPattern) { + result = new TargetExpressionPattern(converter.convert(literalPattern.value)); + } + + @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())); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/generate/TracingStatementVisitor.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/generate/TracingStatementVisitor.java new file mode 100644 index 0000000..4140615 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/generate/TracingStatementVisitor.java @@ -0,0 +1,218 @@ +package de.dhbw.compiler.target.generate; + +import de.dhbw.compiler.parser.SyntaxTreeGenerator.AssignToLocal; +import de.dhbw.compiler.syntaxtree.Method; +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.statement.*; + +// This visitor walks the entire tree, individual methods may be overridden +public abstract class TracingStatementVisitor implements StatementVisitor { + + @Override + public void visit(ThisCall thisCall) { + visit((MethodCall) thisCall); + } + + @Override + public void visit(MethodCall methodCall) { + methodCall.receiver.accept(this); + methodCall.getArgumentList().accept(this); + } + + @Override + public void visit(ArgumentList argumentList) { + argumentList.getArguments().forEach(expr -> expr.accept(this)); + } + + @Override + public void visit(LambdaExpression lambdaExpression) { + lambdaExpression.methodBody.accept(this); + } + + @Override + public void visit(Assign assign) { + assign.rightSide.accept(this); + } + + @Override + public void visit(BinaryExpr binary) { + binary.lexpr.accept(this); + binary.rexpr.accept(this); + } + + @Override + public void visit(BoolExpression bool) { + bool.lexpr.accept(this); + bool.rexpr.accept(this); + } + + @Override + public void visit(Block block) { + for (var expr : block.statements) + expr.accept(this); + } + + @Override + public void visit(CastExpr castExpr) { + + } + + @Override + public void visit(EmptyStmt emptyStmt) { + + } + + @Override + public void visit(FieldVar fieldVar) { + + } + + @Override + public void visit(ForStmt forStmt) { + 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); + if (ifStmt.else_block != null) + ifStmt.else_block.accept(this); + } + + @Override + public void visit(InstanceOf instanceOf) { + + } + + @Override + public void visit(LocalVar localVar) { + + } + + @Override + public void visit(LocalVarDecl localVarDecl) { + + } + + @Override + public void visit(NewClass newClass) { + this.visit((MethodCall) newClass); + } + + @Override + public void visit(NewArray newArray) { + newArray.expr.forEach(expr -> expr.accept(this)); + } + + @Override + public void visit(Return aReturn) { + aReturn.retexpr.accept(this); + } + + @Override + public void visit(ReturnVoid aReturn) { + + } + + @Override + public void visit(Break aBreak) { + + } + + @Override + public void visit(Continue aContinue) { + + } + + @Override + public void visit(StaticClassName staticClassName) { + + } + + @Override + public void visit(Super aSuper) { + + } + + @Override + public void visit(This aThis) { + + } + + @Override + public void visit(WhileStmt whileStmt) { + whileStmt.loopBlock.accept(this); + } + + @Override + public void visit(DoStmt whileStmt) { + whileStmt.loopBlock.accept(this); + } + + @Override + public void visit(AssignToField assignLeftSide) { + + } + + @Override + public void visit(AssignToLocal assignLeftSide) { + + } + + @Override + public void visit(SuperCall superCall) { + visit((MethodCall) superCall); + } + + @Override + public void visit(ExpressionReceiver expressionReceiver) { + expressionReceiver.expr.accept(this); + } + + @Override + public void visit(UnaryExpr unaryExpr) { + unaryExpr.expr.accept(this); + } + + @Override + public void visit(Literal literal) { + + } + + @Override + public void visit(Throw aThrow) { + + } + + @Override + public void visit(Switch switchStmt) { + + } + + @Override + public void visit(SwitchBlock switchBlock) { + + } + + @Override + public void visit(SwitchLabel switchLabel) { + + } + + @Override + public void visit(Yield aYield) { + + } + + @Override + public void visit(Ternary ternary) { + ternary.cond.accept(this); + ternary.iftrue.accept(this); + ternary.iffalse.accept(this); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/generate/TxGenerics.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/generate/TxGenerics.java new file mode 100644 index 0000000..29904de --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/generate/TxGenerics.java @@ -0,0 +1,25 @@ +package de.dhbw.compiler.target.generate; + +import de.dhbw.compiler.syntaxtree.ClassOrInterface; +import de.dhbw.compiler.syntaxtree.Method; +import de.dhbw.compiler.typeinference.result.ResultSet; + +import java.util.Set; + +final class TxGenerics extends GenerateGenerics { + TxGenerics(ASTToTargetAST astToTargetAST, ResultSet constraints) { + super(astToTargetAST, constraints); + } + + @Override + void generics(ClassOrInterface owner, Method method, Set result, Set referenced) { + eliminateInfima(result, referenced); + eliminateInnerTypeVariables(referenced, result); + } + + @Override + void generics(ClassOrInterface classOrInterface, Set result, Set referenced) { + eliminateInfima(result, referenced); + eliminateInnerTypeVariablesOfClass(classOrInterface, result, referenced); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/MethodParameter.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/MethodParameter.java new file mode 100644 index 0000000..84df649 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/MethodParameter.java @@ -0,0 +1,18 @@ +package de.dhbw.compiler.target.tree; + +import de.dhbw.compiler.target.tree.expression.TargetPattern; +import de.dhbw.compiler.target.tree.expression.TargetTypePattern; +import de.dhbw.compiler.target.tree.type.TargetType; + +public record MethodParameter(TargetPattern pattern) { + public MethodParameter(TargetType type, String name) { + this(new TargetTypePattern(type, name)); + } + public MethodParameter withType(TargetType type) { + return new MethodParameter(pattern.withType(type)); + } + + public MethodParameter withName(String name) { + return new MethodParameter(pattern.withName(name)); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/TargetClass.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/TargetClass.java new file mode 100644 index 0000000..1799d55 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/TargetClass.java @@ -0,0 +1,27 @@ +package de.dhbw.compiler.target.tree; + +import de.dhbw.compiler.parser.scope.JavaClassName; +import de.dhbw.compiler.target.tree.expression.TargetBlock; +import de.dhbw.compiler.target.tree.type.TargetRefType; +import de.dhbw.compiler.target.tree.type.TargetType; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public record TargetClass(int modifiers, JavaClassName qualifiedName, TargetType superType, Set generics, Set txGenerics, List implementingInterfaces, + List constructors, TargetMethod staticConstructor, List fields, List methods) implements TargetStructure { + + public TargetClass(int modifiers, JavaClassName qualifiedName) { + this(modifiers, qualifiedName, TargetType.Object, new HashSet<>(), new HashSet<>(), new ArrayList<>(), new ArrayList<>(), null, new ArrayList<>(), new ArrayList<>()); + } + public TargetClass(int modifiers, JavaClassName qualifiedName, List implementingInterfaces) { + this(modifiers, qualifiedName, TargetType.Object, new HashSet<>(), new HashSet<>(), implementingInterfaces, new ArrayList<>(), null, new ArrayList<>(), new ArrayList<>()); + } + + public void addField(int access, TargetRefType type, String name) { + this.fields.add(new TargetField(access, type, name)); + } +} + diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/TargetConstructor.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/TargetConstructor.java new file mode 100644 index 0000000..8fc1cc3 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/TargetConstructor.java @@ -0,0 +1,24 @@ +package de.dhbw.compiler.target.tree; + +import de.dhbw.compiler.syntaxtree.Method; +import de.dhbw.compiler.target.tree.expression.TargetBlock; +import de.dhbw.compiler.target.tree.type.TargetType; + +import java.util.List; +import java.util.Set; + +public record TargetConstructor(int access, Set generics, Set txGenerics, List parameters, List txParameters, TargetBlock block, TargetBlock fieldInitializer) { + + public String getDescriptor() { + return TargetMethod.getDescriptor(null, parameters.stream().map(mp -> mp.pattern().type()).toArray(TargetType[]::new)); + } + + public String getSignature() { + return TargetMethod.getSignature(generics, parameters, null); + } + + public String getTXSignature() { + return TargetMethod.getSignature(txGenerics, txParameters, null); + } +} + diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/TargetField.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/TargetField.java new file mode 100644 index 0000000..b0bd182 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/TargetField.java @@ -0,0 +1,11 @@ +package de.dhbw.compiler.target.tree; + +import de.dhbw.compiler.target.tree.type.TargetType; +import org.objectweb.asm.Opcodes; + +public record TargetField(int access, TargetType type, String name) { + public boolean isStatic() { + return (access & Opcodes.ACC_STATIC) != 0; + } +} + diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/TargetGeneric.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/TargetGeneric.java new file mode 100644 index 0000000..cb7777b --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/TargetGeneric.java @@ -0,0 +1,6 @@ +package de.dhbw.compiler.target.tree; + +import de.dhbw.compiler.target.tree.type.TargetType; + +public record TargetGeneric(String name, TargetType bound) { +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/TargetInterface.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/TargetInterface.java new file mode 100644 index 0000000..79b1198 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/TargetInterface.java @@ -0,0 +1,24 @@ +package de.dhbw.compiler.target.tree; + +import de.dhbw.compiler.parser.scope.JavaClassName; +import de.dhbw.compiler.target.tree.type.TargetType; + +import java.util.List; +import java.util.Set; + +public record TargetInterface(int modifiers, JavaClassName qualifiedName, Set generics, Set txGenerics, List methods, List implementingInterfaces, TargetMethod staticConstructor) implements TargetStructure { + @Override + public TargetType superType() { + return null; + } + + @Override + public List constructors() { + return List.of(); + } + + @Override + public List fields() { + return List.of(); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/TargetMethod.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/TargetMethod.java new file mode 100644 index 0000000..1758989 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/TargetMethod.java @@ -0,0 +1,97 @@ +package de.dhbw.compiler.target.tree; + +import de.dhbw.compiler.target.tree.expression.TargetBlock; +import de.dhbw.compiler.target.tree.expression.TargetPattern; +import de.dhbw.compiler.target.tree.type.TargetType; +import org.objectweb.asm.Opcodes; + +import java.util.List; +import java.util.Objects; +import java.util.Set; + +public record TargetMethod(int access, String name, TargetBlock block, Signature signature, Signature txSignature) { + public record Signature(Set generics, List parameters, TargetType returnType) { + public String getSignature() { + return TargetMethod.getSignature(generics, parameters, returnType); + } + + public String getDescriptor() { + return TargetMethod.getDescriptor(returnType, parameters.stream().map(MethodParameter::pattern).map(TargetPattern::type).toArray(TargetType[]::new)); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Signature signature = (Signature) o; + return Objects.equals(parameters, signature.parameters); + } + + @Override + public int hashCode() { + return Objects.hash(parameters); + } + } + + public static String getDescriptor(TargetType returnType, TargetType... parameters) { + String ret = "("; + for (var parameterType : parameters) { + ret += parameterType.toSignature(); + } + ret += ")"; + if (returnType == null) ret += "V"; + else ret += returnType.toSignature(); + return ret; + } + + public static String getSignature(Set generics, List parameters, TargetType returnType) { + String ret = ""; + if (generics.size() > 0) { + ret += "<"; + for (var generic : generics) { + ret += generic.name() + ":" + generic.bound().toDescriptor(); + } + ret += ">"; + } + ret += "("; + for (var param : parameters) { + ret += param.pattern().type().toDescriptor(); + } + ret += ")"; + if (returnType == null) ret += "V"; + else ret += returnType.toDescriptor(); + return ret; + } + + public String getDescriptor() { + return getDescriptor(signature.returnType, signature.parameters.stream().map(mp -> mp.pattern().type()).toArray(TargetType[]::new)); + } + + public String getSignature() { + return getSignature(signature.generics, signature.parameters, signature.returnType); + } + + public String getTXSignature() { + return getSignature(txSignature.generics, txSignature.parameters, txSignature.returnType); + } + + public boolean isStatic() { + return (access & Opcodes.ACC_STATIC) != 0; + } + + public boolean isPrivate() { + return (access & Opcodes.ACC_PRIVATE) != 0; + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof TargetMethod otherMethod)) return false; + return otherMethod.signature.equals(this.signature) && otherMethod.name.equals(this.name); + } + + @Override + public int hashCode() { + return Objects.hash(name, signature); + } +} + diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/TargetRecord.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/TargetRecord.java new file mode 100644 index 0000000..6de98e3 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/TargetRecord.java @@ -0,0 +1,16 @@ +package de.dhbw.compiler.target.tree; + +import de.dhbw.compiler.parser.scope.JavaClassName; +import de.dhbw.compiler.target.tree.type.TargetRefType; +import de.dhbw.compiler.target.tree.type.TargetType; + +import java.util.List; +import java.util.Set; + +public record TargetRecord(int modifiers, JavaClassName qualifiedName, Set generics, Set txGenerics, List implementingInterfaces, List constructors, TargetMethod staticConstructor, List fields, List methods) implements TargetStructure { + + public static final TargetType RECORD = new TargetRefType("java.lang.Record"); + public TargetType superType() { + return RECORD; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/TargetStructure.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/TargetStructure.java new file mode 100644 index 0000000..155ca48 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/TargetStructure.java @@ -0,0 +1,44 @@ +package de.dhbw.compiler.target.tree; + +import de.dhbw.compiler.parser.scope.JavaClassName; +import de.dhbw.compiler.target.tree.expression.TargetBlock; +import de.dhbw.compiler.target.tree.type.TargetType; + +import java.util.List; +import java.util.Set; + +public interface TargetStructure { + int modifiers(); + JavaClassName qualifiedName(); + TargetType superType(); + Set generics(); + Set txGenerics(); + List implementingInterfaces(); + List constructors(); + + TargetMethod staticConstructor(); + + List fields(); + List methods(); + + default String getName() { + return qualifiedName().toString().replaceAll("\\.", "/"); + } + + // These methods are only meant to be used for test cases, a Class record should be immutable! + default void addMethod(int access, String name, Set generics, List parameterTypes, TargetType returnType, TargetBlock block) { + this.methods().add(new TargetMethod(access, name, block, new TargetMethod.Signature(generics, parameterTypes, returnType), null)); + } + + default void addMethod(int access, String name, List parameterTypes, TargetType returnType, TargetBlock block) { + addMethod(access, name, Set.of(), parameterTypes, returnType, block); + } + + default void addConstructor(int access, Set generics, List paramterTypes, TargetBlock block) { + this.constructors().add(new TargetConstructor(access, generics, Set.of(), paramterTypes, List.of(), block, null)); + } + + default void addConstructor(int access, List paramterTypes, TargetBlock block) { + addConstructor(access, Set.of(), paramterTypes, block); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetAssign.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetAssign.java new file mode 100644 index 0000000..8222a44 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetAssign.java @@ -0,0 +1,6 @@ +package de.dhbw.compiler.target.tree.expression; + +import de.dhbw.compiler.target.tree.type.TargetType; + +public record TargetAssign(TargetType type, TargetExpression left, TargetExpression right) implements TargetStatementExpression { +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetBinaryOp.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetBinaryOp.java new file mode 100644 index 0000000..afed8d5 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetBinaryOp.java @@ -0,0 +1,85 @@ +package de.dhbw.compiler.target.tree.expression; + +import de.dhbw.compiler.target.tree.expression.TargetExpression; +import de.dhbw.compiler.target.tree.type.TargetType; + +public sealed interface TargetBinaryOp extends TargetExpression { + TargetExpression left(); + + TargetExpression right(); + + // Arithmetic + record Add(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp { + } + + record Sub(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp { + } + + record Div(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp { + } + + record Mul(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp { + } + + record Rem(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp { + } + + // Bitwise + record BAnd(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp { + } + + record BOr(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp { + } + + record XOr(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp { + } + + record Shl(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp { + } + + record Shr(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp { + } + + record UShr(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp { + } + + // Conditional + record And(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp { + } + + record Or(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp { + } + + record Instof(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp { + } + + sealed interface TargetRelationalOp extends TargetBinaryOp { + @Override + default TargetType type() { + return TargetType.Boolean; + } + + TargetType exprType(); + } + + // Comparison + // exprType is the type that both arguments get converted to before comparison + record Equal(TargetType exprType, TargetExpression left, TargetExpression right) implements TargetRelationalOp { + } + + record Greater(TargetType exprType, TargetExpression left, TargetExpression right) implements TargetRelationalOp { + } + + record GreaterOrEqual(TargetType exprType, TargetExpression left, TargetExpression right) implements TargetRelationalOp { + } + + record Less(TargetType exprType, TargetExpression left, TargetExpression right) implements TargetRelationalOp { + } + + record LessOrEqual(TargetType exprType, TargetExpression left, TargetExpression right) implements TargetRelationalOp { + } + + record NotEqual(TargetType exprType, TargetExpression left, TargetExpression right) implements TargetRelationalOp { + } + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetBlock.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetBlock.java new file mode 100644 index 0000000..2e380b8 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetBlock.java @@ -0,0 +1,8 @@ +package de.dhbw.compiler.target.tree.expression; + +import de.dhbw.compiler.target.tree.type.TargetType; + +import java.util.List; + +public record TargetBlock(List statements) implements TargetExpression { +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetBreak.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetBreak.java new file mode 100644 index 0000000..2f6a3c9 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetBreak.java @@ -0,0 +1,7 @@ +package de.dhbw.compiler.target.tree.expression; + +import de.dhbw.compiler.target.tree.type.TargetType; + +// TODO This needs a label +public record TargetBreak() implements TargetExpression { +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetCast.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetCast.java new file mode 100644 index 0000000..f1434f2 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetCast.java @@ -0,0 +1,6 @@ +package de.dhbw.compiler.target.tree.expression; + +import de.dhbw.compiler.target.tree.type.TargetType; + +public record TargetCast(TargetType type, TargetExpression expr) implements TargetExpression { +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetClassName.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetClassName.java new file mode 100644 index 0000000..5bae1e7 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetClassName.java @@ -0,0 +1,6 @@ +package de.dhbw.compiler.target.tree.expression; + +import de.dhbw.compiler.target.tree.type.TargetType; + +public record TargetClassName(TargetType type) implements TargetExpression { +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetComplexPattern.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetComplexPattern.java new file mode 100644 index 0000000..fe5b833 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetComplexPattern.java @@ -0,0 +1,17 @@ +package de.dhbw.compiler.target.tree.expression; + +import de.dhbw.compiler.target.tree.type.TargetType; + +import java.util.List; + +public record TargetComplexPattern(TargetType type, String name, List subPatterns) implements TargetPattern { + @Override + public TargetComplexPattern withType(TargetType type) { + return new TargetComplexPattern(type, name, subPatterns); + } + + @Override + public TargetComplexPattern withName(String name) { + return new TargetComplexPattern(type, name, subPatterns); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetContinue.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetContinue.java new file mode 100644 index 0000000..5270173 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetContinue.java @@ -0,0 +1,6 @@ +package de.dhbw.compiler.target.tree.expression; + +import de.dhbw.compiler.target.tree.type.TargetType; + +public record TargetContinue() implements TargetExpression { +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetDo.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetDo.java new file mode 100644 index 0000000..3490d80 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetDo.java @@ -0,0 +1,4 @@ +package de.dhbw.compiler.target.tree.expression; + +public record TargetDo(TargetExpression cond, TargetExpression body) implements TargetExpression { +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetExpression.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetExpression.java new file mode 100644 index 0000000..441cacc --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetExpression.java @@ -0,0 +1,11 @@ +package de.dhbw.compiler.target.tree.expression; + +import de.dhbw.compiler.target.tree.type.*; + +public sealed interface TargetExpression + permits TargetBinaryOp, TargetBlock, TargetBreak, TargetCast, TargetClassName, TargetContinue, TargetDo, 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; + }; +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetExpressionPattern.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetExpressionPattern.java new file mode 100644 index 0000000..0f2d3b7 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetExpressionPattern.java @@ -0,0 +1,20 @@ +package de.dhbw.compiler.target.tree.expression; + +import de.dhbw.compiler.target.tree.type.TargetType; + +public record TargetExpressionPattern(TargetExpression expression) implements TargetPattern { + @Override + public TargetPattern withType(TargetType type) { + return this; + } + + @Override + public TargetType type() { + return expression.type(); + } + + @Override + public TargetPattern withName(String name) { + return this; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetFieldVar.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetFieldVar.java new file mode 100644 index 0000000..2951eab --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetFieldVar.java @@ -0,0 +1,7 @@ +package de.dhbw.compiler.target.tree.expression; + +import de.dhbw.compiler.target.tree.type.TargetRefType; +import de.dhbw.compiler.target.tree.type.TargetType; + +public record TargetFieldVar(TargetType type, TargetType owner, boolean isStatic, TargetExpression left, String right) implements TargetExpression { +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetFor.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetFor.java new file mode 100644 index 0000000..118fe75 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetFor.java @@ -0,0 +1,6 @@ +package de.dhbw.compiler.target.tree.expression; + +import java.util.List; + +public record TargetFor(List init, TargetExpression termination, List increment, TargetExpression body) implements TargetExpression { +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetForEach.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetForEach.java new file mode 100644 index 0000000..de4ad85 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetForEach.java @@ -0,0 +1,4 @@ +package de.dhbw.compiler.target.tree.expression; + +public record TargetForEach(TargetExpression vardecl, TargetExpression expression, TargetExpression body) implements TargetExpression { +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetGuard.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetGuard.java new file mode 100644 index 0000000..e30756e --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetGuard.java @@ -0,0 +1,20 @@ +package de.dhbw.compiler.target.tree.expression; + +import de.dhbw.compiler.target.tree.type.TargetType; + +public record TargetGuard(TargetPattern inner, TargetExpression expression) implements TargetPattern { + @Override + public TargetGuard withType(TargetType type) { + return new TargetGuard(inner.withType(type), expression); + } + + @Override + public TargetType type() { + return inner.type(); + } + + @Override + public TargetGuard withName(String name) { + return new TargetGuard(inner.withName(name), expression); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetIf.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetIf.java new file mode 100644 index 0000000..2da9d04 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetIf.java @@ -0,0 +1,6 @@ +package de.dhbw.compiler.target.tree.expression; + +import de.dhbw.compiler.target.tree.type.TargetType; + +public record TargetIf(TargetExpression cond, TargetExpression if_body, TargetExpression else_body) implements TargetExpression { +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetInstanceOf.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetInstanceOf.java new file mode 100644 index 0000000..1cb2988 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetInstanceOf.java @@ -0,0 +1,12 @@ +package de.dhbw.compiler.target.tree.expression; + +import de.dhbw.compiler.syntaxtree.statement.Expression; +import de.dhbw.compiler.target.tree.type.TargetType; + +public record TargetInstanceOf(TargetExpression left, TargetExpression right) implements TargetExpression { + + @Override + public TargetType type() { + return TargetType.Boolean; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetLambdaExpression.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetLambdaExpression.java new file mode 100644 index 0000000..a0548ed --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetLambdaExpression.java @@ -0,0 +1,11 @@ +package de.dhbw.compiler.target.tree.expression; + +import de.dhbw.compiler.target.tree.MethodParameter; +import de.dhbw.compiler.target.tree.TargetField; +import de.dhbw.compiler.target.tree.TargetMethod; +import de.dhbw.compiler.target.tree.type.TargetType; + +import java.util.List; + +public record TargetLambdaExpression(TargetType type, List captures, TargetMethod.Signature signature, TargetBlock block) implements TargetExpression { +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetLiteral.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetLiteral.java new file mode 100644 index 0000000..94d3707 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetLiteral.java @@ -0,0 +1,68 @@ +package de.dhbw.compiler.target.tree.expression; + +import de.dhbw.compiler.target.tree.type.TargetType; + +public sealed interface TargetLiteral extends TargetExpression { + Object value(); + + record BooleanLiteral(Boolean value) implements TargetLiteral { + @Override + public TargetType type() { + return TargetType.Boolean; + } + } + + record CharLiteral(Character value) implements TargetLiteral { + @Override + public TargetType type() { + return TargetType.Char; + } + } + + record IntLiteral(Integer value) implements TargetLiteral { + @Override + public TargetType type() { + return TargetType.Integer; + } + } + + record LongLiteral(Long value) implements TargetLiteral { + @Override + public TargetType type() { + return TargetType.Long; + } + } + + record FloatLiteral(Float value) implements TargetLiteral { + @Override + public TargetType type() { + return TargetType.Float; + } + } + + record DoubleLiteral(Double value) implements TargetLiteral { + @Override + public TargetType type() { + return TargetType.Double; + } + } + + record StringLiteral(String value) implements TargetLiteral { + @Override + public TargetType type() { + return TargetType.String; + } + } + + record Null() implements TargetLiteral { + @Override + public TargetType type() { + return TargetType.Object; + } + + @Override + public Object value() { + return null; + } + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetLocalVar.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetLocalVar.java new file mode 100644 index 0000000..f075885 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetLocalVar.java @@ -0,0 +1,6 @@ +package de.dhbw.compiler.target.tree.expression; + +import de.dhbw.compiler.target.tree.type.TargetType; + +public record TargetLocalVar(TargetType type, String name) implements TargetExpression { +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetMethodCall.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetMethodCall.java new file mode 100644 index 0000000..f2e9d65 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetMethodCall.java @@ -0,0 +1,17 @@ +package de.dhbw.compiler.target.tree.expression; + +import de.dhbw.compiler.target.tree.TargetMethod; +import de.dhbw.compiler.target.tree.type.TargetType; + +import java.util.List; + +public record TargetMethodCall(TargetType type, TargetType returnType, List parameterTypes, TargetExpression expr, List args, TargetType owner, String name, boolean isStatic, boolean isInterface, boolean isPrivate) implements TargetStatementExpression { + public TargetMethodCall(TargetType type, TargetExpression expr, List args, TargetType owner, String name, boolean isStatic, boolean isInterface, boolean isPrivate) { + this(type, type, args.stream().map(TargetExpression::type).toList(), expr, args, owner, name, isStatic, isInterface, isPrivate); + } + + + public String getDescriptor() { + return TargetMethod.getDescriptor(returnType, parameterTypes.toArray(TargetType[]::new)); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetNew.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetNew.java new file mode 100644 index 0000000..f1701e9 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetNew.java @@ -0,0 +1,12 @@ +package de.dhbw.compiler.target.tree.expression; + +import de.dhbw.compiler.target.tree.TargetMethod; +import de.dhbw.compiler.target.tree.type.TargetType; + +import java.util.List; + +public record TargetNew(TargetType type, List signature, List params) implements TargetStatementExpression { + public String getDescriptor() { + return TargetMethod.getDescriptor(null, signature.toArray(TargetType[]::new)); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetPattern.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetPattern.java new file mode 100644 index 0000000..2490ba5 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetPattern.java @@ -0,0 +1,15 @@ +package de.dhbw.compiler.target.tree.expression; + +import de.dhbw.compiler.target.tree.type.TargetType; + +public sealed interface TargetPattern extends TargetExpression permits TargetComplexPattern, TargetExpressionPattern, TargetGuard, TargetTypePattern { + default String name() { + return null; + } + + TargetPattern withType(TargetType type); + + TargetType type(); + + TargetPattern withName(String name); +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetReturn.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetReturn.java new file mode 100644 index 0000000..6272b5a --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetReturn.java @@ -0,0 +1,6 @@ +package de.dhbw.compiler.target.tree.expression; + +import de.dhbw.compiler.target.tree.type.TargetType; + +public record TargetReturn(TargetExpression expression) implements TargetExpression { +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetStatementExpression.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetStatementExpression.java new file mode 100644 index 0000000..8c666bb --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetStatementExpression.java @@ -0,0 +1,4 @@ +package de.dhbw.compiler.target.tree.expression; + +public sealed interface TargetStatementExpression extends TargetExpression permits TargetAssign, TargetMethodCall, TargetNew, TargetUnaryOp.PostDecrement, TargetUnaryOp.PostIncrement, TargetUnaryOp.PreDecrement, TargetUnaryOp.PreIncrement { +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetSuper.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetSuper.java new file mode 100644 index 0000000..63f51d3 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetSuper.java @@ -0,0 +1,6 @@ +package de.dhbw.compiler.target.tree.expression; + +import de.dhbw.compiler.target.tree.type.TargetType; + +public record TargetSuper(TargetType type) implements TargetExpression { +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetSwitch.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetSwitch.java new file mode 100644 index 0000000..893f6b1 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetSwitch.java @@ -0,0 +1,30 @@ +package de.dhbw.compiler.target.tree.expression; + +import de.dhbw.compiler.target.tree.type.TargetType; + +import java.util.List; + +public record TargetSwitch(TargetExpression expr, List cases, Case default_, TargetType type, boolean isExpression) implements TargetExpression { + + public TargetSwitch(TargetExpression expr, List cases, Case default_) { + this(expr, cases, default_, null, false); + } + + public TargetSwitch(TargetExpression expr, List cases, Case default_, TargetType type) { + this(expr, cases, default_, type, true); + } + + public TargetSwitch(TargetExpression expr, List cases, Case default_, boolean isExpression) { + this(expr, cases, default_, null, isExpression); + } + + public record Case(List labels, TargetBlock body, boolean isSingleExpression) { + public Case(List labels, TargetBlock body) { + this(labels, body, false); + } + public Case(TargetBlock body, boolean isSingleExpression) { + this(List.of(), body, isSingleExpression); + } + } + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetTernary.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetTernary.java new file mode 100644 index 0000000..b1d0c53 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetTernary.java @@ -0,0 +1,6 @@ +package de.dhbw.compiler.target.tree.expression; + +import de.dhbw.compiler.target.tree.type.TargetType; + +public record TargetTernary(TargetType type, TargetExpression cond, TargetExpression iftrue, TargetExpression iffalse) implements TargetExpression { +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetThis.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetThis.java new file mode 100644 index 0000000..8775bb9 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetThis.java @@ -0,0 +1,6 @@ +package de.dhbw.compiler.target.tree.expression; + +import de.dhbw.compiler.target.tree.type.TargetType; + +public record TargetThis(TargetType type) implements TargetExpression { +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetThrow.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetThrow.java new file mode 100644 index 0000000..03ffd14 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetThrow.java @@ -0,0 +1,4 @@ +package de.dhbw.compiler.target.tree.expression; + +public record TargetThrow(TargetExpression expr) implements TargetExpression { +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetTypePattern.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetTypePattern.java new file mode 100644 index 0000000..3ebcbf5 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetTypePattern.java @@ -0,0 +1,15 @@ +package de.dhbw.compiler.target.tree.expression; + +import de.dhbw.compiler.target.tree.type.TargetType; + +public record TargetTypePattern(TargetType type, String name) implements TargetPattern { + @Override + public TargetTypePattern withType(TargetType type) { + return new TargetTypePattern(type, name); + } + + @Override + public TargetTypePattern withName(String name) { + return new TargetTypePattern(type, name); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetUnaryOp.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetUnaryOp.java new file mode 100644 index 0000000..8557928 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetUnaryOp.java @@ -0,0 +1,16 @@ +package de.dhbw.compiler.target.tree.expression; + +import de.dhbw.compiler.target.tree.type.TargetType; + +public sealed interface TargetUnaryOp extends TargetExpression { + TargetExpression expr(); + + record Negate(TargetType type, TargetExpression expr) implements TargetUnaryOp {} + record Add(TargetType type, TargetExpression expr) implements TargetUnaryOp {} + record Not(TargetType type, TargetExpression expr) implements TargetUnaryOp {} + + record PreIncrement(TargetType type, TargetExpression expr) implements TargetStatementExpression, TargetUnaryOp {} + record PostIncrement(TargetType type, TargetExpression expr) implements TargetStatementExpression, TargetUnaryOp {} + record PreDecrement(TargetType type, TargetExpression expr) implements TargetStatementExpression, TargetUnaryOp {} + record PostDecrement(TargetType type, TargetExpression expr) implements TargetStatementExpression, TargetUnaryOp {} +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetVarDecl.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetVarDecl.java new file mode 100644 index 0000000..a854bff --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetVarDecl.java @@ -0,0 +1,11 @@ +package de.dhbw.compiler.target.tree.expression; + +import de.dhbw.compiler.target.tree.type.TargetType; + +public record TargetVarDecl(TargetType varType, String name, TargetExpression value) implements TargetExpression { + + @Override + public TargetType type() { + return null; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetWhile.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetWhile.java new file mode 100644 index 0000000..4d4e618 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetWhile.java @@ -0,0 +1,4 @@ +package de.dhbw.compiler.target.tree.expression; + +public record TargetWhile(TargetExpression cond, TargetExpression body) implements TargetExpression { +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetYield.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetYield.java new file mode 100644 index 0000000..3ee3940 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/expression/TargetYield.java @@ -0,0 +1,10 @@ +package de.dhbw.compiler.target.tree.expression; + +import de.dhbw.compiler.target.tree.type.TargetType; + +public record TargetYield(TargetExpression expression) implements TargetExpression { + @Override + public TargetType type() { + return expression.type(); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/type/TargetExtendsWildcard.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/type/TargetExtendsWildcard.java new file mode 100644 index 0000000..998a3f6 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/type/TargetExtendsWildcard.java @@ -0,0 +1,24 @@ +package de.dhbw.compiler.target.tree.type; + +public record TargetExtendsWildcard(TargetType innerType) implements TargetType { + @Override + public String toSignature() { + return innerType.toSignature(); + } + + @Override + public String toDescriptor() { + return "+" + innerType.toDescriptor(); + } + + @Override + public String getInternalName() { + return innerType.getInternalName(); + } + + @Override + public String name() { + return innerType.name(); + } +} + diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/type/TargetFunNType.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/type/TargetFunNType.java new file mode 100644 index 0000000..2f88f7b --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/type/TargetFunNType.java @@ -0,0 +1,41 @@ +package de.dhbw.compiler.target.tree.type; + +import de.dhbw.compiler.bytecode.FunNGenerator; + +import java.util.List; + +public record TargetFunNType(String name, List funNParams, List params, int returnArguments) implements TargetSpecializedType { + + public static TargetFunNType fromParams(List params, int returnArguments) { + return fromParams(params, params, returnArguments); + } + + public static TargetFunNType fromParams(List params, List realParams, int returnArguments) { + var name = FunNGenerator.getSpecializedClassName(FunNGenerator.getArguments(params), FunNGenerator.getReturnType(params)); + return new TargetFunNType(name, params, realParams, returnArguments); + } + + public String toMethodDescriptor() { + var res = "("; + for (var i = 0; i < funNParams.size() - 1; i++) { + res += "Ljava/lang/Object;"; + } + res += ")"; + if (returnArguments > 0) { + res += "Ljava/lang/Object;"; + } else { + res += "V"; + } + return res; + } + + @Override + public String getInternalName() { + return name; + } + + @Override + public String toSignature() { + return "L" + getInternalName() + ";"; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/type/TargetGenericType.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/type/TargetGenericType.java new file mode 100644 index 0000000..f5f39ed --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/type/TargetGenericType.java @@ -0,0 +1,18 @@ +package de.dhbw.compiler.target.tree.type; + +public record TargetGenericType(String name) implements TargetType { + @Override + public String toSignature() { + return "Ljava/lang/Object;"; // TODO Use bounds for this? + } + + @Override + public String toDescriptor() { + return "T" + getInternalName() + ";"; + } + + @Override + public String getInternalName() { + return name; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/type/TargetPrimitiveType.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/type/TargetPrimitiveType.java new file mode 100644 index 0000000..2342ce4 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/type/TargetPrimitiveType.java @@ -0,0 +1,19 @@ +package de.dhbw.compiler.target.tree.type; + +public record TargetPrimitiveType(String name) implements TargetType { + + @Override + public String toSignature() { + return getInternalName(); + } + + @Override + public String toDescriptor() { + return toSignature(); + } + + @Override + public String getInternalName() { + return name; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/type/TargetRefType.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/type/TargetRefType.java new file mode 100644 index 0000000..7687ca3 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/type/TargetRefType.java @@ -0,0 +1,33 @@ +package de.dhbw.compiler.target.tree.type; + +import java.util.List; +import java.util.Objects; + +public record TargetRefType(String name, List params) implements TargetSpecializedType { + public TargetRefType(String name) { + this(name, List.of()); + } + + public String getInternalName() { + return this.name.replaceAll("\\.", "/"); + } + + @Override + public String toSignature() { + return "L" + getInternalName() + ";"; + } + + // Type erasure means we need to override hashCode and equals to only consider the name + @Override + public int hashCode() { + return Objects.hashCode(name); + } + + @Override + public boolean equals(Object other) { + if (other instanceof TargetRefType refType) { + return refType.name.equals(name); + } + return false; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/type/TargetSpecializedType.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/type/TargetSpecializedType.java new file mode 100644 index 0000000..536071a --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/type/TargetSpecializedType.java @@ -0,0 +1,21 @@ +package de.dhbw.compiler.target.tree.type; + +import java.util.List; + +public sealed interface TargetSpecializedType extends TargetType permits TargetFunNType, TargetRefType { + List params(); + + @Override + default String toDescriptor() { + String ret = "L" + getInternalName(); + if (params().size() > 0) { + ret += "<"; + for (var param : params()) { + ret += param.toDescriptor(); + } + ret += ">"; + } + ret += ";"; + return ret; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/type/TargetSuperWildcard.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/type/TargetSuperWildcard.java new file mode 100644 index 0000000..0811604 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/type/TargetSuperWildcard.java @@ -0,0 +1,25 @@ +package de.dhbw.compiler.target.tree.type; + +public record TargetSuperWildcard(TargetType innerType) implements TargetType { + @Override + public String toSignature() { + return innerType.toSignature(); + } + + @Override + public String toDescriptor() { + return "-" + innerType.toDescriptor(); + } + + @Override + public String getInternalName() { + return innerType.getInternalName(); + } + + @Override + public String name() { + return innerType.name(); + } +} + + diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/type/TargetType.java b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/type/TargetType.java new file mode 100644 index 0000000..e7bdf57 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/target/tree/type/TargetType.java @@ -0,0 +1,73 @@ +package de.dhbw.compiler.target.tree.type; + +import de.dhbw.compiler.syntaxtree.type.RefType; + +public sealed interface TargetType + permits TargetExtendsWildcard, TargetGenericType, TargetSpecializedType, TargetSuperWildcard, TargetPrimitiveType { + + // Builtin types + TargetRefType Boolean = new TargetRefType("java.lang.Boolean"); + TargetRefType Char = new TargetRefType("java.lang.Character"); + TargetRefType Byte = new TargetRefType("java.lang.Byte"); + TargetRefType Short = new TargetRefType("java.lang.Short"); + TargetRefType Integer = new TargetRefType("java.lang.Integer"); + TargetRefType Long = new TargetRefType("java.lang.Long"); + TargetRefType Float = new TargetRefType("java.lang.Float"); + TargetRefType Double = new TargetRefType("java.lang.Double"); + TargetRefType String = new TargetRefType("java.lang.String"); + TargetRefType Object = new TargetRefType("java.lang.Object"); + + // Builtin types + TargetPrimitiveType boolean_ = new TargetPrimitiveType("Z"); + TargetPrimitiveType char_ = new TargetPrimitiveType("C"); + TargetPrimitiveType byte_ = new TargetPrimitiveType("B"); + TargetPrimitiveType short_ = new TargetPrimitiveType("S"); + TargetPrimitiveType int_ = new TargetPrimitiveType("I"); + TargetPrimitiveType long_ = new TargetPrimitiveType("J"); + TargetPrimitiveType float_ = new TargetPrimitiveType("F"); + TargetPrimitiveType double_ = new TargetPrimitiveType("D"); + + static TargetType toPrimitive(TargetType type) { + if (type.equals(Boolean)) return boolean_; + if (type.equals(Char)) return char_; + if (type.equals(Byte)) return byte_; + if (type.equals(Short)) return short_; + if (type.equals(Integer)) return int_; + if (type.equals(Long)) return long_; + if (type.equals(Float)) return float_; + if (type.equals(Double)) return double_; + return type; + } + + static TargetType toPrimitive(RefType type) { + return switch(type.getName().toString()) { + case "java.lang.Boolean" -> boolean_; + case "java.lang.Character" -> char_; + case "java.lang.Byte" -> byte_; + case "java.lang.Short" -> short_; + case "java.lang.Integer" -> int_; + case "java.lang.Long" -> long_; + case "java.lang.Float" -> float_; + case "java.lang.Double" -> double_; + default -> null; + }; + } + + static TargetType toWrapper(TargetType f) { + if (f.equals(boolean_)) return Boolean; + if (f.equals(char_)) return Char; + if (f.equals(byte_)) return Byte; + if (f.equals(short_)) return Short; + if (f.equals(int_)) return Integer; + if (f.equals(long_)) return Long; + if (f.equals(float_)) return Float; + if (f.equals(double_)) return Double; + + return f; + } + + String toSignature(); + String toDescriptor(); + String getInternalName(); + String name(); +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typedeployment/KindOfTypeInsertPoint.java b/LanguageServer/src/main/java/de/dhbw/compiler/typedeployment/KindOfTypeInsertPoint.java new file mode 100644 index 0000000..a6b4752 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typedeployment/KindOfTypeInsertPoint.java @@ -0,0 +1,7 @@ +package de.dhbw.compiler.typedeployment; + +public enum KindOfTypeInsertPoint { + NORMAL_INSERT, + GENERIC_CLASS_INSERT, + GENERERIC_METHOD_INSERT +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typedeployment/TypeInsert.java b/LanguageServer/src/main/java/de/dhbw/compiler/typedeployment/TypeInsert.java new file mode 100644 index 0000000..399810d --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typedeployment/TypeInsert.java @@ -0,0 +1,82 @@ +package de.dhbw.compiler.typedeployment; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +import org.antlr.v4.parse.BlockSetTransformer.setAlt_return; + +import de.dhbw.compiler.syntaxtree.statement.This; +import de.dhbw.compiler.typeinference.result.ResultPair; + +public class TypeInsert { + /** + * point wird hauptsächlich zur Anzeige einer Annotation im Eclipse-plugin benutzt. + */ + public final TypeInsertPoint point; + Set inserts; + ResultPair resultPair; + + public TypeInsert(TypeInsertPoint point, Set additionalPoints, ResultPair resultPair){ + this.point = point; + inserts = additionalPoints; + this.resultPair = resultPair; + } + + public String insert(String intoSource){ + List offsets = new ArrayList<>(); + String ret = intoSource; + + List insertsSorted = new ArrayList<>(); + insertsSorted.add(point); + insertsSorted.addAll(inserts); + Collections.sort(insertsSorted, new TypeInsertPoint.TypeInsertPointPositionComparator().reversed()); + + for(TypeInsertPoint insertPoint : insertsSorted) { + ret = insertPoint.insert(ret, new ArrayList<>()); + offsets.add(insertPoint); + } + return ret; + } + + public String getInsertString(){ + return point.getInsertString(); + } + + public ResultPair getResultPair() { + return this.resultPair; + } + + /* PL 2018-06-18 + * Zwei TypeInsert's sind gleich, wenn ihre point's und ihre inserts' gleich sind + * eingefuegt damit man TypeReplaceMarker vergleichen kann + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object obj) { + if(!(obj instanceof TypeInsert)) { + return false; + } + else { + return ((TypeInsert)obj).point.equals(this.point); + + } + } + + public Set getAdditionalPoints() { + TypeInsertPoint.TypeInsertPointPositionComparator comparator = new TypeInsertPoint.TypeInsertPointPositionComparator(); + TreeSet result = new TreeSet<>(comparator.reversed()); + result.addAll(inserts); + return result; + } + + public Set getAdditionalPointsUnsorted() { + return inserts; + } + + public String toString() { + return point.toString(); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typedeployment/TypeInsertFactory.java b/LanguageServer/src/main/java/de/dhbw/compiler/typedeployment/TypeInsertFactory.java new file mode 100644 index 0000000..730bb34 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typedeployment/TypeInsertFactory.java @@ -0,0 +1,204 @@ +package de.dhbw.compiler.typedeployment; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import de.dhbw.compiler.target.generate.GenerateGenerics; +import de.dhbw.compiler.target.generate.GenericsResult; +import de.dhbw.compiler.target.generate.GenericsResultSet; +import de.dhbw.compiler.typeinference.result.*; +import org.antlr.v4.runtime.Token; + +import de.dhbw.compiler.syntaxtree.ClassOrInterface; +import de.dhbw.compiler.syntaxtree.Method; +import de.dhbw.compiler.syntaxtree.SourceFile; +import de.dhbw.compiler.syntaxtree.type.ExtendsWildcardType; +import de.dhbw.compiler.syntaxtree.type.GenericRefType; +import de.dhbw.compiler.syntaxtree.type.RefType; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.syntaxtree.type.SuperWildcardType; +import de.dhbw.compiler.syntaxtree.type.TypePlaceholder; + +/** + * TODO: + * Falls in Feldern Generics entstehen, dann werden diese als Klassenparameter eingesetzt + * Für die Instanzierung von Klassen kann man dann beispielsweise nur noch den Diamond-Operator verwenden + * + * Es müssen zu einem TPH alle in Beziehung stehenden Constraints gefunden werden + * + * Anmekung: Es wird nur ein RefType gleichzeitug eingesetzt. + * Steht dieser mit anderen Typen in Verbindung, so müssen diese nicht eingesetzt werden + * im Result set können nur TPHs mit <. Beziehung stehen + * Steht ein Typ A über TPHs mit anderen Typen B in Verbindung, so lassen sich diese auch im nächsten Durchgang + * inferieren, wenn A bereits eingesetzt wurde. Es werden dann eben zusätzliche Generics entstehen + */ +public class TypeInsertFactory { + + public static Set createTypeInsertPoints(SourceFile forSourcefile, ResultSet withResults, GenericsResult generics) { + return new TypeInsertPlacer().getTypeInserts(forSourcefile, withResults, generics); + } + + public static TypeInsert createInsertPoints(RefTypeOrTPHOrWildcardOrGeneric type, Token offset, ClassOrInterface cl, Method m, + ResultSet resultSet, GenericsResultSet constraints, GenericsResultSet classConstraints) { + + /* PL 2020-04-11 auskommentiert + * try { + */ + ResolvedType resolvedType = resultSet.resolveType(type); + TypeInsertPoint insertPoint = new TypeInsertPoint(offset, + new TypeToInsertString(resolvedType.resolvedType, constraints, classConstraints).insert, KindOfTypeInsertPoint.NORMAL_INSERT); + /* PL 2020-04-11 auskommentiert + List simplifyResults = JavaTXCompiler.INSTANCE.getGeneratedGenericResultsForAllSourceFiles(newResults); + for (GenericGenratorResultForSourceFile simplifyResultsEntries : simplifyResults) { + GenericsGeneratorResultForClass genericResultsForClass = simplifyResultsEntries.getSimplifyResultsByName(cl.getClassName()); + return new TypeInsert(insertPoint, createGenericInsert(genericResultsForClass, cl, m, resultSet, offset), resolvedType.getResultPair()); + } + + return new TypeInsert(insertPoint, new HashSet<>(), resolvedType.getResultPair()); + */ + //GenericsGeneratorResultForClass genericResultsForClass = genericResult.getSimplifyResultsByName("", cl.getClassName().toString()); + return new TypeInsert(insertPoint, createGenericInsert(constraints, classConstraints, cl, m, resultSet, offset), resolvedType.getResultPair()); + + /* PL 2020-04-11 auskommentiert + } catch (ClassNotFoundException e) { + e.printStackTrace(); + return null; + } + */ + } + + private static synchronized Set createGenericInsert(GenericsResultSet methodConstraints, GenericsResultSet classConstraints,ClassOrInterface cl, Method m, ResultSet resultSet, Token mOffset){ + Set result = createGenericClassInserts(classConstraints, cl); + + if (m != null) { + //List methodConstraints = genericResult.getMethodConstraintsByID(MethodUtility.createID(resolver, m)); + result.addAll(createMethodConstraints(methodConstraints, m.getOffset() != null ? m.getOffset() : mOffset)); + } + + return result; + } + + private static Set createMethodConstraints(GenericsResultSet constraints, Token mOffset) { + Set result = new HashSet<>(); + Token offset = mOffset; + + if (constraints.size() == 0) { + return result; + } + + String insert = " <"; + + for (var genericInsertConstraint : constraints) { + if (genericInsertConstraint instanceof GenerateGenerics.PairEQ peq) { + insert += peq.left.resolve().getName(); + } else if (genericInsertConstraint instanceof GenerateGenerics.PairLT psm) { + insert += psm.left.resolve().getName() + " extends " + psm.right.resolve().getName(); + } + insert += ", "; + } + + insert = insert.substring(0, insert.length() -2); + insert += ">"; + + result.add(new TypeInsertPoint(offset, insert, KindOfTypeInsertPoint.GENERERIC_METHOD_INSERT)); + return result; + } + + private static Set createGenericClassInserts(GenericsResultSet classConstraints, ClassOrInterface cl) { + Set result = new HashSet<>(); + Token offset = cl.getGenerics().getOffset(); + + if (classConstraints == null || classConstraints.size() == 0) { + return result; + } + + String insert = " <"; + + for (var genericInsertConstraint : classConstraints) { + if (genericInsertConstraint instanceof GenerateGenerics.PairEQ peq) { + insert += peq.left.resolve().getName(); + } else if (genericInsertConstraint instanceof GenerateGenerics.PairLT psm) { + insert += psm.left.resolve().getName() + " extends " + psm.right.resolve().getName(); + } + insert += ", "; + } + + insert = insert.substring(0, insert.length() -2); + insert += ">"; + + result.add(new TypeInsertPoint(offset, insert, KindOfTypeInsertPoint.GENERIC_CLASS_INSERT)); + + return result; + } +} + +class TypeToInsertString implements ResultSetVisitor{ + String insert = ""; + private GenericsResultSet constraints; + private GenericsResultSet classConstraints; + + + TypeToInsertString(RefTypeOrTPHOrWildcardOrGeneric type, GenericsResultSet constraints, GenericsResultSet classConstraints){ + this.constraints = constraints; + this.classConstraints = classConstraints; + type.accept(this); + } + + @Override + public void visit(PairTPHsmallerTPH p) { + + } + + @Override + public void visit(PairTPHequalRefTypeOrWildcardType p) { + + } + + @Override + public void visit(PairTPHEqualTPH p) { + + } + + @Override + public void visit(RefType resolved) { + insert = resolved.getName().toString(); + if(resolved.getParaList().size() > 0){ + insert += "<"; + Iterator iterator = resolved.getParaList().iterator(); + while(iterator.hasNext()){ + RefTypeOrTPHOrWildcardOrGeneric typeParam = iterator.next(); + insert += new TypeToInsertString(typeParam, constraints, classConstraints).insert; + if(iterator.hasNext())insert += ", "; + } + insert += ">"; + } + } + + @Override + public void visit(GenericRefType genericRefType) { + insert += genericRefType.getParsedName(); + } + + @Override + public void visit(SuperWildcardType superWildcardType) { + insert += "? super " + new TypeToInsertString(superWildcardType.getInnerType(), constraints, classConstraints).insert; + } + + @Override + public void visit(TypePlaceholder typePlaceholder) { + ResultPair resultPair = null; + if (constraints != null) + resultPair = constraints.getResultPairFor(typePlaceholder).orElse(null); + if (resultPair == null) + resultPair = classConstraints.getResultPairFor(typePlaceholder).orElse(null); + + if (resultPair != null) + insert += ((TypePlaceholder)resultPair.getLeft()).getName(); + } + + @Override + public void visit(ExtendsWildcardType extendsWildcardType) { + insert += "? extends " + new TypeToInsertString(extendsWildcardType.getInnerType(), constraints, classConstraints).insert; + } +} \ No newline at end of file diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typedeployment/TypeInsertPlacer.java b/LanguageServer/src/main/java/de/dhbw/compiler/typedeployment/TypeInsertPlacer.java new file mode 100644 index 0000000..5b06a67 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typedeployment/TypeInsertPlacer.java @@ -0,0 +1,88 @@ +package de.dhbw.compiler.typedeployment; + +import de.dhbw.compiler.syntaxtree.*; +import de.dhbw.compiler.syntaxtree.statement.LambdaExpression; +import de.dhbw.compiler.syntaxtree.type.TypePlaceholder; +import de.dhbw.compiler.target.generate.GenericsResult; +import de.dhbw.compiler.target.generate.GenericsResultSet; +import de.dhbw.compiler.typeinference.result.ResultPair; +import de.dhbw.compiler.typeinference.result.ResultSet; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class TypeInsertPlacer extends AbstractASTWalker { + Set inserts = new HashSet<>(); + private ResultSet withResults; + String pkgName; + private GenericsResult genericsResult; + + public Set getTypeInserts(SourceFile forSourceFile, ResultSet withResults, GenericsResult genericsResult){ + this.withResults = withResults; + this.genericsResult = genericsResult; + pkgName = forSourceFile.getPkgName(); + forSourceFile.accept(this); + return inserts; + } + + @Override + public void visit(ClassOrInterface classOrInterface) { + TypeInsertPlacerClass cl = new TypeInsertPlacerClass(classOrInterface, withResults, genericsResult); + this.inserts.addAll(cl.inserts); + } +} + +class TypeInsertPlacerClass extends AbstractASTWalker{ + protected final ResultSet results; + private GenericsResult generatedGenerics; + protected final ClassOrInterface cl; + public final Set inserts = new HashSet<>(); + private Method method; + + GenericsResultSet constraints; + GenericsResultSet classConstraints; + + TypeInsertPlacerClass(ClassOrInterface forClass, ResultSet withResults, GenericsResult generatedGenerics){ + this.cl = forClass; + this.method = null; + this.results = withResults; + this.generatedGenerics = generatedGenerics; + forClass.accept(this); + } + + @Override + public void visit(Method method) { + this.method = method; + constraints = generatedGenerics.get(method); + classConstraints = generatedGenerics.get(cl); + if(method.getReturnType() instanceof TypePlaceholder) + inserts.add(TypeInsertFactory.createInsertPoints( + method.getReturnType(), method.getReturnType().getOffset(), cl, method, results, constraints, classConstraints)); + super.visit(method); + } + + @Override + public void visit(Field field) { + if(field.getType() instanceof TypePlaceholder){ + classConstraints = generatedGenerics.get(cl); + inserts.add(TypeInsertFactory.createInsertPoints( + field.getType(), field.getType().getOffset(), cl, method, results, null, classConstraints)); + } + super.visit(field); + } + + @Override + public void visit(FormalParameter param) { + if(param.getType() instanceof TypePlaceholder) + inserts.add(TypeInsertFactory.createInsertPoints( + param.getType(), param.getType().getOffset(), cl, method, results, constraints, classConstraints)); + super.visit(param); + } + + @Override + public void visit(LambdaExpression lambdaExpression) { + //Lambda-Ausdrücke brauchen keine Typeinsetzungen + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typedeployment/TypeInsertPoint.java b/LanguageServer/src/main/java/de/dhbw/compiler/typedeployment/TypeInsertPoint.java new file mode 100644 index 0000000..d305c8a --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typedeployment/TypeInsertPoint.java @@ -0,0 +1,93 @@ +package de.dhbw.compiler.typedeployment; + +import java.util.Comparator; +import java.util.List; +import java.util.Set; + +import org.antlr.v4.runtime.Token; + +public class TypeInsertPoint { + public Token point; + private String insertString; + private int extraOffset = 0; + private KindOfTypeInsertPoint kind; + + public TypeInsertPoint(Token point, String toInsert, KindOfTypeInsertPoint kind){ + this.point = point; + this.kind = kind; + this.insertString = (toInsert.endsWith(" ")) ? toInsert : toInsert + " " ; + } + + public boolean isGenericClassInsertPoint() { + return kind == KindOfTypeInsertPoint.GENERIC_CLASS_INSERT; + } + + public String insert(String intoSource, List additionalOffset){ + return new StringBuilder(intoSource).insert(point.getStartIndex()+extraOffset, insertString).toString(); + } + + public String getInsertString() { + return insertString; + } + + public void addExtraOffset(int toAdd) { + this.extraOffset += toAdd; + } + + public int getPositionInCode() { + return point.getStartIndex() + extraOffset; + } + + /* PL 2018-06-19 + * Zwei TypeInsertPoint's sind gleich, wenn ihre point's gleich sind + * eingefuegt damit man TypeReplaceMarker vergleichen kann + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object obj) { + return this == obj; + /* + if(!(obj instanceof TypeInsertPoint)) { + return false; + } + else { + return + ((TypeInsertPoint)obj).getPositionInCode() == this.getPositionInCode() && + ((TypeInsertPoint)obj).insertString.equals(this.insertString); + } + */ + } + + public int hashCode() { + return getPositionInCode() * 11 * insertString.hashCode(); + } + + public Set getAdditionalPoints() { + return this.getAdditionalPoints(); + } + + public String toString() { + return point.getLine() + ":" + point.getCharPositionInLine() + ":" + insertString; + } + + public static final class TypeInsertPointPositionComparator implements Comparator { + + @Override + public int compare(TypeInsertPoint o1, TypeInsertPoint o2) { + if (o1.point == null && o2.point == null) { + return 0; + } else if (o2.point == null) { + return 1; + } else if (o1.point == null) { + return -1; + } + + if (o1.getPositionInCode() > o2.getPositionInCode()) { + return 1; + } else if (o1.getPositionInCode() < o2.getPositionInCode()) { + return -1; + } + return 0; + } + + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/assumptions/Assumption.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/assumptions/Assumption.java new file mode 100644 index 0000000..099c11b --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/assumptions/Assumption.java @@ -0,0 +1,15 @@ +package de.dhbw.compiler.typeinference.assumptions; + +import de.dhbw.compiler.syntaxtree.TypeScope; + +public class Assumption { + private final TypeScope typeScope; + + public Assumption(TypeScope typeScope) { + this.typeScope = typeScope; + } + + public TypeScope getTypeScope() { + return typeScope; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/assumptions/FieldAssumption.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/assumptions/FieldAssumption.java new file mode 100644 index 0000000..dd0d53d --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/assumptions/FieldAssumption.java @@ -0,0 +1,49 @@ +package de.dhbw.compiler.typeinference.assumptions; + +import de.dhbw.compiler.exceptions.NotImplementedException; +import de.dhbw.compiler.parser.NullToken; +import de.dhbw.compiler.syntaxtree.ClassOrInterface; +import de.dhbw.compiler.syntaxtree.GenericTypeVar; +import de.dhbw.compiler.syntaxtree.TypeScope; +import de.dhbw.compiler.syntaxtree.type.GenericRefType; +import de.dhbw.compiler.syntaxtree.type.RefType; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.typeinference.constraints.GenericsResolver; + +import java.util.ArrayList; +import java.util.List; + +public class FieldAssumption extends Assumption{ + private ClassOrInterface receiverClass; + private RefTypeOrTPHOrWildcardOrGeneric type; + private String name; + + public FieldAssumption(String fieldName, ClassOrInterface receiverType, + RefTypeOrTPHOrWildcardOrGeneric type, TypeScope scope){ + super(scope); + this.type = type; + this.receiverClass = receiverType; + this.name = fieldName; + } + + public ClassOrInterface getReceiverClass() { + return receiverClass; + } + + public RefTypeOrTPHOrWildcardOrGeneric getType(GenericsResolver resolver) { + return resolver.resolve(type); + } + + public RefTypeOrTPHOrWildcardOrGeneric getReceiverType(GenericsResolver resolver) { + List params = new ArrayList<>(); + for(GenericTypeVar gtv : receiverClass.getGenerics()){ + //Hier wird ein GenericRefType gebildet, welcher einen für dieses Feld eindeutigen Namen hat + GenericRefType genericRefType = + new GenericRefType(gtv.getName() + , new NullToken()); + //Dieser wird dann korrekt aufgelöst vom Resolver: + params.add(resolver.resolve(genericRefType)); + } + return new RefType(receiverClass.getClassName(), params, new NullToken()); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/assumptions/FunNClass.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/assumptions/FunNClass.java new file mode 100644 index 0000000..5cba7c7 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/assumptions/FunNClass.java @@ -0,0 +1,42 @@ +package de.dhbw.compiler.typeinference.assumptions; + +import de.dhbw.compiler.parser.NullToken; +import de.dhbw.compiler.parser.scope.JavaClassName; +import de.dhbw.compiler.syntaxtree.ClassOrInterface; +import de.dhbw.compiler.syntaxtree.GenericDeclarationList; +import de.dhbw.compiler.syntaxtree.GenericTypeVar; +import de.dhbw.compiler.syntaxtree.Method; +import de.dhbw.compiler.syntaxtree.factory.ASTFactory; +import de.dhbw.compiler.syntaxtree.factory.NameGenerator; +import de.dhbw.compiler.syntaxtree.type.GenericRefType; +import de.dhbw.compiler.syntaxtree.type.RefType; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.syntaxtree.type.TypePlaceholder; + +import org.antlr.v4.runtime.Token; + +import javax.swing.text.html.Option; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +public class FunNClass extends ClassOrInterface { + public FunNClass(List 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(), null); + + } + + private static GenericDeclarationList createGenerics(List funNParams) { + // PL 2018-06-22: so geaendert, dass generierte Generics den Namen der funParams entsprechen. + List generics = new ArrayList<>(); + for (GenericRefType param : funNParams) { + generics.add(new GenericTypeVar(param.getParsedName(), // NameGenerator.makeNewName(), + new ArrayList<>(), new NullToken(), new NullToken())); + } + return new GenericDeclarationList(generics, new NullToken()); + } + + private static List createMethods(List funNParams) { + return null; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/assumptions/MethodAssumption.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/assumptions/MethodAssumption.java new file mode 100644 index 0000000..7a0f52a --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/assumptions/MethodAssumption.java @@ -0,0 +1,83 @@ +package de.dhbw.compiler.typeinference.assumptions; + +import de.dhbw.compiler.parser.NullToken; +import de.dhbw.compiler.parser.scope.JavaClassName; +import de.dhbw.compiler.syntaxtree.ClassOrInterface; +import de.dhbw.compiler.syntaxtree.GenericTypeVar; +import de.dhbw.compiler.syntaxtree.TypeScope; +import de.dhbw.compiler.syntaxtree.type.GenericRefType; +import de.dhbw.compiler.syntaxtree.type.RefType; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.syntaxtree.type.Void; +import de.dhbw.compiler.typeinference.constraints.GenericsResolver; +import de.dhbw.compiler.typeinference.typeAlgo.TYPEStmt; + +import java.util.ArrayList; +import java.util.List; + +public class MethodAssumption extends Assumption{ + private ClassOrInterface receiver; + private RefTypeOrTPHOrWildcardOrGeneric retType; + List params; + private final Boolean isInherited; + private final Boolean isOverridden; + + public MethodAssumption(ClassOrInterface receiver, RefTypeOrTPHOrWildcardOrGeneric retType, + List params, TypeScope scope, Boolean isInherited, Boolean isOverridden){ + super(scope); + this.receiver = receiver; + this.retType = retType; + this.params = params; + this.isInherited = isInherited; + this.isOverridden = isOverridden; + } + + /* + public RefType getReceiverType() { + + return receiver; + } + */ + + public ClassOrInterface getReceiver(){ + return receiver; + } + + public RefTypeOrTPHOrWildcardOrGeneric getReturnType() { + return retType; + } + + public List getArgTypes(){ + return params; + } + + public RefTypeOrTPHOrWildcardOrGeneric getReturnType(GenericsResolver resolver) { + return resolver.resolve(retType); + } + + public List getArgTypes(GenericsResolver resolver) { + List ret = new ArrayList<>(); + for(RefTypeOrTPHOrWildcardOrGeneric param : params){ + param = resolver.resolve(param); + ret.add(param); + } + return ret; + } + + /** + * + * @param resolver + * @return + */ + public RefTypeOrTPHOrWildcardOrGeneric getReceiverType(GenericsResolver resolver) { + return TYPEStmt.getReceiverType(receiver, resolver); + } + + public Boolean isInherited() { + return isInherited; + } + + public Boolean isOverridden() { + return isOverridden; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/assumptions/TypeInferenceBlockInformation.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/assumptions/TypeInferenceBlockInformation.java new file mode 100644 index 0000000..f7913c4 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/assumptions/TypeInferenceBlockInformation.java @@ -0,0 +1,46 @@ +package de.dhbw.compiler.typeinference.assumptions; + +import com.google.common.collect.Iterables; +import com.google.common.collect.Iterators; +import de.dhbw.compiler.bytecode.CodeGenException; +import de.dhbw.compiler.exceptions.DebugException; +import de.dhbw.compiler.syntaxtree.ClassOrInterface; +import de.dhbw.compiler.syntaxtree.GenericTypeVar; +import de.dhbw.compiler.syntaxtree.Method; +import de.dhbw.compiler.syntaxtree.TypeScope; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Set; +import java.util.Stack; +import java.util.stream.Collectors; + +public class TypeInferenceBlockInformation extends TypeInferenceInformation { + private TypeScope methodContext; + private ClassOrInterface currentClass; + + public TypeInferenceBlockInformation(Collection availableClasses, + ClassOrInterface currentClass, TypeScope methodContext) { + super(availableClasses); + this.methodContext = new TypeScopeContainer(currentClass, methodContext); + this.currentClass = currentClass; + } + public TypeInferenceBlockInformation(TypeInferenceBlockInformation oldScope, TypeScope newScope) { + this(oldScope.getAvailableClasses(), oldScope.currentClass, new TypeScopeContainer(oldScope.methodContext, newScope)); + } + public ClassOrInterface getCurrentClass() { + return currentClass; + } + + public ClassOrInterface getSuperClass() { + for (var clazz : getAvailableClasses()) { + if (clazz.getClassName().equals(currentClass.getSuperClass().getName())) + return clazz; + } + throw new DebugException("Class has no superclass!"); + } + public TypeScope getCurrentTypeScope() { + return methodContext; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/assumptions/TypeInferenceInformation.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/assumptions/TypeInferenceInformation.java new file mode 100644 index 0000000..c928fc1 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/assumptions/TypeInferenceInformation.java @@ -0,0 +1,61 @@ +package de.dhbw.compiler.typeinference.assumptions; + +import de.dhbw.compiler.exceptions.NotImplementedException; +import de.dhbw.compiler.parser.NullToken; +import de.dhbw.compiler.syntaxtree.*; +import de.dhbw.compiler.syntaxtree.statement.ArgumentList; +import de.dhbw.compiler.syntaxtree.type.GenericRefType; +import de.dhbw.compiler.syntaxtree.type.RefType; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.syntaxtree.type.TypePlaceholder; +import de.dhbw.compiler.typeinference.constraints.Constraint; +import de.dhbw.compiler.typeinference.constraints.Pair; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Set; + +/* +Anmerkung: +Zwei Möglichkeiten, die TypeAssumptions zu speichern. +1. Die Klassen mit bedeutenden Informationen generieren diese und übergeben sie dann dieser Klasse. +2. Oder es werden nur Referenzen auf den SyntaxTree übergeben, welche diese Klasse hier dann verarbeitet. + +Bei Änderungen des SyntaxTrees müssen beide Methoden angepasst werden. +Zweiteres hat den Vorteil, dass bei der Entwicklung leichter Dinge hinzugefügt werden können. +Die ganze Logik steckt in dieser Klasse. + */ +public class TypeInferenceInformation { + private Collection classes; + + public TypeInferenceInformation(Collection availableClasses){ + classes = availableClasses; + } + + public RefTypeOrTPHOrWildcardOrGeneric checkGTV(RefTypeOrTPHOrWildcardOrGeneric type){ + if(type instanceof GenericRefType){ + return TypePlaceholder.fresh(new NullToken()); + }else{ + return type; + } + } + + public List getFields(String name){ + List ret = new ArrayList<>(); + for(ClassOrInterface cl : classes){ + for(Field m : cl.getFieldDecl()){ + if(m.getName().equals(name)){ + + ret.add(new FieldAssumption(name, cl, m.getType(), new TypeScopeContainer(cl, m))); + } + } + } + return ret; + } + + public Collection getAvailableClasses() { + return classes; + } + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/assumptions/TypeScopeContainer.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/assumptions/TypeScopeContainer.java new file mode 100644 index 0000000..e0ddca1 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/assumptions/TypeScopeContainer.java @@ -0,0 +1,32 @@ +package de.dhbw.compiler.typeinference.assumptions; + +import com.google.common.collect.Iterables; +import de.dhbw.compiler.syntaxtree.GenericTypeVar; +import de.dhbw.compiler.syntaxtree.TypeScope; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; + +import java.util.ArrayList; +import java.util.Stack; +import java.util.stream.Collectors; + +public class TypeScopeContainer implements TypeScope { + ArrayList scopes = new ArrayList<>(); + Stack types = new Stack<>(); + public TypeScopeContainer(TypeScope scope1, TypeScope scope2){ + scopes.add(scope1); + scopes.add(scope2); + types.push(scope1.getReturnType()); + types.push(scope2.getReturnType()); + } + + @Override + public Iterable getGenerics() { + return Iterables.concat(scopes.stream(). + map(TypeScope::getGenerics).collect(Collectors.toList()).toArray(new Iterable[0])); + } + + @Override + public RefTypeOrTPHOrWildcardOrGeneric getReturnType() { + return types.peek(); + } +} \ No newline at end of file diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/constraints/Constraint.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/constraints/Constraint.java new file mode 100644 index 0000000..426432a --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/constraints/Constraint.java @@ -0,0 +1,77 @@ +package de.dhbw.compiler.typeinference.constraints; + +import de.dhbw.compiler.typeinference.unify.model.UnifyPair; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +public class Constraint
extends HashSet { + private static final long serialVersionUID = 1L; + private Boolean isInherited = false;//wird beides nur für die Method-Constraints benoetigt + private Boolean isImplemented = false; + + /* + * wird verwendet um bei der Codegenerierung die richtige Methoden - Signatur + * auszuwaehlen + */ + /*private*/ Set methodSignatureConstraint = new HashSet<>(); + + private Constraint extendConstraint = null; + + public Constraint() { + super(); + } + + public Constraint(Boolean isInherited, Boolean isImplemented) { + this.isInherited = isInherited; + this.isImplemented = isImplemented; + } + + public Constraint(Boolean isInherited, Boolean isImplemented, Constraint extendConstraint, Set methodSignatureConstraint) { + this.isInherited = isInherited; + this.isImplemented = isImplemented; + this.extendConstraint = extendConstraint; + this.methodSignatureConstraint = methodSignatureConstraint; + } + + public void setIsInherited(Boolean isInherited) { + this.isInherited = isInherited; + } + + public Boolean isInherited() { + return isInherited; + } + + public Boolean isImplemented() { + return isImplemented; + } + + public Constraint getExtendConstraint() { + return extendConstraint; + } + + public void setExtendConstraint(Constraint c) { + extendConstraint = c; + } + + public Set getmethodSignatureConstraint() { + return methodSignatureConstraint; + } + + public void setmethodSignatureConstraint(Set c) { + methodSignatureConstraint = c; + } + + public String toString() { + return super.toString() + "\nisInherited = " + isInherited + " isOveridden = " + isImplemented + + methodSignatureConstraint + //" + extendsContraint: " + (extendConstraint != null ? extendConstraint.toStringBase() : "null" ) + + "\n" ; + } + + public String toStringBase() { + return super.toString(); + } + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/constraints/ConstraintSet.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/constraints/ConstraintSet.java new file mode 100644 index 0000000..98e9b77 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/constraints/ConstraintSet.java @@ -0,0 +1,130 @@ +package de.dhbw.compiler.typeinference.constraints; + + +import de.dhbw.compiler.syntaxtree.type.TypePlaceholder; +import de.dhbw.compiler.typeinference.unify.GuavaSetOperations; +import de.dhbw.compiler.typeinference.unify.model.UnifyPair; + +import java.util.*; +import java.util.function.BinaryOperator; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class ConstraintSet { + Constraint undConstraints = new Constraint<>(); + List>> oderConstraints = new ArrayList<>(); + + public void addUndConstraint(A p){ + undConstraints.add(p); + } + + public void addOderConstraint(Set> methodConstraints) { + oderConstraints.add(methodConstraints); + } + + public void addAllUndConstraint(Constraint allUndConstraints){ + undConstraints.addAll(allUndConstraints); + } + + public void addAllOderConstraint(List>> allOderConstraints){ + this.oderConstraints.addAll(allOderConstraints); + } + + public void addAll(ConstraintSet constraints) { + this.addAllUndConstraint(constraints.undConstraints); + this.addAllOderConstraint(constraints.oderConstraints); + } + + @Override + public String toString(){ + BinaryOperator b = (x,y) -> x+y; + return "\nUND:" + this.undConstraints.toString() + "\n" + + "ODER:" + this.oderConstraints.stream().reduce("", (x,y) -> x.toString()+ "\n" +y, b); + //cartesianProduct().toString(); + } + + public Set>> cartesianProduct(){ + Set> toAdd = new HashSet<>(); + toAdd.add(undConstraints); + List>> allConstraints = new ArrayList<>(); + allConstraints.add(toAdd); + allConstraints.addAll(oderConstraints); + return new GuavaSetOperations().cartesianProduct(allConstraints); + } + + public ConstraintSet map(Function o) { + Hashtable,Constraint> CSA2CSB = new Hashtable<>(); + ConstraintSet ret = new ConstraintSet<>(); + ret.undConstraints = undConstraints.stream().map(o).collect(Collectors.toCollection(Constraint::new)); + List>> newOder = new ArrayList<>(); + /* + for(Set> oderConstraint : oderConstraints){ + oderConstraint.forEach(as -> { + Constraint newConst = as.stream() + .map(o) + .collect(Collectors.toCollection( + () -> new Constraint (as.isInherited()))); + CSA2CSB.put(as, newConst);} ); + } + */ + + for(Set> oderConstraint : oderConstraints){ + newOder.add( + oderConstraint.stream().map((Constraint as) -> { + + Constraint newConst = as.stream() + .map(o) + .collect(Collectors.toCollection(( + () -> new Constraint (as.isInherited(), + as.isImplemented(), + (as.getExtendConstraint() != null) + ? as.getExtendConstraint().stream().map(o).collect(Collectors.toCollection(Constraint::new)) + : null, + as.getmethodSignatureConstraint().stream().map(o).collect(Collectors.toCollection(HashSet::new)))) + )); + + //CSA2CSB.put(as, newConst); + + return newConst; + + /* + Constraint bs = CSA2CSB.get(as); + if (as.getExtendConstraint() != null) { + bs.setExtendConstraint(CSA2CSB.get(as.getExtendConstraint())); + } + return bs; + */ + }).collect(Collectors.toSet()) + ); + } + + ret.oderConstraints = newOder; + return ret; + } + + public void forEach (Consumer c) { + undConstraints.stream().forEach(c); + for(Set> oderConstraint : oderConstraints){ + oderConstraint.parallelStream().forEach((Constraint as) -> + as.stream().forEach(c)); + } + } + + public Set getAll () { + Set ret = new HashSet<>(); + ret.addAll(undConstraints); + for(Set> oderConstraint : oderConstraints){ + oderConstraint.parallelStream().forEach((Constraint as) -> ret.addAll(as)); + } + return ret; + } + + public List>> getOderConstraints() { + return oderConstraints; + } + + public Set getUndConstraints() { + return undConstraints; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/constraints/GenericsResolver.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/constraints/GenericsResolver.java new file mode 100644 index 0000000..d3139ba --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/constraints/GenericsResolver.java @@ -0,0 +1,14 @@ +package de.dhbw.compiler.typeinference.constraints; + +import de.dhbw.compiler.syntaxtree.GenericTypeVar; +import de.dhbw.compiler.syntaxtree.type.GenericRefType; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.syntaxtree.type.TypePlaceholder; + +/** + * Wird für Generics benötigt + * TODO: Erklörung! + */ +public interface GenericsResolver { + public RefTypeOrTPHOrWildcardOrGeneric resolve(RefTypeOrTPHOrWildcardOrGeneric generic); +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/constraints/Pair.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/constraints/Pair.java new file mode 100644 index 0000000..e7fe610 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/constraints/Pair.java @@ -0,0 +1,155 @@ +package de.dhbw.compiler.typeinference.constraints; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +import de.dhbw.compiler.parser.NullToken; +import de.dhbw.compiler.parser.SourceLoc; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.syntaxtree.type.TypePlaceholder; +import de.dhbw.compiler.typeinference.unify.model.PairOperator; +import org.antlr.v4.runtime.Token; + + +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; + + + private Pair(RefTypeOrTPHOrWildcardOrGeneric TA1, RefTypeOrTPHOrWildcardOrGeneric TA2 ) + { + this.TA1 = TA1; + this.TA2 = TA2; + if(TA1 == null || TA2 == null) + throw new NullPointerException(); + eOperator = PairOperator.SMALLER; + } + + public Pair(RefTypeOrTPHOrWildcardOrGeneric TA1, RefTypeOrTPHOrWildcardOrGeneric TA2, PairOperator eOp) + { + // Konstruktor + this(TA1,TA2); + 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) + { + // Konstruktor + this(TA1,TA2); + this.eOperator = eOp; + this.noUnification = noUnification; + } + + public SourceLoc getLocation() { + return this.location; + } + + public String toString() + { + // otth: Gibt ein Paar als String aus --> zum Debuggen und Vergleichen + String strElement1 = "NULL"; + String strElement2 = "NULL"; + String Operator = "<."; + + if( TA1 != null ) + strElement1 = TA1.toString(); + + if( TA2 != null ) + strElement2 = TA2.toString(); + + /* PL ausskommentiert 2018-05-24 + if(OperatorEqual()) + Operator = "="; + if(OperatorSmaller()) + Operator = "<."; + if(OperatorSmallerExtends()) + Operator = "Author: J�rg B�uerle + * @param obj + * @return + */ + public boolean equals(Object obj) + { + boolean ret = true; + ret &= (obj instanceof Pair); + if(!ret)return ret; + ret &= ((Pair)obj).TA1.equals(this.TA1); + ret &= ((Pair)obj).TA2.equals(this.TA2); + return ret; + } + + /** + * Author: Arne Lüdtke
+ * Abfrage, ob Operator vom Typ Equal ist. + */ + public boolean OperatorEqual() + { + return eOperator == PairOperator.EQUALSDOT; + } + + /** + * Author: Arne Lüdtke
+ * Abfrage, ob Operator vom Typ Smaller ist. + */ + public boolean OperatorSmaller() + { + return eOperator == PairOperator.SMALLER; + } + + /** + * Author: Arne Lüdtke
+ * Abfrage, ob Operator vom Typ SmallerExtends ist. + */ + public boolean OperatorSmallerExtends() + { + return eOperator == PairOperator.SMALLERDOTWC; + } + + /** + * Author: Arne Lüdtke
+ * Gibt den Operator zurück. + */ + public PairOperator GetOperator() + { + return eOperator; + } + + public boolean OperatorSmallerDot() { + return eOperator == PairOperator.SMALLERDOT; + } + + + static public Map generateTPHMap(ConstraintSet constraints) { + HashMap ret = new HashMap<>(); + constraints.map((Pair p) -> { + if (p.TA1 instanceof TypePlaceholder) { + ret.put(((TypePlaceholder) p.TA1).getName(), (TypePlaceholder) p.TA1); + } + if (p.TA2 instanceof TypePlaceholder) { + ret.put(((TypePlaceholder) p.TA2).getName(), (TypePlaceholder) p.TA2); + } + return null; + }); + return ret; + } +} +// ino.end diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/GenericInsertPair.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/GenericInsertPair.java new file mode 100644 index 0000000..99f774f --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/GenericInsertPair.java @@ -0,0 +1,31 @@ +package de.dhbw.compiler.typeinference.result; + +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.syntaxtree.type.TypePlaceholder; +import de.dhbw.compiler.typeinference.constraints.Pair; + +public class GenericInsertPair { + public TypePlaceholder TA1; + public TypePlaceholder TA2; + + public GenericInsertPair(TypePlaceholder additionalTPH, TypePlaceholder superType) { + TA1 = additionalTPH; + TA2 = superType; + } + + public GenericInsertPair(Pair pair) { + TA1 = (TypePlaceholder) pair.TA1; + TA2 = (TypePlaceholder) pair.TA2; + } + + public boolean contains(TypePlaceholder additionalTPH) { + if(TA1.equals(additionalTPH))return true; + if(TA2.equals(additionalTPH))return true; + return false; + } + + @Override + public String toString() { + return "GenIns(" + TA1.toString() + " < " + TA2.toString() + ")"; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/PairNoResult.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/PairNoResult.java new file mode 100644 index 0000000..8110475 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/PairNoResult.java @@ -0,0 +1,32 @@ +package de.dhbw.compiler.typeinference.result; + +import de.dhbw.compiler.exceptions.NotImplementedException; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.syntaxtree.type.TypePlaceholder; + +/** + * enthaelt alle Paare, die in einem Ergebnis nicht vorkommen koennen + * sie sind noetig fuer origPairs in PairTPHsmallerTPH, da hier auch + * Paare vorkommen koennen die keine Result sind (z.B. bei FunN$$) + */ +public class PairNoResult extends ResultPair{ + //public final TypePlaceholder left; + //public final TypePlaceholder right; + + /* + * urspruengliches Paar aus diesem dieses Resultpair erzeugt wurde + * wichtig fuer generated Generics + */ + ResultPair origPair; + + public PairNoResult(RefTypeOrTPHOrWildcardOrGeneric left, RefTypeOrTPHOrWildcardOrGeneric right){ + super(left, right); + } + + /* noch nicht implementiert. */ + @Override + public void accept(ResultPairVisitor visitor) { + throw new NotImplementedException(); + //visitor.visit(this); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/PairTPHEqualTPH.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/PairTPHEqualTPH.java new file mode 100644 index 0000000..abd12a0 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/PairTPHEqualTPH.java @@ -0,0 +1,15 @@ +package de.dhbw.compiler.typeinference.result; + +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.syntaxtree.type.TypePlaceholder; + +public class PairTPHEqualTPH extends ResultPair { + public PairTPHEqualTPH(TypePlaceholder tl, TypePlaceholder tr) { + super(tl, tr); + } + + @Override + public void accept(ResultPairVisitor visitor) { + visitor.visit(this); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/PairTPHequalRefTypeOrWildcardType.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/PairTPHequalRefTypeOrWildcardType.java new file mode 100644 index 0000000..4a726aa --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/PairTPHequalRefTypeOrWildcardType.java @@ -0,0 +1,29 @@ +package de.dhbw.compiler.typeinference.result; + +import de.dhbw.compiler.syntaxtree.type.RefType; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.syntaxtree.type.TypePlaceholder; + +/** + * Steht für A =. RefType + */ +public class PairTPHequalRefTypeOrWildcardType extends ResultPair{ + public final TypePlaceholder left; + public final RefTypeOrTPHOrWildcardOrGeneric right; + + public PairTPHequalRefTypeOrWildcardType(TypePlaceholder left, RefTypeOrTPHOrWildcardOrGeneric right){ + super(left, right); + this.left = left; + this.right = right; + } + + @Override + public void accept(ResultPairVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "(" + left.toString() + " = " + right.toString() + ")"; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/PairTPHsmallerTPH.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/PairTPHsmallerTPH.java new file mode 100644 index 0000000..b6d6fdc --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/PairTPHsmallerTPH.java @@ -0,0 +1,39 @@ +package de.dhbw.compiler.typeinference.result; + +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.syntaxtree.type.TypePlaceholder; + +/** + * Steht für: A <. B + */ +public class PairTPHsmallerTPH extends ResultPair{ + public final TypePlaceholder left; + public final TypePlaceholder right; + + /* + * urspruengliches Paar aus diesem dieses Resultpair erzeugt wurde + * wichtig fuer generated Generics + */ + ResultPair origPair; + + public PairTPHsmallerTPH(TypePlaceholder left, TypePlaceholder right){ + super(left, right); + this.left = left; + this.right = right; + } + + public PairTPHsmallerTPH(TypePlaceholder left, TypePlaceholder right, ResultPair origPair){ + this(left, right); + this.origPair = origPair; + } + + @Override + public void accept(ResultPairVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "(" + left.toString() + " < " + right.toString() + ")"; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/ResolvedType.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/ResolvedType.java new file mode 100644 index 0000000..1cb4c4e --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/ResolvedType.java @@ -0,0 +1,27 @@ +package de.dhbw.compiler.typeinference.result; + +import de.dhbw.compiler.syntaxtree.type.GenericRefType; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.syntaxtree.type.TypePlaceholder; + +import java.util.Set; + +public class ResolvedType{ + private ResultPair resultPair; + + public final RefTypeOrTPHOrWildcardOrGeneric resolvedType; + //public final Set additionalGenerics; + + public ResolvedType(RefTypeOrTPHOrWildcardOrGeneric resolvedType, Set additionalGenerics){ + this.resolvedType = resolvedType; + //this.additionalGenerics = additionalGenerics; + } + + public void setResultPair(ResultPair resultPair) { + this.resultPair = resultPair; + } + + public ResultPair getResultPair() { + return resultPair; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/ResultPair.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/ResultPair.java new file mode 100644 index 0000000..eee8403 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/ResultPair.java @@ -0,0 +1,62 @@ +package de.dhbw.compiler.typeinference.result; + +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; + +/** + * Paare, welche das Unifikationsergebnis darstellen + */ +public abstract class ResultPair
{ + private final A left; + private final B right; + + public abstract void accept(ResultPairVisitor visitor); + + public ResultPair(A left, B right){ + this.left = left; + this.right = right; + } + + public A getLeft() { + return left; + } + + public B getRight() { + return right; + } + + public String toString() { + return "(" + left.toString() + ", " + right.toString() + ")"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((left == null) ? 0 : left.getOffset().hashCode()); + result = prime * result + ((right == null) ? 0 : right.getOffset().hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + ResultPair other = (ResultPair) obj; + if (left == null) { + if (other.left != null) + return false; + } else if (!left.getOffset().equals(other.left.getOffset())) + return false; + if (right == null) { + if (other.right != null) + return false; + } else if (!right.getOffset().equals(other.right.getOffset())) + return false; + return true; + } + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/ResultPairVisitor.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/ResultPairVisitor.java new file mode 100644 index 0000000..7bfc2e6 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/ResultPairVisitor.java @@ -0,0 +1,10 @@ +package de.dhbw.compiler.typeinference.result; + +public interface ResultPairVisitor { + void visit(PairTPHsmallerTPH p); + void visit(PairTPHequalRefTypeOrWildcardType p); + void visit(PairTPHEqualTPH p); + + //bisher nicht umgesetzt + //void visit(PairNoResult p); +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/ResultSet.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/ResultSet.java new file mode 100644 index 0000000..c5beb0e --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/ResultSet.java @@ -0,0 +1,309 @@ +package de.dhbw.compiler.typeinference.result; + +import java.util.HashSet; +import java.util.Set; + +import de.dhbw.compiler.exceptions.NotImplementedException; +import de.dhbw.compiler.syntaxtree.type.ExtendsWildcardType; +import de.dhbw.compiler.syntaxtree.type.GenericRefType; +import de.dhbw.compiler.syntaxtree.type.RefType; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.syntaxtree.type.SuperWildcardType; +import de.dhbw.compiler.syntaxtree.type.TypePlaceholder; + +@SuppressWarnings("rawtypes") +public class ResultSet { + + public final Set results; + public Set> genIns; + + public ResultSet(Set set){ + this.results = set; + this.genIns = new HashSet<>(); + results.forEach(x -> { if (x instanceof PairTPHsmallerTPH) { this.genIns.add(x);}} ); + } + + public boolean contains(ResultPair toCheck) { + return this.results.contains(toCheck); + } + + public void remove(ResultPair toCheck) { + results.remove(toCheck); + } + + public ResolvedType resolveType(RefTypeOrTPHOrWildcardOrGeneric type) { + if(type instanceof TypePlaceholder) + return new Resolver(this).resolve((TypePlaceholder)type); + if(type instanceof GenericRefType)return new ResolvedType(type, new HashSet<>()); + if(type instanceof RefType) { + RelatedTypeWalker related = new RelatedTypeWalker(null, this); + type.accept(related); + return new ResolvedType(type, related.relatedTPHs); + } else { + throw new NotImplementedException(); + //return new ResolvedType(type,new HashSet<>()); + } + } + + public String toString() { + return results.toString(); + } + + @Override + public boolean equals(Object o) { + if (o instanceof ResultSet) { + ResultSet other = (ResultSet)o; + return this.results.equals(other.results); + } else { + return false; + } + } + + @Override + public int hashCode() { + return results.hashCode(); + } +} + +class Resolver implements ResultSetVisitor { + private final ResultSet result; + private TypePlaceholder toResolve; + private RefTypeOrTPHOrWildcardOrGeneric resolved; + private final Set additionalTPHs = new HashSet<>(); + private ResultPair currentPair; + + public Resolver(ResultSet resultPairs){ + this.result = resultPairs; + } + + public ResolvedType resolve(TypePlaceholder tph){ + toResolve = tph; + resolved = null; + System.out.println(tph.toString()); + for(ResultPair resultPair : result.results) { + if(resultPair instanceof PairTPHEqualTPH && ((PairTPHEqualTPH) resultPair).getLeft().equals(toResolve)){ + currentPair = resultPair; + return resolve(((PairTPHEqualTPH) resultPair).getRight()); + } + } + for(ResultPair resultPair : result.results){ + currentPair = resultPair; + resultPair.accept(this); + } + if(resolved==null){//TPH kommt nicht im Result vor: + resolved = tph; + } + + ResolvedType result = new ResolvedType(resolved, additionalTPHs);//resolved; + result.setResultPair(currentPair); + return result; + } + + @Override + public void visit(PairTPHsmallerTPH p) { + currentPair = p; + if(p.left.equals(toResolve)){ + additionalTPHs.add(new GenericInsertPair(p.left, p.right)); + additionalTPHs.addAll(new RelatedTypeWalker(p.right, result).relatedTPHs); + } + if(p.right.equals(toResolve)) + additionalTPHs.addAll(new RelatedTypeWalker(p.left, result).relatedTPHs); + } + + @Override + public void visit(PairTPHequalRefTypeOrWildcardType p) { + currentPair = p; + if(p.left.equals(toResolve)){ + resolved = p.right; + RelatedTypeWalker related = new RelatedTypeWalker(null, result); + p.right.accept(related); + additionalTPHs.addAll(related.relatedTPHs); + } + } + + @Override + public void visit(PairTPHEqualTPH p) { + //Do nothing. Dieser Fall wird in der resolve-Methode abgefangen + } + + @Override + public void visit(RefType refType) { + + } + + @Override + public void visit(GenericRefType genericRefType) { + + } + + @Override + public void visit(SuperWildcardType superWildcardType) { + + } + + @Override + public void visit(TypePlaceholder typePlaceholder) { + + } + + @Override + public void visit(ExtendsWildcardType extendsWildcardType) { + + } + + + +} + +/** + * Sucht aus dem Result Set den Sub/supertyp für einen TPH + */ +@SuppressWarnings("rawtypes") +class TPHResolver implements ResultSetVisitor { + + private final TypePlaceholder tph; + Set resolved = new HashSet<>(); + private final ResultSet resultSet; + + TPHResolver(TypePlaceholder tph, ResultSet resultSet){ + this.resultSet = resultSet; + this.tph = tph; + for(ResultPair p : resultSet.results){ + p.accept(this); + } + if(resolved.size() == 0){ + resolved.add(new GenericInsertPair(tph, null)); + } + } + + @Override + public void visit(PairTPHsmallerTPH p) { + if(p.left.equals(tph) || p.right.equals(tph)){ + resolved.add(new GenericInsertPair(p.left, p.right)); + } + } + + @Override + public void visit(PairTPHequalRefTypeOrWildcardType p) { + TypePlaceholder otherSide = null; + if(p.right.equals(tph)){ + otherSide = p.left; + } + if(otherSide != null){ + Set newResultSet = new HashSet<>(this.resultSet.results); + newResultSet.remove(p); + resolved.addAll(new TPHResolver(otherSide, new ResultSet(newResultSet)).resolved); + } + } + + @Override + public void visit(PairTPHEqualTPH p) { + //ignorieren. Wird vom Resolver behandelt + } + + @Override + public void visit(RefType refType) { + + } + + @Override + public void visit(GenericRefType genericRefType) { + + } + + @Override + public void visit(SuperWildcardType superWildcardType) { + + } + + @Override + public void visit(TypePlaceholder typePlaceholder) { + + } + + @Override + public void visit(ExtendsWildcardType extendsWildcardType) { + + } +} + +@SuppressWarnings("rawtypes") +class RelatedTypeWalker implements ResultSetVisitor { + + final Set relatedTPHs = new HashSet<>(); + private final TypePlaceholder toResolve; + private final ResultSet resultSet; + + /** + * Läuft über das resultSet und speichert alle TPHs, welche mit start in Verbindung stehen + * @param start - kann null sein, wenn der Walker für einen RefType benutzt wird + * @param resultSet + */ + RelatedTypeWalker(TypePlaceholder start, ResultSet resultSet){ + this.toResolve = start; + this.resultSet = resultSet; + int resolved = 0; + do{ + resolved = relatedTPHs.size(); + for(ResultPair p : resultSet.results){ + p.accept(this); + p.accept(this); + } + }while(resolved - relatedTPHs.size() > 0); + } + + @Override + public void visit(PairTPHsmallerTPH p) { + if(p.getRight().equals(toResolve)){ + relatedTPHs.addAll(new TPHResolver(p.right, resultSet).resolved); + //relatedTPHs.addAll(new RelatedTypeWalker(p.right, resultSet).relatedTPHs); + } + if(p.getLeft().equals(toResolve)){ + relatedTPHs.addAll(new TPHResolver(p.left, resultSet).resolved); + //relatedTPHs.addAll(new RelatedTypeWalker(p.left, resultSet).relatedTPHs); + } + } + + @Override + public void visit(PairTPHequalRefTypeOrWildcardType p) { + if(p.getLeft().equals(toResolve)){ + p.getRight().accept(this); + } + } + + @Override + public void visit(PairTPHEqualTPH p) { + //Kann ignoriert werden. Diese Fälle werden vom Resolver behandelt + } + + /* + Die folgenden Funktionen fügen alle TPHs an die relatedTPHs an, denen sie begegnen: + Das wird verwendet, wenn alle relatedTPHs aus den Parametern eines RefTypes angefügt werden sollen + */ + + @Override + public void visit(RefType refType) { + for(RefTypeOrTPHOrWildcardOrGeneric param : refType.getParaList()){ + param.accept(this); + } + } + + @Override + public void visit(SuperWildcardType superWildcardType) { + superWildcardType.getInnerType().accept(this); + } + + @Override + public void visit(TypePlaceholder typePlaceholder) { + relatedTPHs.addAll(new TPHResolver(typePlaceholder, resultSet).resolved); + } + + @Override + public void visit(ExtendsWildcardType extendsWildcardType) { + extendsWildcardType.getInnerType().accept(this); + } + + @Override + public void visit(GenericRefType genericRefType) { + } +} \ No newline at end of file diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/ResultSetVisitor.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/ResultSetVisitor.java new file mode 100644 index 0000000..f32f098 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/result/ResultSetVisitor.java @@ -0,0 +1,17 @@ +package de.dhbw.compiler.typeinference.result; + +import de.dhbw.compiler.syntaxtree.type.*; + +public interface ResultSetVisitor extends ResultPairVisitor{ + + void visit(RefType refType); + + void visit(GenericRefType genericRefType); + + void visit(SuperWildcardType superWildcardType); + + void visit(TypePlaceholder typePlaceholder); + + void visit(ExtendsWildcardType extendsWildcardType); + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/typeAlgo/GenericsResolverSameName.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/typeAlgo/GenericsResolverSameName.java new file mode 100644 index 0000000..9af52f6 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/typeAlgo/GenericsResolverSameName.java @@ -0,0 +1,56 @@ +package de.dhbw.compiler.typeinference.typeAlgo; + +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.syntaxtree.type.*; +import de.dhbw.compiler.typeinference.constraints.GenericsResolver; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * Ein GenericsResolver, welcher Generics mit dem selben Namen den selben TPH zuordnet + */ +public class GenericsResolverSameName implements GenericsResolver, TypeVisitor{ + + HashMap map = new HashMap<>(); + + @Override + public RefTypeOrTPHOrWildcardOrGeneric resolve(RefTypeOrTPHOrWildcardOrGeneric generic) { + return generic.acceptTV(this); + } + + @Override + public RefTypeOrTPHOrWildcardOrGeneric visit(RefType refType) { + List params = new ArrayList<>(); + for(RefTypeOrTPHOrWildcardOrGeneric param : refType.getParaList()){ + params.add(param.acceptTV(this)); + } + RefType ret = new RefType(refType.getName(), params, refType.getOffset()); + return ret; + } + + @Override + public RefTypeOrTPHOrWildcardOrGeneric visit(SuperWildcardType superWildcardType) { + return new SuperWildcardType(superWildcardType.getInnerType().acceptTV(this), superWildcardType.getOffset()); + } + + @Override + public RefTypeOrTPHOrWildcardOrGeneric visit(TypePlaceholder typePlaceholder) { + return typePlaceholder; + } + + @Override + public RefTypeOrTPHOrWildcardOrGeneric visit(ExtendsWildcardType extendsWildcardType) { + return new ExtendsWildcardType(extendsWildcardType.getInnerType().acceptTV(this), extendsWildcardType.getOffset()); + } + + @Override + public RefTypeOrTPHOrWildcardOrGeneric visit(GenericRefType genericRefType) { + String name = genericRefType.getParsedName(); + if(!map.containsKey(name)){ + map.put(name, TypePlaceholder.fresh(genericRefType.getOffset())); + } + return map.get(name); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/typeAlgo/TYPE.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/typeAlgo/TYPE.java new file mode 100644 index 0000000..ea042dd --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/typeAlgo/TYPE.java @@ -0,0 +1,138 @@ +package de.dhbw.compiler.typeinference.typeAlgo; + +import de.dhbw.compiler.exceptions.DebugException; +import de.dhbw.compiler.parser.SourceLoc; + +import de.dhbw.compiler.parser.scope.JavaClassName; +import de.dhbw.compiler.syntaxtree.*; +import de.dhbw.compiler.syntaxtree.factory.ASTFactory; +import de.dhbw.compiler.syntaxtree.statement.Statement; +import de.dhbw.compiler.syntaxtree.type.RefType; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.typeinference.assumptions.TypeInferenceBlockInformation; +import de.dhbw.compiler.typeinference.assumptions.TypeInferenceInformation; +import de.dhbw.compiler.typeinference.constraints.ConstraintSet; +import de.dhbw.compiler.typeinference.constraints.Pair; +import de.dhbw.compiler.typeinference.unify.model.PairOperator; +import de.dhbw.compiler.util.BiRelation; +import org.antlr.v4.runtime.Token; + +import java.util.*; + +public class TYPE { + + private final SourceFile sf; + private final Set allAvailableClasses; + + public TYPE(SourceFile sf, Set allAvailableClasses){ + this.sf = sf; + this.allAvailableClasses = allAvailableClasses; + } + + public ConstraintSet getConstraints() { + ConstraintSet ret = new ConstraintSet(); + for (ClassOrInterface cl : sf.KlassenVektor) { + var allClasses = new HashSet(); + allClasses.addAll(allAvailableClasses); + allClasses.addAll(sf.availableClasses); + ret.addAll(getConstraintsClass(cl, new TypeInferenceInformation(allClasses))); + } + return ret; + } + + private ConstraintSet getConstraintsClass(ClassOrInterface cl, TypeInferenceInformation info) { + ConstraintSet ret = new ConstraintSet(); + ConstraintSet methConstrains; + for(Method m : cl.getMethods()){ + ret.addAll(methConstrains = getConstraintsMethod(m,info, cl)); + m.constraints.addAll(methConstrains); + } + for(Constructor m : cl.getConstructors()){ + ret.addAll(getConstraintsConstructor(m,info, cl)); + } + if (cl.getfieldInitializations().isPresent()) { + ret.addAll(getConstraintsConstructor(cl.getfieldInitializations().get(), info, cl)); + } + if (cl.getStaticInitializer().isPresent()) { + ret.addAll(getConstraintsMethod(cl.getStaticInitializer().get(), info, cl)); + } + + return ret; + } + /* + TODO: Hier eine Information erstellen nur mit den importierte Klassen einer einzigen SourceFile + private TypeInferenceInformation getTypeInferenceInformation(sourceFile) { + DirectoryClassLoader classLoader = DirectoryClassLoader.getSystemClassLoader(); + Set classes = new HashSet<>(); + + for(SourceFile sourceFile : sfs){ + for(JavaClassName importName : sourceFile.imports){ + System.out.println(importName); + try { + classes.add(ASTFactory.createClass(classLoader.loadClass(importName.toString()))); + } catch (ClassNotFoundException e) { + throw new DebugException("Klasse " + importName + " konnte nicht geladen werden"); + } + } + classes.addAll(sourceFile.KlassenVektor); + } + + return new TypeInferenceInformation(classes); + } + */ + + private ConstraintSet getConstraintsMethod(Method m, TypeInferenceInformation info, ClassOrInterface currentClass) { + if(m.block == null)return new ConstraintSet(); //Abstrakte Methoden generieren keine Constraints + TypeInferenceBlockInformation blockInfo = new TypeInferenceBlockInformation(info.getAvailableClasses(), currentClass, m); + TYPEStmt methodScope = new TYPEStmt(blockInfo); + ConstraintSet constraintSet = new ConstraintSet(); + m.getParameterList().getFormalparalist().forEach(el -> { + if(el instanceof RecordPattern){ + constraintSet.addAll(addRecursiveParameterConstraints((RecordPattern) el, blockInfo)); + + } + }); + m.block.accept(methodScope); + constraintSet.addAll(methodScope.getConstraints()); + return constraintSet; + } + + public ConstraintSet addRecursiveParameterConstraints(RecordPattern recordPattern, TypeInferenceBlockInformation blockInformation){ + ConstraintSet constraintSet = new ConstraintSet(); + + var subPatternList = recordPattern.getSubPattern(); + + int counter = 0; + for(Pattern el : subPatternList){ + + if(el instanceof RecordPattern){ + constraintSet.addAll(addRecursiveParameterConstraints((RecordPattern) el, blockInformation)); + }else if (recordPattern.getType() instanceof RefType refType){ + var allClasses = blockInformation.getAvailableClasses(); + RefTypeOrTPHOrWildcardOrGeneric type; + var typename = refType.getName().getClassName(); + + for (ClassOrInterface allClass : allClasses) { + var className = allClass.getClassName().getClassName(); + if(className.equals(typename)){ + type = allClass.getConstructors().getFirst().getParameterList().getParameterAt(counter).getType(); + constraintSet.addUndConstraint(new Pair(el.getType(), type, PairOperator.SMALLERDOT, new SourceLoc(blockInformation.getCurrentClass().getFileName(), el.getOffset().getLine()))); + } + } + + } + counter++; + } + + return constraintSet; + } + + private ConstraintSet getConstraintsConstructor(Constructor m, TypeInferenceInformation info, ClassOrInterface currentClass) { + TypeInferenceBlockInformation blockInfo = new TypeInferenceBlockInformation(info.getAvailableClasses(), currentClass, m); + TYPEStmt methodScope = new TYPEStmt(blockInfo); + //for(Statement stmt : m.fieldInitializations)stmt.accept(methodScope); + ConstraintSet ret = this.getConstraintsMethod(m, info, currentClass); + ret.addAll(methodScope.getConstraints()); + return ret; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/typeAlgo/TYPEStmt.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/typeAlgo/TYPEStmt.java new file mode 100644 index 0000000..304fbe8 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/typeAlgo/TYPEStmt.java @@ -0,0 +1,944 @@ +//PL 2018-12-19: Merge chekcen +package de.dhbw.compiler.typeinference.typeAlgo; + +import java.util.*; +import java.util.stream.Collectors; + +import de.dhbw.compiler.exceptions.NotImplementedException; +import de.dhbw.compiler.exceptions.TypeinferenceException; +import de.dhbw.compiler.parser.NullToken; +import de.dhbw.compiler.parser.SourceLoc; +import de.dhbw.compiler.parser.SyntaxTreeGenerator.AssignToLocal; +import de.dhbw.compiler.parser.scope.JavaClassName; +import de.dhbw.compiler.syntaxtree.*; +import de.dhbw.compiler.syntaxtree.factory.ASTFactory; +import de.dhbw.compiler.syntaxtree.factory.NameGenerator; +import de.dhbw.compiler.syntaxtree.statement.*; +import de.dhbw.compiler.syntaxtree.type.ExtendsWildcardType; +import de.dhbw.compiler.syntaxtree.type.GenericRefType; +import de.dhbw.compiler.syntaxtree.type.RefType; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.syntaxtree.type.TypePlaceholder; +import de.dhbw.compiler.syntaxtree.type.Void; +import de.dhbw.compiler.typeinference.assumptions.*; +import de.dhbw.compiler.typeinference.constraints.Constraint; +import de.dhbw.compiler.typeinference.constraints.ConstraintSet; +import de.dhbw.compiler.typeinference.constraints.GenericsResolver; +import de.dhbw.compiler.typeinference.constraints.Pair; +import de.dhbw.compiler.typeinference.unify.model.PairOperator; +import org.antlr.v4.runtime.Token; + +public class TYPEStmt implements StatementVisitor { + + private final TypeInferenceBlockInformation info; + private final ConstraintSet constraintsSet = new ConstraintSet(); + private final Stack switchStack = new Stack<>(); + + public TYPEStmt(TypeInferenceBlockInformation info) { + this.info = info; + } + + public ConstraintSet getConstraints() { + 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. + * + * @return + */ + private static GenericsResolver getResolverInstance() { + return new GenericsResolverSameName(); + } + + private static TypeScope createTypeScope(ClassOrInterface cl, Method method) { + return null; + } + + @Override + public void visit(ArgumentList arglist) { + for (int i = 0; i < arglist.getArguments().size(); i++) { + arglist.getArguments().get(i).accept(this); + } + } + + @Override + public void visit(LambdaExpression lambdaExpression) { + TypePlaceholder tphRetType = TypePlaceholder.fresh(new NullToken()); + List lambdaParams = lambdaExpression.params.getFormalparalist().stream().map((formalParameter -> formalParameter.getType())).collect(Collectors.toList()); + lambdaParams.add(tphRetType); + // 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, 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)); + lambdaExpression.methodBody.accept(lambdaScope); + constraintsSet.addAll(lambdaScope.getConstraints()); + } + + @Override + 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, loc(assign.getOffset()))); + } + + @Override + public void visit(Block block) { + for (Statement stmt : block.getStatements()) { + stmt.accept(this); + } + } + + @Override + public void visit(CastExpr castExpr) { + castExpr.expr.accept(this); + constraintsSet.addUndConstraint(new Pair(castExpr.getType(), castExpr.expr.getType(), PairOperator.SMALLERDOT)); + } + + @Override + public void visit(EmptyStmt emptyStmt) { + // Nothing :) + } + + @Override + public void visit(FieldVar fieldVar) { + fieldVar.receiver.accept(this); + Set oderConstraints = new HashSet<>(); + + + 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, 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) + throw new TypeinferenceException("Kein Feld " + fieldVar.fieldVarName + " gefunden", fieldVar.getOffset()); + constraintsSet.addOderConstraint(oderConstraints); + } + @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(Iterable.class).getClassName(), Arrays.asList(new ExtendsWildcardType(forEachStmt.statement.getType(), new NullToken())), 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(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, 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, loc(ifStmt.getOffset()))); + } + + } + + @Override + public void visit(InstanceOf instanceOf) { + instanceOf.getExpression().accept(this); + } + + @Override + public void visit(LocalVar localVar) { + // Es werden nur bei Feldvariablen Constraints generiert. Lokale Variablen sind eindeutig + } + + @Override + public void visit(LocalVarDecl localVarDecl) { + // Hier ist nichts zu tun. Allen lokalen Variablen bekommen beim parsen schon den korrekten Typ + } + + @Override + // Es wird in OderConstraints davon ausgegangen dass die Bedingungen für die Typen der Argumente links stehen + // und die Typen der Rückgabewerte immer rechts stehen (vgl. JavaTXCompiler) + public void visit(MethodCall methodCall) { + + methodCall.receiver.accept(this); + // Overloading: + Set> methodConstraints = new HashSet<>(); + for (MethodAssumption m : this.getMethods(methodCall.name, methodCall.arglist, info)) { + GenericsResolver resolver = getResolverInstance(); + Set> oneMethodConstraints = generateConstraint(methodCall, m, info, resolver); + methodConstraints.addAll(oneMethodConstraints); + + /* + * pl 2023-01-20: in generateConstraint bereits umgesetzt Constraint extendsOneMethodConstraint = oneMethodConstraint.stream() .map(x -> (x.TA1 instanceof TypePlaceholder && x.GetOperator() == PairOperator.EQUALSDOT && !(x.TA2 instanceof TypePlaceholder)) ? new Pair(x.TA1, new ExtendsWildcardType(x.TA2, x.TA2.getOffset()), PairOperator.EQUALSDOT) : x) .collect(Collectors.toCollection(() -> new Constraint(oneMethodConstraint.isInherited()))); + * oneMethodConstraint.setExtendConstraint(extendsOneMethodConstraint); extendsOneMethodConstraint.setExtendConstraint(oneMethodConstraint); methodConstraints.add(extendsOneMethodConstraint); + */ + } + if (methodConstraints.size() < 1) { + throw new TypeinferenceException("Methode " + methodCall.name + " ist nicht vorhanden!", methodCall.getOffset()); + } + constraintsSet.addOderConstraint(methodConstraints); + } + + @Override + public void visit(NewClass methodCall) { + // Overloading: + Set methodConstraints = new HashSet<>(); + for (MethodAssumption m : this.getConstructors(info, (RefType) methodCall.getType(), methodCall.getArgumentList())) { + methodConstraints.add(generateConstructorConstraint(methodCall, m, info, getResolverInstance())); + } + if (methodConstraints.size() < 1) { + throw new TypeinferenceException("Konstruktor in Klasse " + methodCall.getType().toString() + " ist nicht vorhanden!", methodCall.getOffset()); + } + constraintsSet.addOderConstraint(methodConstraints); + } + + @Override + public void visit(NewArray newArray) { + throw new NotImplementedException(); + } + + @Override + public void visit(ExpressionReceiver receiver) { + receiver.expr.accept(this); + } + + private final RefType number = new RefType(ASTFactory.createClass(Number.class).getClassName(), new NullToken()); + private final RefType longg = new RefType(ASTFactory.createClass(Long.class).getClassName(), new NullToken()); + private final RefType integer = new RefType(ASTFactory.createClass(Integer.class).getClassName(), new NullToken()); + private final RefType shortt = new RefType(ASTFactory.createClass(Short.class).getClassName(), new NullToken()); + private final RefType bytee = new RefType(ASTFactory.createClass(Byte.class).getClassName(), new NullToken()); + private final RefType floatt = new RefType(ASTFactory.createClass(Float.class).getClassName(), new NullToken()); + private final RefType doublee = new RefType(ASTFactory.createClass(Double.class).getClassName(), new NullToken()); + 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, 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, loc(unaryExpr.getOffset()))); + } else if (unaryExpr.operation == UnaryExpr.Operation.NOT) { + constraintsSet.addUndConstraint(new Pair(unaryExpr.expr.getType(), unaryExpr.getType(), PairOperator.EQUALSDOT, loc(unaryExpr.getOffset()))); + constraintsSet.addUndConstraint(new Pair(unaryExpr.expr.getType(), new RefType(ASTFactory.createClass(Boolean.class).getClassName(), new NullToken()), PairOperator.EQUALSDOT, loc(unaryExpr.getOffset()))); + } else { + throw new NotImplementedException(); + } + } + + @Override + // Es wird in OderConstraints davon ausgegangen dass die Bedingungen für die Typen der Argumente links stehen + // und die Typen der Rückgabewerte immer rechts stehen (vgl. JavaTXCompiler) + public void visit(BinaryExpr binary) { + binary.lexpr.accept(this); + binary.rexpr.accept(this); + if (binary.operation.equals(BinaryExpr.Operator.DIV) + || binary.operation.equals(BinaryExpr.Operator.MUL) + || binary.operation.equals(BinaryExpr.Operator.MOD) + || binary.operation.equals(BinaryExpr.Operator.ADD) + || binary.operation.equals(BinaryExpr.Operator.SUB) + || binary.operation.equals(BinaryExpr.Operator.OR) + || binary.operation.equals(BinaryExpr.Operator.AND) + || binary.operation.equals(BinaryExpr.Operator.XOR)) { + + Set> numericAdditionOrStringConcatenation = new HashSet<>(); + + // TODO PL 2018-11-06 + + // Auf importierte Typen einschraenken + // pruefen, ob Typen richtig bestimmt werden. + + // Zuerst der Fall für Numerische AusdrücPairOpnumericeratorke, das sind Mul, Mod und Div immer: + // see: https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.17 + // Expression muss zu Numeric Convertierbar sein. also von Numeric erben + Constraint numeric; + // 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, 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, 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, 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, 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, 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, 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); + } + /* + * PL auskommentiert Anfang 2018-07-17 /* In Java passiert bei den binären Operatoren eine sogenannte Type Promotion: https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.6.2 Das bedeutet, dass Java die Typen je nach belieben castet, so lange sie nur von Number erben + * + * numeric = new Constraint<>(); numeric.add(new Pair(binary.getType(), number, PairOperator.SMALLERDOT)); numericAdditionOrStringConcatenation.add(numeric); PL auskommentiert Ende 2018-07-17 + */ + + if (binary.operation.equals(BinaryExpr.Operator.ADD)) { + // 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 stringConcat = new Constraint<>(); + 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); + } + } + if (numericAdditionOrStringConcatenation.size() < 1) { + throw new TypeinferenceException("Kein Typ für " + binary.operation.toString() + " vorhanden", binary.getOffset()); + } + constraintsSet.addOderConstraint(numericAdditionOrStringConcatenation); + } else if (binary.operation.equals(BinaryExpr.Operator.LESSEQUAL) || binary.operation.equals(BinaryExpr.Operator.BIGGEREQUAL) || binary.operation.equals(BinaryExpr.Operator.BIGGERTHAN) || binary.operation.equals(BinaryExpr.Operator.LESSTHAN)) { + /* + * //eingefuegt PL 2018-05-24 Set> numericRelationConcatenation = new HashSet<>(); Constraint 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(), bool, PairOperator.SMALLERDOT)); numericRelationConcatenation.add(numeric); 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(), bool, PairOperator.SMALLERDOT)); numericRelationConcatenation.add(numeric); 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(binary.getType(), bool, PairOperator.SMALLERDOT)); + * numericRelationConcatenation.add(numeric); 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(binary.getType(), bool, PairOperator.SMALLERDOT)); numericRelationConcatenation.add(numeric); 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(binary.getType(), bool, PairOperator.SMALLERDOT)); numericRelationConcatenation.add(numeric); 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(binary.getType(), bool, PairOperator.SMALLERDOT)); numericRelationConcatenation.add(numeric); + * + * //***ACHTUNG: Moeglicherweise oder und und-Contraint falsch constraintsSet.addOderConstraint(numericRelationConcatenation); //***ACHTUNG: Moeglicherweise oder und und-Contraint falsch + */ + // 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, 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, loc(binary.getOffset()))); + + // auskommentiert PL 2018-05-24 + // constraintsSet.addUndConstraint(new Pair(binary.lexpr.getType(), number, PairOperator.SMALLERDOT)); + // constraintsSet.addUndConstraint(new Pair(binary.rexpr.getType(), number, PairOperator.SMALLERDOT)); + // Rückgabetyp ist Boolean + // constraintsSet.addUndConstraint(new Pair(bool, binary.getType(), PairOperator.EQUALSDOT)); + } else if (binary.operation.equals(BinaryExpr.Operator.EQUAL) || binary.operation.equals(BinaryExpr.Operator.NOTEQUAL)) { + /* + * 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, loc(binary.getOffset()))); + } else { + throw new NotImplementedException(); + } + } + + @Override + public void visit(BoolExpression expr) { + + 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; + } + + @Override + public void visit(Literal literal) { + // Nothing to do here. Literale erzeugen keine Constraints + // PL 2018-06-23 Sie haben einen Typ. Der muesste hier eingefuegt werden + // 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, loc(literal.getOffset()))); + return; + } + if (literal.value instanceof Byte) { + 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, loc(literal.getOffset()))); + return; + } + if (literal.value instanceof Double) { + 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, loc(literal.getOffset()))); + return; + } + if (literal.value instanceof Integer) { + // constraintsSet.addUndConstraint(new Pair(literal.getType(),integer, PairOperator.EQUALSDOT)); + // /* + HashSet clNames = info.getAvailableClasses().stream().map(x -> x.getClassName()).collect(Collectors.toCollection(HashSet::new)); + Set oderConstraints = new HashSet<>(); + Constraint constraint = new Constraint(); + 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, 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, 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, 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, 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, loc(literal.getOffset()))); + oderConstraints.add(constraint); + } + constraintsSet.addOderConstraint(oderConstraints); + // */ + return; + } + if (literal.value instanceof Short) { + 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, loc(literal.getOffset()))); + return; + } + if (literal.value instanceof Float) { + 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, loc(literal.getOffset()))); + return; + } + if (literal.value instanceof Boolean) { + constraintsSet.addUndConstraint(new Pair(literal.getType(), bool, PairOperator.EQUALSDOT, loc(literal.getOffset()))); + return; + } + 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(Ternary ternary) { + ternary.cond.accept(this); + ternary.iftrue.accept(this); + ternary.iffalse.accept(this); + constraintsSet.addUndConstraint(new Pair(ternary.cond.getType(), bool, PairOperator.EQUALSDOT)); + constraintsSet.addUndConstraint(new Pair(ternary.iftrue.getType(), ternary.getType(), PairOperator.SMALLERDOT)); + constraintsSet.addUndConstraint(new Pair(ternary.iffalse.getType(), ternary.getType(), PairOperator.SMALLERDOT)); + } + + @Override + public void visit(Return returnExpr) { + returnExpr.retexpr.accept(this); + constraintsSet.addUndConstraint(new Pair(returnExpr.getType(), info.getCurrentTypeScope().getReturnType(), PairOperator.SMALLERDOT, loc(returnExpr.getOffset()))); + } + + @Override + public void visit(ReturnVoid aReturn) { + visit((Return) aReturn); + } + + @Override + public void visit(Break aBreak) { + + } + + @Override + public void visit(Continue aContinue) { + + } + + @Override + public void visit(StaticClassName staticClassName) { + // Hier entstehen keine Constraints + } + + @Override + public void visit(Super aSuper) { + var superClass = info.getSuperClass(); + var params = new ArrayList(); + for (var gtv : superClass.getGenerics()) { + params.add(new GenericRefType(gtv.getName(), aSuper.getOffset())); + } + var superType = new RefType(superClass.getClassName(), params, aSuper.getOffset()); + constraintsSet.addUndConstraint(new Pair(aSuper.getType(), superType, PairOperator.EQUALSDOT, loc(aSuper.getOffset()))); + } + + @Override + public void visit(This aThis) { + // Im Falle von this, müssen die Generics in der Klasse als RefTypes behandelt werden. + ClassOrInterface currentClass = info.getCurrentClass(); + List params = new ArrayList<>(); + for (GenericTypeVar gtv : currentClass.getGenerics()) { + 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, loc(aThis.getOffset()))); + } + + private static TypeScope createNullTypeScope() { + return new TypeScope() { + @Override + public Iterable getGenerics() { + return new ArrayList<>(); + } + + @Override + public RefTypeOrTPHOrWildcardOrGeneric getReturnType() { + return null; + } + }; + } + + @Override + public void visit(WhileStmt whileStmt) { + RefType booleanType = new RefType(ASTFactory.createClass(Boolean.class).getClassName(), new NullToken()); + // Expression inferieren: + whileStmt.expr.accept(this); + // Expression muss boolean sein: + constraintsSet.addUndConstraint(new Pair(whileStmt.expr.getType(), booleanType, PairOperator.EQUALSDOT, loc(whileStmt.expr.getOffset()))); + // LoopBlock inferieren: + whileStmt.loopBlock.accept(this); + } + + @Override + public void visit(DoStmt whileStmt) { + RefType booleanType = new RefType(ASTFactory.createClass(Boolean.class).getClassName(), new NullToken()); + whileStmt.expr.accept(this); + constraintsSet.addUndConstraint(new Pair(whileStmt.expr.getType(), booleanType, PairOperator.EQUALSDOT, loc(whileStmt.expr.getOffset()))); + whileStmt.loopBlock.accept(this); + } + + @Override + public void visit(AssignToField assignLeftSide) { + // Hier ist kein Code nötig. Es werden keine extra Constraints generiert + // HIER muss Code rein PL 2018-10-24 + assignLeftSide.field.accept(this); + } + + @Override + public void visit(AssignToLocal assignLeftSide) { + // Hier ist kein Code nötig. Es werden keine extra Constraints generiert + } + + @Override + public void visit(SuperCall superCall) { + Set> methodConstraints = new HashSet<>(); + var clazz = info.getSuperClass(); + 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, false); + + GenericsResolver resolver = getResolverInstance(); + Set> oneMethodConstraints = generateConstraint(superCall, assumption, info, resolver); + methodConstraints.addAll(oneMethodConstraints); + } + constraintsSet.addUndConstraint(new Pair(superCall.receiver.getType(), getReceiverType(info.getSuperClass(), getResolverInstance()), PairOperator.EQUALSDOT)); + constraintsSet.addOderConstraint(methodConstraints); + } + + @Override + public void visit(ThisCall thisCall) { + Set> methodConstraints = new HashSet<>(); + for (var ctor : info.getCurrentClass().getConstructors()) { + var params = convertParams(ctor.getParameterList(), info); + if (params.size() != thisCall.arglist.getArguments().size()) continue; + var assumption = new MethodAssumption(null, new Void(new NullToken()), params, createTypeScope(info.getCurrentClass(), ctor), ctor.isInherited, false); + + GenericsResolver resolver = getResolverInstance(); + Set> oneMethodConstraints = generateConstraint(thisCall, assumption, info, resolver); + methodConstraints.addAll(oneMethodConstraints); + } + constraintsSet.addUndConstraint(new Pair(thisCall.receiver.getType(), getReceiverType(info.getCurrentClass(), getResolverInstance()), PairOperator.EQUALSDOT)); + constraintsSet.addOderConstraint(methodConstraints); + } + + public static RefTypeOrTPHOrWildcardOrGeneric getReceiverType(ClassOrInterface receiver, GenericsResolver resolver) { + if (receiver == null) return null; + List params = new ArrayList<>(); + for (GenericTypeVar gtv : receiver.getGenerics()) { + //Die Generics werden alle zu TPHs umgewandelt. + params.add(resolver.resolve(new GenericRefType(gtv.getName(), new NullToken()))); + } + RefTypeOrTPHOrWildcardOrGeneric receiverType; + if (receiver instanceof FunNClass) { + receiverType = new RefType(new JavaClassName(receiver.getClassName().toString() + "$$"), params, new NullToken()); // new FunN(params); + } else { + receiverType = new RefType(receiver.getClassName(), params, new NullToken()); + } + + return receiverType; + } + + /* + * METHOD CALL Section: + */ + + protected Set> generateConstraint(MethodCall forMethod, MethodAssumption assumption, TypeInferenceBlockInformation info, GenericsResolver resolver) { + Constraint methodConstraint, extendsMethodConstraint; + methodConstraint = new Constraint<>(assumption.isInherited(), assumption.isOverridden()); + extendsMethodConstraint = new Constraint<>(assumption.isInherited(), assumption.isOverridden());// PL 2023-01-24: Ersetzt die Dopplung in visit(MethodCall) + + ClassOrInterface receiverCl = assumption.getReceiver(); + /* + * List params = new ArrayList<>(); for(GenericTypeVar gtv : receiverCl.getGenerics()){ //Die Generics werden alle zu TPHs umgewandelt. params.add(resolver.resolve(gtv.getName())); } + * + * RefTypeOrTPHOrWildcardOrGeneric receiverType = new RefType(assumption.getReceiver().getClassName(), params, forMethod.getOffset()); + */ + + RefTypeOrTPHOrWildcardOrGeneric receiverType = assumption.getReceiverType(resolver); + 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, loc(forMethod.getOffset()))); + } + + // gegenseite Verschraenkung der beiden Mengen von Typannahmen + methodConstraint.setExtendConstraint(extendsMethodConstraint); + extendsMethodConstraint.setExtendConstraint(methodConstraint); + + // Fuer Bytecodegenerierung PL 2020-03-09 wird derzeit nicht benutzt ANFANG + // methodConstraint.add(new Pair(forMethod.receiverType, retType, + // PairOperator.EQUALSDOT)); + // Fuer Bytecodegenerierung PL 2020-03-09 wird derzeit nicht benutzt ENDE + + 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)); + + if (forMethod.getType() instanceof TypePlaceholder tph) + tph.setOrCons((byte) -1);// fuer Maximums-Bestimmung + + Set parameterContraints = generateParameterConstraints(forMethod, assumption, info, resolver); + + methodConstraint.addAll(parameterContraints); + extendsMethodConstraint.addAll(parameterContraints); + + Set methodSignatureConstraint = generatemethodSignatureConstraint(forMethod, assumption, info, resolver); + + //System.out.println("methodSignatureConstraint: " + methodSignatureConstraint); + //System.out.println("methodConstraint: " + methodConstraint); + + methodConstraint.setmethodSignatureConstraint(methodSignatureConstraint); + extendsMethodConstraint.setmethodSignatureConstraint(methodSignatureConstraint); + + Set> ret = new HashSet<>(); + ret.add(methodConstraint); + ret.add(extendsMethodConstraint); + + return ret; + } + + protected Set generateParameterConstraints(MethodCall foMethod, MethodAssumption assumption, TypeInferenceBlockInformation info, GenericsResolver resolver) { + Set ret = new HashSet<>(); + for (int i = 0; i < foMethod.arglist.getArguments().size(); i++) { + foMethod.arglist.getArguments().get(i).accept(this); + RefTypeOrTPHOrWildcardOrGeneric argType = foMethod.arglist.getArguments().get(i).getType(); + RefTypeOrTPHOrWildcardOrGeneric assType = assumption.getArgTypes(resolver).get(i); + + 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)); + // Fuer Bytecodegenerierung PL 2020-03-09 wird derzeit nicht benutzt ENDE + } + return ret; + } + + protected Set generatemethodSignatureConstraint(MethodCall foMethod, MethodAssumption assumption, TypeInferenceBlockInformation info, GenericsResolver resolver) { + Set ret = new HashSet<>(); + + for (int i = 0; i < foMethod.arglist.getArguments().size(); i++) { + // Zuordnung von MethoCall.signature (Argumenttypen) zu der Argumenttypen der ausgewaehlten Methode (assumption.params) + ret.add(new Pair(foMethod.signature.get(i), assumption.getArgTypes().get(i), PairOperator.EQUALSDOT)); + + } + + // Zuordnung von MethodCall.signature(ReturnType) zu dem ReturnType der ausgewaehlten Methode (assumption.returnType) + ret.add(new Pair(foMethod.signature.get(foMethod.signature.size() - 1), assumption.getReturnType(), PairOperator.EQUALSDOT)); + return ret; + } + + public static List getMethods(String name, int numArgs, TypeInferenceBlockInformation info) { + List ret = new ArrayList<>(); + // TODO: apply Methoden wieder anfügen. Diese könnten möglicherweise auch in den Assumptions auftauchen (überdenken) + if (name.equals("apply")) { + List funNParams = new ArrayList<>(); + for (int i = 0; i < numArgs + 1; i++) { + // funNParams.add(TypePlaceholder.fresh(new NullToken())); + funNParams.add(new GenericRefType(NameGenerator.makeNewName(), new NullToken())); + } + funNParams.get(funNParams.size() - 1); + ret.add(new MethodAssumption(new FunNClass(funNParams), funNParams.get(funNParams.size() - 1), funNParams.subList(0, funNParams.size() - 1), new TypeScope() { + @Override + public Iterable getGenerics() { + throw new NotImplementedException(); + } + + @Override + public RefTypeOrTPHOrWildcardOrGeneric getReturnType() { + throw new NotImplementedException(); + } + }, false, false)); + } + for (ClassOrInterface cl : info.getAvailableClasses()) { + for (Method m : cl.getMethods()) { + if (m.getName().equals(name) && m.getParameterList().getFormalparalist().size() == numArgs) { + RefTypeOrTPHOrWildcardOrGeneric retType = m.getReturnType();// info.checkGTV(m.getReturnType()); + + ret.add(new MethodAssumption(cl, retType, convertParams(m.getParameterList(), info), createTypeScope(cl, m), m.isInherited, m.isImplemented)); + } + } + } + return ret; + } + + public static List getMethods(String name, ArgumentList arglist, TypeInferenceBlockInformation info) { + return getMethods(name, arglist.getArguments().size(), info); + } + + protected static List convertParams(ParameterList parameterList, TypeInferenceBlockInformation info) { + // TODO: Hier müssen die Parameter mit den TPHs in den GEnerics des Receivers verknüpft werden + /* + * BEispiel: auto test = new List(); test.add("hallo"); + * + * Hier kriegt der Receiver ja den COnstraint TPH REceiver <. List Dann mus bei dem Parameter der COnstraint entstehen: TPH A <. String + */ + List params = new ArrayList<>(); + for (Pattern fp : parameterList.getFormalparalist()) { + params.add(fp.getType()); // info.checkGTV(fp.getType())); //PL 2018-06-22 GTV sollen in Argumenten erhalten bleiben + } + return params; + } + + public List getConstructors(TypeInferenceBlockInformation info, RefType ofType, ArgumentList argList) { + List ret = new ArrayList<>(); + for (ClassOrInterface cl : info.getAvailableClasses()) { + if (cl.getClassName().equals(ofType.getName())) { + for (Method m : cl.getConstructors()) { + if (m.getParameterList().getFormalparalist().size() == argList.getArguments().size()) { + var params = convertParams(m.getParameterList(), info); + ret.add(new MethodAssumption(cl, cl.generateTypeOfThisClass(), params, createTypeScope(cl, m), m.isInherited, m.isImplemented)); + } + } + } + } + return ret; + } + + protected Constraint generateConstructorConstraint(NewClass forConstructor, MethodAssumption assumption, TypeInferenceBlockInformation info, GenericsResolver resolver) { + 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, loc(forConstructor.getOffset()))); + // WELCHEN SINN MACHT DIESER CONSTRAINT??? + methodConstraint.addAll(generateParameterConstraints(forConstructor, assumption, info, resolver)); + + Set methodSignatureConstraint = generatemethodSignatureConstraint(forConstructor, assumption, info, resolver); + methodConstraint.setmethodSignatureConstraint(methodSignatureConstraint); + + methodConstraint.addAll(methodSignatureConstraint); + + return methodConstraint; + } + + @Override + public void visit(Switch switchStmt) { + System.out.println("TESTTTTTTTTTTTTTTTTTTTTTTTTTTTTT"); + switchStack.push(switchStmt); + + if(switchStmt.getSwitch().getType() instanceof TypePlaceholder){ + ((TypePlaceholder) switchStmt.getSwitch().getType()).setVariance(-1); + } + + RefTypeOrTPHOrWildcardOrGeneric caseExpressionType = null; + for (var child : switchStmt.getBlocks()) { + for (var label : child.getLabels()) { + if (!(label.getPattern() instanceof FormalParameter) && !(label.getType() instanceof Void)) { + if (caseExpressionType != null && !caseExpressionType.equals(label.getType())) + throw new TypeinferenceException("Case labels must all have the same Type if they are expressions", label); + caseExpressionType = label.getType(); + } + } + } + if (caseExpressionType == null) { + for (var child : switchStmt.getBlocks()) { + for (var label : child.getLabels()) { + if (label.getPattern() == null) { + //System.out.println("DefaultCase"); + } else { + 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, loc(switchStmt.getSwitch().getOffset()))); + } + + if (caseExpressionType == null) { + for (var child : switchStmt.getBlocks()) { + for (var label : child.getLabels()) { + if (label.getPattern() == null) { + constraintsSet.addUndConstraint(new Pair(new RefType(new JavaClassName("java.lang.Object"), new NullToken()), switchStmt.getSwitch().getType(), PairOperator.SMALLERDOT, loc(label.getOffset()))); + } + if (label.getPattern() instanceof RecordPattern) { + RecordPattern recordPattern = (RecordPattern) label.getPattern(); + //constraintsSet.addUndConstraint(new Pair(label.getPattern().getType(), switchStmt.getSwitch().getType(), PairOperator.SMALLERDOT, loc(label.getOffset()))); + } else if (label.getPattern() instanceof FormalParameter) { + 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, loc(switchStmt.getSwitch().getOffset()))); + } + + + for (var child : switchStmt.getBlocks()) { + + + child.getLabels().forEach(el -> { + if (el.getType() instanceof RefType) { + var recType = el; + + if (el.getPattern() instanceof RecordPattern) { + System.out.println("TESTTTTTTTTTTTTTTTTTTTTTTTTTTTTT"); + var pattern = (RecordPattern) recType.getPattern(); + recursivelyAddRecordConstraints(pattern); + } + + } + }); + + constraintsSet.addUndConstraint(new Pair(child.getType(), switchStmt.getType(), PairOperator.SMALLERDOT, loc(switchStmt.getOffset()))); + child.accept(this); + } + + + switchStack.pop(); + } + + public void recursivelyAddRecordConstraints(RecordPattern pattern) { + + var allClasses = info.getAvailableClasses(); + var interestingClasses = allClasses.stream().filter(as -> as.getClassName().equals(((RefType) pattern.getType()).getName())).toList(); + var constructors = interestingClasses.get(0).getConstructors(); + var resolver = getResolverInstance(); + + int counter = 0; + + for (var subPattern : pattern.getSubPattern()) { + for (Constructor con : constructors) { + System.out.println("----------------------\n" + subPattern.getType() + " | " + con.getParameterList().getParameterAt(counter).getType() + "\n----------------------\n"); + //TODO: Do something with this Field Assumption and get the Type of the Generic + FieldAssumption assumption = null; //new FieldAssumption(((RecordPattern) subPattern).getName(), interestingClasses.get(0), subPattern.getType(), new TypeScopeContainer(interestingClasses.get(0), con)); + RefTypeOrTPHOrWildcardOrGeneric receiverType = assumption == null ? null : assumption.getReceiverType(resolver); + System.out.println("----------------------\nRecieverType: " + receiverType + "\n----------------------\n"); + constraintsSet.addUndConstraint(new Pair(receiverType == null ? subPattern.getType() : receiverType, con.getParameterList().getParameterAt(counter).getType(), PairOperator.SMALLERDOT, loc(con.getParameterList().getParameterAt(counter).getOffset()))); + } + if (subPattern instanceof RecordPattern) recursivelyAddRecordConstraints((RecordPattern) subPattern); + else if (subPattern instanceof LiteralPattern lp) lp.value.accept(this); + counter++; + } + } + + + @Override + public void visit(SwitchBlock switchBlock) { + for (var stmt : switchBlock.statements) { + stmt.accept(this); + } + } + + @Override + public void visit(SwitchLabel switchLabel) { + } + + @Override + public void visit(Yield aYield) { + aYield.retexpr.accept(this); + constraintsSet.addUndConstraint(new Pair(aYield.getType(), switchStack.peek().getType(), PairOperator.EQUALSDOT, loc(aYield.getOffset()))); + // TODO Auto-generated method stub + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/GuavaSetOperations.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/GuavaSetOperations.java new file mode 100644 index 0000000..a3fba14 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/GuavaSetOperations.java @@ -0,0 +1,23 @@ +package de.dhbw.compiler.typeinference.unify; + +import java.util.List; +import java.util.Set; + +import com.google.common.collect.Sets; + +import de.dhbw.compiler.typeinference.unify.interfaces.ISetOperations; + +/** + * Implements set operations using google guava. + * @author DH10STF + * + */ +public class GuavaSetOperations implements ISetOperations { + + @Override + public Set> cartesianProduct(List> sets) { + // Wraps the call to google guava + return Sets.cartesianProduct(sets); + } + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/MartelliMontanariUnify.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/MartelliMontanariUnify.java new file mode 100644 index 0000000..1800e51 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/MartelliMontanariUnify.java @@ -0,0 +1,108 @@ +package de.dhbw.compiler.typeinference.unify; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import de.dhbw.compiler.typeinference.unify.interfaces.IUnify; +import de.dhbw.compiler.typeinference.unify.model.PairOperator; +import de.dhbw.compiler.typeinference.unify.model.PlaceholderType; +import de.dhbw.compiler.typeinference.unify.model.TypeParams; +import de.dhbw.compiler.typeinference.unify.model.Unifier; +import de.dhbw.compiler.typeinference.unify.model.UnifyPair; +import de.dhbw.compiler.typeinference.unify.model.UnifyType; + +/** + * Implementation of the Martelli-Montanari unification algorithm. + * @author Florian Steurer + */ +public class MartelliMontanariUnify implements IUnify { + + @Override + public Optional unify(Set terms) { + // Sets with less than 2 terms are trivially unified + if(terms.size() < 2) + return Optional.of(Unifier.identity()); + + // For the the set of terms {t1,...,tn}, + // build a list of equations {(t1 = t2), (t2 = t3), (t3 = t4), ....} + ArrayList termsList = new ArrayList(); + Iterator iter = terms.iterator(); + UnifyType prev = iter.next(); + while(iter.hasNext()) { + UnifyType next = iter.next(); + termsList.add(new UnifyPair(prev, next, PairOperator.EQUALSDOT)); + prev = next; + } + + // Start with the identity unifier. Substitutions will be added later. + Unifier mgu = Unifier.identity(); + + // Apply rules while possible + int idx = 0; + while(idx < termsList.size()) { + UnifyPair pair = termsList.get(idx); + UnifyType rhsType = pair.getRhsType(); + UnifyType lhsType = pair.getLhsType(); + TypeParams rhsTypeParams = rhsType.getTypeParams(); + TypeParams lhsTypeParams = lhsType.getTypeParams(); + + // REDUCE - Rule + if(!(rhsType instanceof PlaceholderType) && !(lhsType instanceof PlaceholderType)) { + Set result = new HashSet<>(); + + // f<...> = g<...> with f != g are not unifiable + if(!rhsType.getName().equals(lhsType.getName())) + return Optional.empty(); // conflict + // f = f are not unifiable + if(rhsTypeParams.size() != lhsTypeParams.size()) + return Optional.empty(); // conflict + // f = g is not unifiable (cannot be f = f because erase rule would have been applied) + //if(rhsTypeParams.size() == 0) + //return Optional.empty(); + + // Unpack the arguments + for(int i = 0; i < rhsTypeParams.size(); i++) + result.add(new UnifyPair(rhsTypeParams.get(i), lhsTypeParams.get(i), PairOperator.EQUALSDOT)); + + termsList.remove(idx); + termsList.addAll(result); + continue; + } + + // DELETE - Rule + if(pair.getRhsType().equals(pair.getLhsType())) { + termsList.remove(idx); + continue; + } + + // SWAP - Rule + if(!(lhsType instanceof PlaceholderType) && (rhsType instanceof PlaceholderType)) { + termsList.remove(idx); + termsList.add(new UnifyPair(rhsType, lhsType, PairOperator.EQUALSDOT)); + continue; + } + + // OCCURS-CHECK + if(pair.getLhsType() instanceof PlaceholderType + && pair.getRhsType().getTypeParams().occurs((PlaceholderType) pair.getLhsType())) + return Optional.empty(); + + // SUBST - Rule + if(lhsType instanceof PlaceholderType) { + mgu.add((PlaceholderType) lhsType, rhsType); + //PL 2018-04-01 nach checken, ob es richtig ist, dass keine Substitutionen uebergeben werden muessen. + termsList = termsList.stream().map(x -> mgu.apply(x)).collect(Collectors.toCollection(ArrayList::new)); + idx = idx+1 == termsList.size() ? 0 : idx+1; + continue; + } + + idx++; + } + + return Optional.of(mgu); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/Match.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/Match.java new file mode 100644 index 0000000..b2b7ac6 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/Match.java @@ -0,0 +1,93 @@ +package de.dhbw.compiler.typeinference.unify; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import de.dhbw.compiler.typeinference.unify.interfaces.IMatch; +import de.dhbw.compiler.typeinference.unify.model.PairOperator; +import de.dhbw.compiler.typeinference.unify.model.PlaceholderType; +import de.dhbw.compiler.typeinference.unify.model.TypeParams; +import de.dhbw.compiler.typeinference.unify.model.Unifier; +import de.dhbw.compiler.typeinference.unify.model.UnifyPair; +import de.dhbw.compiler.typeinference.unify.model.UnifyType; + +/** + * Implementation of match derived from unification algorithm. + * @author Martin Pluemicke + */ +public class Match implements IMatch { + + @Override + //vorne muss das Pattern stehen + //A =. A ==> True + //A =. A ==> False + public Optional match(ArrayList termsList) { + + // Start with the identity unifier. Substitutions will be added later. + Unifier mgu = Unifier.identity(); + + // Apply rules while possible + int idx = 0; + while(idx < termsList.size()) { + UnifyPair pair = termsList.get(idx); + UnifyType rhsType = pair.getRhsType(); + UnifyType lhsType = pair.getLhsType(); + TypeParams rhsTypeParams = rhsType.getTypeParams(); + TypeParams lhsTypeParams = lhsType.getTypeParams(); + + // REDUCE - Rule + if(!(rhsType instanceof PlaceholderType) && !(lhsType instanceof PlaceholderType)) { + Set result = new HashSet<>(); + + // f<...> = g<...> with f != g are not unifiable + if(!rhsType.getName().equals(lhsType.getName())) + return Optional.empty(); // conflict + // f = f are not unifiable + if(rhsTypeParams.size() != lhsTypeParams.size()) + return Optional.empty(); // conflict + // f = g is not unifiable (cannot be f = f because erase rule would have been applied) + //if(rhsTypeParams.size() == 0) + //return Optional.empty(); + + // Unpack the arguments + for(int i = 0; i < rhsTypeParams.size(); i++) + result.add(new UnifyPair(lhsTypeParams.get(i), rhsTypeParams.get(i), PairOperator.EQUALSDOT)); + + termsList.remove(idx); + termsList.addAll(result); + continue; + } + + // DELETE - Rule + if(pair.getRhsType().equals(pair.getLhsType())) { + termsList.remove(idx); + continue; + } + + // SWAP - Rule + if(!(lhsType instanceof PlaceholderType) && (rhsType instanceof PlaceholderType)) { + return Optional.empty(); // conflict + } + + // OCCURS-CHECK + //deleted + + // SUBST - Rule + if(lhsType instanceof PlaceholderType) { + mgu.add((PlaceholderType) lhsType, rhsType); + idx = idx+1 == termsList.size() ? 0 : idx+1; + //PL 2024-04-08 falsch da es sich nicht um Unifikation handelt + //termsList = termsList.stream().map(mgu::applyleft).collect(Collectors.toCollection(ArrayList::new)); + //continue; + } + + idx++; + } + + return Optional.of(mgu); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/RuleSet.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/RuleSet.java new file mode 100644 index 0000000..c4e710a --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/RuleSet.java @@ -0,0 +1,1091 @@ +package de.dhbw.compiler.typeinference.unify; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; +import java.util.Queue; +import java.util.Set; +import java.util.Stack; +import java.util.function.Function; +import java.util.stream.Collectors; + +import de.dhbw.compiler.core.JavaTXCompiler; +import de.dhbw.compiler.exceptions.DebugException; +import de.dhbw.compiler.syntaxtree.factory.UnifyTypeFactory; +import de.dhbw.compiler.syntaxtree.type.ExtendsWildcardType; +import de.dhbw.compiler.syntaxtree.type.RefType; +import de.dhbw.compiler.typeinference.unify.interfaces.IFiniteClosure; +import de.dhbw.compiler.typeinference.unify.interfaces.IRuleSet; +import de.dhbw.compiler.typeinference.unify.model.*; +import de.dhbw.compiler.typeinference.constraints.Constraint; +import de.dhbw.compiler.typeinference.unify.distributeVariance; + +import java.io.FileWriter; +import java.io.IOException; +import java.io.Writer; +import java.io.OutputStreamWriter; + +import org.apache.commons.io.output.NullOutputStream; + +/** + * Implementation of the type inference rules. + * @author Florian Steurer + * + */ +public class RuleSet implements IRuleSet{ + + Writer logFile; + + public RuleSet() { + super(); + logFile = new OutputStreamWriter(new NullOutputStream()); + } + + RuleSet(Writer logFile) { + this.logFile = logFile; + } + + @Override + public Optional reduceUp(UnifyPair pair) { + // Check if reduce up is applicable + if(pair.getPairOp() != PairOperator.SMALLERDOT) + return Optional.empty(); + + UnifyType rhsType = pair.getRhsType(); + if(!(rhsType instanceof SuperType)) + return Optional.empty(); + + UnifyType lhsType = pair.getLhsType(); + if(!(lhsType instanceof ReferenceType) && !(lhsType instanceof PlaceholderType)) + return Optional.empty(); + + // Rule is applicable, unpack the SuperType + return Optional.of(new UnifyPair(lhsType, ((SuperType) rhsType).getSuperedType(), PairOperator.SMALLERDOT, pair.getSubstitution(), pair.getBasePair())); + } + + @Override + public Optional reduceLow(UnifyPair pair) { + // Check if rule is applicable + if(pair.getPairOp() != PairOperator.SMALLERDOT) + return Optional.empty(); + + UnifyType lhsType = pair.getLhsType(); + if(!(lhsType instanceof ExtendsType)) + return Optional.empty(); + + UnifyType rhsType = pair.getRhsType(); + if(!(rhsType instanceof ReferenceType) && !(rhsType instanceof PlaceholderType)) + return Optional.empty(); + + // Rule is applicable, unpack the ExtendsType + return Optional.of(new UnifyPair(((ExtendsType) lhsType).getExtendedType(), rhsType, PairOperator.SMALLERDOT, pair.getSubstitution(), pair.getBasePair())); + } + + @Override + public Optional reduceUpLow(UnifyPair pair) { + // Check if rule is applicable + if(pair.getPairOp() != PairOperator.SMALLERDOT) + return Optional.empty(); + + UnifyType lhsType = pair.getLhsType(); + if(!(lhsType instanceof ExtendsType)) + return Optional.empty(); + + UnifyType rhsType = pair.getRhsType(); + if(!(rhsType instanceof SuperType)) + return Optional.empty(); + + // Rule is applicable, unpack both sides + return Optional.of(new UnifyPair(((ExtendsType) lhsType).getExtendedType(),((SuperType) rhsType).getSuperedType(), PairOperator.SMALLERDOT, pair.getSubstitution(), pair.getBasePair())); + } + + @Override + public Optional> reduceExt(UnifyPair pair, IFiniteClosure fc) { + if(pair.getPairOp() != PairOperator.SMALLERDOTWC) + return Optional.empty(); + + UnifyType x = pair.getLhsType(); + UnifyType sTypeX; + + if(x instanceof ReferenceType) + sTypeX = x; + else if(x instanceof ExtendsType) + sTypeX = ((ExtendsType) x).getExtendedType(); + else + return Optional.empty(); + + UnifyType extY = pair.getRhsType(); + + if(!(extY instanceof ExtendsType)) + return Optional.empty(); + + if(x.getTypeParams().empty() || extY.getTypeParams().size() != x.getTypeParams().size()) + return Optional.empty(); + + UnifyType xFromFc = fc.getLeftHandedType(sTypeX.getName()).orElse(null); + + if(xFromFc == null || !xFromFc.getTypeParams().arePlaceholders()) + return Optional.empty(); + + if(x instanceof ExtendsType) + xFromFc = new ExtendsType(xFromFc); + + UnifyType extYFromFc = fc.grArg(xFromFc, new HashSet<>()).stream().filter(t -> t.getName().equals(extY.getName())).filter(t -> t.getTypeParams().arePlaceholders()).findAny().orElse(null); + + if(extYFromFc == null || extYFromFc.getTypeParams() != xFromFc.getTypeParams()) + return Optional.empty(); + + TypeParams extYParams = extY.getTypeParams(); + TypeParams xParams = x.getTypeParams(); + + int[] pi = pi(xParams, extYParams); + + if(pi.length == 0) + return Optional.empty(); + + Set result = new HashSet<>(); + + for(int rhsIdx = 0; rhsIdx < extYParams.size(); rhsIdx++) + result.add(new UnifyPair(xParams.get(pi[rhsIdx]), extYParams.get(rhsIdx), PairOperator.SMALLERDOTWC, pair.getSubstitution(), pair.getBasePair())); + + return Optional.of(result); + } + + @Override + public Optional> reduceSup(UnifyPair pair, IFiniteClosure fc) { + if(pair.getPairOp() != PairOperator.SMALLERDOTWC) + return Optional.empty(); + + UnifyType x = pair.getLhsType(); + UnifyType sTypeX; + + if(x instanceof ReferenceType) + sTypeX = x; + else if(x instanceof SuperType) + sTypeX = ((SuperType) x).getSuperedType(); + else + return Optional.empty(); + + UnifyType supY = pair.getRhsType(); + + if(!(supY instanceof SuperType)) + return Optional.empty(); + + if(x.getTypeParams().empty() || supY.getTypeParams().size() != x.getTypeParams().size()) + return Optional.empty(); + + UnifyType xFromFc = fc.getLeftHandedType(sTypeX.getName()).orElse(null); + + if(xFromFc == null || !xFromFc.getTypeParams().arePlaceholders()) + return Optional.empty(); + + if(x instanceof SuperType) + xFromFc = new SuperType(xFromFc); + + UnifyType supYFromFc = fc.grArg(xFromFc, new HashSet<>()).stream().filter(t -> t.getName().equals(supY.getName())).filter(t -> t.getTypeParams().arePlaceholders()).findAny().orElse(null); + + if(supYFromFc == null || supYFromFc.getTypeParams() != xFromFc.getTypeParams()) + return Optional.empty(); + + TypeParams supYParams = supY.getTypeParams(); + TypeParams xParams = x.getTypeParams(); + Set result = new HashSet<>(); + + int[] pi = pi(xParams, supYParams); + + if(pi.length == 0) + return Optional.empty(); + + for(int rhsIdx = 0; rhsIdx < supYParams.size(); rhsIdx++) + result.add(new UnifyPair(supYParams.get(rhsIdx), xParams.get(pi[rhsIdx]), PairOperator.SMALLERDOTWC, pair.getSubstitution(), pair.getBasePair())); + + return Optional.of(result); + } + + @Override + public Optional> reduceEq(UnifyPair pair) { + if(pair.getPairOp() != PairOperator.SMALLERDOTWC) + return Optional.empty(); + + UnifyType lhsType = pair.getLhsType(); + if(lhsType instanceof PlaceholderType || lhsType.getTypeParams().empty()) + return Optional.empty(); + + UnifyType rhsType = pair.getRhsType(); + + if(!rhsType.getName().equals(lhsType.getName())) + return Optional.empty(); + + if(rhsType instanceof PlaceholderType || lhsType instanceof PlaceholderType || rhsType.getTypeParams().empty()) + return Optional.empty(); + + if(rhsType.getTypeParams().size() != lhsType.getTypeParams().size()) + return Optional.empty(); + + // Keine Permutation wie im Paper nötig + Set result = new HashSet<>(); + TypeParams lhsTypeParams = lhsType.getTypeParams(); + TypeParams rhsTypeParams = rhsType.getTypeParams(); + + for(int i = 0; i < lhsTypeParams.size(); i++) + result.add(new UnifyPair(lhsTypeParams.get(i), rhsTypeParams.get(i), PairOperator.EQUALSDOT, pair.getSubstitution(), pair.getBasePair())); + + return Optional.of(result); + } + + @Override + public Optional> reduce1(UnifyPair pair, IFiniteClosure fc) { + if(pair.getPairOp() != PairOperator.SMALLERDOT) + return Optional.empty(); + + UnifyType c = pair.getLhsType(); + if(!(c instanceof ReferenceType)) + return Optional.empty(); + + UnifyType d = pair.getRhsType(); + if(!(d instanceof ReferenceType)) + return Optional.empty(); + + ReferenceType lhsSType = (ReferenceType) c; + ReferenceType rhsSType = (ReferenceType) d; + + //try { + // logFile.write("PAIR Rules: " + pair + "\n"); + // logFile.flush(); + //} + //catch (IOException e) { } + + if(lhsSType.getTypeParams().empty() || lhsSType.getTypeParams().size() != rhsSType.getTypeParams().size()) + return Optional.empty(); + + UnifyType cFromFc = fc.getLeftHandedType(c.getName()).orElse(null); + //2018-02-23: liefert Vector>: Das kann nicht sein. + + //NOCHMAL UEBERPRUEFEN + //PL 18-02-09 Eingfuegt Anfang + //C und D koennen auch gleich sein. + if (c.getName().equals(d.getName())) { + Set result = new HashSet<>(); + TypeParams rhsTypeParams = d.getTypeParams(); + TypeParams lhsTypeParams = c.getTypeParams(); + for(int rhsIdx = 0; rhsIdx < c.getTypeParams().size(); rhsIdx++) + result.add(new UnifyPair(lhsTypeParams.get(rhsIdx), rhsTypeParams.get(rhsIdx), PairOperator.SMALLERDOTWC, pair.getSubstitution(), pair.getBasePair())); + + return Optional.of(result); + } + //PL 18-02-09 Eingfuegt ENDE + + //try { + // logFile.write("cFromFc: " + cFromFc); + // logFile.flush(); + //} + //catch (IOException e) { } + + if(cFromFc == null || !cFromFc.getTypeParams().arePlaceholders()) + return Optional.empty(); + + UnifyType dFromFc = fc.getAncestors(cFromFc).stream().filter(x -> x.getName().equals(d.getName())).findAny().orElse(null); + + //try { + // logFile.write("cFromFc: " + cFromFc); + // logFile.flush(); + //} + //catch (IOException e) { } + + if(dFromFc == null || !dFromFc.getTypeParams().arePlaceholders() || dFromFc.getTypeParams().size() != cFromFc.getTypeParams().size()) + return Optional.empty(); + //System.out.println("cFromFc: " + cFromFc); + //System.out.println("dFromFc: " + dFromFc); + int[] pi = pi(cFromFc.getTypeParams(), dFromFc.getTypeParams()); + + if(pi.length == 0) + return Optional.empty(); + + TypeParams rhsTypeParams = d.getTypeParams(); + TypeParams lhsTypeParams = c.getTypeParams(); + Set result = new HashSet<>(); + + for(int rhsIdx = 0; rhsIdx < rhsTypeParams.size(); rhsIdx++) + result.add(new UnifyPair(lhsTypeParams.get(pi[rhsIdx]), rhsTypeParams.get(rhsIdx), PairOperator.SMALLERDOTWC, pair.getSubstitution(), pair.getBasePair())); + + return Optional.of(result); + } + + @Override + public Optional> reduce2(UnifyPair pair) { + if(pair.getPairOp() != PairOperator.EQUALSDOT) + return Optional.empty(); + + UnifyType lhsType = pair.getLhsType(); + ReferenceType lhsSType; + UnifyType rhsType = pair.getRhsType(); + ReferenceType rhsSType; + + if ((lhsType instanceof ReferenceType) && (rhsType instanceof ReferenceType)) { + lhsSType = (ReferenceType) lhsType; + rhsSType = (ReferenceType) rhsType; + } + else if (((lhsType instanceof ExtendsType) && (rhsType instanceof ExtendsType)) + || ((lhsType instanceof SuperType) && (rhsType instanceof SuperType))) { + UnifyType lhsSTypeRaw = ((WildcardType) lhsType).getWildcardedType(); + UnifyType rhsSTypeRaw = ((WildcardType) rhsType).getWildcardedType(); + if ((lhsSTypeRaw instanceof ReferenceType) && (rhsSTypeRaw instanceof ReferenceType)) { + lhsSType = (ReferenceType) lhsSTypeRaw; + rhsSType = (ReferenceType) rhsSTypeRaw; + } + else + return Optional.empty(); + } + else + return Optional.empty(); + + if(lhsSType.getTypeParams().empty()) + return Optional.empty(); + + /* PL 2018-01-22 in obere Teil integriert + UnifyType rhsType = pair.getRhsType(); + ReferenceType rhsSType; + + if(rhsType instanceof ReferenceType) + rhsSType = (ReferenceType) rhsType; + else if(rhsType instanceof WildcardType) { + UnifyType rhsSTypeRaw = ((WildcardType) rhsType).getWildcardedType(); + if(rhsSTypeRaw instanceof ReferenceType) + rhsSType = (ReferenceType) rhsSTypeRaw; + else + return Optional.empty(); + } + else + return Optional.empty(); + */ + + if(!rhsSType.getName().equals(lhsSType.getName())) + return Optional.empty(); + + if(!(lhsSType.getTypeParams().size()==rhsSType.getTypeParams().size()))throw new DebugException("Fehler in Unifizierung"+ " " + lhsSType.toString() + " " + rhsSType.toString()); + //if(rhsSType.getTypeParams().size() != lhsSType.getTypeParams().size()) + // return Optional.empty(); + + Set result = new HashSet<>(); + + TypeParams rhsTypeParams = rhsSType.getTypeParams(); + TypeParams lhsTypeParams = lhsSType.getTypeParams(); + for(int i = 0; i < rhsTypeParams.size(); i++) + result.add(new UnifyPair(lhsTypeParams.get(i), rhsTypeParams.get(i), PairOperator.EQUALSDOT, pair.getSubstitution(), pair.getBasePair())); + + return Optional.of(result); + } + + @Override + public boolean erase1(UnifyPair pair, IFiniteClosure fc) { + if((pair.getPairOp() != PairOperator.SMALLERDOT) && (pair.getPairOp() != PairOperator.SMALLERNEQDOT)) + return false; + + UnifyType lhsType = pair.getLhsType(); + UnifyType rhsType = pair.getRhsType(); + + /* + * ty <. ? extends ty' is wrong + */ + if (rhsType instanceof ExtendsType) { + return false; + } + + /* + * ? super ty <. ty' is wrong + * except Ty' = Object or ty' = ? super Object + */ + if ((lhsType instanceof SuperType) && + (!(rhsType.equals(new ReferenceType("java.lang.Object", false)))) && + !(rhsType.equals(new SuperType (new ReferenceType("java.lang.Object", false))))) { + return false; + } + + /* + * ? extends ty <. ty' is equivalent to ty < ty' + */ + if (lhsType instanceof ExtendsType) { + lhsType = ((WildcardType)lhsType).getWildcardedType(); + } + + /* + * ty <. ? super ty' ist equivalent to ty <. ty' + */ + if (rhsType instanceof SuperType) { + rhsType = ((WildcardType)rhsType).getWildcardedType(); + } + + /* + * SMALLERNEQDOT => type must not be equal + */ + if (pair.getPairOp() == PairOperator.SMALLERNEQDOT && lhsType.equals(rhsType)){ + return false; + } + + if(!(lhsType instanceof ReferenceType) && !(lhsType instanceof PlaceholderType)) + return false; + + + if(!(rhsType instanceof ReferenceType) && !(rhsType instanceof PlaceholderType)) + return false; + + return fc.greater(lhsType, new HashSet<>(), pair.getLocation()).contains(rhsType); + } + + @Override + public boolean erase2(UnifyPair pair, IFiniteClosure fc) { + if(pair.getPairOp() != PairOperator.SMALLERDOTWC) + return false; + + UnifyType lhsType = pair.getLhsType(); + UnifyType rhsType = pair.getRhsType(); + + return fc.grArg(lhsType, new HashSet<>()).contains(rhsType); + } + + @Override + public boolean erase3(UnifyPair pair) { + if(pair.getPairOp() != PairOperator.EQUALSDOT) + return false; + + return pair.getLhsType().equals(pair.getRhsType()); + } + + @Override + public Optional swap(UnifyPair pair) { + if(pair.getPairOp() != PairOperator.EQUALSDOT) + return Optional.empty(); + + if(pair.getLhsType() instanceof PlaceholderType) + return Optional.empty(); + + if(!(pair.getRhsType() instanceof PlaceholderType)) + return Optional.empty(); + + return Optional.of(new UnifyPair(pair.getRhsType(), pair.getLhsType(), PairOperator.EQUALSDOT, pair.getSubstitution(), pair.getBasePair())); + } + + @Override + public Optional adapt(UnifyPair pair, IFiniteClosure fc) { + if(pair.getPairOp() != PairOperator.SMALLERDOT) + return Optional.empty(); + + UnifyType typeD = pair.getLhsType(); + if(!(typeD instanceof ReferenceType)) + return Optional.empty(); + + UnifyType typeDs = pair.getRhsType(); + if(!(typeDs instanceof ReferenceType)) + return Optional.empty(); + + /*if(typeD.getTypeParams().size() == 0 || typeDs.getTypeParams().size() == 0) + return Optional.empty();*/ + + if(typeD.getName().equals(typeDs.getName())) + return Optional.empty(); + + + Optional opt = fc.getLeftHandedType(typeD.getName()); + if(!opt.isPresent()) + return Optional.empty(); + + // The generic Version of Type D (D) + UnifyType typeDgen = opt.get(); + + // Actually greater+ because the types are ensured to have different names + Set greater = fc.getAncestors(typeDgen); + opt = greater.stream().filter(x -> x.getName().equals(typeDs.getName())).findAny(); + + if(!opt.isPresent()) + return Optional.empty(); + + UnifyType newLhs = opt.get(); + + TypeParams typeDParams = typeD.getTypeParams(); + TypeParams typeDgenParams = typeDgen.getTypeParams(); + + //System.out.println("Pair: " +pair); + //System.out.println("typeD: " +typeD); + //System.out.println("typeDParams: " +typeDParams); + //System.out.println("typeDgen: " +typeD); + //System.out.println("typeDgenParams: " +typeDgenParams); + Unifier unif = Unifier.identity(); + for(int i = 0; i < typeDParams.size(); i++) { + //System.out.println("ADAPT" +typeDgenParams); + if (typeDgenParams.get(i) instanceof PlaceholderType) + unif.add((PlaceholderType) typeDgenParams.get(i), typeDParams.get(i)); + else System.out.println("ERROR"); + } + return Optional.of(new UnifyPair(unif.apply(newLhs), typeDs, PairOperator.SMALLERDOT, pair.getSubstitution(), pair.getBasePair())); + } + + @Override + public Optional adaptExt(UnifyPair pair, IFiniteClosure fc) { + if(pair.getPairOp() != PairOperator.SMALLERDOTWC) + return Optional.empty(); + + UnifyType typeD = pair.getLhsType(); + if(!(typeD instanceof ReferenceType) && !(typeD instanceof ExtendsType)) + return Optional.empty(); + + UnifyType typeExtDs = pair.getRhsType(); + if(!(typeExtDs instanceof ExtendsType)) + return Optional.empty(); + + if(typeD.getTypeParams().size() == 0 || typeExtDs.getTypeParams().size() == 0) + return Optional.empty(); + + UnifyType typeDgen; + if(typeD instanceof ReferenceType) + typeDgen = fc.getLeftHandedType(typeD.getName()).orElse(null); + else { + Optional opt = fc.getLeftHandedType(((ExtendsType) typeD).getExtendedType().getName()); + typeDgen = opt.isPresent() ? new ExtendsType(opt.get()) : null; + } + + if(typeDgen == null) + return Optional.empty(); + + Set grArg = fc.grArg(typeDgen, new HashSet<>()); + + Optional opt = grArg.stream().filter(x -> x.getName().equals(typeExtDs.getName())).findAny(); + + if(!opt.isPresent()) + return Optional.empty(); + + UnifyType newLhs = ((ExtendsType) opt.get()).getExtendedType(); + + TypeParams typeDParams = typeD.getTypeParams(); + TypeParams typeDgenParams = typeDgen.getTypeParams(); + + Unifier unif = new Unifier((PlaceholderType) typeDgenParams.get(0), typeDParams.get(0)); + for(int i = 1; i < typeDParams.size(); i++) + unif.add((PlaceholderType) typeDgenParams.get(i), typeDParams.get(i)); + + return Optional.of(new UnifyPair(unif.apply(newLhs), typeExtDs, PairOperator.SMALLERDOTWC, pair.getSubstitution(), pair.getBasePair())); + } + + @Override + public Optional adaptSup(UnifyPair pair, IFiniteClosure fc) { + if(pair.getPairOp() != PairOperator.SMALLERDOTWC) + return Optional.empty(); + + UnifyType typeDs = pair.getLhsType(); + if(!(typeDs instanceof ReferenceType) && !(typeDs instanceof SuperType)) + return Optional.empty(); + + UnifyType typeSupD = pair.getRhsType(); + if(!(typeSupD instanceof SuperType)) + return Optional.empty(); + + if(typeDs.getTypeParams().size() == 0 || typeSupD.getTypeParams().size() == 0) + return Optional.empty(); + + + Optional opt = fc.getLeftHandedType(((SuperType) typeSupD).getSuperedType().getName()); + + if(!opt.isPresent()) + return Optional.empty(); + + UnifyType typeDgen = opt.get(); + UnifyType typeSupDgen = new SuperType(typeDgen); + + // Use of smArg instead of grArg because + // a in grArg(b) => b in smArg(a) + Set smArg = fc.smArg(typeSupDgen, new HashSet<>()); + opt = smArg.stream().filter(x -> x.getName().equals(typeDs.getName())).findAny(); + + if(!opt.isPresent()) + return Optional.empty(); + + // New RHS + UnifyType newRhs = null; + if(typeDs instanceof ReferenceType) + newRhs = new ExtendsType(typeDs); + else + newRhs = new ExtendsType(((SuperType) typeDs).getSuperedType()); + + // New LHS + UnifyType newLhs = opt.get(); + TypeParams typeDParams = typeSupD.getTypeParams(); + TypeParams typeSupDsgenParams = typeSupDgen.getTypeParams(); + + Unifier unif = new Unifier((PlaceholderType) typeSupDsgenParams.get(0), typeDParams.get(0)); + for(int i = 1; i < typeDParams.size(); i++) + unif.add((PlaceholderType) typeSupDsgenParams.get(i), typeDParams.get(i)); + + return Optional.of(new UnifyPair(unif.apply(newLhs), newRhs, PairOperator.SMALLERDOTWC, pair.getSubstitution(), pair.getBasePair())); + } + + /** + * Finds the permutation pi of the type arguments of two types based on the finite closure + * @param cArgs The type which arguments are permuted + * @param dArgs The other type + * @return An array containing the values of pi for every type argument of C or an empty array if the search failed. + */ + private int[] pi(TypeParams cArgs, TypeParams dArgs) { + if(!(cArgs.size()==dArgs.size()))throw new DebugException("Fehler in Unifizierung"); + + int[] permutation = new int[dArgs.size()]; + + boolean succ = true; + for (int dArgIdx = 0; dArgIdx < dArgs.size() && succ; dArgIdx++) { + UnifyType dArg = dArgs.get(dArgIdx); + succ = false; + for (int pi = 0; pi < cArgs.size(); pi++) + if (cArgs.get(pi).getName().equals(dArg.getName())) { + permutation[dArgIdx] = pi; + succ = true; + break; + } + } + + return succ ? permutation : new int[0]; + } + + public Optional> subst(Set pairs) { + return subst(pairs, new ArrayList<>()); + } + + @Override + public Optional> subst(Set pairs, List>> oderConstraints) { + HashMap typeMap = new HashMap<>(); + + Stack occuringTypes = new Stack<>(); + + for(UnifyPair pair : pairs) { + occuringTypes.push(pair.getLhsType()); + occuringTypes.push(pair.getRhsType()); + } + + while(!occuringTypes.isEmpty()) { + UnifyType t1 = occuringTypes.pop(); + if(!typeMap.containsKey(t1)) + typeMap.put(t1, 0); + typeMap.put(t1, typeMap.get(t1)+1); + + if(t1 instanceof ExtendsType) + occuringTypes.push(((ExtendsType) t1).getExtendedType()); + if(t1 instanceof SuperType) + occuringTypes.push(((SuperType) t1).getSuperedType()); + else + t1.getTypeParams().forEach(x -> occuringTypes.push(x)); + } + Queue result1 = new LinkedList(pairs); + ArrayList result = new ArrayList(); + boolean applied = false; + + while(!result1.isEmpty()) { + UnifyPair pair = result1.poll(); + PlaceholderType lhsType = null; + UnifyType rhsType; + + if(pair.getPairOp() == PairOperator.EQUALSDOT + && pair.getLhsType() instanceof PlaceholderType) + lhsType = (PlaceholderType) pair.getLhsType(); + rhsType = pair.getRhsType(); //PL eingefuegt 2017-09-29 statt !((rhsType = pair.getRhsType()) instanceof PlaceholderType) + + if(lhsType != null + //&& !((rhsType = pair.getRhsType()) instanceof PlaceholderType) //PL geloescht am 2017-09-29 Begründung: auch Typvariablen muessen ersetzt werden. + && typeMap.get(lhsType) > 1 // The type occurs in more pairs in the set than just the recent pair. + && !rhsType.getTypeParams().occurs(lhsType) + && !((rhsType instanceof WildcardType) && ((WildcardType)rhsType).getWildcardedType().equals(lhsType))) //PL eigefuegt 2018-02-18 + { + Unifier uni = new Unifier(lhsType, rhsType); + result = result.stream().map(x -> uni.apply(pair,x)).collect(Collectors.toCollection(ArrayList::new)); + result1 = result1.stream().map(x -> uni.apply(pair,x)).collect(Collectors.toCollection(LinkedList::new)); + + Function,? extends Constraint> applyUni = b -> b.stream().map( + x -> uni.apply(pair,x)).collect(Collectors.toCollection((b.getExtendConstraint() != null) + ? () -> new Constraint( + b.isInherited(), + b.isImplemented(), + b.getExtendConstraint().stream().map(x -> uni.apply(pair,x)).collect(Collectors.toCollection(Constraint::new)), + b.getmethodSignatureConstraint().stream().map(x -> uni.apply(pair,x)).collect(Collectors.toCollection(HashSet::new))) + : () -> new Constraint(b.isInherited(), b.isImplemented()) + )); + oderConstraints.replaceAll(oc -> oc.stream().map(applyUni).collect(Collectors.toCollection(HashSet::new))); + /* + oderConstraints = oderConstraints.stream().map( + a -> a.stream().map(applyUni + //b -> b.stream().map( + // x -> uni.apply(pair,x)).collect(Collectors.toCollection(HashSet::new) ) + ).collect(Collectors.toCollection(HashSet::new)) + ).collect(Collectors.toList(ArrayList::new)); + } + */ + applied = true; + } + result.add(pair); + } + + return applied ? Optional.of(new HashSet<>(result)) : Optional.empty(); + } + + @Override + public Optional reduceWildcardLow(UnifyPair pair) { + if(pair.getPairOp() != PairOperator.SMALLERDOTWC) + return Optional.empty(); + + UnifyType lhsType = pair.getLhsType(); + UnifyType rhsType = pair.getRhsType(); + if(!(lhsType instanceof ExtendsType) || !(rhsType instanceof ExtendsType)) + return Optional.empty(); + + return Optional.of(new UnifyPair(((ExtendsType) lhsType).getExtendedType(), ((ExtendsType) rhsType).getExtendedType(), PairOperator.SMALLERDOT, pair.getSubstitution(), pair.getBasePair())); + } + + @Override + public Optional reduceWildcardLowRight(UnifyPair pair) { + if(pair.getPairOp() != PairOperator.SMALLERDOTWC) + return Optional.empty(); + + UnifyType lhsType = pair.getLhsType(); + UnifyType rhsType = pair.getRhsType(); + if(!(lhsType instanceof ReferenceType) || !(rhsType instanceof ExtendsType)) + return Optional.empty(); + + return Optional.of(new UnifyPair(lhsType, ((ExtendsType) rhsType).getExtendedType(), PairOperator.SMALLERDOT, pair.getSubstitution(), pair.getBasePair())); + } + + @Override + public Optional reduceWildcardUp(UnifyPair pair) { + if(pair.getPairOp() != PairOperator.SMALLERDOTWC) + return Optional.empty(); + + UnifyType lhsType = pair.getLhsType(); + UnifyType rhsType = pair.getRhsType(); + if(!(lhsType instanceof SuperType) || !(rhsType instanceof SuperType)) + return Optional.empty(); + + return Optional.of(new UnifyPair(((SuperType) rhsType).getSuperedType(), ((SuperType) lhsType).getSuperedType(), PairOperator.SMALLERDOT, pair.getSubstitution(), pair.getBasePair())); + } + + @Override + public Optional reduceWildcardUpRight(UnifyPair pair) { + if(pair.getPairOp() != PairOperator.SMALLERDOTWC) + return Optional.empty(); + + UnifyType lhsType = pair.getLhsType(); + UnifyType rhsType = pair.getRhsType(); + if(!(lhsType instanceof ReferenceType) || !(rhsType instanceof SuperType)) + return Optional.empty(); + + return Optional.of(new UnifyPair(((SuperType) rhsType).getSuperedType(), lhsType, PairOperator.SMALLERDOTWC, pair.getSubstitution(), pair.getBasePair())); + } + + /* PL 2018-03-06 auskommentiert sind mutmaßlich falsch + * vgl. JAVA_BSP/Wildcard6.java + @Override + public Optional reduceWildcardLowUp(UnifyPair pair) { + if(pair.getPairOp() != PairOperator.SMALLERDOTWC) + return Optional.empty(); + + UnifyType lhsType = pair.getLhsType(); + UnifyType rhsType = pair.getRhsType(); + if(!(lhsType instanceof ExtendsType) || !(rhsType instanceof SuperType)) + return Optional.empty(); + + return Optional.of(new UnifyPair(((ExtendsType) lhsType).getExtendedType(), ((SuperType) rhsType).getSuperedType(), PairOperator.EQUALSDOT)); + } + + @Override + public Optional reduceWildcardUpLow(UnifyPair pair) { + if(pair.getPairOp() != PairOperator.SMALLERDOTWC) + return Optional.empty(); + + UnifyType lhsType = pair.getLhsType(); + UnifyType rhsType = pair.getRhsType(); + if(!(lhsType instanceof SuperType) || !(rhsType instanceof ExtendsType)) + return Optional.empty(); + + return Optional.of(new UnifyPair(((SuperType) lhsType).getSuperedType(), ((ExtendsType) rhsType).getExtendedType(), PairOperator.EQUALSDOT)); + } + + + @Override + public Optional reduceWildcardLeft(UnifyPair pair) { + if(pair.getPairOp() != PairOperator.SMALLERDOTWC) + return Optional.empty(); + + UnifyType rhsType = pair.getRhsType(); + if(!(rhsType instanceof ReferenceType)) + return Optional.empty(); + + UnifyType lhsType = pair.getLhsType(); + + if(lhsType instanceof WildcardType) + return Optional.of(new UnifyPair(((WildcardType) lhsType).getWildcardedType(), rhsType, PairOperator.EQUALSDOT)); + + return Optional.empty(); + } + */ + @Override + public Optional> reduceFunN(UnifyPair pair) { + if((pair.getPairOp() != PairOperator.SMALLERDOT) + && (pair.getPairOp() != PairOperator.EQUALSDOT)) //PL 2017-10-03 hinzugefuegt + //da Regel auch fuer EQUALSDOT anwendbar + //TODO: fuer allen anderen Relationen noch pruefen + return Optional.empty(); + + UnifyType lhsType = pair.getLhsType(); + UnifyType rhsType = pair.getRhsType(); + + if(!(lhsType instanceof FunNType) || !(rhsType instanceof FunNType)) + return Optional.empty(); + + FunNType funNLhsType = (FunNType) lhsType; + FunNType funNRhsType = (FunNType) rhsType; + + if(funNLhsType.getN() != funNRhsType.getN()) + return Optional.empty(); + + Set result = new HashSet(); + if (pair.getPairOp() == PairOperator.SMALLERDOT) { + result.add(new UnifyPair(funNLhsType.getTypeParams().get(funNLhsType.getTypeParams().size()-1), funNRhsType.getTypeParams().get(funNRhsType.getTypeParams().size()-1), PairOperator.SMALLERDOT, pair.getSubstitution(), pair.getBasePair())); + for(int i = 0; i < funNLhsType.getTypeParams().size()-1; i++) { + result.add(new UnifyPair(funNRhsType.getTypeParams().get(i), funNLhsType.getTypeParams().get(i), PairOperator.SMALLERDOT, pair.getSubstitution(), pair.getBasePair())); + } + } + else {// pair.getPairOp() == PairOperator.EQUALDOT + result.add(new UnifyPair(funNLhsType.getTypeParams().get(funNLhsType.getTypeParams().size()-1), funNRhsType.getTypeParams().get(funNRhsType.getTypeParams().size()-1), PairOperator.EQUALSDOT, pair.getSubstitution(), pair.getBasePair())); + for(int i = 0; i < funNLhsType.getTypeParams().size()-1; i++) { + result.add(new UnifyPair(funNRhsType.getTypeParams().get(i), funNLhsType.getTypeParams().get(i), PairOperator.EQUALSDOT, pair.getSubstitution(), pair.getBasePair())); + } + } + result.stream().forEach(x -> { UnifyType l = x.getLhsType(); + if (l instanceof PlaceholderType) { ((PlaceholderType)l).disableWildcardtable(); } + UnifyType r = x.getRhsType(); + if (r instanceof PlaceholderType) { ((PlaceholderType)r).disableWildcardtable(); } + } ); + try { + logFile.write("FUNgreater: " + pair + "\n"); + logFile.write("FUNred: " + result + "\n"); + logFile.flush(); + } + catch (IOException e) { + System.out.println("logFile-Error"); + } + return Optional.of(result); + } + + + @Override + public Optional> greaterFunN(UnifyPair pair, IFiniteClosure fc) { + if(pair.getPairOp() != PairOperator.SMALLERDOT) + return Optional.empty(); + + UnifyType lhsType = pair.getLhsType(); + UnifyType rhsType = pair.getRhsType(); + + if(!(lhsType instanceof FunNType)) + return Optional.empty(); + + //FunN$$<...> <. FunctinalInterface<...> wird umgewandelt in FunN$$<...> <. FunN$$<... args aus FuntionalInterface ...> + if (rhsType instanceof ReferenceType) { + UnifyType typeFI = pair.getRhsType(); + + Optional opt = fc.getRightHandedFunctionalInterfaceType(typeFI.getName()); + if(!opt.isPresent()) + return Optional.empty(); + + if (!(typeFI instanceof ReferenceType refType) || !(refType instanceof FunInterfaceType intf)) + return Optional.empty(); + + var fiArgs = intf.getFunctionalInterfaceTypeArguments(refType); + var retType = fiArgs.getFirst(); + var lhsArgs = intf.getFunctionalInterfaceTypeArguments(lhsType); + var lhsRet = lhsArgs.getFirst(); + + Set result = new HashSet<>(); + if (retType instanceof ExtendsType) { + result.add(new UnifyPair(lhsRet, retType, PairOperator.SMALLERDOTWC)); + } else if (retType instanceof SuperType) { + return Optional.empty(); + } else { + result.add(new UnifyPair(lhsRet, retType, PairOperator.EQUALSDOT)); + } + + for (var i = 1; i < fiArgs.size(); i++) { + var lh = lhsArgs.get(i); + var rh = fiArgs.get(i); + + if (rh instanceof SuperType) { + result.add(new UnifyPair(lh, rh, PairOperator.SMALLERDOTWC)); + } else if (rh instanceof ExtendsType) { + return Optional.empty(); + } else { + result.add(new UnifyPair(lh, rh, PairOperator.EQUALSDOT)); + } + } + + return Optional.of(result); + } + + else { + if(!(rhsType instanceof PlaceholderType)) + return Optional.empty(); + } + + FunNType funNLhsType = (FunNType) lhsType; + + Set result = new HashSet(); + + Integer variance = ((PlaceholderType)rhsType).getVariance(); + Integer inversVariance = distributeVariance.inverseVariance(variance); + + UnifyType[] freshPlaceholders = new UnifyType[funNLhsType.getTypeParams().size()]; + for(int i = 0; i < freshPlaceholders.length-1; i++) { + freshPlaceholders[i] = PlaceholderType.freshPlaceholder(); + ((PlaceholderType)freshPlaceholders[i]).setVariance(inversVariance); + } + freshPlaceholders[freshPlaceholders.length-1] = PlaceholderType.freshPlaceholder(); + ((PlaceholderType)freshPlaceholders[freshPlaceholders.length-1]).setVariance(variance); + result.add(new UnifyPair(funNLhsType.getTypeParams().get(funNLhsType.getTypeParams().size()-1), freshPlaceholders[funNLhsType.getTypeParams().size()-1], PairOperator.SMALLERDOT, pair.getSubstitution(), pair.getBasePair())); + + for(int i = 0; i < funNLhsType.getTypeParams().size()-1; i++) { + result.add(new UnifyPair(freshPlaceholders[i], funNLhsType.getTypeParams().get(i), PairOperator.SMALLERDOT, pair.getSubstitution(), pair.getBasePair())); + } + + result.add(new UnifyPair(rhsType, funNLhsType.setTypeParams(new TypeParams(freshPlaceholders)), PairOperator.EQUALSDOT, pair.getSubstitution(), pair.getBasePair())); + + result.stream().forEach(x -> { UnifyType l = x.getLhsType(); + if (l instanceof PlaceholderType) { ((PlaceholderType)l).disableWildcardtable(); } + UnifyType r = x.getRhsType(); + if (r instanceof PlaceholderType) { ((PlaceholderType)r).disableWildcardtable(); } + } ); + try { + logFile.write("FUNgreater: " + pair + "\n"); + logFile.write("FUNgreater: " + result + "\n"); + logFile.flush(); + } + catch (IOException e) { + System.out.println("lofFile-Error"); + } + return Optional.of(result); + } + + @Override + public Optional> smallerFunN(UnifyPair pair) { + if(pair.getPairOp() != PairOperator.SMALLERDOT) + return Optional.empty(); + + UnifyType lhsType = pair.getLhsType(); + UnifyType rhsType = pair.getRhsType(); + + if(!(lhsType instanceof PlaceholderType) || !(rhsType instanceof FunNType)) + return Optional.empty(); + + FunNType funNRhsType = (FunNType) rhsType; + + Set result = new HashSet(); + + Integer variance = ((PlaceholderType)lhsType).getVariance(); + Integer inversVariance = distributeVariance.inverseVariance(variance); + + UnifyType[] freshPlaceholders = new UnifyType[funNRhsType.getTypeParams().size()]; + for(int i = 0; i < freshPlaceholders.length-1; i++) { + freshPlaceholders[i] = PlaceholderType.freshPlaceholder(); + ((PlaceholderType)freshPlaceholders[i]).setVariance(inversVariance); + } + freshPlaceholders[freshPlaceholders.length-1] = PlaceholderType.freshPlaceholder(); + ((PlaceholderType)freshPlaceholders[freshPlaceholders.length-1]).setVariance(variance); + + result.add(new UnifyPair(freshPlaceholders[funNRhsType.getTypeParams().size()-1], funNRhsType.getTypeParams().get(funNRhsType.getTypeParams().size()-1), PairOperator.SMALLERDOT, pair.getSubstitution(), pair.getBasePair())); + + for(int i = 0; i < funNRhsType.getTypeParams().size()-1; i++) { + result.add(new UnifyPair(funNRhsType.getTypeParams().get(i), freshPlaceholders[i], PairOperator.SMALLERDOT, pair.getSubstitution(), pair.getBasePair())); + } + + result.add(new UnifyPair(lhsType, funNRhsType.setTypeParams(new TypeParams(freshPlaceholders)), PairOperator.EQUALSDOT, pair.getSubstitution(), pair.getBasePair())); + + result.stream().forEach(x -> { UnifyType l = x.getLhsType(); + if (l instanceof PlaceholderType) { ((PlaceholderType)l).disableWildcardtable(); } + UnifyType r = x.getRhsType(); + if (r instanceof PlaceholderType) { ((PlaceholderType)r).disableWildcardtable(); } + } ); + try { + logFile.write("FUNgreater: " + pair + "\n"); + logFile.write("FUNsmaller: " + result + "\n"); + logFile.flush(); + } + catch (IOException e) { + System.out.println("lofFile-Error"); + } + return Optional.of(result); + } + + @Override + public Optional reduceTph(UnifyPair pair) { + if(pair.getPairOp() != PairOperator.SMALLERDOTWC) + return Optional.empty(); + + UnifyType lhsType = pair.getLhsType(); + UnifyType rhsType = pair.getRhsType(); + if(!(lhsType instanceof PlaceholderType) || !(rhsType instanceof ReferenceType)) + return Optional.empty(); + + return Optional.of(new UnifyPair(lhsType, rhsType, PairOperator.EQUALSDOT, pair.getSubstitution(), pair.getBasePair())); + } + + @Override + public Optional> reduceTphExt(UnifyPair pair) { + if(pair.getPairOp() != PairOperator.SMALLERDOTWC) + return Optional.empty(); + + UnifyType lhsType = pair.getLhsType(); + UnifyType rhsType = pair.getRhsType(); + if(!(lhsType instanceof ExtendsType) || !(rhsType instanceof PlaceholderType)) + return Optional.empty(); + + UnifyType extendedType = ((ExtendsType)lhsType).getExtendedType(); + + if (extendedType.equals(rhsType)) return Optional.empty(); //PL 2019-02-18 eingefügt ? extends a <.? a + + boolean isGen = extendedType instanceof PlaceholderType && !((PlaceholderType) extendedType).isGenerated(); + + Set result = new HashSet<>(); + if(isGen) + result.add(new UnifyPair(rhsType, lhsType, PairOperator.EQUALSDOT, pair.getSubstitution(), pair.getBasePair())); + else { + UnifyType freshTph = PlaceholderType.freshPlaceholder(); + result.add(new UnifyPair(rhsType, new ExtendsType(freshTph), PairOperator.EQUALSDOT, pair.getSubstitution(), pair.getBasePair())); + result.add(new UnifyPair(extendedType, freshTph, PairOperator.SMALLERDOT, pair.getSubstitution(), pair.getBasePair())); + } + + return Optional.of(result); + } + + @Override + public Optional> reduceTphSup(UnifyPair pair) { + if(pair.getPairOp() != PairOperator.SMALLERDOTWC) + return Optional.empty(); + + UnifyType lhsType = pair.getLhsType(); + UnifyType rhsType = pair.getRhsType(); + if(!(lhsType instanceof SuperType) || !(rhsType instanceof PlaceholderType)) + return Optional.empty(); + + UnifyType superedType = ((SuperType)lhsType).getSuperedType(); + + if (superedType.equals(rhsType)) return Optional.empty(); //PL 2019-02-18 eingefügt ? super a <.? a + + boolean isGen = superedType instanceof PlaceholderType && !((PlaceholderType) superedType).isGenerated(); + + Set result = new HashSet<>(); + if(isGen) + result.add(new UnifyPair(rhsType, lhsType, PairOperator.EQUALSDOT, pair.getSubstitution(), pair.getBasePair())); + else { + UnifyType freshTph = PlaceholderType.freshPlaceholder(); + result.add(new UnifyPair(rhsType, new SuperType(freshTph), PairOperator.EQUALSDOT, pair.getSubstitution(), pair.getBasePair())); + Set fBounded = pair.getfBounded(); + fBounded.add(lhsType); + result.add(new UnifyPair(freshTph, superedType, PairOperator.SMALLERDOT, pair.getSubstitution(), pair.getBasePair(), fBounded)); + } + + return Optional.of(result); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/TypeUnify.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/TypeUnify.java new file mode 100644 index 0000000..49476c9 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/TypeUnify.java @@ -0,0 +1,121 @@ +package de.dhbw.compiler.typeinference.unify; + +import java.io.FileWriter; +import java.io.IOException; +import java.io.Writer; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ForkJoinPool; + +import de.dhbw.compiler.core.JavaTXCompiler; +import de.dhbw.compiler.typeinference.constraints.Constraint; +import de.dhbw.compiler.typeinference.constraints.ConstraintSet; +import de.dhbw.compiler.typeinference.constraints.Pair; +import de.dhbw.compiler.typeinference.unify.interfaces.IFiniteClosure; +import de.dhbw.compiler.typeinference.unify.model.FiniteClosure; +import de.dhbw.compiler.typeinference.unify.model.UnifyPair; + +public class TypeUnify { + + /** + * unify parallel ohne result modell + * @param undConstrains + * @param oderConstraints + * @param fc + * @param logFile + * @param log + * @param cons + * @return + */ + public Set> unify(Set undConstrains, List>> oderConstraints, IFiniteClosure fc, Writer logFile, Boolean log, UnifyResultModel ret, UnifyTaskModel usedTasks) { + TypeUnifyTask unifyTask = new TypeUnifyTask(undConstrains, oderConstraints, fc, true, logFile, log, 0, ret, usedTasks); + ForkJoinPool pool = new ForkJoinPool(); + pool.invoke(unifyTask); + Set> res = unifyTask.join(); + try { + logFile.write("\nnoShortendElements: " + unifyTask.noShortendElements + "\n"); + logFile.flush(); + } + catch (IOException e) { + System.err.println("no log-File"); + } + return res; + } + + /** + * unify asynchron mit Rückgabe UnifyResultModel ohne dass alle results gesammelt sind + * @param undConstrains + * @param oderConstraints + * @param fc + * @param logFile + * @param log + * @param cons + * @param ret + * @return + */ + public UnifyResultModel unifyAsync(Set undConstrains, List>> oderConstraints, IFiniteClosure fc, Writer logFile, Boolean log, UnifyResultModel ret, UnifyTaskModel usedTasks) { + TypeUnifyTask unifyTask = new TypeUnifyTask(undConstrains, oderConstraints, fc, true, logFile, log, 0, ret, usedTasks); + ForkJoinPool pool = new ForkJoinPool(); + pool.invoke(unifyTask); + return ret; + } + + /** + * unify parallel mit Rückgabe UnifyResultModel nachdem alle results gesammelt sind + * @param undConstrains + * @param oderConstraints + * @param fc + * @param logFile + * @param log + * @param cons + * @param ret + * @return + */ + public UnifyResultModel unifyParallel(Set undConstrains, List>> oderConstraints, IFiniteClosure fc, Writer logFile, Boolean log, UnifyResultModel ret, UnifyTaskModel usedTasks) { + TypeUnifyTask unifyTask = new TypeUnifyTask(undConstrains, oderConstraints, fc, true, logFile, log, 0, ret, usedTasks); + ForkJoinPool pool = new ForkJoinPool(); + pool.invoke(unifyTask); + Set> res = unifyTask.join(); + try { + logFile.write("\nnoShortendElements: " + unifyTask.noShortendElements +"\n"); + logFile.flush(); + } + catch (IOException e) { + System.err.println("no log-File"); + } + return ret; + } + + /* + public Set> unifySequential(Set eq, IFiniteClosure fc, FileWriter logFile, Boolean log) { + TypeUnifyTask unifyTask = new TypeUnifyTask(eq, fc, false, logFile, log); + Set> res = unifyTask.compute(); + return res; + } + */ + + /** + * unify sequentiell mit oderconstraints + * @param undConstrains + * @param oderConstraints + * @param fc + * @param logFile + * @param log + * @param cons + * @return + */ + public Set> unifyOderConstraints(Set undConstrains, List>> oderConstraints, IFiniteClosure fc, Writer logFile, Boolean log, UnifyResultModel ret, UnifyTaskModel usedTasks) { + TypeUnifyTask unifyTask = new TypeUnifyTask(undConstrains, oderConstraints, fc, false, logFile, log, 0, ret, usedTasks); + Set> res = unifyTask.compute(); + try { + logFile.write("\nnoShortendElements: " + unifyTask.noShortendElements +"\n"); + logFile.flush(); + } + catch (IOException e) { + System.err.println("no log-File"); + } + return res; + } + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/TypeUnify2Task.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/TypeUnify2Task.java new file mode 100644 index 0000000..2a13ac8 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/TypeUnify2Task.java @@ -0,0 +1,66 @@ +package de.dhbw.compiler.typeinference.unify; + +import java.io.FileWriter; +import java.io.IOException; +import java.io.Writer; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import de.dhbw.compiler.typeinference.constraints.Constraint; +import de.dhbw.compiler.typeinference.constraints.ConstraintSet; +import de.dhbw.compiler.typeinference.constraints.Pair; +import de.dhbw.compiler.typeinference.unify.interfaces.IFiniteClosure; +import de.dhbw.compiler.typeinference.unify.model.UnifyPair; + +public class TypeUnify2Task extends TypeUnifyTask { + + Set> setToFlatten; + Set methodSignatureConstraintUebergabe; + + public TypeUnify2Task(Set> setToFlatten, Set eq, List>> oderConstraints, Set nextSetElement, IFiniteClosure fc, boolean parallel, Writer logFile, Boolean log, int rekTiefe, UnifyResultModel urm, UnifyTaskModel usedTasks, Set methodSignatureConstraintUebergabe) { + super(eq, oderConstraints, fc, parallel, logFile, log, rekTiefe, urm, usedTasks); + this.setToFlatten = setToFlatten; + this.nextSetElement = nextSetElement; + this.methodSignatureConstraintUebergabe = methodSignatureConstraintUebergabe; + } + + Set getNextSetElement() { + return nextSetElement; + } + + @Override + protected Set> compute() { + if (one) { + System.out.println("two"); + } + one = true; + Set> res = unify2(setToFlatten, eq, oderConstraintsField, fc, parallel, rekTiefeField, methodSignatureConstraintUebergabe); + /*if (isUndefinedPairSetSet(res)) { + return new HashSet<>(); } + else + */ + //writeLog("xxx"); + //noOfThread--; + synchronized (usedTasks) { + if (this.myIsCancelled()) { + return new HashSet<>(); + } + else { + return res; + } + } + } + + public void closeLogFile() { + + try { + logFile.close(); + } + catch (IOException ioE) { + System.err.println("no log-File" + thNo); + } + + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/TypeUnifyTask.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/TypeUnifyTask.java new file mode 100644 index 0000000..8db171d --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/TypeUnifyTask.java @@ -0,0 +1,2628 @@ +//PL 2018-12-19: Merge checken +package de.dhbw.compiler.typeinference.unify; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.RecursiveTask; +import java.util.function.BiFunction; +import java.util.function.BinaryOperator; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.apache.commons.io.output.NullOutputStream; + +import de.dhbw.compiler.exceptions.TypeinferenceException; +import de.dhbw.compiler.parser.NullToken; +import de.dhbw.compiler.syntaxtree.factory.UnifyTypeFactory; +import de.dhbw.compiler.typeinference.constraints.Constraint; +import de.dhbw.compiler.typeinference.constraints.ConstraintSet; +import de.dhbw.compiler.typeinference.result.ResultSet; +import de.dhbw.compiler.typeinference.unify.interfaces.IFiniteClosure; +import de.dhbw.compiler.typeinference.unify.interfaces.IMatch; +import de.dhbw.compiler.typeinference.unify.interfaces.IRuleSet; +import de.dhbw.compiler.typeinference.unify.interfaces.ISetOperations; +import de.dhbw.compiler.typeinference.unify.interfaces.IUnify; +import de.dhbw.compiler.typeinference.unify.model.ExtendsType; +import de.dhbw.compiler.typeinference.unify.model.FunNType; +import de.dhbw.compiler.typeinference.unify.model.OrderingExtend; +import de.dhbw.compiler.typeinference.unify.model.PairOperator; +import de.dhbw.compiler.typeinference.unify.model.PlaceholderType; +import de.dhbw.compiler.typeinference.unify.model.ReferenceType; +import de.dhbw.compiler.typeinference.unify.model.SuperType; +import de.dhbw.compiler.typeinference.unify.model.TypeParams; +import de.dhbw.compiler.typeinference.unify.model.Unifier; +import de.dhbw.compiler.typeinference.unify.model.UnifyPair; +import de.dhbw.compiler.typeinference.unify.model.UnifyType; +import de.dhbw.compiler.typeinference.unify.model.WildcardType; +import de.dhbw.compiler.util.Pair; +import de.dhbw.compiler.typeinference.unify.model.OrderingUnifyPair; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.Writer; + +import com.google.common.collect.Ordering; + + +/** + * Implementation of the type unification algorithm + * @author Florian Steurer + */ +public class TypeUnifyTask extends RecursiveTask>> { + + private static final long serialVersionUID = 1L; + private static int i = 0; + private boolean printtag = false; + Boolean log = true; //gibt an ob ein Log-File nach System.getProperty("user.dir")+"/test/logFiles/log" geschrieben werden soll? + + /** + * Element, das aus dem nextSet den Gleichunen dieses Threads hinzugefuegt wurde + */ + Set nextSetElement; + + /** + * Fuer die Threads + */ + UnifyResultModel urm; + protected static int noOfThread = 0; + private static int totalnoOfThread = 0; + int thNo; + protected boolean one = false; + Integer MaxNoOfThreads = 8; + + public static final String rootDirectory = System.getProperty("user.dir")+"/test/logFiles/"; + Writer logFile; + + /** + * The implementation of setOps that will be used during the unification + */ + protected ISetOperations setOps = new GuavaSetOperations(); + + /** + * The implementation of the standard unify that will be used during the unification + */ + protected IUnify stdUnify = new MartelliMontanariUnify(); + + /** + * The implementation of the rules that will be used during the unification. + */ + protected IRuleSet rules; + + protected Set eq; //und-constraints + + protected List>> oderConstraintsField; + + protected IFiniteClosure fc; + + protected OrderingExtend> oup; + + protected boolean parallel; + + //Gives if unify is not called from checkA + private boolean finalresult = true; + + int rekTiefeField; + + Integer nOfUnify = 0; + + Integer noUndefPair = 0; + + Integer noAllErasedElements = 0; + + static Integer noou = 0; + + static int noBacktracking; + + static Integer noShortendElements = 0; + + Boolean myIsCanceled = false; + + volatile UnifyTaskModel usedTasks; + + public TypeUnifyTask() { + rules = new RuleSet(); + } + + /* + public TypeUnifyTask(Set eq, IFiniteClosure fc, boolean parallel, FileWriter logFile, Boolean log) { + this.eq = eq; + this.fc = fc; + this.oup = new OrderingUnifyPair(fc); + this.parallel = parallel; + this.logFile = logFile; + this.log = log; + rules = new RuleSet(logFile); + noOfThread++; + thNo = noOfThread; + } + */ + + + public TypeUnifyTask(Set eq, List>> oderConstraints, IFiniteClosure fc, boolean parallel, Writer logFile, Boolean log, int rekTiefe, UnifyResultModel urm, UnifyTaskModel usedTasks) { + synchronized (this) { + this.eq = eq; + //this.oderConstraints = oderConstraints.stream().map(x -> x.stream().map(y -> new HashSet<>(y)).collect(Collectors.toSet(HashSet::new))).collect(Collectors.toList(ArrayList::new)); + this.oderConstraintsField = oderConstraints; /*.stream().map(x -> { + Set> ret = new HashSet<>(); + for (Constraint y : x) { + ret.add(new HashSet<>(y)); + } + return ret; + }).collect(Collectors.toCollection(ArrayList::new)); + */ + + //x.stream().map(y -> new HashSet<>(y)).collect(Collectors.toSet(HashSet::new))).collect(Collectors.toList(ArrayList::new)); + this.nextSetElement = nextSetElement; + this.fc = fc; + this.oup = new OrderingUnifyPair(fc); + this.parallel = parallel; + this.logFile = logFile; + this.log = log; + + noOfThread++; + totalnoOfThread++; + //writeLog("thNo1 " + thNo); + thNo = totalnoOfThread; + writeLog("thNo2 " + thNo); + try { + this.logFile = log ? new FileWriter(new File(System.getProperty("user.dir") + "/logFiles/" + "Thread_"+thNo)) + : new OutputStreamWriter(new NullOutputStream()); + logFile.write(""); + } + catch (IOException e) { + System.err.println("log-File nicht vorhanden"); + } + /*Abbruchtest + if (thNo > 10) { + System.out.println("cancel"); + usedTasks.cancel(); + writeLog(nOfUnify.toString() + "cancel"); + System.out.println("cancel"); + try { + logFile.write("Abbruch"); + } + catch (IOException e) { + System.err.println("log-File nicht vorhanden"); + } + } + */ + rules = new RuleSet(logFile); + this.rekTiefeField = rekTiefe; + this.urm = urm; + this.usedTasks = usedTasks; + this.usedTasks.add(this); + } + } + + /** + * Vererbt alle Variancen + * @param eq The set of constraints + */ + /* PL 2018-05- 17 verschoben nach JavaTXCompiler + private void varianceInheritance(Set eq) { + Set usedTPH = new HashSet<>(); + Set phSet = eq.stream().map(x -> { + Set pair = new HashSet<>(); + if (x.getLhsType() instanceof PlaceholderType) pair.add((PlaceholderType)x.getLhsType()); + if (x.getRhsType() instanceof PlaceholderType) pair.add((PlaceholderType)x.getRhsType()); + return pair; + }).reduce(new HashSet<>(), (a,b) -> { a.addAll(b); return a;} , (c,d) -> { c.addAll(d); return c;}); + + ArrayList phSetVariance = new ArrayList<>(phSet); + phSetVariance.removeIf(x -> (x.getVariance() == 0)); + while(!phSetVariance.isEmpty()) { + PlaceholderType a = phSetVariance.remove(0); + usedTPH.add(a); + //HashMap ht = new HashMap<>(); + //ht.put(a, a.getVariance()); + Set eq1 = new HashSet<>(eq); + eq1.removeIf(x -> !(x.getLhsType() instanceof PlaceholderType && ((PlaceholderType)x.getLhsType()).equals(a))); + eq1.stream().forEach(x -> { x.getRhsType().accept(new distributeVariance(), a.getVariance());}); + eq1 = new HashSet<>(eq); + eq1.removeIf(x -> !(x.getRhsType() instanceof PlaceholderType && ((PlaceholderType)x.getRhsType()).equals(a))); + eq1.stream().forEach(x -> { x.getLhsType().accept(new distributeVariance(), a.getVariance());}); + phSetVariance = new ArrayList<>(phSet); + phSetVariance.removeIf(x -> (x.getVariance() == 0 || usedTPH.contains(x))); + } +} +*/ + void myCancel(Boolean b) { + myIsCanceled = true; + } + + public boolean myIsCancelled() { + return myIsCanceled; + } + + protected Set> compute() { + if (one) { + System.out.println("two"); + } + one = true; + Set neweq = new HashSet<>(eq); + /* 1-elementige Oder-Constraints werden in und-Constraints umgewandelt */ + Set methodSignatureConstraint = new HashSet<>(); + oderConstraintsField.stream() + .filter(x -> x.size()==1) + .map(y -> y.stream().findFirst().get()).forEach(x -> { neweq.addAll(x); methodSignatureConstraint.addAll(x.getmethodSignatureConstraint());} ); + ArrayList>> remainingOderconstraints = oderConstraintsField.stream() + .filter(x -> x.size()>1) + .collect(Collectors.toCollection(ArrayList::new)); + Set> res = unify(neweq, remainingOderconstraints, fc, parallel, rekTiefeField, methodSignatureConstraint); + noOfThread--; + try { + logFile.close(); + } + catch (IOException ioE) { + System.err.println("no log-File"); + } + if (isUndefinedPairSetSet(res)) { + //fuer debug-Zwecke + ArrayList al = res.stream().map(x -> x.stream().collect(Collectors.toCollection(ArrayList::new))) + .collect(Collectors.toCollection(ArrayList::new)); + throw new TypeinferenceException("Unresolved constraints: " + res.toString(), new NullToken()); //return new HashSet<>(); + } + else { + synchronized (usedTasks) { + if (this.myIsCancelled()) { + return new HashSet<>(); + } + else { + return res; + } + } + } + } +/* + @Override + protected Set> compute() { + Set> fstElems = new HashSet<>(); + fstElems.add(eq); + Set> res = computeCartesianRecursiveOderConstraints(fstElems, oderConstraints, fc, parallel); + if (isUndefinedPairSetSet(res)) { return new HashSet<>(); } + else return res; + } +*/ + + + + + /** + * Computes all principal type unifiers for a set of constraints. + * @param eq The set of constraints + * @param fc The finite closure + * @return The set of all principal type unifiers + */ + protected Set> unify(final Set eq, List>> oderConstraints, IFiniteClosure fc, boolean parallel, int rekTiefe, Set methodSignatureConstraint) { + //Set aas = eq.stream().filter(x -> x.getLhsType().getName().equals("AA") //&& x.getPairOp().equals(PairOperator.SMALLERDOT) + // ).collect(Collectors.toCollection(HashSet::new)); + //writeLog(nOfUnify.toString() + " AA: " + aas.toString()); + //if (aas.isEmpty()) { + // System.out.println(""); + //} + + //.collect(Collectors.toCollection(HashSet::new))); + + synchronized (usedTasks) { + if (this.myIsCancelled()) { + return new HashSet<>(); + } + } + + rekTiefe++; + nOfUnify++; + writeLog(nOfUnify.toString() + " Unifikation: " + eq.toString()); + writeLog(nOfUnify.toString() + " Oderconstraints: " + oderConstraints.toString()); + + /* + * Variancen auf alle Gleichungen vererben + */ + //PL 2018-05-17 nach JavaTXCompiler verschoben + //varianceInheritance(eq); + + /* + * ? extends ? extends Theta rausfiltern + */ + Set doubleExt = eq.stream().filter(x -> (x.wrongWildcard())).map(x -> { x.setUndefinedPair(); return x;}) + .collect(Collectors.toCollection(HashSet::new)); + if (doubleExt.size() > 0) { + Set> ret = new HashSet<>(); + ret.add(doubleExt); + return ret; + } + + /* + * Occurs-Check durchfuehren + */ + + Set ocurrPairs = eq.stream().filter(x -> { + UnifyType lhs, rhs; + return (lhs = x.getLhsType()) instanceof PlaceholderType + && !((rhs = x.getRhsType()) instanceof PlaceholderType) + && rhs.getTypeParams().occurs((PlaceholderType)lhs);}) + .map(x -> { x.setUndefinedPair(); return x;}) + .collect(Collectors.toCollection(HashSet::new)); + writeLog("ocurrPairs: " + ocurrPairs); + if (ocurrPairs.size() > 0) { + Set> ret = new HashSet<>(); + ret.add(ocurrPairs); + return ret; + } + + + + /* + * Step 1: Repeated application of reduce, adapt, erase, swap + */ + Set eq0; + Set eq0Prime; + Optional> eqSubst = Optional.of(eq); + do { + eq0Prime = eqSubst.get(); + eq0 = applyTypeUnificationRules(eq0Prime, fc); + /* In commit dfd91b5f8b7fca1cb5f302eec4b0ba3330271c9b eingefuegt ANFANG */ + Set occurcheck = new HashSet<>(eq0); + occurcheck.removeAll(eq0Prime); + ocurrPairs = occurcheck.stream().filter(x -> { + UnifyType lhs, rhs; + return (lhs = x.getLhsType()) instanceof PlaceholderType + && !((rhs = x.getRhsType()) instanceof PlaceholderType) + && rhs.getTypeParams().occurs((PlaceholderType)lhs);}) + .map(x -> { x.setUndefinedPair(); return x;}) + .collect(Collectors.toCollection(HashSet::new)); + writeLog("ocurrPairs: " + ocurrPairs); + if (ocurrPairs.size() > 0) { + Set> ret = new HashSet<>(); + ret.add(ocurrPairs); + return ret; + } + /* In commit dfd91b5f8b7fca1cb5f302eec4b0ba3330271c9b eingefuegt ENDE */ + eqSubst = rules.subst(eq0, oderConstraints); + } while (eqSubst.isPresent()); + + eq0.forEach(x -> x.disableCondWildcards()); + + writeLog(nOfUnify.toString() + " Unifikation nach applyTypeUnificationRules: " + eq.toString()); + writeLog(nOfUnify.toString() + " Oderconstraints nach applyTypeUnificationRules: " + oderConstraints.toString()); + + /* + * Step 2 and 3: Create a subset eq1s of pairs where both sides are TPH and eq2s of the other pairs + */ + Set eq1s = new HashSet<>(); + Set eq2s = new HashSet<>(); + splitEq(eq0, eq1s, eq2s); + + /* + * Step 4: Create possible typings + * + * "Manche Autoren identifizieren die Paare (a, (b,c)) und ((a,b),c) + * mit dem geordneten Tripel (a,b,c), wodurch das kartesische Produkt auch assoziativ wird." - Wikipedia + */ + + // There are up to 10 toplevel set. 8 of 10 are the result of the + // cartesian product of the sets created by pattern matching. + List>> topLevelSets = new ArrayList<>(); + + //System.out.println(eq2s); + + if(eq1s.size() != 0) { // Do not add empty sets or the cartesian product will always be empty. + Set> wrap = new HashSet<>(); + wrap.add(eq1s); + topLevelSets.add(wrap); // Add Eq1' + } + + // Add the set of [a =. Theta | (a=. Theta) in Eq2'] + //TODO: Occurscheck anwenden als Fehler identifizieren + Set bufferSet = eq2s.stream() + .filter(x -> x.getPairOp() == PairOperator.EQUALSDOT && x.getLhsType() instanceof PlaceholderType) + .collect(Collectors.toSet()); + + if(bufferSet.size() != 0) { // Do not add empty sets or the cartesian product will always be empty. + Set> wrap = new HashSet<>(); + wrap.add(bufferSet); + topLevelSets.add(wrap); + eq2s.removeAll(bufferSet); + } + + // Sets that originate from pair pattern matching + // Sets of the "second level" + Set undefinedPairs = new HashSet<>(); + if (printtag) System.out.println("eq2s " + eq2s); + //writeLog("BufferSet: " + bufferSet.toString()+"\n"); + List>> oderConstraintsOutput = new ArrayList<>();//new ArrayList<>(oderConstraints); + Set>>> secondLevelSets = calculatePairSets(eq2s, oderConstraints, fc, undefinedPairs, oderConstraintsOutput); + //PL 2017-09-20: Im calculatePairSets wird möglicherweise O .< java.lang.Integer + //nicht ausgewertet Faculty Beispiel im 1. Schritt + //PL 2017-10-03 geloest, muesste noch mit FCs mit kleineren + //Typen getestet werden. + writeLog(nOfUnify.toString() + " Oderconstraints2: " + oderConstraintsOutput.toString()); + if (printtag) System.out.println("secondLevelSets:" +secondLevelSets); + // If pairs occured that did not match one of the cartesian product cases, + // those pairs are contradictory and the unification is impossible. + if(!undefinedPairs.isEmpty()) { + noUndefPair++; + for (UnifyPair up : undefinedPairs) { + writeLog(noUndefPair.toString() + " UndefinedPairs; " + up); + writeLog("BasePair; " + up.getBasePair()); + } + Set> error = new HashSet<>(); + undefinedPairs = undefinedPairs.stream().map(x -> { x.setUndefinedPair(); return x;}).collect(Collectors.toCollection(HashSet::new)); + error.add(undefinedPairs); + undefinedPairs.forEach(x -> writeLog("AllSubst: " +x.getAllSubstitutions().toString())); + return error; + } + + /* Up to here, no cartesian products are calculated. + * filters for pairs and sets can be applied here */ + + // Alternative: Sub cartesian products of the second level (pattern matched) sets + // "the big (x)" + /* for(Set>> secondLevelSet : secondLevelSets) { + //System.out.println("secondLevelSet "+secondLevelSet.size()); + List>> secondLevelSetList = new ArrayList<>(secondLevelSet); + Set>> cartResult = setOps.cartesianProduct(secondLevelSetList); + //System.out.println("CardResult: "+cartResult.size()); + // Flatten and add to top level sets + Set> flat = new HashSet<>(); + int j = 0; + for(List> s : cartResult) { + j++; + //System.out.println("s from CardResult: "+cartResult.size() + " " + j); + Set flat1 = new HashSet<>(); + for(Set s1 : s) + flat1.addAll(s1); + flat.add(flat1); + } + //topLevelSets.add(flat); + } + */ + + //Alternative KEIN KARTESISCHES PRODUKT der secondlevel Ebene bilden + for(Set>> secondLevelSet : secondLevelSets) { + for (Set> secondlevelelem : secondLevelSet) { + topLevelSets.add(secondlevelelem); + } + } + //System.out.println(topLevelSets); + //System.out.println(); + + + //Aufruf von computeCartesianRecursive ANFANG + //writeLog("topLevelSets: " + topLevelSets.toString()); + return computeCartesianRecursive(new ArrayList<>(topLevelSets), eq, oderConstraintsOutput, fc, parallel, rekTiefe, methodSignatureConstraint); + + } + + + Set> unify2(Set> setToFlatten, Set eq, List>> oderConstraints, IFiniteClosure fc, boolean parallel, int rekTiefe, Set methodSignatureConstraint) { + //Aufruf von computeCartesianRecursive ENDE + + //keine Ahnung woher das kommt + //Set> setToFlatten = topLevelSets.stream().map(x -> x.iterator().next()).collect(Collectors.toCollection(HashSet::new)); + + //Muss auskommentiert werden, wenn computeCartesianRecursive ANFANG + // Cartesian product over all (up to 10) top level sets + //Set>> eqPrimeSet = setOps.cartesianProduct(topLevelSets) + // .stream().map(x -> new HashSet<>(x)) + // .collect(Collectors.toCollection(HashSet::new)); + //Muss auskommentiert werden, wenn computeCartesianRecursive ENDE + + synchronized (usedTasks) { + if (this.myIsCancelled()) { + return new HashSet<>(); + } + } + + Set> eqPrimePrimeSet = new HashSet<>(); + + Set forks = new HashSet<>(); + + //Muss auskommentiert werden, wenn computeCartesianRecursive ANFANG + //for(Set> setToFlatten : eqPrimeSet) { + // Flatten the cartesian product + //Muss auskommentiert werden, wenn computeCartesianRecursive ENDE + Set eqPrime = new HashSet<>(); + setToFlatten.stream().forEach(x -> eqPrime.addAll(x)); + + /* + * Step 5: Substitution + */ + //writeLog("vor Subst: " + eqPrime); + writeLog("vor Subst: " + oderConstraints); + String ocString = oderConstraints.toString(); + List>> newOderConstraints = new ArrayList<>(oderConstraints); + Optional> eqPrimePrime = rules.subst(eqPrime, newOderConstraints); + Set> unifyres1 = null; + Set> unifyres2 = null; + if (!ocString.equals(newOderConstraints.toString())) writeLog("nach Subst: " + newOderConstraints); + //writeLog("nach Subst: " + eqPrimePrime); + /* + * Step 6 a) Restart (fork) for pairs where subst was applied + */ + /* + if(parallel) { + if (eqPrime.equals(eq) && !eqPrimePrime.isPresent() + && oderConstraints.isEmpty()) //PL 2017-09-29 //(!eqPrimePrime.isPresent()) auskommentiert und durch + //PL 2017-09-29 dies ersetzt //(!eqPrimePrime.isPresent()) + //PL 2018-05-18 beide Bedingungen muessen gelten, da eqPrime Veränderungen in allem ausser subst + //eqPrimePrime Veraenderungen in subst repraesentieren. + eqPrimePrimeSet.add(eqPrime); + else if(eqPrimePrime.isPresent()) { + //System.out.println("nextStep: " + eqPrimePrime.get()); + TypeUnifyTask fork = new TypeUnifyTask(eqPrimePrime.get(), fc, true, logFile, log); + forks.add(fork); + fork.fork(); + } + else { + //System.out.println("nextStep: " + eqPrime); + TypeUnifyTask fork = new TypeUnifyTask(eqPrime, fc, true, logFile, log); + forks.add(fork); + fork.fork(); + } + } + else */ + {// sequentiell (Step 6b is included) + if (printtag) System.out.println("nextStep: " + eqPrimePrime); + if (eqPrime.equals(eq) && !eqPrimePrime.isPresent() + && oderConstraints.isEmpty()) { //PL 2017-09-29 //(!eqPrimePrime.isPresent()) auskommentiert und durch + //PL 2017-09-29 dies ersetzt //(!eqPrimePrime.isPresent()) + //PL 2018-05-18 beide Bedingungen muessen gelten, da eqPrime Veränderungen in allem ausser subst + //eqPrimePrime Veraenderungen in subst repraesentieren. + //try { + //if (isSolvedForm(eqPrime)) { + // writeLog("eqPrime:" + eqPrime.toString()+"\n"); + //} + //} + //catch (IOException e) { + // System.err.println("log-File nicht vorhanden"); + //} + eqPrimePrimeSet.add(eqPrime); + if (finalresult && isSolvedForm(eqPrime)) { + writeLog("eqPrime:" + eqPrime.toString()+"\n"); + + /* methodconstraintsets werden zum Ergebnis hinzugefuegt + * Anfang + */ + //System.out.println("methodSignatureConstraint Return: " + methodSignatureConstraint + "\n"); + eqPrimePrimeSet.forEach(x -> x.addAll(methodSignatureConstraint)); + + //Substitutionen in methodcontraintsets werdne ausgeführt + /* PL auskommentiert 2024-05-02 + eqPrimePrimeSet = eqPrimePrimeSet.stream().map( + x -> { Optional> help = rules.subst(x); + return help.isPresent() ? + help.get(): + x; }).collect(Collectors.toSet()); + */ + /* + * Ende + */ + + + urm.notify(eqPrimePrimeSet); + } + } + else if(eqPrimePrime.isPresent()) { + Set> unifyres = unifyres1 = unify(eqPrimePrime.get(), newOderConstraints, fc, parallel, rekTiefe, methodSignatureConstraint); + + eqPrimePrimeSet.addAll(unifyres); + } + else { + Set> unifyres = unifyres2 = unify(eqPrime, newOderConstraints, fc, parallel, rekTiefe, methodSignatureConstraint); + + + eqPrimePrimeSet.addAll(unifyres); + } + } + //Muss auskommentiert werden, wenn computeCartesianRecursive ANFANG + //} + //Muss auskommentiert werden, wenn computeCartesianRecursive ENDE + + /* + * Step 6 b) Build the union over everything. + */ + /* + * PL 2019-01-22: geloescht + + if(parallel) + for(TypeUnifyTask fork : forks) + eqPrimePrimeSet.addAll(fork.join()); + */ + /* + * Step 7: Filter empty sets; + */ + eqPrimePrimeSet = eqPrimePrimeSet.stream().filter(x -> isSolvedForm(x) || this.isUndefinedPairSet(x)).collect(Collectors.toCollection(HashSet::new)); + if (!eqPrimePrimeSet.isEmpty() && !isUndefinedPairSetSet(eqPrimePrimeSet)) { + writeLog("Result1 " + eqPrimePrimeSet.toString()); + } + return eqPrimePrimeSet; + } + + + /** + * Computes the cartesian product of topLevelSets step by step. + * @param topLevelSets List of Sets of Sets, where a cartesian product have to be built + * Ex.: [{{a =. Integer}, {a = Object}}, {{a = Vector, b =. Integer}, {a = Vector, b =. Object}}] + * @param eq Original set of equations which should be unified + * @param oderConstraints Remaining or-constraints + * @param fc The finite closure + * @param parallel If the algorithm should be parallelized run + * @param rekTiefe Deep of recursive calls + * @return The set of all principal type unifiers + */ + Set> computeCartesianRecursive(ArrayList>> topLevelSets, Set eq, List>> oderConstraints, IFiniteClosure fc, boolean parallel, int rekTiefe, Set methodSignatureConstraint) { + + //oneElems: Alle 1-elementigen Mengen, die nur ein Paar + //a <. theta, theta <. a oder a =. theta enthalten + Set> oneElems = new HashSet<>(); + oneElems.addAll(topLevelSets.stream() + .filter(x -> x.size()==1) + .map(y -> y.stream().findFirst().get()) + .collect(Collectors.toCollection(HashSet::new))); + oneElems.forEach(x -> { if (x instanceof Constraint) methodSignatureConstraint.addAll(((Constraint)x).getmethodSignatureConstraint());}); + //optNextSet: Eine mehrelementige Menge, wenn vorhanden + Optional>> optNextSet = topLevelSets.stream().filter(x -> x.size()>1).findAny(); + + if (!optNextSet.isPresent()) {//Alle Elemente sind 1-elementig + Set> result = unify2(oneElems, eq, oderConstraints, fc, parallel, rekTiefe, methodSignatureConstraint); + return result; + } + + Set> nextSet = optNextSet.get(); + //writeLog("nextSet: " + nextSet.toString()); + List> nextSetasList =new ArrayList<>(nextSet); + /* + try { + //List> + //nextSetasList = oup.sortedCopy(nextSet);//new ArrayList<>(nextSet); + } + catch (java.lang.IllegalArgumentException e) { + System.out.print(""); + } + */ + Set> result = new HashSet<>(); + int variance = 0; + + /* Varianzbestimmung Anfang + * Oderconstraint, wenn entweder kein Basepair oder unterschiedliche Basepairs => oderConstraint = true; + * Varianz = 1 => Argumentvariable + * Varianz = -1 => Rückgabevariable + * Varianz = 0 => unklar + * Varianz = 2 => Operatoren oderConstraints */ + ArrayList zeroNextElem = new ArrayList<>(nextSetasList.get(0)); + UnifyPair fstBasePair = zeroNextElem.remove(0).getBasePair(); + Boolean oderConstraint = false; + + if (fstBasePair != null) { + Boolean sameBase = true; + for (UnifyPair ele : nextSetasList.get(0)) {//check ob a <. ty base oder ob Ueberladung + sameBase = sameBase && ele.getBasePair() != null && ele.getBasePair().equals(fstBasePair); + } + if (sameBase) { //angefuegt PL 2020-02-30 + Optional xi = nextSetasList.stream().map(x -> x.stream().filter(y -> (y.getLhsType() instanceof PlaceholderType && !(y.getRhsType() instanceof PlaceholderType))) + .filter(z -> ((PlaceholderType)z.getLhsType()).getVariance() != 0) + .map(c -> ((PlaceholderType)c.getLhsType()).getVariance()) + .reduce((a,b)-> {if (a==b) return a; else return 0; })) //2 kommt insbesondere bei Oder-Constraints vor + .filter(d -> d.isPresent()) + .map(e -> e.get()) + .findAny(); + if (xi.isPresent()) { + variance = xi.get(); + } + } + else { + oderConstraint = true; + } + } + else { + oderConstraint = true; + } + + //Varianz-Bestimmung Oder-Constraints + if (oderConstraint) { + if (printtag) System.out.println("nextSetasList " + nextSetasList); + Optional optVariance = + nextSetasList.iterator() + .next() + .stream() + .filter(x -> x.getGroundBasePair().getLhsType() instanceof PlaceholderType && + ! (x.getRhsType() instanceof PlaceholderType) && + x.getPairOp() == PairOperator.EQUALSDOT) + .map(x -> + ((PlaceholderType)x.getGroundBasePair().getLhsType()).getVariance()) + .reduce((n,m) -> { if ((n == 0) && (m==0)) return 0; + else if (n !=0) return n; //es muss mindestens eine Variance != 0 sein + else return m; + }); + //Fuer Operatorenaufrufe wird variance auf 2 gesetzt. + //da kein Receiver existiert also kein x.getGroundBasePair().getLhsType() instanceof PlaceholderType + //Bei Varianz = 2 werden alle Elemente des Kartesischen Produkts abgearbeitet + variance = optVariance.isPresent() ? optVariance.get() : 2; + } + /* Varianzbestimmung Ende */ + + //writeLog("nextSetasList: " + nextSetasList.toString()); + Set nextSetElem = nextSetasList.get(0); + //writeLog("BasePair1: " + nextSetElem + " " + nextSetElem.iterator().next().getBasePair()); + + /* sameEqSet-Bestimmung: Wenn a = ty \in nextSet dann enthaelt sameEqSet + * alle Paare a < ty1 oder ty2 < a aus oneElems */ + Set sameEqSet = new HashSet<>(); + + //optOrigPair enthaelt ggf. das Paar a = ty \in nextSet + Optional optOrigPair = null; + if (!oderConstraint) { + optOrigPair = nextSetElem.stream().filter(x -> ( + //x.getBasePair() != null && ist gegeben wenn variance != 2 + //x.getBasePair().getPairOp().equals(PairOperator.SMALLERDOT) && + (x.getPairOp().equals(PairOperator.EQUALSDOT) + /* + (x.getBasePair().getLhsType() instanceof PlaceholderType + && x.getLhsType().equals(x.getBasePair().getLhsType())) + || (x.getBasePair().getRhsType() instanceof PlaceholderType + && x.getLhsType().equals(x.getBasePair().getRhsType()) + */ + ))).filter(x -> //Sicherstellen, dass bei a = ty a auch wirklich die gesuchte Typvariable ist + x.getLhsType().equals(x.getBasePair().getLhsType()) || + x.getLhsType().equals(x.getBasePair().getRhsType()) + ).findFirst(); + writeLog("optOrigPair: " + optOrigPair); + if (optOrigPair.isPresent()) { + UnifyPair origPair = optOrigPair.get(); + UnifyType tyVar; + if (!((tyVar = origPair.getLhsType()) instanceof PlaceholderType)) { + tyVar = origPair.getRhsType(); + } + UnifyType tyVarEF = tyVar; + sameEqSet = oneElems.stream().map(xx -> xx.iterator().next()) + .filter(x -> (((x.getLhsType().equals(tyVarEF) && !(x.getRhsType() instanceof PlaceholderType)) + || (x.getRhsType().equals(tyVarEF) && !(x.getLhsType() instanceof PlaceholderType))))) + .collect(Collectors.toCollection(HashSet::new)); + } + } + /* sameEqSet-Bestimmung Ende */ + + Set a = null; + while (nextSetasList.size() > 0) { + Set a_last = a; + + /* Liste der Faelle für die parallele Verarbeitung + * Enthaelt Elemente, die nicht in Relation zu aktuellem Fall in der + * Variablen a stehen. Diese muesse auf alle Faelle bearbeitet werden, + * Deshalb wird ihre Berechnung parallel angestossen. + */ + List> nextSetasListRest = new ArrayList<>(); + + /* Liste der Faelle, bei dem Receiver jeweils "? extends" enthaelt bzw. nicht enthaelt + * In der Regel ist dies genau ein Element + * Dieses Element wird später aus nextSetasList geloescht, wenn das jeweils andere Element zum Erfolg + * gefuehrt hat. + */ + List> nextSetasListOderConstraints = new ArrayList<>(); + + writeLog("nextSet: " + nextSet.toString()); + writeLog("nextSetasList: " + nextSetasList.toString()); + if (variance == 1) { + a = oup.max(nextSetasList.iterator()); + writeLog("Max: a in " + variance + " "+ a); + nextSetasList.remove(a); + if (oderConstraint) { + nextSetasListOderConstraints.add(((Constraint)a).getExtendConstraint()); + } + writeLog("nextSetasListOderConstraints 1: " + nextSetasListOderConstraints); + nextSetasListRest = new ArrayList<>(nextSetasList); + Iterator> nextSetasListItRest = new ArrayList>(nextSetasListRest).iterator(); + while (nextSetasListItRest.hasNext()) { + Set a_next = nextSetasListItRest.next(); + if (//a.equals(a_next) || + (oup.compare(a, a_next) == 1)) { + nextSetasListRest.remove(a_next); + } + } + + //Alle maximale Elemente in nextSetasListRest bestimmen + //nur für diese wird parallele Berechnung angestossen. + nextSetasListRest = oup.maxElements(nextSetasListRest); + } + else if (variance == -1) { + a = oup.min(nextSetasList.iterator()); + writeLog("Min: a in " + variance + " "+ a); + if (oderConstraint) { + nextSetasListOderConstraints.add(((Constraint)a).getExtendConstraint()); + } + writeLog("nextSetasListOderConstraints -1: " + nextSetasListOderConstraints); + nextSetasList.remove(a); + nextSetasListRest = new ArrayList<>(nextSetasList); + Iterator> nextSetasListItRest = new ArrayList>(nextSetasListRest).iterator(); + while (nextSetasListItRest.hasNext()) { + Set a_next = nextSetasListItRest.next(); + if (//a.equals(a_next) || + (oup.compare(a, a_next) == -1)) { + nextSetasListRest.remove(a_next); + } + } + //Alle minimalen Elemente in nextSetasListRest bestimmen + //nur für diese wird parallele Berechnung angestossen. + nextSetasListRest = oup.minElements(nextSetasListRest); + } + else if (variance == 2) { + a = nextSetasList.remove(0); + + //Fuer alle Elemente wird parallele Berechnung angestossen. + nextSetasListRest = new ArrayList<>(nextSetasList); + } + else if (variance == 0) { + //wenn a <. theta dann ist ein maximales Element sehr wahrscheinlich + //wenn theta <. a dann ist ein minimales Element sehr wahrscheinlich + if (!oderConstraint && optOrigPair != null && optOrigPair.isPresent()) { + if (optOrigPair.get().getBasePair().getLhsType() instanceof PlaceholderType) { + a = oup.max(nextSetasList.iterator()); + } + else { + a = oup.min(nextSetasList.iterator()); + } + nextSetasList.remove(a); + } + else { + if (oderConstraint) { + a = oup.max(nextSetasList.iterator()); + nextSetasList.remove(a); + nextSetasListOderConstraints.add(((Constraint)a).getExtendConstraint()); + } + else { + a = nextSetasList.remove(0); + } + } + } + + if (oderConstraint) {//Methodconstraints werden abgespeichert für die Bytecodegenerierung von Methodenaufrufen + methodSignatureConstraint.addAll(((Constraint)a).getmethodSignatureConstraint()); + writeLog("ERSTELLUNG methodSignatureConstraint: " + methodSignatureConstraint); + //System.out.println("ERSTELLUNG methodSignatureConstraint: " +noOfThread+" "+methodSignatureConstraint); + //System.out.println("a: " +a); + //System.out.println("eq: " +eq); + //System.out.println(); + } + + i++; + Set> elems = new HashSet>(oneElems); + writeLog("a1: " + rekTiefe + " "+ "variance: "+ variance + " " + a.toString()+ "\n"); + + //Ergebnisvariable für den aktuelle Thread + Set> res = new HashSet<>(); + + //Menge der Ergebnisse der geforkten Threads + Set>> add_res = new HashSet<>(); + + + Set> aParDef = new HashSet<>(); + + /* Wenn bei (a \in theta) \in a zu Widerspruch in oneElems wird + * a verworfen und zu nächstem Element von nextSetasList gegangen + */ + if (!oderConstraint && !sameEqSet.isEmpty() && !checkNoContradiction(a, sameEqSet, result)) { + a = null; + noShortendElements++; + continue; + } + + /* Wenn parallel gearbeitet wird, wird je nach Varianz ein neuer Thread + * gestartet, der parallel weiterarbeitet. + */ + if(parallel && (variance == 1) && noOfThread <= MaxNoOfThreads) { + Set forks = new HashSet<>(); + Set newEqOrig = new HashSet<>(eq); + Set> newElemsOrig = new HashSet<>(elems); + List>> newOderConstraintsOrig = new ArrayList<>(oderConstraints); + newElemsOrig.add(a); + + /* FORK ANFANG */ + TypeUnify2Task forkOrig = new TypeUnify2Task(newElemsOrig, newEqOrig, newOderConstraintsOrig, a, fc, parallel, logFile, log, rekTiefe, urm, usedTasks, methodSignatureConstraint); + //forks.add(forkOrig); + synchronized(usedTasks) { + if (this.myIsCancelled()) { + return new HashSet<>(); + } + forkOrig.fork(); + } + /* FORK ENDE */ + + synchronized (this) { + writeLog("a in " + variance + " "+ a); + writeLog("nextSetasListRest: " + nextSetasListRest.toString()); + } + while (!nextSetasListRest.isEmpty()) { + Set nSaL = nextSetasListRest.remove(0); + synchronized (this) { nextSetasList.remove(nSaL); + writeLog("1 RM" + nSaL.toString()); + } + + if (!oderConstraint) { + //ueberpruefung ob zu a =. ty \in nSaL in sameEqSet ein Widerspruch besteht + if (!sameEqSet.isEmpty() && !checkNoContradiction(nSaL, sameEqSet, result)) { + nSaL = null; + noShortendElements++; + continue; + } + } + else { + nextSetasListOderConstraints.add(((Constraint)nSaL).getExtendConstraint()); + } + Set newEq = new HashSet<>(eq); + Set> newElems = new HashSet<>(elems); + List>> newOderConstraints = new ArrayList<>(oderConstraints); + newElems.add(nSaL); + TypeUnify2Task fork = new TypeUnify2Task(newElems, newEq, newOderConstraints, nSaL, fc, parallel, logFile, log, rekTiefe, urm, usedTasks, new HashSet<>(methodSignatureConstraint)); + forks.add(fork); + synchronized(usedTasks) { + if (this.myIsCancelled()) { + return new HashSet<>(); + } + fork.fork(); + } + } + //res = unify2(newElemsOrig, newEqOrig, newOderConstraintsOrig, fc, parallel, rekTiefe); + + /* FORK ANFANG */ + synchronized (this) { + writeLog("wait "+ forkOrig.thNo); + noOfThread--; + res = forkOrig.join(); + synchronized (usedTasks) { + if (this.myIsCancelled()) { + return new HashSet<>(); + } + } + //noOfThread++; + forkOrig.writeLog("final Orig 1"); + forkOrig.closeLogFile(); + //Set> fork_res = forkOrig.join(); + writeLog("JoinOrig " + new Integer(forkOrig.thNo).toString()); + //noOfThread--; an das Ende von compute verschoben + //add_res.add(fork_res); + }; + /* FORK ENDE */ + + forks.forEach(x -> writeLog("wait: " + x.thNo)); + for(TypeUnify2Task fork : forks) { + synchronized (this) { + noOfThread--; + Set> fork_res = fork.join(); + synchronized (usedTasks) { + if (this.myIsCancelled()) { + return new HashSet<>(); + } + } + //noOfThread++; + writeLog("Join " + new Integer(fork.thNo).toString()); + //noOfThread--; an das Ende von compute verschoben + writeLog("fork_res: " + fork_res.toString()); + writeLog(new Boolean((isUndefinedPairSetSet(fork_res))).toString()); + add_res.add(fork_res); + if (!isUndefinedPairSetSet(fork_res)) { + aParDef.add(fork.getNextSetElement()); + } + fork.writeLog("final 1"); + fork.closeLogFile(); + }; + } + //noOfThread++; + } else { + if(parallel && (variance == -1) && noOfThread <= MaxNoOfThreads) { + Set forks = new HashSet<>(); + Set newEqOrig = new HashSet<>(eq); + Set> newElemsOrig = new HashSet<>(elems); + List>> newOderConstraintsOrig = new ArrayList<>(oderConstraints); + newElemsOrig.add(a); + + /* FORK ANFANG */ + TypeUnify2Task forkOrig = new TypeUnify2Task(newElemsOrig, newEqOrig, newOderConstraintsOrig, a, fc, parallel, logFile, log, rekTiefe, urm, usedTasks, new HashSet<>(methodSignatureConstraint)); + //forks.add(forkOrig); + synchronized(usedTasks) { + if (this.myIsCancelled()) { + return new HashSet<>(); + } + forkOrig.fork(); + } + /* FORK ENDE */ + + synchronized (this) { + writeLog("a in " + variance + " "+ a); + writeLog("nextSetasListRest: " + nextSetasListRest.toString()); + } + while (!nextSetasListRest.isEmpty()) { + Set nSaL = nextSetasListRest.remove(0); + synchronized (this) { nextSetasList.remove(nSaL); + writeLog("-1 RM" + nSaL.toString()); + } + + if (!oderConstraint) { + //ueberpruefung ob zu a =. ty \in nSaL in sameEqSet ein Widerspruch besteht + if (!sameEqSet.isEmpty() && !checkNoContradiction(nSaL, sameEqSet, result)) { + nSaL = null; + noShortendElements++; + continue; + } + } + else { + nextSetasListOderConstraints.add(((Constraint)nSaL).getExtendConstraint()); + } + Set newEq = new HashSet<>(eq); + Set> newElems = new HashSet<>(elems); + List>> newOderConstraints = new ArrayList<>(oderConstraints); + newElems.add(nSaL); + TypeUnify2Task fork = new TypeUnify2Task(newElems, newEq, newOderConstraints, nSaL, fc, parallel, logFile, log, rekTiefe, urm, usedTasks, new HashSet<>(methodSignatureConstraint)); + forks.add(fork); + synchronized(usedTasks) { + if (this.myIsCancelled()) { + return new HashSet<>(); + } + fork.fork(); + } + } + //res = unify2(newElemsOrig, newEqOrig, newOderConstraintsOrig, fc, parallel, rekTiefe); + + /* FORK ANFANG */ + synchronized (this) { + writeLog("wait "+ forkOrig.thNo); + noOfThread--; + res = forkOrig.join(); + synchronized (usedTasks) { + if (this.myIsCancelled()) { + return new HashSet<>(); + } + } + //noOfThread++; + forkOrig.writeLog("final Orig -1"); + forkOrig.closeLogFile(); + //Set> fork_res = forkOrig.join(); + writeLog("JoinOrig " + new Integer(forkOrig.thNo).toString()); + //noOfThread--; an das Ende von compute verschoben + //add_res.add(fork_res); + }; + /* FORK ENDE */ + + forks.forEach(x -> writeLog("wait: " + x.thNo)); + for(TypeUnify2Task fork : forks) { + synchronized (this) { + noOfThread--; + Set> fork_res = fork.join(); + synchronized (usedTasks) { + if (this.myIsCancelled()) { + return new HashSet<>(); + } + } + //noOfThread++; + writeLog("Join " + new Integer(fork.thNo).toString()); + //noOfThread--; an das Ende von compute verschoben + writeLog("fork_res: " + fork_res.toString()); + writeLog(new Boolean((isUndefinedPairSetSet(fork_res))).toString()); + add_res.add(fork_res); + if (!isUndefinedPairSetSet(fork_res)) { + aParDef.add(fork.getNextSetElement()); + } + fork.writeLog("final -1"); + fork.closeLogFile(); + }; + } + //noOfThread++; + } else { + if(parallel && (variance == 2) && noOfThread <= MaxNoOfThreads) { + writeLog("var2einstieg"); + Set forks = new HashSet<>(); + Set newEqOrig = new HashSet<>(eq); + Set> newElemsOrig = new HashSet<>(elems); + List>> newOderConstraintsOrig = new ArrayList<>(oderConstraints); + newElemsOrig.add(a); + + /* FORK ANFANG */ + TypeUnify2Task forkOrig = new TypeUnify2Task(newElemsOrig, newEqOrig, newOderConstraintsOrig, a, fc, parallel, logFile, log, rekTiefe, urm, usedTasks, new HashSet<>(methodSignatureConstraint)); + //forks.add(forkOrig); + synchronized(usedTasks) { + if (this.myIsCancelled()) { + return new HashSet<>(); + } + forkOrig.fork(); + } + /* FORK ENDE */ + + synchronized (this) { + writeLog("a in " + variance + " "+ a); + writeLog("nextSetasListRest: " + nextSetasListRest.toString()); + } + + //Fuer parallele Berechnung der Oder-Contraints wird methodSignature kopiert + //und jeweils die methodSignature von a bzw. nSaL wieder gelöscht, wenn es keine Lösung ist. + Set methodSignatureConstraintForParallel = new HashSet<>(methodSignatureConstraint); + Set nSaL = a; + + while (!nextSetasListRest.isEmpty()) { + methodSignatureConstraintForParallel.removeAll(((Constraint)nSaL).getmethodSignatureConstraint()); + nSaL = nextSetasListRest.remove(0); + nextSetasList.remove(nSaL); //PL einkommentiert 20-02-03 + methodSignatureConstraintForParallel.addAll(((Constraint)nSaL).getmethodSignatureConstraint()); + Set newEq = new HashSet<>(eq); + Set> newElems = new HashSet<>(elems); + List>> newOderConstraints = new ArrayList<>(oderConstraints); + newElems.add(nSaL); + TypeUnify2Task fork = new TypeUnify2Task(newElems, newEq, newOderConstraints, nSaL, fc, parallel, logFile, log, rekTiefe, urm, usedTasks, new HashSet<>(methodSignatureConstraintForParallel)); + forks.add(fork); + synchronized(usedTasks) { + if (this.myIsCancelled()) { + return new HashSet<>(); + } + fork.fork(); + } + } + //res = unify2(newElemsOrig, newEqOrig, newOderConstraintsOrig, fc, parallel, rekTiefe); + + /* FORK ANFANG */ + synchronized (this) { + writeLog("wait "+ forkOrig.thNo); + noOfThread--; + res = forkOrig.join(); + synchronized (usedTasks) { + if (this.myIsCancelled()) { + return new HashSet<>(); + } + } + //noOfThread++; + forkOrig.writeLog("final Orig 2"); + forkOrig.closeLogFile(); + //Set> fork_res = forkOrig.join(); + writeLog("JoinOrig " + new Integer(forkOrig.thNo).toString()); + //noOfThread--; an das Ende von compute verschoben + //add_res.add(fork_res); //vermutlich falsch + }; + /* FORK ENDE */ + forks.forEach(x -> writeLog("wait: " + x.thNo)); + for(TypeUnify2Task fork : forks) { + synchronized (this) { + noOfThread--; + Set> fork_res = fork.join(); + synchronized (usedTasks) { + if (this.myIsCancelled()) { + return new HashSet<>(); + } + } + //noOfThread++; + writeLog("Join " + new Integer(fork.thNo).toString()); + //noOfThread--; an das Ende von compute verschoben + add_res.add(fork_res); + fork.writeLog("final 2"); + fork.closeLogFile(); + }; + } + //noOfThread++; + } else {//parallel = false oder MaxNoOfThreads ist erreicht, sequentiell weiterarbeiten + elems.add(a); //PL 2019-01-16 muss das wirklich hin steht schon in Zeile 859 ja braucht man siehe Zeile 859 + res = unify2(elems, eq, oderConstraints, fc, parallel, rekTiefe, new HashSet<>(methodSignatureConstraint)); + }}} + + //Ab hier alle parallele Berechnungen wieder zusammengeführt. + if (oderConstraint) {//Wenn weiteres Element nextSetasList genommen wird, muss die vorherige methodsignatur geloescht werden + methodSignatureConstraint.removeAll(((Constraint)a).getmethodSignatureConstraint()); + //System.out.println("REMOVE: " +methodSignatureConstraint); + } + if (!isUndefinedPairSetSet(res) && isUndefinedPairSetSet(result)) { + //wenn korrektes Ergebnis gefunden alle Fehlerfaelle loeschen + result = res; + } + else { + if ((isUndefinedPairSetSet(res) && isUndefinedPairSetSet(result)) + || (!isUndefinedPairSetSet(res) && !isUndefinedPairSetSet(result)) + || result.isEmpty()) { + + if ((!result.isEmpty() && !res.isEmpty() && !isUndefinedPairSetSet(res) && !isUndefinedPairSetSet(result)) //korrekte Loesungen aus und-constraints + && (a.stream().map(x-> (x.getBasePair() != null)).reduce(true, (x, y) -> (x && y)))) //bei oder-Constraints nicht ausfuehren + { + //TODO: PL 2019-01-15: Bug 129: Im Moment wird nur das Maximum und das Minimum des aktuellen Elements betrachtet. + //Die zu vereinigenden Mengen können mehrere Elemente enthalten. Das ist bisher nicht berücksichtigt + + //Alle Variablen bestimmen die nicht hinzugefügt wurden in a + //PL 2018-12-28: Hier gab es eine ClassCastException, war nicht reproduzierbar + System.out.println(""); + List vars_a = + a.stream().filter(x -> ((x.getLhsType().getName().equals(x.getBasePair().getLhsType().getName()) + && (x.getLhsType() instanceof PlaceholderType) && (x.getBasePair().getLhsType() instanceof PlaceholderType)) + || ((x.getLhsType().getName().equals(x.getBasePair().getRhsType().getName())) + && (x.getLhsType() instanceof PlaceholderType) && (x.getBasePair().getRhsType() instanceof PlaceholderType))) + ) + .map(y -> (PlaceholderType)y.getLhsType()).collect(Collectors.toCollection(ArrayList::new)); + Set fstElemRes = res.iterator().next(); + Set compRes = fstElemRes.stream().filter(x -> vars_a.contains(((PlaceholderType)x.getLhsType()))).collect(Collectors.toCollection(HashSet::new)); + + //Alle Variablen bestimmen die nicht hinzugefügt wurden in a_last + //System.out.println(a_last); + + try {//PL eingefuegt 2019-03-06 da bei map mmer wieder Nullpointer kamen + a_last.forEach(x -> {writeLog("a_last_elem:" + x + " basepair: " + x.getBasePair());});//PL 2019-05-13 ins try hinzugefuegt Nullpointer-Exception ist in der Zeile aufgetaucht. + List varsLast_a = + a_last.stream().filter(x -> ((x.getLhsType().getName().equals(x.getBasePair().getLhsType().getName()) + && (x.getLhsType() instanceof PlaceholderType) && (x.getBasePair().getLhsType() instanceof PlaceholderType)) + || ((x.getLhsType().getName().equals(x.getBasePair().getRhsType().getName()))) + && (x.getLhsType() instanceof PlaceholderType) && (x.getBasePair().getRhsType() instanceof PlaceholderType))) + .map(y -> (PlaceholderType)y.getLhsType()).collect(Collectors.toCollection(ArrayList::new)); + //[(java.util.Vector <. gen_aq, , 1), (CEK =. ? extends gen_aq, 1)] KANN VORKOMMEN + //erstes Element genügt, da vars immer auf die gleichen Elemente zugeordnet werden muessen + Set fstElemResult = result.iterator().next(); + Set compResult = fstElemResult.stream().filter(x -> varsLast_a.contains(((PlaceholderType)x.getLhsType()))).collect(Collectors.toCollection(HashSet::new));; + if (variance == 1) { + writeLog("a_last:" + a_last + " a: " + a); + writeLog("varsLast_a:" + varsLast_a + " vars_a: " + vars_a); + writeLog("compResult:" + compResult + " compRes: " + compRes); + int resOfCompare = oup.compare(compResult, compRes); + if (resOfCompare == -1) { + writeLog("Geloescht result: " + result); + result = res; + } else { + if (resOfCompare == 0) { + result.addAll(res); + } //else { + if (resOfCompare == 1) { + writeLog("Geloescht res: " + res); + //result = result; + }}} + else { if (variance == -1) { + writeLog("a_last:" + a_last + " a: " + a); + writeLog("varsLast_a:" + varsLast_a + " vars_a: " + vars_a); + writeLog("compResult:" + compResult + " compRes: " + compRes); + int resOfCompare = oup.compare(compResult, compRes); + if (resOfCompare == 1) { + writeLog("Geloescht result: " + result); + result = res; + } else { + if (resOfCompare == 0) { + result.addAll(res); + } else { + if (resOfCompare == -1) { + writeLog("Geloescht res: " + res); + //result = result; + }}}} + else { if (variance == 0) { + writeLog("RES var=1 ADD:" + result.toString() + " " + res.toString()); + result.addAll(res); + }}} + } + catch (NullPointerException e) { + writeLog("NullPointerException: " + a_last.toString()); + } + } + else { + //alle Fehlerfaelle und alle korrekten Ergebnis jeweils adden + writeLog("RES Fst: result: " + result.toString() + " res: " + res.toString()); + result.addAll(res); + } + } + //else { + //wenn Korrekte Ergebnisse da und Feherfälle dazukommen Fehlerfälle ignorieren + // if (isUndefinedPairSetSet(res) && !isUndefinedPairSetSet(result)) { + // result = result; + // } + //} + } + + if (parallel) { + for (Set> par_res : add_res) { + if (!isUndefinedPairSetSet(par_res) && isUndefinedPairSetSet(result)) { + //wenn korrektes Ergebnis gefunden alle Fehlerfaelle loeschen + result = par_res; + if (!par_res.isEmpty() && par_res.iterator().next() instanceof WildcardType) { + System.out.println(""); + } + } + else { + if ((isUndefinedPairSetSet(par_res) && isUndefinedPairSetSet(result)) + || (!isUndefinedPairSetSet(par_res) && !isUndefinedPairSetSet(result)) + || result.isEmpty()) { + //alle Fehlerfaelle und alle korrekten Ergebnis jeweils adden + writeLog("RES var1 ADD:" + result.toString() + " " + par_res.toString()); + result.addAll(par_res); + } + } + } + //break; + } + + /* auskommentiert um alle Max und min Betrachtung auszuschalten ANFANG */ + if (!result.isEmpty() && (!isUndefinedPairSetSet(res) || !aParDef.isEmpty())) { + if (nextSetasList.iterator().hasNext() && nextSetasList.iterator().next().stream().filter(x -> x.getLhsType().getName().equals("B")).findFirst().isPresent() && nextSetasList.size()>1) + System.out.print(""); + Iterator> nextSetasListIt = new ArrayList>(nextSetasList).iterator(); + if (variance == 1) { + System.out.println(""); + writeLog("a: " + rekTiefe + " variance: " + variance + a.toString()); + writeLog("aParDef: " + aParDef.toString()); + aParDef.add(a); + Iterator> aParDefIt = aParDef.iterator(); + if (oderConstraint) { + nextSetasList.removeAll(nextSetasListOderConstraints); + nextSetasListOderConstraints = new ArrayList<>(); + writeLog("Removed: " + nextSetasListOderConstraints); + while(aParDefIt.hasNext()) { + Set a_new = aParDefIt.next(); + List> smallerSetasList = oup.smallerThan(a_new, nextSetasList); + writeLog("smallerSetasList: " + smallerSetasList); + List> notInherited = smallerSetasList.stream() + .filter(x -> !((Constraint)x).isInherited() && !((Constraint)x).isImplemented()) + .collect(Collectors.toCollection(ArrayList::new)); + writeLog("notInherited: " + notInherited+"\n"); + List> notErased = new ArrayList<>(); + notInherited.stream().forEach(x -> { notErased.addAll(oup.smallerEqThan(x, smallerSetasList)); }); + List> erased = new ArrayList<>(smallerSetasList); + writeLog("notErased: " + notErased+"\n"); + erased.removeAll(notErased); + nextSetasList.removeAll(erased); + + writeLog("Removed: " + erased); + + writeLog("Not Removed: " + nextSetasList); + + } + } + else { + while(aParDefIt.hasNext()) { + //nextSetasListIt = nextSetasList.iterator(); Sollte eingefuegt werden PL 2020-04-28 + Set a_new = aParDefIt.next(); + List> erased = oup.smallerEqThan(a_new, nextSetasList); + nextSetasList.removeAll(erased); + + writeLog("Removed: " + erased); + + writeLog("Not Removed: " + nextSetasList); + } + } + } + else { if (variance == -1) { + System.out.println(""); + writeLog("a: " + rekTiefe + " variance: " + variance + a.toString()); + writeLog("aParDef: " + aParDef.toString()); + aParDef.add(a); + Iterator> aParDefIt = aParDef.iterator(); + if (oderConstraint) { + nextSetasList.removeAll(nextSetasListOderConstraints); + writeLog("Removed: " + nextSetasListOderConstraints); + nextSetasListOderConstraints = new ArrayList<>(); + while(aParDefIt.hasNext()) { + Set a_new = aParDefIt.next(); + List> greaterSetasList = oup.greaterThan(a_new, nextSetasList); + + //a_new muss hingefuegt werden, wenn es nicht vererbt ist, dann wird es spaeter wieder geloescht + if (!((Constraint)a_new).isInherited()) { + greaterSetasList.add(a_new); + } + List> notInherited = greaterSetasList.stream() + .filter(x -> !((Constraint)x).isInherited()) + .collect(Collectors.toCollection(ArrayList::new)); + List> notErased = new ArrayList<>(); + + //Wenn x nicht vererbt ist, beginnt beim naechstgroesseren Element die naechste Ueberladung + notInherited.stream().forEach(x -> { notErased.addAll(oup.greaterEqThan(x, greaterSetasList)); }); + + //das kleineste Element ist das Element von dem a_new geerbt hat + //muss deshalb geloescht werden + Iterator> notErasedIt = notErased.iterator(); + if (notErasedIt.hasNext()) { + Set min = oup.min(notErasedIt); + notErased.remove(min); + notErased.remove(((Constraint)min).getExtendConstraint()); + } + + List> erased = new ArrayList<>(greaterSetasList); + erased.removeAll(notErased); + nextSetasList.removeAll(erased); + + writeLog("Removed: " + erased); + + writeLog("Not Removed: " + nextSetasList); + + } + } + else { + while(aParDefIt.hasNext()) { + //nextSetasListIt = nextSetasList.iterator(); Sollte eingefuegt werden PL 2020-04-28 + Set a_new = aParDefIt.next(); + List> erased = oup.greaterEqThan(a_new, nextSetasList); + + nextSetasList.removeAll(erased); + + writeLog("Removed: " + erased); + + writeLog("Not Removed: " + nextSetasList); + } + } + } + else { if (variance == 0) { + writeLog("a: " + rekTiefe + " variance: " + variance + a.toString()); + if (!oderConstraint) { + break; + } + else { + nextSetasList.removeAll(nextSetasListOderConstraints); + nextSetasListOderConstraints = new ArrayList<>(); + writeLog("Removed: " + nextSetasListOderConstraints); + List> smallerSetasList = oup.smallerThan(a, nextSetasList); + List> notInherited = smallerSetasList.stream() + .filter(x -> !((Constraint)x).isInherited()) + .collect(Collectors.toCollection(ArrayList::new)); + List> notErased = new ArrayList<>(); + notInherited.stream().forEach(x -> { notErased.addAll(oup.smallerEqThan(x, smallerSetasList)); }); + List> erased = new ArrayList<>(smallerSetasList); + erased.removeAll(notErased); + nextSetasList.removeAll(erased); + + writeLog("Removed: " + erased); + + writeLog("Not Removed: " + nextSetasList); + + } + + } + else { if (variance == 2) { + }}} + writeLog("a: " + rekTiefe + " variance: " + variance + a.toString()); + } + } + /* auskommentiert um alle Max und min Betrachtung auszuschalten ENDE */ + + if (isUndefinedPairSetSet(res) && aParDef.isEmpty()) { + int nofstred= 0; + Set abhSubst = res.stream() + .map(b -> + b.stream() + .map(x -> x.getAllSubstitutions()) + .reduce((y,z) -> { y.addAll(z); return y;}).get()) + .reduce((y,z) -> { y.addAll(z); return y;}).get(); + abhSubst.addAll( + res.stream() + .map(b -> + b.stream() + .map(x -> x.getThisAndAllBases()) //getAllBases durch getThisAndAllBases ersetzt, weil auch im UnifyPair selbst schon ein Fehler liegen kann. + .reduce((y,z) -> { y.addAll(z); return y;}).get()) + .reduce((y,z) -> { y.addAll(z); return y;}).get() + ); + Set b = a;//effective final a + Set durchschnitt = abhSubst.stream() + .filter(x -> b.contains(x)) + //.filter(y -> abhSubst.contains(y)) + .collect(Collectors.toCollection(HashSet::new)); + //Set vars = durchschnitt.stream().map(x -> (PlaceholderType)x.getLhsType()).collect(Collectors.toCollection(HashSet::new)); + int len = nextSetasList.size(); + Set undefRes = res.stream().reduce((y,z) -> { y.addAll(z); return y;}).get(); //flatten aller undef results + Set, UnifyPair>> reducedUndefResSubstGroundedBasePair = undefRes.stream() + .map(x -> { Set su = x.getAllSubstitutions(); //alle benutzten Substitutionen + su.add(x.getGroundBasePair()); // urspruengliches Paar + su.removeAll(durchschnitt); //alle aktuell genänderten Paare entfernen + return new Pair<>(su, x.getGroundBasePair());}) + .collect(Collectors.toCollection(HashSet::new)); + if (res.size() > 1) { + System.out.println(); + } + writeLog("nextSetasList vor filter-Aufruf: " + nextSetasList); + if (!oderConstraint) {//PL 2023-02-08 eingefuegt: Bei oderconstraints sind Subststitutionen nicht als Substitutionen in idesem Sinne zu sehen + nextSetasList = nextSetasList.stream().filter(x -> { + //Boolean ret = false; + //for (PlaceholderType var : vars) { + // ret = ret || x.stream().map(b -> b.getLhsType().equals(var)).reduce((c,d) -> c || d).get(); + //} + return (!x.containsAll(durchschnitt)); + })//.filter(y -> couldBecorrect(reducedUndefResSubstGroundedBasePair, y)) //fuer testzwecke auskommentiert um nofstred zu bestimmen PL 2018-10-10 + .collect(Collectors.toCollection(ArrayList::new)); + } + writeLog("nextSetasList nach filter-Aufruf: " + nextSetasList); + nofstred = nextSetasList.size(); + //NOCH NICHT korrekt PL 2018-10-12 + //nextSetasList = nextSetasList.stream().filter(y -> couldBecorrect(reducedUndefResSubstGroundedBasePair, y)) + // .collect(Collectors.toCollection(ArrayList::new)); + writeLog("res (undef): " + res.toString()); + writeLog("abhSubst: " + abhSubst.toString()); + writeLog("a2: " + rekTiefe + " " + a.toString()); + writeLog("Durchschnitt: " + durchschnitt.toString()); + writeLog("nextSet: " + nextSet.toString()); + writeLog("nextSetasList: " + nextSetasList.toString()); + writeLog("Number first erased Elements (undef): " + (len - nofstred)); + writeLog("Number second erased Elements (undef): " + (nofstred- nextSetasList.size())); + writeLog("Number erased Elements (undef): " + (len - nextSetasList.size())); + noAllErasedElements = noAllErasedElements + (len - nextSetasList.size()); + writeLog("Number of all erased Elements (undef): " + noAllErasedElements.toString()); + noBacktracking++; + writeLog("Number of Backtracking: " + noBacktracking); + System.out.println(""); + } + //if (nextSetasList.size() == 0 && isUndefinedPairSetSet(result) && nextSet.size() > 1) { + // return result; + //} + //else { + // result.removeIf(y -> isUndefinedPairSet(y)); + //} + //else result.stream().filter(y -> !isUndefinedPairSet(y)); + writeLog("res: " + res.toString()); + } + //2020-02-02: if (variance ==2) Hier Aufruf von filterOverriding einfuegen + writeLog("Return computeCR: " + result.toString()); + return result; + } + + /** + * checks if there is for (a = ty) \in a in sameEqSet a constradiction + * @param a Set of actual element of constraints with a =. ty \in a + * @param sameEqSet Set of constraints where a <. ty' and ty' <. a + * @param result set of results which contains correct solution s and the + * the error constraints. Error constraints are added + * @result contradiction of (a = ty) in sameEqSet + */ + protected Boolean checkNoContradiction(Set a, Set sameEqSet, Set> result) { + + //optAPair enthaelt ggf. das Paar a = ty' \in a + //unterscheidet sich von optOrigPair, da dort a = ty + Optional optAPair = + a.stream().filter(x -> (x.getPairOp().equals(PairOperator.EQUALSDOT))) + .filter(x -> //Sicherstellen, dass bei a = ty a auch wirklich die gesuchte Typvariable ist + x.getLhsType().equals(x.getBasePair().getLhsType()) || + x.getLhsType().equals(x.getBasePair().getRhsType())) + .findFirst(); + + if (optAPair.isPresent()) {//basepair ist entweder a <. Ty oder ty <. a + UnifyPair aPair = optAPair.get(); + //writeLog("optOrigPair: " + optOrigPair + " " + "aPair: " + aPair+ " " + "aPair.basePair(): " + aPair.getBasePair()); + + writeLog("checkA: " + aPair + "sameEqSet: " + sameEqSet); + for (UnifyPair sameEq : sameEqSet) { + if (sameEq.getLhsType() instanceof PlaceholderType) { + Set localEq = new HashSet<>(); + Set unitedSubst = new HashSet<>(aPair.getAllSubstitutions()); + unitedSubst.addAll(aPair.getAllBases()); + unitedSubst.addAll(sameEq.getAllSubstitutions()); + unitedSubst.addAll(sameEq.getAllBases()); + localEq.add(new UnifyPair(aPair.getRhsType(), sameEq.getRhsType(), sameEq.getPairOp(), unitedSubst, null)); + finalresult = false; + Set> localRes = unify(localEq, new ArrayList<>(), fc, false, 0, new HashSet<>()); + finalresult = true; + if (isUndefinedPairSetSet(localRes)) { + if (result.isEmpty() || isUndefinedPairSetSet(result)) { + result.addAll(localRes); + } + writeLog("FALSE: " + aPair + "sameEqSet: " + sameEqSet); + return false; + } + } + else { + Set localEq = new HashSet<>(); + Set unitedSubst = new HashSet<>(aPair.getAllSubstitutions()); + unitedSubst.addAll(aPair.getAllBases()); + unitedSubst.addAll(sameEq.getAllSubstitutions()); + unitedSubst.addAll(sameEq.getAllBases()); + localEq.add(new UnifyPair(sameEq.getLhsType(), aPair.getRhsType(), sameEq.getPairOp(), unitedSubst, null)); + finalresult = false; + Set> localRes = unify(localEq, new ArrayList<>(), fc, false, 0, new HashSet<>()); + finalresult = true; + if (isUndefinedPairSetSet(localRes)) { + if (result.isEmpty() || isUndefinedPairSetSet(result)) { + result.addAll(localRes); + } + writeLog("FALSE: " + aPair + "sameEqSet: " + sameEqSet); + return false; + } + } + } + writeLog("TRUE: " + aPair + "sameEqSet: " + sameEqSet); + return true; + } + return true; + } + + + protected boolean couldBecorrect(Set, UnifyPair>> reducedUndefResSubstGroundedBasePair, Set nextElem) { + return reducedUndefResSubstGroundedBasePair.stream() + .map(pair -> { + Set reducedAbhSubst = pair.getKey(); + reducedAbhSubst.addAll(nextElem); + Optional> substRes = rules.subst(reducedAbhSubst); + if (!substRes.isPresent()) { + return true; + } + //PL 2018-10-12 + //Evtl. zurest applyTypeUnification aufrufen + //evtl auch unify aufrufen + else { + UnifyPair checkPair = substRes.get().stream() + .filter(x -> x.getGroundBasePair().equals(pair.getValue().get())).findFirst().get(); + if (((checkPair.getLhsType() instanceof PlaceholderType) || (checkPair.getRhsType() instanceof PlaceholderType)) + && (checkPair.getPairOp() == PairOperator.SMALLERDOT || checkPair.getPairOp() == PairOperator.SMALLERDOTWC)) + { + /* + Set setCheckPair = new HashSet<>(); + setCheckPair.add(checkPair); + Set setReturnCheckPair = applyTypeUnificationRules(setCheckPair, fc); + UnifyPair checkPair1 = setReturnCheckPair.iterator().next(); + Set up = new HashSet<>(); + up.add(checkPair1); + Set undef = new HashSet<>(); + */ + PairOperator pairOp = checkPair.getPairOp(); + UnifyType lhsType = checkPair.getLhsType(); + UnifyType rhsType = checkPair.getRhsType(); + ///* Case 1: (a <. Theta') + if ((((pairOp == PairOperator.SMALLERDOT) || (pairOp == PairOperator.SMALLERNEQDOT)) && lhsType instanceof PlaceholderType) + // Case 2: (a <.? ? ext Theta') + || (pairOp == PairOperator.SMALLERDOTWC && lhsType instanceof PlaceholderType && rhsType instanceof ExtendsType) + // Case 3: (a <.? ? sup Theta') + || (pairOp == PairOperator.SMALLERDOTWC && lhsType instanceof PlaceholderType && rhsType instanceof SuperType) + + // Case 4 was replaced by an inference rule + // Case 4: (a <.? Theta') + || (pairOp == PairOperator.SMALLERDOTWC && lhsType instanceof PlaceholderType) + // Case 5: (Theta <. a) + || ((pairOp == PairOperator.SMALLERDOT) && rhsType instanceof PlaceholderType) + // Case 6 was replaced by an inference rule. + // Case 6: (? ext Theta <.? a) + || (pairOp == PairOperator.SMALLERDOTWC && lhsType instanceof ExtendsType && rhsType instanceof PlaceholderType) + // Case 7 was replaced by an inference rule + // Case 7: (? sup Theta <.? a) + || (pairOp == PairOperator.SMALLERDOTWC && lhsType instanceof SuperType && rhsType instanceof PlaceholderType) + // Case 8: (Theta <.? a) + || (pairOp == PairOperator.SMALLERDOTWC && rhsType instanceof PlaceholderType) + //reduceWildcardLow + || (pairOp == PairOperator.SMALLERDOTWC && (lhsType instanceof ExtendsType) && (rhsType instanceof ExtendsType)) + //reduceWildcardLowRight + || ((pairOp == PairOperator.SMALLERDOTWC) && (lhsType instanceof ReferenceType) && (rhsType instanceof ExtendsType)) + //reduceWildcardUp + || ((pairOp == PairOperator.SMALLERDOTWC) && (lhsType instanceof SuperType) && (rhsType instanceof SuperType)) + //reduceWildcardUpRight + || ((pairOp == PairOperator.SMALLERDOTWC) && (lhsType instanceof ReferenceType) && (rhsType instanceof SuperType)) + //reduceFunN + || (((pairOp == PairOperator.SMALLERDOT) || (pairOp == PairOperator.EQUALSDOT)) + //PL 2017-10-03 hinzugefuegt + //da Regel auch fuer EQUALSDOT anwendbar + && (lhsType instanceof FunNType) && (rhsType instanceof FunNType)) + //greaterFunN + || ((pairOp== PairOperator.SMALLERDOT) && (lhsType instanceof FunNType) && (rhsType instanceof PlaceholderType)) + //smallerFunN + || ((pairOp == PairOperator.SMALLERDOT) && (lhsType instanceof PlaceholderType && rhsType instanceof FunNType)) + //reduceTph + || ((pairOp == PairOperator.SMALLERDOTWC) && (lhsType instanceof PlaceholderType && rhsType instanceof ReferenceType)) + //reduceTphExt + || ((pairOp == PairOperator.SMALLERDOTWC) && (lhsType instanceof ExtendsType) && rhsType instanceof PlaceholderType) + //reduceTphSup + || ((pairOp == PairOperator.SMALLERDOTWC) && (lhsType instanceof SuperType) && rhsType instanceof PlaceholderType)) { + return true; + } + // Case unknown: If a pair fits no other case, then the type unification has failed. + // Through application of the rules, every pair should have one of the above forms. + // Pairs that do not have one of the aboves form are contradictory. + else { + writeLog("Second erase:" +checkPair.toString()); + return false; + } + //*/ + } else { + //Pair type <. ? extends ? extends type betrachten TODO PL 2018-10-09 + }} + return true;}).reduce((xx, yy) -> xx || yy).get(); + } + + protected boolean isUndefinedPairSet(Set s) { + if (s.size() >= 1 ) { + Boolean ret = s.stream().map(x -> x.isUndefinedPair()).reduce(true, (x,y)-> (x && y)); + return ret; + } + else { + return false; + } + } + + protected boolean isUndefinedPairSetSet(Set> s) { + if (s.size() >= 1) { + Boolean ret = s.stream(). map(x -> isUndefinedPairSet(x)).reduce(true, (x,y)-> (x && y)); + return ret; + } + return false; + + } + /** + * Checks whether a set of pairs is in solved form. + * @param eqPrimePrime The set of pair + * @return True if in solved form, false otherwise. + */ + protected boolean isSolvedForm(Set eqPrimePrime) { + for(UnifyPair pair : eqPrimePrime) { + UnifyType lhsType = pair.getLhsType(); + UnifyType rhsType = pair.getRhsType(); + + if(!(lhsType instanceof PlaceholderType)) + return false; + + // If operator is not equals, both sides must be placeholders + if(pair.getPairOp() != PairOperator.EQUALSDOT && !(rhsType instanceof PlaceholderType)) + return false; + } + return true; + } + + /** + * Repeatedly applies type unification rules to a set of equations. + * This is step one of the unification algorithm. + * @return The set of pairs that results from repeated application of the inference rules. + */ + public Set applyTypeUnificationRules(Set eq, IFiniteClosure fc) { + + /* + * Rule Application Strategy: + * + * 1. Swap all pairs and erase all erasable pairs + * 2. Apply all possible rules to a single pair, then move it to the result set. + * Iterating over pairs first, then iterating over rules prevents the application + * of rules to a "finished" pair over and over. + * 2.1 Apply all rules repeatedly except for erase rules. If + * the application of a rule creates new pairs, check immediately + * against the erase rules. + */ + + + LinkedHashSet targetSet = new LinkedHashSet(); + LinkedList eqQueue = new LinkedList<>(); + + /* + * Swap all pairs and erase all erasable pairs + */ + eq.forEach(x -> swapAddOrErase(x, fc, eqQueue)); + + /* + * Apply rules until the queue is empty + */ + while(!eqQueue.isEmpty()) { + UnifyPair pair = eqQueue.pollFirst(); + + // ReduceUp, ReduceLow, ReduceUpLow + Optional opt = rules.reduceUpLow(pair); + opt = opt.isPresent() ? opt : rules.reduceLow(pair); + opt = opt.isPresent() ? opt : rules.reduceUp(pair); + opt = opt.isPresent() ? opt : rules.reduceWildcardLow(pair); + opt = opt.isPresent() ? opt : rules.reduceWildcardLowRight(pair); + opt = opt.isPresent() ? opt : rules.reduceWildcardUp(pair); + opt = opt.isPresent() ? opt : rules.reduceWildcardUpRight(pair); + //PL 2018-03-06 auskommentiert muesste falsch sein vgl. JAVA_BSP/Wildcard6.java + //opt = opt.isPresent() ? opt : rules.reduceWildcardLowUp(pair); + //opt = opt.isPresent() ? opt : rules.reduceWildcardUpLow(pair); + //opt = opt.isPresent() ? opt : rules.reduceWildcardLeft(pair); + + // Reduce TPH + opt = opt.isPresent() ? opt : rules.reduceTph(pair); + + // One of the rules has been applied + if(opt.isPresent()) { + swapAddOrErase(opt.get(), fc, eqQueue); + continue; + } + + // Reduce1, Reduce2, ReduceExt, ReduceSup, ReduceEq + //try { + // logFile.write("PAIR1 " + pair + "\n"); + // logFile.flush(); + //} + //catch (IOException e) { } + + Optional> optSet = rules.reduce1(pair, fc); + optSet = optSet.isPresent() ? optSet : rules.reduce2(pair); + optSet = optSet.isPresent() ? optSet : rules.reduceExt(pair, fc); + optSet = optSet.isPresent() ? optSet : rules.reduceSup(pair, fc); + optSet = optSet.isPresent() ? optSet : rules.reduceEq(pair); + + // ReduceTphExt, ReduceTphSup + optSet = optSet.isPresent() ? optSet : rules.reduceTphExt(pair); + optSet = optSet.isPresent() ? optSet : rules.reduceTphSup(pair); + + + // FunN Rules + optSet = optSet.isPresent() ? optSet : rules.reduceFunN(pair); + optSet = optSet.isPresent() ? optSet : rules.greaterFunN(pair, fc); + optSet = optSet.isPresent() ? optSet : rules.smallerFunN(pair); + + // One of the rules has been applied + if(optSet.isPresent()) { + optSet.get().forEach(x -> swapAddOrErase(x, fc, eqQueue)); + continue; + } + + // Adapt, AdaptExt, AdaptSup + //try { + // logFile.write("PAIR2 " + pair + "\n"); + // logFile.flush(); + //} + //catch (IOException e) { } + opt = rules.adapt(pair, fc); + opt = opt.isPresent() ? opt : rules.adaptExt(pair, fc); + opt = opt.isPresent() ? opt : rules.adaptSup(pair, fc); + + // One of the rules has been applied + if(opt.isPresent()) { + swapAddOrErase(opt.get(), fc, eqQueue); + continue; + } + + // None of the rules has been applied + targetSet.add(pair); + } + + return targetSet; + } + + /** + * Applies the rule swap to a pair if possible. Then adds the pair to the set if no erase rule applies. + * If an erase rule applies, the pair is not added (erased). + * @param pair The pair to swap and add or erase. + * @param collection The collection to which the pairs are added. + */ + protected void swapAddOrErase(UnifyPair pair, IFiniteClosure fc, Collection collection) { + Optional opt = rules.swap(pair); + UnifyPair pair2 = opt.isPresent() ? opt.get() : pair; + + if(rules.erase1(pair2, fc) || rules.erase3(pair2) || rules.erase2(pair2, fc)) + return; + + collection.add(pair2); + } + + /** + * Splits the equation eq into a set eq1s where both terms are type variables, + * and a set eq2s where one of both terms is not a type variable. + * @param eq Set of pairs to be splitted. + * @param eq1s Subset of eq where both terms are type variables. + * @param eq2s eq/eq1s. + */ + protected void splitEq(Set eq, Set eq1s, Set eq2s) { + for(UnifyPair pair : eq) + if(pair.getLhsType() instanceof PlaceholderType && pair.getRhsType() instanceof PlaceholderType) + eq1s.add(pair); + else + eq2s.add(pair); + } + + /** + * Creates sets of pairs specified in the fourth step. Does not calculate cartesian products. + * @param undefined All pairs that did not match one of the 8 cases are added to this set. + * @return The set of the eight cases (without empty sets). Each case is a set, containing sets generated + * from the pairs that matched the case. Each generated set contains singleton sets or sets with few elements + * (as in case 1 where sigma is added to the innermost set). + */ + protected Set>>> calculatePairSets(Set eq2s, List>> oderConstraintsInput, IFiniteClosure fc, Set undefined, List>> oderConstraintsOutput) { + writeLog("eq2s: " + eq2s.toString()); + oderConstraintsOutput.addAll(oderConstraintsInput); + List>>> result = new ArrayList<>(9); + + // Init all 8 cases + 9. Case: oderConstraints + for(int i = 0; i < 9; i++) + result.add(new HashSet<>()); + + ArrayList eq2sprime = new ArrayList<>(eq2s); + Iterator eq2sprimeit = eq2sprime.iterator(); + ArrayList eq2sAsListFst = new ArrayList<>(); + ArrayList eq2sAsListSnd = new ArrayList<>(); + ArrayList eq2sAsListThird = new ArrayList<>(); + ArrayList eq2sAsListFourth = new ArrayList<>(); + ArrayList eq2sAsListBack = new ArrayList<>(); + ArrayList eq2sAsList = new ArrayList<>(); + Boolean first = true; + while(eq2sprimeit.hasNext()) {// alle mit Variance != 0 nach vorne schieben + UnifyPair up = eq2sprimeit.next(); + if ((up.getLhsType() instanceof PlaceholderType && + ((PlaceholderType)up.getLhsType()).getVariance() == 1 && + !((PlaceholderType)up.getLhsType()).isInnerType()) || + (up.getRhsType() instanceof PlaceholderType && + ((PlaceholderType)up.getRhsType()).getVariance() == -1) && + !((PlaceholderType)up.getRhsType()).isInnerType()) + { + eq2sAsListFst.add(up); + eq2s.remove(up); + } + else if ((up.getLhsType() instanceof PlaceholderType && ((PlaceholderType)up.getLhsType()).getVariance() == 1 && ((PlaceholderType)up.getLhsType()).isInnerType()) + || (up.getRhsType() instanceof PlaceholderType && ((PlaceholderType)up.getRhsType()).getVariance() == -1) && ((PlaceholderType)up.getRhsType()).isInnerType()) { + eq2sAsListSnd.add(up); + eq2s.remove(up); + } + else if ((up.getLhsType() instanceof PlaceholderType && + ((PlaceholderType)up.getLhsType()).getVariance() == -1 && + !((PlaceholderType)up.getLhsType()).isInnerType()) || + (up.getRhsType() instanceof PlaceholderType && + ((PlaceholderType)up.getRhsType()).getVariance() == -1) && + !((PlaceholderType)up.getRhsType()).isInnerType()) + { + eq2sAsListThird.add(up); + eq2s.remove(up); + } + else if ((up.getLhsType() instanceof PlaceholderType && ((PlaceholderType)up.getLhsType()).getVariance() == -1 && ((PlaceholderType)up.getLhsType()).isInnerType()) + || (up.getRhsType() instanceof PlaceholderType && ((PlaceholderType)up.getRhsType()).getVariance() == 1) && ((PlaceholderType)up.getRhsType()).isInnerType()) { + eq2sAsListFourth.add(up); + eq2s.remove(up); + } + else if ((up.getLhsType() instanceof PlaceholderType && ((PlaceholderType)up.getLhsType()).isInnerType()) + || (up.getRhsType() instanceof PlaceholderType && ((PlaceholderType)up.getRhsType()).isInnerType())) { + eq2sAsListBack.add(up); + eq2s.remove(up); + } + } + //if (eq2sAsListFst.isEmpty()) + { + List>> oderConstraintsVariance = oderConstraintsOutput.stream() //Alle Elemente rauswerfen, die Variance 0 haben oder keine TPH in LHS oder RHS sind + .filter(x -> x.stream() + .filter(y -> + y.stream().filter(z -> ((z.getLhsType() instanceof PlaceholderType) + && (((PlaceholderType)(z.getLhsType())).getVariance() != 0)) + || ((z.getRhsType() instanceof PlaceholderType) + && (((PlaceholderType)(z.getRhsType())).getVariance() != 0)) + ).findFirst().isPresent() + ).findFirst().isPresent()).collect(Collectors.toList()); + if (!oderConstraintsVariance.isEmpty()) { + Set> ret = oderConstraintsVariance.get(0); + oderConstraintsOutput.remove(ret); + //Set retFlat = new HashSet<>(); + //ret.stream().forEach(x -> retFlat.addAll(x)); + + //Alle wildcard Faelle rausfiltern bei not wildcardable + ret = ret.stream().filter(x -> { Optional optElem; + return !((optElem=x.stream().filter(y -> (y.getLhsType()) instanceof PlaceholderType + && !((PlaceholderType)y.getLhsType()).isWildcardable() + && y.getPairOp() == PairOperator.EQUALSDOT + && !(y.getRhsType() instanceof PlaceholderType)) + .findAny()).isPresent() + && optElem.get().getRhsType() instanceof ExtendsType);}) + .collect(Collectors.toSet()); + ret.stream().forEach(x -> x.stream().forEach(y -> { Set x_new = new HashSet<>(x); //PL 2020-03-18: y selbst darf nicht in die Substitutionen + x_new.remove(y); + y.addSubstitutions(x_new); + })); + result.get(8).add(ret); + first = false; + } + } + + writeLog("eq2s: " + eq2s.toString()); + writeLog("eq2sAsListFst: " + eq2sAsListFst.toString()); + writeLog("eq2sAsListSnd: " + eq2sAsListSnd.toString()); + writeLog("eq2sAsListBack: " + eq2sAsListBack.toString()); + + eq2sAsList.addAll(eq2sAsListFst); + eq2sAsList.addAll(eq2sAsListSnd); + eq2sAsList.addAll(eq2sAsListThird); + eq2sAsList.addAll(eq2sAsListFourth); + eq2sAsList.addAll(eq2s); + eq2sAsList.addAll(eq2sAsListBack); + + if (eq2sAsList.isEmpty() && first) {//Alle eq2s sind empty und alle oderConstraints mit Variance != 0 sind bearbeitet + if (!oderConstraintsOutput.isEmpty()) { + Set> ret = oderConstraintsOutput.remove(0); + //if (ret.iterator().next().iterator().next().getLhsType().getName().equals("M")) + // System.out.println("M"); + //Set retFlat = new HashSet<>(); + //ret.stream().forEach(x -> retFlat.addAll(x)); + + //Alle wildcard Faelle rausfiltern bei not wildcardable + ret = ret.stream().filter(x -> { Optional optElem; + return !((optElem=x.stream().filter(y -> (y.getLhsType()) instanceof PlaceholderType + && !((PlaceholderType)y.getLhsType()).isWildcardable() + && y.getPairOp() == PairOperator.EQUALSDOT + && !(y.getRhsType() instanceof PlaceholderType)) + .findAny()).isPresent() + && optElem.get().getRhsType() instanceof ExtendsType);}) + .collect(Collectors.toSet()); + + ret.stream().forEach(x -> x.stream().forEach(y -> { Set x_new = new HashSet<>(x); //PL 2020-03-18: y selbst darf nicht in die Substitutionen + x_new.remove(y); + y.addSubstitutions(x_new); + })); + result.get(8).add(ret); + first = false; + } + } + /* + Bei allen die Abhaengigkeit der Elemente aus eq2sAsList als evtl. als Substitution + hinzufuegen + */ + Set consideredElements = new HashSet<>(); + for(UnifyPair pair : eq2sAsList) { + if (consideredElements.contains(pair)) { + continue; + } + PairOperator pairOp = pair.getPairOp(); + UnifyType lhsType = pair.getLhsType(); + UnifyType rhsType = pair.getRhsType(); + + // Case 1: (a <. Theta') + if (((pairOp == PairOperator.SMALLERDOT) || (pairOp == PairOperator.SMALLERNEQDOT)) && lhsType instanceof PlaceholderType) { + //System.out.println(pair); + if (first) { //writeLog(pair.toString()+"\n"); + Set> x1 = new HashSet<>(); + if (pair.getRhsType().getName().equals("void")) { + Set resultOne = new HashSet<>(); + resultOne.add(new UnifyPair (pair.getLhsType(), pair.getRhsType(), PairOperator.EQUALSDOT, pair.getSubstitution(), pair)); + x1.add(resultOne); + } + else { + x1 = unifyCase1(pair, fc); + } + if (pairOp == PairOperator.SMALLERNEQDOT) { + Set remElem = new HashSet<>(); + remElem.add(new UnifyPair(pair.getLhsType(), pair.getRhsType(), PairOperator.EQUALSDOT)); + x1.remove(remElem); + remElem = new HashSet<>(); + remElem.add(new UnifyPair(pair.getLhsType(), new ExtendsType(pair.getRhsType()), PairOperator.EQUALSDOT)); + x1.remove(remElem); + remElem = new HashSet<>(); + remElem.add(new UnifyPair(pair.getLhsType(), new SuperType(pair.getRhsType()), PairOperator.EQUALSDOT)); + x1.remove(remElem); + } + /* ZU LOESCHEN ANFANG + //System.out.println(x1); + Set sameEqSet = eq2sAsList.stream() + .filter(x -> ((x.getLhsType().equals(lhsType) || x.getRhsType().equals(lhsType)) && !x.equals(pair))) + .collect(Collectors.toCollection(HashSet::new)); + consideredElements.addAll(sameEqSet); + Set> x2 = x1; + Set> x1Res = new HashSet<>(); + writeLog("pair:\n" + pair.toString()); + writeLog("x1 Start:\n" + x1.toString()); + writeLog("sameEqSet:\n" + sameEqSet.toString()); + for (UnifyPair sameEq : sameEqSet) { + writeLog("x1 Original:\n" + x1.toString()); + if (sameEq.getLhsType() instanceof PlaceholderType) { + x1 = x1.stream().filter(y -> { + UnifyPair type = y.stream().filter(z -> z.getLhsType().equals(lhsType)).findFirst().get(); + Set localEq = new HashSet<>(); + Set unitedSubst = new HashSet<>(type.getSubstitution()); + unitedSubst.addAll(sameEq.getSubstitution()); + localEq.add(new UnifyPair(type.getRhsType(), sameEq.getRhsType(), sameEq.getPairOp(), unitedSubst, null)); + Set> localRes = unify(localEq, new ArrayList<>(), fc, false, 0, false); + Boolean localCorr = !isUndefinedPairSetSet(localRes); + if (!localCorr) { + collectErr.addAll(localRes); + } + else { + localRes.forEach(z -> z.addAll(y)); + x1Res.addAll(localRes); + } + return localCorr; + } + ).collect(Collectors.toCollection(HashSet::new)); + } + else { + x1 = x1.stream().filter(y -> { + UnifyPair type = y.stream().filter(z -> z.getLhsType().equals(lhsType)).findFirst().get(); + Set localEq = new HashSet<>(); + Set unitedSubst = new HashSet<>(type.getSubstitution()); + unitedSubst.addAll(sameEq.getSubstitution()); + localEq.add(new UnifyPair(sameEq.getLhsType(), type.getRhsType(), sameEq.getPairOp(), unitedSubst, null)); + Set> localRes = unify(localEq, new ArrayList<>(), fc, false, 0, false); + Boolean localCorr = !isUndefinedPairSetSet(localRes); + if (!localCorr) { + collectErr.addAll(localRes); + } + else { + localRes.forEach(z -> z.addAll(y)); + x1Res.addAll(localRes); + } + return localCorr; + } + ).collect(Collectors.toCollection(HashSet::new)); + } + writeLog("x1 nach Loeschung von " + sameEq.toString()+" :\n" + x1.toString()); + } + Set> x1ResPrime; + if (sameEqSet.isEmpty()) { + x1ResPrime = x1; + } + else { + x1ResPrime = x1Res; + } + result.get(0).add(x1ResPrime); + ZU LOESCHEN ENDE */ + result.get(0).add(x1); + if (x1.isEmpty()) { + undefined.add(pair); //Theta ist nicht im FC => Abbruch + } + } + else { + Set s1 = new HashSet<>(); + s1.add(pair); + Set> s2 = new HashSet<>(); + s2.add(s1); + result.get(0).add(s2); + } + + } + // Case 2: (a <.? ? ext Theta') + else if(pairOp == PairOperator.SMALLERDOTWC && lhsType instanceof PlaceholderType && rhsType instanceof ExtendsType) + if (first) { //writeLog(pair.toString()+"\n"); + Set> x1 = unifyCase2(pair, fc); + result.get(1).add(x1); + if (x1.isEmpty()) { + undefined.add(pair); //Theta ist nicht im FC + } + } + else { + Set s1 = new HashSet<>(); + s1.add(pair); + Set> s2 = new HashSet<>(); + s2.add(s1); + result.get(1).add(s2); + } + + // Case 3: (a <.? ? sup Theta') + else if(pairOp == PairOperator.SMALLERDOTWC && lhsType instanceof PlaceholderType && rhsType instanceof SuperType) + if (first) { //writeLog(pair.toString()+"\n"); + Set> x1 = unifyCase3(pair, fc); + result.get(2).add(x1); + if (x1.isEmpty()) { + undefined.add(pair); //Theta ist nicht im FC + } + } + else { + Set s1 = new HashSet<>(); + s1.add(pair); + Set> s2 = new HashSet<>(); + s2.add(s1); + result.get(2).add(s2); + } + + // Case 4 was replaced by an inference rule + // Case 4: (a <.? Theta') + //else if(pairOp == PairOperator.SMALLERDOTWC && lhsType instanceof PlaceholderType) + // result.get(3).add(unifyCase4((PlaceholderType) lhsType, rhsType, fc)); + + // Case 5: (Theta <. a) + else if ((pairOp == PairOperator.SMALLERDOT) && rhsType instanceof PlaceholderType) + if (first) { //writeLog(pair.toString()+"\n"); + Set> x1 = new HashSet<>(); + if (pair.getLhsType().getName().equals("void")) { + Set resultOne = new HashSet<>(); + resultOne.add(new UnifyPair (pair.getRhsType(), pair.getLhsType(), PairOperator.EQUALSDOT, pair.getSubstitution(), pair)); + x1.add(resultOne); + } + else { + x1 = unifyCase5(pair, fc); + } + result.get(4).add(x1); + if (x1.isEmpty()) { + undefined.add(pair); //Theta ist nicht im FC + } + } + else { + Set s1 = new HashSet<>(); + s1.add(pair); + Set> s2 = new HashSet<>(); + s2.add(s1); + result.get(4).add(s2); + } + + // Case 6 was replaced by an inference rule. + // Case 6: (? ext Theta <.? a) + //else if(pairOp == PairOperator.SMALLERDOTWC && lhsType instanceof ExtendsType && rhsType instanceof PlaceholderType) + // result.get(5).add(unifyCase6((ExtendsType) lhsType, (PlaceholderType) rhsType, fc)); + + // Case 7 was replaced by an inference rule + // Case 7: (? sup Theta <.? a) + //else if(pairOp == PairOperator.SMALLERDOTWC && lhsType instanceof SuperType && rhsType instanceof PlaceholderType) + // result.get(6).add(unifyCase7((SuperType) lhsType, (PlaceholderType) rhsType, fc)); + + // Case 8: (Theta <.? a) + else if(pairOp == PairOperator.SMALLERDOTWC && rhsType instanceof PlaceholderType) + if (first) { //writeLog(pair.toString()+"\n"); + Set> x1 = unifyCase8(pair, fc); + result.get(7).add(x1); + if (x1.isEmpty()) { + undefined.add(pair); //Theta ist nicht im FC + } + } + else { + Set s1 = new HashSet<>(); + s1.add(pair); + Set> s2 = new HashSet<>(); + s2.add(s1); + result.get(7).add(s2); + } + // Case unknown: If a pair fits no other case, then the type unification has failed. + // Through application of the rules, every pair should have one of the above forms. + // Pairs that do not have one of the aboves form are contradictory. + else { + // If a pair is not defined, the unificiation will fail, so the loop can be stopped here. + undefined.add(pair); + break; + } + first = false; + } + + // Filter empty sets or sets that only contain an empty set. + return result.stream().map(x -> x.stream().filter(y -> y.size() > 0).collect(Collectors.toCollection(HashSet::new))) + .filter(x -> x.size() > 0).collect(Collectors.toCollection(HashSet::new)); + } + + //TODO: Wenn Theta' nicht im FC muss ein Fehler produziert werden PL 18-04-20 + /** + * Cartesian product Case 1: (a <. Theta') + */ + protected Set> unifyCase1(UnifyPair pair, IFiniteClosure fc) { + PlaceholderType a = (PlaceholderType)pair.getLhsType(); + UnifyType thetaPrime = pair.getRhsType(); + + if (thetaPrime instanceof ExtendsType) { + thetaPrime = ((ExtendsType)thetaPrime).getExtendedType(); + } + + if (thetaPrime instanceof SuperType) { + //HIER MUSS NOCH WAS UEBERLEGT WERDEN + } + + Set> result = new HashSet<>(); + + if (thetaPrime instanceof ReferenceType && ((ReferenceType)thetaPrime).isGenTypeVar()) { + Set resultOne = new HashSet<>(); + resultOne.add(new UnifyPair (a, thetaPrime, PairOperator.EQUALSDOT, pair.getSubstitution(), pair)); + result.add(resultOne); + } + + boolean allGen = thetaPrime.getTypeParams().size() > 0; + for(UnifyType t : thetaPrime.getTypeParams()) + if(!(t instanceof PlaceholderType) || !((PlaceholderType) t).isGenerated()) { + allGen = false; + break; + } + //if (thetaPrime.getName().equals("java.util.Vector") //Fuer Bug 127 + // && thetaPrime instanceof ReferenceType + // && ((ReferenceType)thetaPrime).getTypeParams().iterator().next() instanceof PlaceholderType) //.getName().equals("java.util.Vector")) + // && ((ReferenceType)((ReferenceType)thetaPrime).getTypeParams().iterator().next()).getTypeParams().iterator().next().getName().equals("java.lang.Integer")) { + // { + // System.out.println(""); + //} + Set cs = fc.getAllTypesByName(thetaPrime.getName());//cs= [java.util.Vector, java.util.Vector>, ????java.util.Vector???] + + writeLog("cs: " + cs.toString()); + //PL 18-02-06 entfernt, kommt durch unify wieder rein + //cs.add(thetaPrime); + //PL 18-02-06 entfernt + + //cs muessen fresh Typvars gesetzt werden PL 2018-03-18 + Set csPHRenamed = cs.stream().map(x -> { + BinaryOperator> combiner = (aa,b) -> { aa.putAll(b); return aa;}; + HashMap hm = x.getInvolvedPlaceholderTypes().stream() + .reduce(new HashMap(), + (aa, b)-> { aa.put(b,PlaceholderType.freshPlaceholder()); return aa; }, combiner); + return x.accept(new freshPlaceholder(), hm); + }).collect(Collectors.toCollection(HashSet::new)); + + IMatch match = new Match(); + for(UnifyType c : csPHRenamed) { + //PL 18-02-05 getChildren durch smaller ersetzt in getChildren werden die Varianlen nicht ersetzt. + Set thetaQs = new HashSet<>(); + //TODO smaller wieder reinnehmen? + //thetaQs.add(c);// + thetaQs = fc.smaller(c, new HashSet<>()).stream().collect(Collectors.toCollection(HashSet::new)); + ArrayList ml = new ArrayList<>(); + ml.add(new UnifyPair(c, thetaPrime, PairOperator.EQUALSDOT)); + if (!(match.match(ml)).isPresent()) { + thetaQs.remove(c); + } + writeLog("thetaQs von " + c + ": " + thetaQs.toString()); + //Set thetaQs = fc.getChildren(c).stream().collect(Collectors.toCollection(HashSet::new)); + //thetaQs.add(thetaPrime); //PL 18-02-05 wieder geloescht + //PL 2017-10-03: War auskommentiert habe ich wieder einkommentiert, + //da children offensichtlich ein echtes kleiner und kein kleinergleich ist + + //PL 18-02-06: eingefuegt, thetaQs der Form V> <. V'> werden entfernt + //TODO PL 19-01-14 wieder reinnehmen kurzfristig auskommentiert + //thetaQs = thetaQs.stream().filter(ut -> ut.getTypeParams().arePlaceholders()).collect(Collectors.toCollection(HashSet::new)); + //PL 18-02-06: eingefuegt + + Set thetaQPrimes = new HashSet<>(); + TypeParams cParams = c.getTypeParams(); + if(cParams.size() == 0) + thetaQPrimes.add(c); + else { + ArrayList> candidateParams = new ArrayList<>(); + + for(UnifyType param : cParams) + candidateParams.add(fc.grArg(param, new HashSet<>())); + + for(TypeParams tp : permuteParams(candidateParams)) + thetaQPrimes.add(c.setTypeParams(tp)); + } + writeLog("thetaQPrimes von " + c + ": " + thetaQPrimes.toString()); + for(UnifyType tqp : thetaQPrimes) {//PL 2020-03-08 umbauen in der Schleife wird nur unifizierbarer Typ gesucht break am Ende + Collection tphs = tqp.getInvolvedPlaceholderTypes(); + Optional opt = stdUnify.unify(tqp, thetaPrime); + if (!opt.isPresent()) { + continue; + } + Unifier unifier = opt.get(); + unifier.swapPlaceholderSubstitutions(thetaPrime.getTypeParams()); + Set substitutionSet = new HashSet<>(); + for (Entry sigma : unifier) { + if (!tphs.contains(sigma.getKey())) {//eingefuegt PL 2019-02-02 Bug 127 + substitutionSet.add(new UnifyPair(sigma.getKey(), sigma.getValue(), PairOperator.EQUALSDOT, + //TODO: nochmals ueberlegen ob hier pair.getSubstitution() korrekt ist, oder ob leere Menge hin müsste + //alle folgenden New UnifyPair ebenfalls ueberpruefen PL 2018-04-19 + pair.getSubstitution(), pair)); + } + } + //List freshTphs = new ArrayList<>(); PL 18-02-06 in die For-Schleife verschoben + for (UnifyType tq : thetaQs) { + //geaendert PL 20-03-07 + Set smaller = new HashSet<>(); + smaller.add(unifier.apply(tq)); + //Set smaller = fc.smaller(unifier.apply(tq), new HashSet<>()); + //eingefuegt PL 2018-03-29 Anfang ? ext. theta hinzufuegen + if (a.isWildcardable()) { + Set smaller_ext = smaller.stream().filter(x -> !(x instanceof ExtendsType) && !(x instanceof SuperType)) + .map(x -> { + //BinaryOperator> combiner = (aa,b) -> { aa.putAll(b); return aa;}; //Variablenumbenennung rausgenommen + //HashMap hm = x.getInvolvedPlaceholderTypes().stream() //Variablen muessen wahrscheinlich erhalten bleiben + // .reduce(new HashMap(), + // (aa, b)-> { aa.put(b,PlaceholderType.freshPlaceholder()); return aa; }, combiner); + return new ExtendsType (x);})//.accept(new freshPlaceholder(), hm));} + .collect(Collectors.toCollection(HashSet::new)); + smaller.addAll(smaller_ext); + } + //eingefuegt PL 2018-03-29 Ende ? ext. theta hinzufuegen + for(UnifyType theta : smaller) { + List freshTphs = new ArrayList<>(); + Set resultPrime = new HashSet<>(); + + for(int i = 0; !allGen && i < theta.getTypeParams().size(); i++) { + if(freshTphs.size()-1 < i)//IST DAS RICHTIG??? PL 2018-12-12 + freshTphs.add(PlaceholderType.freshPlaceholder()); + freshTphs.forEach(x -> ((PlaceholderType)x).setInnerType(true)); + resultPrime.add(new UnifyPair(freshTphs.get(i), theta.getTypeParams().get(i), PairOperator.SMALLERDOTWC, pair.getSubstitution(), pair)); + } + + if(allGen) { + UnifyPair up = new UnifyPair(a, theta, PairOperator.EQUALSDOT, pair.getSubstitution(), pair); + Iterator upit = up.getRhsType().getTypeParams().iterator(); + //TODO PL 2019-01-24: upit.next() ist nicht unbedingt ein PlaceholderType -> Visitor erledigt + while (upit.hasNext()) upit.next().accept(new distributeVariance(), a.getVariance());//((PlaceholderType)upit.next()).setVariance(a.getVariance()); + resultPrime.add(up); + } + else { + UnifyPair up = new UnifyPair(a, theta.setTypeParams(new TypeParams(freshTphs.toArray(new UnifyType[0]))), PairOperator.EQUALSDOT, pair.getSubstitution(), pair); + Iterator upit = up.getRhsType().getTypeParams().iterator(); + distributeVariance dv = new distributeVariance(); + //TODO PL 2019-01-24: upit.next() ist nicht unbedingt ein PlaceholderType -> Visitor erledigt + while (upit.hasNext()) upit.next().accept(new distributeVariance(), a.getVariance()); //((PlaceholderType)upit.next()).setVariance(a.getVariance()); + resultPrime.add(up); + } + resultPrime.addAll(substitutionSet); + //writeLog("Substitution: " + substitutionSet.toString()); + result.add(resultPrime); + //writeLog("Result: " + resultPrime.toString()); + //writeLog("MAX: " + oup.max(resultPrime.iterator()).toString()); + } + } + } + } + writeLog("result von " + pair + ": " + result.toString()); + return result; + } + + /** + * Cartesian Product Case 2: (a <.? ? ext Theta') + */ + private Set> unifyCase2(UnifyPair pair, IFiniteClosure fc) { + PlaceholderType a = (PlaceholderType) pair.getLhsType(); + ExtendsType extThetaPrime = (ExtendsType) pair.getRhsType(); + Set> result = new HashSet<>(); + + UnifyType aPrime = PlaceholderType.freshPlaceholder(); + ((PlaceholderType)aPrime).setVariance(((PlaceholderType)a).getVariance()); + ((PlaceholderType)aPrime).disableWildcardtable(); + UnifyType extAPrime = new ExtendsType(aPrime); + UnifyType thetaPrime = extThetaPrime.getExtendedType(); + Set resultPrime = new HashSet<>(); + resultPrime.add(new UnifyPair(a, thetaPrime, PairOperator.SMALLERDOT, pair.getSubstitution(), pair)); + result.add(resultPrime); + + resultPrime = new HashSet<>(); + resultPrime.add(new UnifyPair(a, extAPrime, PairOperator.EQUALSDOT, pair.getSubstitution(), pair)); + resultPrime.add(new UnifyPair(aPrime, thetaPrime, PairOperator.SMALLERDOT, pair.getSubstitution(), pair)); + result.add(resultPrime); + //writeLog("Result: " + resultPrime.toString()); + return result; + } + + /** + * Cartesian Product Case 3: (a <.? ? sup Theta') + */ + private Set> unifyCase3(UnifyPair pair, IFiniteClosure fc) { + PlaceholderType a = (PlaceholderType) pair.getLhsType(); + a.reversVariance(); + SuperType subThetaPrime = (SuperType) pair.getRhsType(); + Set> result = new HashSet<>(); + + UnifyType aPrime = PlaceholderType.freshPlaceholder(); + ((PlaceholderType)aPrime).setVariance(((PlaceholderType)a).getVariance()); + ((PlaceholderType)aPrime).disableWildcardtable(); + UnifyType supAPrime = new SuperType(aPrime); + UnifyType thetaPrime = subThetaPrime.getSuperedType(); + Set resultPrime = new HashSet<>(); + resultPrime.add(new UnifyPair(thetaPrime, a, PairOperator.SMALLERDOT, pair.getSubstitution(), pair, pair.getfBounded())); + result.add(resultPrime); + //writeLog(resultPrime.toString()); + + resultPrime = new HashSet<>(); + resultPrime.add(new UnifyPair(a, supAPrime, PairOperator.EQUALSDOT, pair.getSubstitution(), pair)); + resultPrime.add(new UnifyPair(thetaPrime, aPrime, PairOperator.SMALLERDOT, pair.getSubstitution(), pair)); + result.add(resultPrime); + //writeLog(resultPrime.toString()); + + return result; + } + + /** + * Cartesian Product Case 5: (Theta <. a) + */ + private Set> unifyCase5(UnifyPair pair, IFiniteClosure fc) { + UnifyType theta = pair.getLhsType(); + PlaceholderType a = (PlaceholderType) pair.getRhsType(); + Set> result = new HashSet<>(); + + boolean allGen = theta.getTypeParams().size() > 0; + for(UnifyType t : theta.getTypeParams()) + if(!(t instanceof PlaceholderType) || !((PlaceholderType) t).isGenerated()) { + allGen = false; + break; + } + + //eingefuegt PL 2019-01-03 ANFANG + //fc.setLogTrue(); + //writeLog("FBOUNDED: " + pair.getfBounded()); + //writeLog("Pair: " + pair); + Set greater = fc.greater(theta, pair.getfBounded()); + //writeLog("GREATER: " + greater + pair + "THETA: " + theta + "FBOUNDED: " + pair.getfBounded() + " "); + if (a.isWildcardable()) { + Set greater_ext = greater.stream().filter(x -> !(x instanceof ExtendsType) && !(x instanceof SuperType)) + .map(x -> { + //BinaryOperator> combiner = (aa,b) -> { aa.putAll(b); return aa;}; //Variablenumbenennung rausgenommen + //HashMap hm = x.getInvolvedPlaceholderTypes().stream() //Variablen muessen wahrscheinlich erhalten bleiben + // .reduce(new HashMap(), + // (aa, b)-> { aa.put(b,PlaceholderType.freshPlaceholder()); return aa; }, combiner); + return new SuperType (x);})//.accept(new freshPlaceholder(), hm));} + .collect(Collectors.toCollection(HashSet::new)); + greater.addAll(greater_ext); + } + //eingefuegt PL 2019-01-03 ENDE + + //for(UnifyType thetaS : fc.greater(theta, pair.getfBounded())) { + for(UnifyType thetaS : greater) { + Set resultPrime = new HashSet<>(); + Match match = new Match(); + + UnifyType[] freshTphs = new UnifyType[thetaS.getTypeParams().size()]; + for(int i = 0; !allGen && i < freshTphs.length; i++) { + freshTphs[i] = PlaceholderType.freshPlaceholder(); + ((PlaceholderType)freshTphs[i]).setVariance(((PlaceholderType)a).getVariance()); + Set fBounded = new HashSet<>(pair.getfBounded()); //PL 2019-01-09 new HashSet eingefuegt + + int i_ef = i; + BiFunction f = (x,y) -> + { + ArrayList termList = new ArrayList(); + termList.add(new UnifyPair(y,thetaS.getTypeParams().get(i_ef), PairOperator.EQUALSDOT)); + return ((match.match(termList).isPresent()) || x); + }; + //if (parai.getName().equals("java.lang.Integer")) { + // System.out.println(""); + //} + BinaryOperator bo = (x,y) -> (x || y); + if (fBounded.stream().reduce(false,f,bo)) { + resultPrime.add(new UnifyPair(freshTphs[i], thetaS.getTypeParams().get(i), PairOperator.EQUALSDOT, pair.getSubstitution(), pair)); + } + else { + fBounded.add(thetaS.getTypeParams().get(i)); + resultPrime.add(new UnifyPair(thetaS.getTypeParams().get(i), freshTphs[i], PairOperator.SMALLERDOTWC, pair.getSubstitution(), pair, fBounded)); + } + } + + if(allGen) + resultPrime.add(new UnifyPair(a, thetaS, PairOperator.EQUALSDOT, pair.getSubstitution(), pair)); + else + resultPrime.add(new UnifyPair(a, thetaS.setTypeParams(new TypeParams(freshTphs)), PairOperator.EQUALSDOT, pair.getSubstitution(), pair)); + result.add(resultPrime); + //writeLog("FBOUNDED2: " + pair.getfBounded()); + //writeLog("resultPrime Theta < a: " + greater + pair + "THETA: " + theta + "FBOUNDED: " + pair.getfBounded() + " " + resultPrime.toString()); + } + + return result; + } + + /** + * Cartesian Product Case 8: (Theta <.? a) + */ + private Set> unifyCase8(UnifyPair pair, IFiniteClosure fc) { + UnifyType theta = pair.getLhsType(); + PlaceholderType a = (PlaceholderType) pair.getRhsType(); + Set> result = new HashSet<>(); + //for(UnifyType thetaS : fc.grArg(theta)) { + Set resultPrime = new HashSet<>(); + resultPrime.add(new UnifyPair(a, theta, PairOperator.EQUALSDOT, pair.getSubstitution(), pair)); + result.add(resultPrime); + //writeLog(resultPrime.toString()); + + UnifyType freshTph = PlaceholderType.freshPlaceholder(); + + ((PlaceholderType)freshTph).setVariance(a.getVariance()); + ((PlaceholderType)freshTph).disableWildcardtable(); + resultPrime = new HashSet<>(); + resultPrime.add(new UnifyPair(a, new ExtendsType(freshTph), PairOperator.EQUALSDOT, pair.getSubstitution(), pair)); + resultPrime.add(new UnifyPair(theta, freshTph, PairOperator.SMALLERDOT, pair.getSubstitution(), pair, pair.getfBounded())); + result.add(resultPrime); + //writeLog("resultPrime: " + resultPrime.toString()); + + resultPrime = new HashSet<>(); + resultPrime.add(new UnifyPair(a, new SuperType(freshTph), PairOperator.EQUALSDOT, pair.getSubstitution(), pair)); + resultPrime.add(new UnifyPair(freshTph, theta, PairOperator.SMALLERDOT, pair.getSubstitution(), pair)); + result.add(resultPrime); + //writeLog(resultPrime.toString()); + //} + + return result; + } + + /** + * Takes a set of candidates for each position and computes all possible permutations. + * @param candidates The length of the list determines the number of type params. Each set + * contains the candidates for the corresponding position. + */ + protected Set permuteParams(ArrayList> candidates) { + Set result = new HashSet<>(); + permuteParams(candidates, 0, result, new UnifyType[candidates.size()]); + return result; + } + + /** + * Takes a set of candidates for each position and computes all possible permutations. + * @param candidates The length of the list determines the number of type params. Each set + * contains the candidates for the corresponding position. + * @param idx Idx for the current permutatiton. + * @param result Set of all permutations found so far + * @param current The permutation of type params that is currently explored + */ + private void permuteParams(ArrayList> candidates, int idx, Set result, UnifyType[] current) { + if(candidates.size() == idx) { + result.add(new TypeParams(Arrays.copyOf(current, current.length))); + return; + } + + Set localCandidates = candidates.get(idx); + + for(UnifyType t : localCandidates) { + current[idx] = t; + permuteParams(candidates, idx+1, result, current); + } + } + + void writeLog(String str) { + synchronized ( this ) { + if (log && finalresult) { + try { + logFile.write("Thread no.:" + thNo + "\n"); + logFile.write("noOfThread:" + noOfThread + "\n"); + logFile.write("parallel:" + parallel + "\n"); + logFile.write(str+"\n\n"); + logFile.flush(); + + } + catch (IOException e) { + System.err.println("kein LogFile"); + } + } + } + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/Unifikationsalgorithmus.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/Unifikationsalgorithmus.java new file mode 100644 index 0000000..128dbce --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/Unifikationsalgorithmus.java @@ -0,0 +1,11 @@ +package de.dhbw.compiler.typeinference.unify; + +import java.util.Set; + +import de.dhbw.compiler.typeinference.unify.model.UnifyPair; + +public interface Unifikationsalgorithmus { + + public Set> apply (Set E); + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/UnifyResultEvent.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/UnifyResultEvent.java new file mode 100644 index 0000000..5c00b4c --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/UnifyResultEvent.java @@ -0,0 +1,18 @@ +package de.dhbw.compiler.typeinference.unify; + +import java.util.List; + +import de.dhbw.compiler.typeinference.result.ResultSet; + +public class UnifyResultEvent { + + private List newTypeResult; + + public UnifyResultEvent(List newTypeResult) { + this.newTypeResult = newTypeResult; + } + + public List getNewTypeResult() { + return newTypeResult; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/UnifyResultListener.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/UnifyResultListener.java new file mode 100644 index 0000000..221157e --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/UnifyResultListener.java @@ -0,0 +1,7 @@ +package de.dhbw.compiler.typeinference.unify; + +public interface UnifyResultListener { + + void onNewTypeResultFound(UnifyResultEvent evt); + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/UnifyResultListenerImpl.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/UnifyResultListenerImpl.java new file mode 100644 index 0000000..ac9e1e2 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/UnifyResultListenerImpl.java @@ -0,0 +1,21 @@ +package de.dhbw.compiler.typeinference.unify; + +import java.util.ArrayList; +import java.util.List; + +import de.dhbw.compiler.typeinference.result.ResultSet; +import de.dhbw.compiler.typeinference.unify.model.UnifyPair; + +public class UnifyResultListenerImpl implements UnifyResultListener { + + List results = new ArrayList<>(); + + public synchronized void onNewTypeResultFound(UnifyResultEvent evt) { + results.addAll(evt.getNewTypeResult()); + } + + public List getResults() { + return results; + } + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/UnifyResultModel.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/UnifyResultModel.java new file mode 100644 index 0000000..cacbe28 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/UnifyResultModel.java @@ -0,0 +1,59 @@ +package de.dhbw.compiler.typeinference.unify; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import de.dhbw.compiler.syntaxtree.factory.UnifyTypeFactory; +import de.dhbw.compiler.typeinference.constraints.ConstraintSet; +import de.dhbw.compiler.typeinference.result.ResultSet; +import de.dhbw.compiler.typeinference.unify.interfaces.IFiniteClosure; +import de.dhbw.compiler.typeinference.unify.model.PairOperator; +import de.dhbw.compiler.typeinference.unify.model.UnifyPair; + +public class UnifyResultModel { + + ConstraintSet cons; + + IFiniteClosure fc; + + public UnifyResultModel(ConstraintSet cons, + IFiniteClosure fc) { + this.cons = cons; + this.fc = fc; + } + + private List listeners = new ArrayList<>(); + + public void addUnifyResultListener(UnifyResultListener listenerToAdd) { + listeners.add(listenerToAdd); + } + + public void removeUnifyResultListener(UnifyResultListener listenerToRemove) { + listeners.remove(listenerToRemove); + } + + public void notify(Set> eqPrimePrimeSet) { + Set> eqPrimePrimeSetRet = eqPrimePrimeSet.stream().map(x -> { + Optional> res = new RuleSet().subst(x.stream().map(y -> { + if (y.getPairOp() == PairOperator.SMALLERDOTWC) y.setPairOp(PairOperator.EQUALSDOT); + return y; //alle Paare a <.? b erden durch a =. b ersetzt + }).collect(Collectors.toCollection(HashSet::new))); + if (res.isPresent()) {//wenn subst ein Erg liefert wurde was veraendert + return new TypeUnifyTask().applyTypeUnificationRules(res.get(), fc); + } + else return x; //wenn nichts veraendert wurde wird x zurueckgegeben + }).collect(Collectors.toCollection(HashSet::new)); + List newResult = eqPrimePrimeSetRet.stream().map(unifyPairs -> + new ResultSet(UnifyTypeFactory.convert(unifyPairs, de.dhbw.compiler.typeinference.constraints.Pair.generateTPHMap(cons)))) + .collect(Collectors.toList()); + UnifyResultEvent evt = new UnifyResultEvent(newResult); + + for (UnifyResultListener listener : listeners) { + listener.onNewTypeResultFound(evt); + } + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/UnifyTaskModel.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/UnifyTaskModel.java new file mode 100644 index 0000000..d137fb4 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/UnifyTaskModel.java @@ -0,0 +1,18 @@ +package de.dhbw.compiler.typeinference.unify; + +import java.util.ArrayList; + +public class UnifyTaskModel { + + ArrayList usedTasks = new ArrayList<>(); + + public synchronized void add(TypeUnifyTask t) { + usedTasks.add(t); + } + + public synchronized void cancel() { + for(TypeUnifyTask t : usedTasks) { + t.myCancel(true); + } + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/distributeVariance.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/distributeVariance.java new file mode 100644 index 0000000..f998552 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/distributeVariance.java @@ -0,0 +1,54 @@ +package de.dhbw.compiler.typeinference.unify; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import de.dhbw.compiler.typeinference.unify.model.FunNType; +import de.dhbw.compiler.typeinference.unify.model.PlaceholderType; +import de.dhbw.compiler.typeinference.unify.model.TypeParams; +import de.dhbw.compiler.typeinference.unify.model.UnifyType; + +public class distributeVariance extends visitUnifyTypeVisitor { + + public static int inverseVariance(int variance) { + Integer ret = 0; + if (variance == 1) { + ret = -1; + } + if (variance == -1) { + ret = 1; + } + return ret; + } + + + @Override + public PlaceholderType visit(PlaceholderType phty, Integer ht) { + if (ht != 0) { + if (phty.getVariance() == 0) { + phty.setVariance(ht); + } + //PL 2018-05-17 urspruengliche Variance nicht veraendern + //else if (phty.getVariance() != ht) { + // phty.setVariance(0); + //} + } + return phty; + } + + public FunNType visit(FunNType funnty, Integer ht) { + List param = new ArrayList<>(funnty.getTypeParams().get().length); + param.addAll(Arrays.asList(funnty.getTypeParams().get())); + UnifyType resultType = param.remove(param.size()-1); + Integer htInverse = inverseVariance(ht); + param = param.stream() + .map(x -> x.accept(this, htInverse)) + .collect(Collectors.toCollection(ArrayList::new)); + param.add(resultType.accept(this, ht)); + return FunNType.getFunNType(new TypeParams(param)); + } + + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/freshPlaceholder.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/freshPlaceholder.java new file mode 100644 index 0000000..e975024 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/freshPlaceholder.java @@ -0,0 +1,15 @@ +package de.dhbw.compiler.typeinference.unify; + + +import java.util.HashMap; + +import de.dhbw.compiler.typeinference.unify.model.PlaceholderType; + + +public class freshPlaceholder extends visitUnifyTypeVisitor> { + + @Override + public PlaceholderType visit(PlaceholderType phty, HashMap ht) { + return ht.get(phty); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/interfaces/IFiniteClosure.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/interfaces/IFiniteClosure.java new file mode 100644 index 0000000..fda0efd --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/interfaces/IFiniteClosure.java @@ -0,0 +1,78 @@ +package de.dhbw.compiler.typeinference.unify.interfaces; + +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import de.dhbw.compiler.parser.SourceLoc; +import de.dhbw.compiler.typeinference.unify.model.ExtendsType; +import de.dhbw.compiler.typeinference.unify.model.FunNType; +import de.dhbw.compiler.typeinference.unify.model.PairOperator; +import de.dhbw.compiler.typeinference.unify.model.PlaceholderType; +import de.dhbw.compiler.typeinference.unify.model.ReferenceType; +import de.dhbw.compiler.typeinference.unify.model.SuperType; +import de.dhbw.compiler.typeinference.unify.model.UnifyType; +import org.antlr.v4.runtime.Token; + +/** + * + * @author Florian Steurer + */ +public interface IFiniteClosure { + + public void setLogTrue(); + /** + * Returns all types of the finite closure that are subtypes of the argument. + * @return The set of subtypes of the argument. + */ + public Set smaller(UnifyType type, Set fBounded, Token position); + public default Set smaller(UnifyType type, Set 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 greater(UnifyType type, Set fBounded, SourceLoc position); + public default Set greater(UnifyType type, Set fBounded) { + return this.greater(type, fBounded, null); + } + + /** + * Wo passt Type rein? + * @param type + * @return + */ + public Set grArg(UnifyType type, Set fBounded); + + /** + * Was passt in Type rein? + * @param type + * @return + */ + public Set smArg(UnifyType type, Set fBounded); + + public Set grArg(ReferenceType type, Set fBounded); + public Set smArg(ReferenceType type, Set fBounded); + + public Set grArg(ExtendsType type, Set fBounded); + public Set smArg(ExtendsType type, Set fBounded); + + public Set grArg(SuperType type, Set fBounded); + public Set smArg(SuperType type, Set fBounded); + + public Set grArg(PlaceholderType type, Set fBounded); + public Set smArg(PlaceholderType type, Set fBounded); + + public Set grArg(FunNType type, Set fBounded); + public Set smArg(FunNType type, Set fBounded); + + public Optional getLeftHandedType(String typeName); + public Optional getRightHandedFunctionalInterfaceType(String typeName); + public Set getAncestors(UnifyType t); + public Set getChildren(UnifyType t); + public Set getAllTypesByName(String typeName); + + public int compare(UnifyType rhsType, UnifyType rhsType2, PairOperator pairop); +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/interfaces/IMatch.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/interfaces/IMatch.java new file mode 100644 index 0000000..5704b75 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/interfaces/IMatch.java @@ -0,0 +1,29 @@ +package de.dhbw.compiler.typeinference.unify.interfaces; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import de.dhbw.compiler.typeinference.unify.model.UnifyType; +import de.dhbw.compiler.typeinference.unify.model.Unifier; +import de.dhbw.compiler.typeinference.unify.model.UnifyPair; + +/** + * Match + * @author Martin Pluemicke + * abgeleitet aus IUnify.java + */ +public interface IMatch { + + /** + * Finds the most general matcher sigma of the set {t1 =. t1',...,tn =. tn'} so that + * sigma(t1) = t1' , ... sigma(tn) = tn'. + * @param terms The set of terms to be matched + * @return An optional of the most general matcher if it exists or an empty optional if there is no matcher. + */ + public Optional match(ArrayList termsList); + + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/interfaces/IRuleSet.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/interfaces/IRuleSet.java new file mode 100644 index 0000000..901d3ca --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/interfaces/IRuleSet.java @@ -0,0 +1,104 @@ +package de.dhbw.compiler.typeinference.unify.interfaces; + +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import de.dhbw.compiler.typeinference.constraints.Constraint; +import de.dhbw.compiler.typeinference.unify.model.UnifyPair; + +/** + * Contains the inference rules that are applied to the set Eq. + * @author Florian Steurer + */ +public interface IRuleSet { + + public Optional reduceUp(UnifyPair pair); + public Optional reduceLow(UnifyPair pair); + public Optional reduceUpLow(UnifyPair pair); + public Optional> reduceExt(UnifyPair pair, IFiniteClosure fc); + public Optional> reduceSup(UnifyPair pair, IFiniteClosure fc); + public Optional> reduceEq(UnifyPair pair); + public Optional> reduce1(UnifyPair pair, IFiniteClosure fc); + public Optional> reduce2(UnifyPair pair); + + /* + * Missing Reduce-Rules for Wildcards + */ + public Optional reduceWildcardLow(UnifyPair pair); + public Optional reduceWildcardLowRight(UnifyPair pair); + public Optional reduceWildcardUp(UnifyPair pair); + public Optional reduceWildcardUpRight(UnifyPair pair); + + /* + * vgl. JAVA_BSP/Wildcard6.java + public Optional reduceWildcardLowUp(UnifyPair pair); + public Optional reduceWildcardUpLow(UnifyPair pair); + public Optional reduceWildcardLeft(UnifyPair pair); + */ + + /* + * Additional Rules which replace cases of the cartesian product + */ + + /** + * Rule that replaces the fourth case of the cartesian product where (a <.? Theta) + */ + public Optional reduceTph(UnifyPair pair); + + /** + * Rule that replaces the sixth case of the cartesian product where (? ext Theta <.? a) + */ + public Optional> reduceTphExt(UnifyPair pair); + + /** + * Rule that replaces the fourth case of the cartesian product where (? sup Theta <.? a) + */ + public Optional> reduceTphSup(UnifyPair pair); + + /* + * FunN Rules + */ + public Optional> reduceFunN(UnifyPair pair); + public Optional> greaterFunN(UnifyPair pair, IFiniteClosure fc); + public Optional> smallerFunN(UnifyPair pair); + + /** + * Checks whether the erase1-Rule applies to the pair. + * @return True if the pair is erasable, false otherwise. + */ + public boolean erase1(UnifyPair pair, IFiniteClosure fc); + + /** + * Checks whether the erase2-Rule applies to the pair. + * @return True if the pair is erasable, false otherwise. + */ + public boolean erase2(UnifyPair pair, IFiniteClosure fc); + + /** + * Checks whether the erase3-Rule applies to the pair. + * @return True if the pair is erasable, false otherwise. + */ + public boolean erase3(UnifyPair pair); + + public Optional swap(UnifyPair pair); + + public Optional adapt(UnifyPair pair, IFiniteClosure fc); + public Optional adaptExt(UnifyPair pair, IFiniteClosure fc); + public Optional adaptSup(UnifyPair pair, IFiniteClosure fc); + + /** + * Applies the subst-Rule to a set of pairs (usually Eq'). + * @param pairs The set of pairs where the subst rule should apply. + * @return An optional of the modified set, if there were any substitutions. An empty optional if there were no substitutions. + */ + public Optional> subst(Set pairs, List>> oderConstraints); + + /** + * Applies the subst-Rule to a set of pairs (usually Eq'). + * @param pairs The set of pairs where the subst rule should apply. + * @return An optional of the modified set, if there were any substitutions. An empty optional if there were no substitutions. + */ + public Optional> subst(Set pairs); + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/interfaces/ISetOperations.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/interfaces/ISetOperations.java new file mode 100644 index 0000000..17ff3f7 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/interfaces/ISetOperations.java @@ -0,0 +1,16 @@ +package de.dhbw.compiler.typeinference.unify.interfaces; + +import java.util.List; +import java.util.Set; + +/** + * Contains operations on sets. + * @author Florian Steurer + */ +public interface ISetOperations { + /** + * Calculates the cartesian product of the sets. + * @return The cartesian product + */ + Set> cartesianProduct(List> sets); +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/interfaces/IUnify.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/interfaces/IUnify.java new file mode 100644 index 0000000..27c828b --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/interfaces/IUnify.java @@ -0,0 +1,35 @@ +package de.dhbw.compiler.typeinference.unify.interfaces; + +import java.util.Arrays; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import de.dhbw.compiler.typeinference.unify.model.UnifyType; +import de.dhbw.compiler.typeinference.unify.model.Unifier; + +/** + * Standard unification algorithm (e.g. Robinson, Paterson-Wegman, Martelli-Montanari) + * @author Florian Steurer + */ +public interface IUnify { + + /** + * Finds the most general unifier sigma of the set {t1 =. t1',...,tn =. tn'} so that + * sigma(t1) = sigma(t1') , ... sigma(tn) = sigma(tn'). + * @param terms The set of terms to be unified + * @return An optional of the most general unifier if it exists or an empty optional if there is no unifier. + */ + public Optional unify(Set terms); + + /** + * Finds the most general unifier sigma of the set {t1 =. t1',...,tn =. tn'} so that + * sigma(t1) = sigma(t1') , ... sigma(tn) = sigma(tn'). + * @param terms The set of terms to be unified + * @return An optional of the most general unifier if it exists or an empty optional if there is no unifier. + */ + default public Optional unify(UnifyType... terms) { + return unify(Arrays.stream(terms).collect(Collectors.toSet())); + } + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/interfaces/UnifyTypeVisitor.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/interfaces/UnifyTypeVisitor.java new file mode 100644 index 0000000..2b02c53 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/interfaces/UnifyTypeVisitor.java @@ -0,0 +1,23 @@ +package de.dhbw.compiler.typeinference.unify.interfaces; + +import java.util.HashMap; + +import de.dhbw.compiler.typeinference.unify.model.ExtendsType; +import de.dhbw.compiler.typeinference.unify.model.FunNType; +import de.dhbw.compiler.typeinference.unify.model.PlaceholderType; +import de.dhbw.compiler.typeinference.unify.model.ReferenceType; +import de.dhbw.compiler.typeinference.unify.model.SuperType; + +public interface UnifyTypeVisitor { + + public ReferenceType visit(ReferenceType refty, T ht); + + public PlaceholderType visit(PlaceholderType phty, T ht); + + public FunNType visit(FunNType funnty, T ht); + + public SuperType visit(SuperType suty, T ht); + + public ExtendsType visit(ExtendsType extty, T ht); + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/ExtendsType.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/ExtendsType.java new file mode 100644 index 0000000..17eb29f --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/ExtendsType.java @@ -0,0 +1,96 @@ +package de.dhbw.compiler.typeinference.unify.model; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Set; + +import de.dhbw.compiler.typeinference.unify.interfaces.IFiniteClosure; +import de.dhbw.compiler.typeinference.unify.interfaces.UnifyTypeVisitor; + +/** + * An extends wildcard type "? extends T". + */ +public final class ExtendsType extends WildcardType { + + public UnifyType accept(UnifyTypeVisitor visitor, T ht) { + return visitor.visit(this, ht); + } + + /** + * Creates a new extends wildcard type. + * @param extendedType The extended type e.g. Integer in "? extends Integer" + */ + public ExtendsType(UnifyType extendedType) { + super("? extends " + extendedType.getName(), extendedType); + if (extendedType instanceof ExtendsType) { + System.out.print(""); + } + } + + /** + * The extended type e.g. Integer in "? extends Integer" + */ + public UnifyType getExtendedType() { + return wildcardedType; + } + + /** + * Sets the type parameters of the wildcarded type and returns a new extendstype that extends that type. + */ + @Override + public UnifyType setTypeParams(TypeParams newTp) { + UnifyType newType = wildcardedType.setTypeParams(newTp); + if(newType == wildcardedType) + return this; // Reduced the amount of objects created + return new ExtendsType(wildcardedType.setTypeParams(newTp)); + } + + @Override + Set smArg(IFiniteClosure fc, Set fBounded) { + return fc.smArg(this, fBounded); + } + + @Override + Set grArg(IFiniteClosure fc, Set fBounded) { + return fc.grArg(this, fBounded); + } + + @Override + UnifyType apply(Unifier unif) { + UnifyType newType = wildcardedType.apply(unif); + if(newType.hashCode() == wildcardedType.hashCode() && newType.equals(wildcardedType)) + return this; // Reduced the amount of objects created + return new ExtendsType(newType); + } + + @Override + public int hashCode() { + /* + * It is important that the prime that is added is different to the prime added in hashCode() of SuperType. + * Otherwise ? extends T and ? super T have the same hashCode() for every Type T. + */ + return wildcardedType.hashCode() + 229; + } + + @Override + public boolean equals(Object obj) { + if(!(obj instanceof ExtendsType)) + return false; + + if(obj.hashCode() != this.hashCode()) + return false; + + ExtendsType other = (ExtendsType) obj; + + + return other.getWildcardedType().equals(wildcardedType); + } + + @Override + public String toString() { + return "? extends " + wildcardedType; + } + + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/FiniteClosure.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/FiniteClosure.java new file mode 100644 index 0000000..9b418f7 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/FiniteClosure.java @@ -0,0 +1,806 @@ +package de.dhbw.compiler.typeinference.unify.model; + +import java.io.FileWriter; +import java.io.IOException; +import java.io.Writer; +import java.lang.reflect.Modifier; +import java.sql.Array; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.function.BiFunction; +import java.util.function.BinaryOperator; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +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.dhbw.compiler.core.JavaTXCompiler; +import de.dhbw.compiler.parser.SourceLoc; +import de.dhbw.compiler.parser.scope.JavaClassName; +import de.dhbw.compiler.syntaxtree.factory.UnifyTypeFactory; +import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbw.compiler.syntaxtree.type.TypePlaceholder; +import de.dhbw.compiler.typeinference.unify.MartelliMontanariUnify; + +import de.dhbw.compiler.typeinference.unify.Match; +import de.dhbw.compiler.typeinference.unify.TypeUnifyTask; +import de.dhbw.compiler.typeinference.unify.interfaces.IFiniteClosure; +import de.dhbw.compiler.typeinference.unify.interfaces.IUnify; +import de.dhbw.compiler.util.Pair; +import org.antlr.v4.runtime.Token; +import org.apache.commons.io.output.NullWriter; + +/** + * The finite closure for the type unification + * @author Florian Steurer + */ +public class FiniteClosure //extends Ordering //entfernt PL 2018-12-11 +implements IFiniteClosure { + + final JavaTXCompiler compiler; + + Writer logFile; + static Boolean log = false; + public void setLogTrue() { + log = true; + } + /** + * A map that maps every type to the node in the inheritance graph that contains that type. + */ + private HashMap> inheritanceGraph; + + /** + * A map that maps every typename to the nodes of the inheritance graph that contain a type with that name. + */ + private HashMap>> strInheritanceGraph; + + + /** + * The initial pairs of that define the inheritance tree + */ + private Set pairs; + + /** + * Hastable fuer die greater-Werte, damit sie nicht doppelt berechnet werden muessen + */ + Hashtable> greaterHash = new Hashtable<>(); + + /** + * Hastable fuer die smaller-Werte, damit sie nicht doppelt berechnet werden muessen + */ + Hashtable> smallerHash = new Hashtable<>(); + + /** + * Creates a new instance using the inheritance tree defined in the pairs. + */ + public FiniteClosure(Set pairs, Writer logFile, JavaTXCompiler compiler) { + this.compiler = compiler; + this.logFile = logFile; + this.pairs = new HashSet<>(pairs); + inheritanceGraph = new HashMap>(); + + // Build the transitive closure of the inheritance tree + for(UnifyPair pair : pairs) { + + /* + try { + logFile.write("Pair: " + pair + "\n"); + logFile.flush(); + } + catch (IOException e) { + System.err.println("no LogFile"); + } + */ + + if(pair.getPairOp() != PairOperator.SMALLER) + continue; + + //VERSUCH PL 18-02-06 + //koennte ggf. die FC reduzieren + //TO DO: Ueberpruefen, ob das sinnvll und korrekt ist + //if (!pair.getLhsType().getTypeParams().arePlaceholders() + // && !pair.getRhsType().getTypeParams().arePlaceholders()) + // continue; +; + // Add nodes if not already in the graph + if(!inheritanceGraph.containsKey(pair.getLhsType())) + inheritanceGraph.put(pair.getLhsType(), new Node(pair.getLhsType())); + if(!inheritanceGraph.containsKey(pair.getRhsType())) + inheritanceGraph.put(pair.getRhsType(), new Node(pair.getRhsType())); + + Node childNode = inheritanceGraph.get(pair.getLhsType()); + Node parentNode = inheritanceGraph.get(pair.getRhsType()); + + // Add edge + parentNode.addDescendant(childNode); + + // Add edges to build the transitive closure + parentNode.getPredecessors().stream().forEach(x -> x.addDescendant(childNode)); + childNode.getDescendants().stream().forEach(x -> x.addPredecessor(parentNode)); + + //PL eingefuegt 2020-05-07 File UnitTest InheritTest.java + this.inheritanceGraph.forEach((x,y) -> { if (y.getDescendants().contains(parentNode)) { y.addDescendant(childNode); y.addAllDescendant(childNode.getDescendants());}; + if (y.getPredecessors().contains(childNode)) { y.addPredecessor(parentNode); y.addAllPredecessor(parentNode.getPredecessors());};} ); + } + + // Build the alternative representation with strings as keys + strInheritanceGraph = new HashMap<>(); + for(UnifyType key : inheritanceGraph.keySet()) { + if(!strInheritanceGraph.containsKey(key.getName())) + strInheritanceGraph.put(key.getName(), new HashSet<>()); + + strInheritanceGraph.get(key.getName()).add(inheritanceGraph.get(key)); + } + } + + public FiniteClosure(Set constraints, Writer writer) { + this(constraints, writer, null); + } + + void testSmaller() { + UnifyType tq1, tq2, tq3; + tq1 = new ExtendsType(PlaceholderType.freshPlaceholder()); + List l1 = new ArrayList<>(); + List l2 = new ArrayList<>(); + l1.add(tq1); + tq2 = new ReferenceType("java.util.Vector", new TypeParams(l1)); + l2.add(tq2); + tq3 = new ReferenceType("java.util.Vector", new TypeParams(l2)); + Set smaller = smaller(tq3, new HashSet<>()); + } + + /** + * Returns all types of the finite closure that are subtypes of the argument. + * @return The set of subtypes of the argument. + */ + @Override + public Set smaller(UnifyType type, Set fBounded, Token position) { + + Set ret; + if ((ret = smallerHash.get(new hashKeyType(type))) != null) { + //System.out.println(greaterHash); + return new HashSet<>(ret); + } + + if(type instanceof FunNType) + return computeSmallerFunN((FunNType) type, fBounded); + + Set>> ts = new HashSet<>(); + ts.add(new Pair<>(type, fBounded)); + Set result = computeSmaller(ts); + smallerHash.put(new hashKeyType(type), result); + /* + try { + logFile.write("\ntype: " + type + "\nret: " + ret + "\nresult: " + result);//"smallerHash: " + greaterHash.toString()); + logFile.flush(); + } + catch (IOException e) { + System.err.println("no LogFile"); + }*/ + return result; + } + + /** + * Computes the smaller functions for every type except FunNTypes. + */ + private Set computeSmaller(Set>> types) { + Set>> result = new HashSet<>(); + + //PL 18-02-05 Unifier durch Matcher ersetzt + //IUnify unify = new MartelliMontanariUnify(); + Match match = new Match(); + + for(Pair> pt : types) { + UnifyType t = pt.getKey(); + Set fBounded = pt.getValue().get(); + + // if T = T' then T <* T' + try { + result.add(new Pair<>(t, fBounded)); + } + catch (StackOverflowError e) { + System.out.println(""); + } + + // if C<...> <* C<...> then ... (third case in definition of <*) + if(t.getTypeParams().size() > 0) { + ArrayList> paramCandidates = new ArrayList<>(); + for (int i = 0; i < t.getTypeParams().size(); i++) + paramCandidates.add(smArg(t.getTypeParams().get(i), fBounded)); + permuteParams(paramCandidates).forEach(x -> result.add(new Pair<>(t.setTypeParams(x), fBounded))); + } + + if(!strInheritanceGraph.containsKey(t.getName())) + continue; + + // if T <* T' then sigma(T) <* sigma(T') + Set> candidates = strInheritanceGraph.get(t.getName()); //cadidates= [???Node(java.util.Vector>)??? + // , Node(java.util.Vector) + //] + for(Node candidate : candidates) { + UnifyType theta2 = candidate.getContent(); + //PL 18-02-05 Unifier durch Matcher ersetzt ANFANG + ArrayList termList= new ArrayList(); + termList.add(new UnifyPair(theta2,t, PairOperator.EQUALSDOT)); + Optional optSigma = match.match(termList); + //PL 18-02-05 Unifier durch Matcher ersetzt ENDE + if(!optSigma.isPresent()) + continue; + + Unifier sigma = optSigma.get(); + sigma.swapPlaceholderSubstitutions(t.getTypeParams()); + + Set theta1Set = candidate.getContentOfDescendants(); + + for(UnifyType theta1 : theta1Set) + result.add(new Pair<>(theta1.apply(sigma), fBounded)); + } + } + + HashSet resut = result.stream().map(x -> x.getKey()).collect(Collectors.toCollection(HashSet::new)); + if(resut.equals(types.stream().map(x -> x.getKey()).collect(Collectors.toCollection(HashSet::new)))) + return resut; + return computeSmaller(result); + } + + /** + * Computes the smaller-Function for FunNTypes. + */ + private Set computeSmallerFunN(FunNType type, Set fBounded) { + Set result = new HashSet<>(); + + // if T = T' then T <=* T' + result.add(type); + + // Because real function types are implicitly variant + // it is enough to permute the params with the values of greater / smaller. + ArrayList> paramCandidates = new ArrayList<>(); + paramCandidates.add(smaller(type.getTypeParams().get(0), fBounded)); + for (int i = 1; i < type.getTypeParams().size(); i++) + paramCandidates.add(greater(type.getTypeParams().get(i), new HashSet<>())); + + permuteParams(paramCandidates).forEach(x -> result.add(type.setTypeParams(x))); + return result; + } + + /** + * Returns all types of the finite closure that are supertypes of the argument. + * @return The set of supertypes of the argument. + */ + @Override + //Eingefuegt PL 2018-05-24 F-Bounded Problematik + public Set greater(UnifyType type, Set fBounded, SourceLoc location) { + Set ret; + if ((ret = greaterHash.get(new hashKeyType(type))) != null) { + //System.out.println(greaterHash); + return new HashSet<>(ret); + } + + + if(type instanceof FunNType) { + return computeGreaterFunN((FunNType) type, fBounded); + } + + Set result = new HashSet<>(); + Set>> PairResultFBounded = new HashSet<>(); + + Match match = new Match(); + + + // if T = T' then T <=* T' + result.add(type); + if(!strInheritanceGraph.containsKey(type.getName())) + return result; + + // if T <* T' then sigma(T) <* sigma(T') + Set> candidates = strInheritanceGraph.get(type.getName()); + + /* + try { + if (log) logFile.write(candidates.toString()); + //log = false; + } + catch (IOException e) { + System.err.println("no LogFile"); + } + */ + + for(Node candidate : candidates) { + UnifyType theta1 = candidate.getContent(); + + //PL 18-04-05 Unifier durch Matcher ersetzt ANFANG + ArrayList termList= new ArrayList(); + termList.add(new UnifyPair(theta1,type, PairOperator.EQUALSDOT, location)); + Optional optSigma = match.match(termList); + //PL 18-04-05 Unifier durch Matcher ersetzt ENDE + if(!optSigma.isPresent()) { + continue; + } + Unifier sigma = optSigma.get(); + sigma.swapPlaceholderSubstitutionsReverse(theta1.getTypeParams()); + + Set fBoundedNew = new HashSet<>(fBounded); + fBoundedNew.add(theta1); + Set theta2Set = candidate.getContentOfPredecessors(); + //System.out.println(""); + for(UnifyType theta2 : theta2Set) { + result.add(theta2.apply(sigma)); + PairResultFBounded.add(new Pair<>(theta2.apply(sigma), fBoundedNew)); + } + } + /* + try { + if (log) logFile.write(PairResultFBounded.toString()); + log = false; + } + catch (IOException e) { + System.err.println("no LogFile"); + } + */ + for(Pair> pt : PairResultFBounded) { + UnifyType t = pt.getKey(); + Set lfBounded = pt.getValue().get(); + + // if C<...> <* C<...> then ... (third case in definition of <*) + //TypeParams typeparams = t.getTypeParams(); + if(t.getTypeParams().size() > 0) { + ArrayList> paramCandidates = new ArrayList<>(); + + for (int i = 0; i < t.getTypeParams().size(); i++) { + //UnifyType parai = t.getTypeParams().get(i); + int i_ef = i; + BiFunction f = (x,y) -> + { + ArrayList termList = new ArrayList(); + 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")) { + // System.out.println(""); + //} + BinaryOperator bo = (a,b) -> (a || b); + if (lfBounded.stream().reduce(false,f,bo)) { + //F-Bounded Endlosrekursion + HashSet res = new HashSet(); + paramCandidates.add(res); + } + else { + paramCandidates.add(grArg(t.getTypeParams().get(i), new HashSet<>(fBounded) )); + } + } + permuteParams(paramCandidates).forEach(x -> result.add(t.setTypeParams(x))); + //System.out.println(""); + } + } + + greaterHash.put(new hashKeyType(type), result); + /* + try { + logFile.write("\ntype: " + type + "\nret: " + ret + "\nresult: " + result);//"greaterHash: " + greaterHash.toString()); + logFile.flush(); + } + catch (IOException e) { + System.err.println("no LogFile"); + }*/ + return result; + } + + /* auskommentiert PL 2018-05-24 + /** + * Returns all types of the finite closure that are supertypes of the argument. + * @return The set of supertypes of the argument. + * + //@Override + public Set oldgreater(UnifyType type, Set fBounded) { + if(type instanceof FunNType) + return computeGreaterFunN((FunNType) type, fBounded); + + Set>> ts = new HashSet<>(); + ts.add(new Pair<>(type, fBounded)); + return computeGreater(ts); + } + + /** + * Computes the greater function for all types except function types. + * + protected Set computeGreater(Set>> types) { + Set>> result = new HashSet<>(); + + //PL 18-04-05 Unifier durch Matcher ersetzt + //IUnify unify = new MartelliMontanariUnify(); + Match match = new Match(); + + for(Pair> pt : types) { + UnifyType t = pt.getKey(); + Set fBounded = pt.getValue().get(); + // if T = T' then T <=* T' + result.add(pt); + + // if C<...> <* C<...> then ... (third case in definition of <*) + if(t.getTypeParams().size() > 0) { + ArrayList> paramCandidates = new ArrayList<>(); + for (int i = 0; i < t.getTypeParams().size(); i++) { + UnifyType parai = t.getTypeParams().get(i); + int i_ef = i; + BiFunction f = (x,y) -> + { + ArrayList termList = new ArrayList(); + termList.add(new UnifyPair(y,t.getTypeParams().get(i_ef), PairOperator.EQUALSDOT)); + return ((match.match(termList).isPresent()) || x); + }; + if (parai.getName().equals("java.lang.Integer")) { + System.out.println(""); + } + BinaryOperator bo = (a,b) -> (a || b); + if (fBounded.stream().reduce(false,f,bo)) continue; //F-Bounded Endlosrekursion + paramCandidates.add(grArg(t.getTypeParams().get(i), new HashSet<>(fBounded) )); + } + permuteParams(paramCandidates).forEach(x -> result.add(new Pair<>(t.setTypeParams(x), new HashSet<>(fBounded)))); + } + + if(!strInheritanceGraph.containsKey(t.getName())) + continue; + + // if T <* T' then sigma(T) <* sigma(T') + Set> candidates = strInheritanceGraph.get(t.getName()); + for(Node candidate : candidates) { + UnifyType theta1 = candidate.getContent(); + + //PL 18-04-05 Unifier durch Matcher ersetzt ANFANG + ArrayList termList= new ArrayList(); + termList.add(new UnifyPair(theta1,t, PairOperator.EQUALSDOT)); + Optional optSigma = match.match(termList); + //PL 18-04-05 Unifier durch Matcher ersetzt ENDE + if(!optSigma.isPresent()) + continue; + + Unifier sigma = optSigma.get(); + sigma.swapPlaceholderSubstitutionsReverse(theta1.getTypeParams()); + + Set fBoundedNew = new HashSet<>(fBounded); + fBoundedNew.add(theta1); + Set theta2Set = candidate.getContentOfPredecessors(); + + for(UnifyType theta2 : theta2Set) + result.add(new Pair<>(theta2.apply(sigma), fBoundedNew)); + } + + } + + HashSet resut = result.stream().map(x -> x.getKey()).collect(Collectors.toCollection(HashSet::new)); + System.out.println(resut); + if(resut.equals(types.stream().map(x -> x.getKey()).collect(Collectors.toCollection(HashSet::new)))) + return resut; + return computeGreater(result); + } + */ + + /** + * Computes the greater function for FunN-Types + */ + protected Set computeGreaterFunN(FunNType type, Set fBounded) { + Set result = new HashSet<>(); + + // if T = T' then T <=* T' + result.add(type); + + // Because real function types are implicitly variant + // it is enough to permute the params with the values of greater / smaller. + ArrayList> paramCandidates = new ArrayList<>(); + paramCandidates.add(greater(type.getTypeParams().get(0), new HashSet<>())); + for (int i = 1; i < type.getTypeParams().size(); i++) + paramCandidates.add(smaller(type.getTypeParams().get(i), fBounded)); + permuteParams(paramCandidates).forEach(x -> result.add(type.setTypeParams(x))); + return result; + } + + + @Override + public Set grArg(UnifyType type, Set fBounded) { + return type.grArg(this, fBounded); + } + + @Override + public Set grArg(ReferenceType type, Set fBounded) { + Set result = new HashSet(); + result.add(type); + smaller(type, fBounded).forEach(x -> result.add(new SuperType(x))); + greater(type,fBounded).forEach(x -> result.add(new ExtendsType(x))); + return result; + } + + @Override + public Set grArg(FunNType type, Set fBounded) { + Set result = new HashSet(); + result.add(type); + smaller(type, fBounded).forEach(x -> result.add(new SuperType(x))); + greater(type, fBounded).forEach(x -> result.add(new ExtendsType(x))); + return result; + } + + @Override + public Set grArg(ExtendsType type, Set fBounded) { + Set result = new HashSet(); + result.add(type); + UnifyType t = type.getExtendedType(); + greater(t, fBounded).forEach(x -> result.add(new ExtendsType(x))); + return result; + } + + @Override + public Set grArg(SuperType type, Set fBounded) { + Set result = new HashSet(); + result.add(type); + UnifyType t = type.getSuperedType(); + smaller(t, fBounded).forEach(x -> result.add(new SuperType(x))); + return result; + } + + @Override + public Set grArg(PlaceholderType type, Set fBounded) { + HashSet result = new HashSet<>(); + result.add(type); + return result; + } + + @Override + public Set smArg(UnifyType type, Set fBounded) { + return type.smArg(this, fBounded); + } + + @Override + public Set smArg(ReferenceType type, Set fBounded) { + Set result = new HashSet(); + result.add(type); + return result; + } + + @Override + public Set smArg(FunNType type, Set fBounded) { + Set result = new HashSet(); + result.add(type); + return result; + } + + @Override + public Set smArg(ExtendsType type, Set fBounded) { + Set result = new HashSet(); + result.add(type); + UnifyType t = type.getExtendedType(); + result.add(t); + smaller(t, fBounded).forEach(x -> { + result.add(new ExtendsType(x)); + result.add(x); + }); + return result; + } + + + @Override + public Set smArg(SuperType type, Set fBounded) { + Set result = new HashSet(); + result.add(type); + UnifyType t = type.getSuperedType(); + result.add(t); +//*** ACHTUNG das koennte FALSCH sein PL 2018-05-23 evtl. HashSet durch smArg durchschleifen + greater(t, fBounded).forEach(x -> { + result.add(new SuperType(x)); + result.add(x); + }); + return result; + } + + @Override + public Set smArg(PlaceholderType type, Set fBounded) { + HashSet result = new HashSet<>(); + result.add(type); + return result; + } + + @Override + public Set getAllTypesByName(String typeName) { + if(!strInheritanceGraph.containsKey(typeName)) + return new HashSet<>(); + return strInheritanceGraph.get(typeName).stream().map(x -> x.getContent()).collect(Collectors.toCollection(HashSet::new)); + } + + @Override + public Optional getLeftHandedType(String typeName) { + if(!strInheritanceGraph.containsKey(typeName)) + return Optional.empty(); + + for(UnifyPair pair : pairs) + if(pair.getLhsType().getName().equals(typeName) && pair.getLhsType().typeParams.arePlaceholders()) + return Optional.of(pair.getLhsType()); + + return Optional.empty(); + } + + @Override + public Optional getRightHandedFunctionalInterfaceType(String typeName) { + if(!strInheritanceGraph.containsKey(typeName)) + return Optional.empty(); + + for(UnifyPair pair : pairs) + if(pair.getRhsType().getName().equals(typeName)) + return Optional.of(pair.getRhsType()); + + return Optional.empty(); + } + + @Override + public Set getAncestors(UnifyType t) { + if(!inheritanceGraph.containsKey(t)) + return new HashSet<>(); + Set result = inheritanceGraph.get(t).getContentOfPredecessors(); + result.add(t); + return result; + } + + @Override + public Set getChildren(UnifyType t) { + if(!inheritanceGraph.containsKey(t)) + return new HashSet<>(); + Set result = inheritanceGraph.get(t).getContentOfDescendants(); + result.add(t); + return result; + } + + /** + * Takes a set of candidates for each position and computes all possible permutations. + * @param candidates The length of the list determines the number of type params. Each set + * contains the candidates for the corresponding position. + */ + protected Set permuteParams(ArrayList> candidates) { + Set result = new HashSet<>(); + permuteParams(candidates, 0, result, new UnifyType[candidates.size()]); + return result; + } + + /** + * Takes a set of candidates for each position and computes all possible permutations. + * @param candidates The length of the list determines the number of type params. Each set + * contains the candidates for the corresponding position. + * @param idx Idx for the current permutatiton. + * @param result Set of all permutations found so far + * @param current The permutation of type params that is currently explored + */ + protected void permuteParams(ArrayList> candidates, int idx, Set result, UnifyType[] current) { + if(candidates.size() == idx) { + result.add(new TypeParams(Arrays.copyOf(current, current.length))); + return; + } + + Set localCandidates = candidates.get(idx); + + for(UnifyType t : localCandidates) { + current[idx] = t; + permuteParams(candidates, idx+1, result, current); + } + } + + @Override + public String toString(){ + return this.inheritanceGraph.toString(); + } + + /* entfernt PL 2018-12-11 + public int compare (UnifyType left, UnifyType right) { + return compare(left, right, PairOperator.SMALLERDOT); + } + */ + + public int compare (UnifyType left, UnifyType right, PairOperator pairop) { + try {logFile.write("left: "+ left + " right: " + right + " pairop: " + pairop +"\n");} catch (IOException ie) {} + if (left.getName().equals("Matrix") || right.getName().equals("Matrix")) + System.out.println(""); + /* + pairop = PairOperator.SMALLERDOTWC; + List al = new ArrayList<>(); + PlaceholderType xx =new PlaceholderType("xx"); + al.add(xx); + left = new ExtendsType(new ReferenceType("Vector", new TypeParams(al))); + + List alr = new ArrayList<>(); + UnifyType exx = new ExtendsType(xx); + alr.add(exx); + right = new ExtendsType(new ReferenceType("Vector", new TypeParams(alr))); + */ + /* + List al = new ArrayList<>(); + PlaceholderType xx =new PlaceholderType("xx"); + al.add(xx); + left = new ExtendsType(xx); + right = xx; + */ + /* + List al = new ArrayList<>(); + PlaceholderType xx =new PlaceholderType("xx"); + PlaceholderType yy =new PlaceholderType("yy"); + al.add(xx); + left = yy; + right = new ExtendsType(xx); + */ + //Die Faelle abfangen, bei den Variablen verglichen werden PL 2018-12-11 + UnifyType ex; + if (left instanceof PlaceholderType) { + if ((right instanceof WildcardType) + && ((ex = ((WildcardType)right).wildcardedType) instanceof PlaceholderType) + && ((PlaceholderType)left).getName().equals(((PlaceholderType)ex).getName())) {// a <.? ? extends a oder a <.? ? super a + return -1; + } + else { + return 0; + } + } + if (right instanceof PlaceholderType) {//&& (left instanceof WildcardType)) {PL geloescht 2019-01-15 analog zu oben + if ((left instanceof WildcardType) //PL eingefuegt 2019-01-15 analog zu oben + && ((ex = ((WildcardType)left).wildcardedType) instanceof PlaceholderType) + && ((PlaceholderType)right).getName().equals(((PlaceholderType)ex).getName())) {// ? extends a <. a oder ? super a <. a + return 1; + } + else { + return 0; + } + } + UnifyPair up = new UnifyPair(left, right, pairop); + TypeUnifyTask unifyTask = new TypeUnifyTask(); + HashSet hs = new HashSet<>(); + hs.add(up); + Set smallerRes = unifyTask.applyTypeUnificationRules(hs, this); + + //if (left.getName().equals("Vector") || right.getName().equals("AbstractList")) + {try { + logFile.write("\nsmallerRes: " + smallerRes);//"smallerHash: " + greaterHash.toString()); + logFile.flush(); + } + catch (IOException e) { + System.err.println("no LogFile");}} + + //Gleichungen der Form a <./=. Theta oder Theta <./=. a oder a <./=. b sind ok. + Predicate delFun = x -> !((x.getLhsType() instanceof PlaceholderType || + x.getRhsType() instanceof PlaceholderType) + && !((x.getLhsType() instanceof WildcardType) && //? extends/super a <.? a + ((WildcardType)x.getLhsType()).getWildcardedType().equals(x.getRhsType())) + ); + long smallerLen = smallerRes.stream().filter(delFun).count(); + try { + logFile.write("\nsmallerLen: " + smallerLen +"\n"); + logFile.flush(); + } + catch (IOException e) { + System.err.println("no LogFile");} + if (smallerLen == 0) return -1; + else { + up = new UnifyPair(right, left, pairop); + //TypeUnifyTask unifyTask = new TypeUnifyTask(); + hs = new HashSet<>(); + hs.add(up); + Set greaterRes = unifyTask.applyTypeUnificationRules(hs, this); + + //if (left.getName().equals("Vector") || right.getName().equals("AbstractList")) + {try { + logFile.write("\ngreaterRes: " + greaterRes);//"smallerHash: " + greaterHash.toString()); + logFile.flush(); + } + catch (IOException e) { + System.err.println("no LogFile");}} + + //Gleichungen der Form a <./=. Theta oder Theta <./=. a oder a <./=. b sind ok. + long greaterLen = greaterRes.stream().filter(delFun).count(); + if (greaterLen == 0) return 1; + else { + //try {logFile.write("0 left: "+ left + " right: " + right + " pairop: " + pairop);} catch (IOException ie) {} + return 0; + } + } + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/FunInterfaceType.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/FunInterfaceType.java new file mode 100644 index 0000000..f2a7047 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/FunInterfaceType.java @@ -0,0 +1,49 @@ +package de.dhbw.compiler.typeinference.unify.model; + +import de.dhbw.compiler.parser.scope.JavaClassName; +import de.dhbw.compiler.syntaxtree.factory.UnifyTypeFactory; + +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class FunInterfaceType extends ReferenceType { + final List intfArgTypes; + final UnifyType intfReturnType; + final List generics; + + public FunInterfaceType(String name, TypeParams params, List intfArgTypes, UnifyType intfReturnType, List generics) { + super(name, params); + this.intfArgTypes = intfArgTypes; + this.intfReturnType = intfReturnType; + this.generics = generics; + } + + public List getFunctionalInterfaceTypeArguments(UnifyType t) { + if (t instanceof FunNType) { + var ret = new ArrayList(); + if (t.getTypeParams().size() > 0) { + ret.add(t.getTypeParams().get(t.getTypeParams().size() - 1)); + ret.addAll(Arrays.asList(t.getTypeParams().get()).subList(0, t.getTypeParams().size() - 1)); + } + return ret; + } + + var args = new ArrayList(); + args.add(intfReturnType); + args.addAll(intfArgTypes); + + // TODO There might be a better way of dealing with this + var i = 0; + for (var generic : generics) { + for (var j = 0; j < args.size(); j++) { + if (args.get(j).getName().equals(generic)) + args.set(j, t.getTypeParams().get(i)); + } + i += 1; + } + + return args; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/FunNType.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/FunNType.java new file mode 100644 index 0000000..7676078 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/FunNType.java @@ -0,0 +1,103 @@ +package de.dhbw.compiler.typeinference.unify.model; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Set; + +import de.dhbw.compiler.typeinference.unify.interfaces.IFiniteClosure; +import de.dhbw.compiler.typeinference.unify.interfaces.UnifyTypeVisitor; + +/** + * A real function type in java. + * @author Florian Steurer + */ +public class FunNType extends UnifyType { + + public UnifyType accept(UnifyTypeVisitor visitor, T ht) { + return visitor.visit(this, ht); + } + + /** + * Creates a FunN-Type with the specified TypeParameters. + */ + protected FunNType(TypeParams p) { + super("Fun"+(p.size()-1)+"$$", p); + } + + /** + * Creates a new FunNType. + * @param tp The parameters of the type. + * @return A FunNType. + * @throws IllegalArgumentException is thrown when there are to few type parameters or there are wildcard-types. + */ + public static FunNType getFunNType(TypeParams tp) throws IllegalArgumentException { + if(tp.size() == 0) + throw new IllegalArgumentException("FunNTypes need at least one type parameter"); + for(UnifyType t : tp) + if(t instanceof WildcardType) + throw new IllegalArgumentException("Invalid TypeParams for a FunNType: " + tp); + return new FunNType(tp); + } + + /** + * Returns the degree of the function type, e.g. 2 for FunN. + */ + public int getN() { + return typeParams.size()-1; + } + + @Override + public UnifyType setTypeParams(TypeParams newTp) { + if(newTp.hashCode() == typeParams.hashCode() && newTp.equals(typeParams)) + return this; + return getFunNType(newTp); + } + + @Override + Set smArg(IFiniteClosure fc, Set fBounded) { + return fc.smArg(this, fBounded); + } + + @Override + Set grArg(IFiniteClosure fc, Set fBounded) { + return fc.grArg(this, fBounded); + } + + @Override + UnifyType apply(Unifier unif) { + // TODO this bypasses the validation of the type parameters. + // Wildcard types can be unified into FunNTypes. + TypeParams newParams = typeParams.apply(unif); + if(newParams.hashCode() == typeParams.hashCode() && newParams.equals(typeParams)) + return this; + + return new FunNType(newParams); + } + + @Override + public Boolean wrongWildcard() { + return (new ArrayList(Arrays.asList(getTypeParams() + .get())).stream().filter(x -> (x instanceof WildcardType)).findFirst().isPresent()); + } + + @Override + public int hashCode() { + return 181 + typeParams.hashCode(); + } + + + @Override + public boolean equals(Object obj) { + if(!(obj instanceof FunNType)) + return false; + + if(obj.hashCode() != this.hashCode()) + return false; + + FunNType other = (FunNType) obj; + + return other.getTypeParams().equals(typeParams); + } + +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/Node.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/Node.java new file mode 100644 index 0000000..748cac0 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/Node.java @@ -0,0 +1,118 @@ +package de.dhbw.compiler.typeinference.unify.model; + +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * A node of a directed graph. + * @author Florian Steurer + * + * @param The type of the content of the node. + */ +class Node { + + /** + * The content of the node. + */ + private T content; + + /** + * The set of predecessors + */ + private HashSet> predecessors = new HashSet<>(); + + /** + * The set of descendants + */ + private HashSet> descendants = new HashSet<>(); + + /** + * Creates a node containing the specified content. + */ + public Node(T content) { + this.content = content; + } + + /** + * Adds a directed edge from this node to the descendant (this -> descendant) + */ + public void addDescendant(Node descendant) { + if(descendants.contains(descendant)) + return; + + descendants.add(descendant); + descendant.addPredecessor(this); + } + + /** + * Adds some directed edges from this node to the descendant (this -> descendant) + */ + public void addAllDescendant(Set> allDescendants) { + for(Node descendant: allDescendants) { + addDescendant(descendant); + } + } + + /** + * Adds a directed edge from the predecessor to this node (predecessor -> this) + */ + public void addPredecessor(Node predecessor) { + if(predecessors.contains(predecessor)) + return; + + predecessors.add(predecessor); + predecessor.addDescendant(this); + } + + /** + * Adds some directed edges from the predecessor to this node (predecessor -> this) + */ + public void addAllPredecessor(Set> allPredecessors) { + for(Node predecessor: allPredecessors) { + addPredecessor(predecessor); + } + } + + /** + * The content of this node. + */ + public T getContent() { + return content; + } + + /** + * Returns all predecessors (nodes that have a directed edge to this node) + */ + public Set> getPredecessors() { + return predecessors; + } + + /** + * Returns all descendants. All nodes M, where there is a edge from this node to the node M. + * @return + */ + public Set> getDescendants() { + return descendants; + } + + /** + * Retrieves the content of all descendants. + */ + public Set getContentOfDescendants() { + return descendants.stream().map(x -> x.getContent()).collect(Collectors.toSet()); + } + + /** + * Retrieves the content of all predecessors. + */ + public Set getContentOfPredecessors() { + return predecessors.stream().map(x -> x.getContent()).collect(Collectors.toSet()); + } + + @Override + public String toString() { + return "Elem: Node(" + content.toString() + ")\nPrec: " + getContentOfPredecessors().toString() + + "\nDesc: " + getContentOfDescendants().toString() + "\n\n"; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/OrderingExtend.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/OrderingExtend.java new file mode 100644 index 0000000..6af7928 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/OrderingExtend.java @@ -0,0 +1,89 @@ +package de.dhbw.compiler.typeinference.unify.model; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +public abstract class OrderingExtend extends com.google.common.collect.Ordering { + + public List maxElements(Iterable iterable) { + ArrayList ret = new ArrayList<>(); + while (iterable.iterator().hasNext()) { + Set believe = new HashSet<>(); + + T max = max(iterable); + ret.add(max); + + Iterator it = iterable.iterator(); + while (it.hasNext()) { + T elem = it.next(); + if (!(compare(max, elem) == 1) && !max.equals(elem)) { + believe.add(elem); + } + } + iterable = believe; + } + return ret; + } + + public List minElements(Iterable iterable) { + ArrayList ret = new ArrayList<>(); + while (iterable.iterator().hasNext()) { + Set believe = new HashSet<>(); + + T min = min(iterable); + ret.add(min); + + Iterator it = iterable.iterator(); + while (it.hasNext()) { + T elem = it.next(); + if (!(compare(min, elem) == -1) && !min.equals(elem)) { + believe.add(elem); + } + } + iterable = believe; + } + return ret; + } + + + public List smallerEqThan(T elem, Iterable iterable) { + List ret = smallerThan(elem, iterable); + ret.add(elem); + return ret; + + } + + public List smallerThan(T elem, Iterable iterable) { + ArrayList ret = new ArrayList<>(); + Iterator it = iterable.iterator(); + while (it.hasNext()) { + T itElem = it.next(); + if (!itElem.equals(elem) && compare(elem, itElem) == 1) { + ret.add(itElem); + } + } + return ret; + } + + public List greaterEqThan(T elem, Iterable iterable) { + List ret = greaterThan(elem, iterable); + ret.add(elem); + return ret; + + } + + public List greaterThan(T elem, Iterable iterable) { + ArrayList ret = new ArrayList<>(); + Iterator it = iterable.iterator(); + while (it.hasNext()) { + T itElem = it.next(); + if (!itElem.equals(elem) && (compare(elem, itElem) == -1)) { + ret.add(itElem); + } + } + return ret; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/OrderingUnifyPair.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/OrderingUnifyPair.java new file mode 100644 index 0000000..3c1e2a1 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/OrderingUnifyPair.java @@ -0,0 +1,457 @@ +package de.dhbw.compiler.typeinference.unify.model; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.function.BinaryOperator; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import com.google.common.collect.Ordering; + +import de.dhbw.compiler.typeinference.unify.Match; +import de.dhbw.compiler.typeinference.unify.TypeUnifyTask; +import de.dhbw.compiler.typeinference.unify.interfaces.IFiniteClosure; +import de.dhbw.compiler.util.Pair; + + + +public class OrderingUnifyPair extends OrderingExtend> { + + protected IFiniteClosure fc; + + public OrderingUnifyPair(IFiniteClosure fc) { + this.fc = fc; + } + + /* + * vergleicht Paare (a =. Theta) und (a =. Theta') + * in dem compare(Theta, Theta') aufgerufen wird. + */ + public int compareEq (UnifyPair left, UnifyPair right) { + try { + //if (left.getRhsType() instanceof WildcardType || right.getRhsType() instanceof WildcardType) {//PL 2019-01-12 ausgetauscht + if (((PlaceholderType)left.getLhsType()).isInnerType() && ((PlaceholderType)right.getLhsType()).isInnerType()) { + return fc.compare(left.getRhsType(), right.getRhsType(), PairOperator.SMALLERDOTWC); + } + else { + return fc.compare(left.getRhsType(), right.getRhsType(), PairOperator.SMALLERDOT); + }} + catch (ClassCastException e) { + try { + ((FiniteClosure)fc).logFile.write("ClassCastException: " + left.toString() + " " + left.getGroundBasePair() + "\n\n"); + ((FiniteClosure)fc).logFile.flush(); + } + catch (IOException ie) { + } + return -99; + } + } + + /* + public int compareEq (UnifyPair left, UnifyPair right) { + if (left == null || right == null) + System.out.println("Fehler"); + if (left.getLhsType() instanceof PlaceholderType) { + return fc.compare(left.getRhsType(), right.getRhsType(), left.getPairOp()); + } + else { + return fc.compare(left.getLhsType(), right.getLhsType(), left.getPairOp()); + } + } + */ + + public Pair> compare (UnifyType left, UnifyType right) { + UnifyPair up; + if (left instanceof WildcardType || right instanceof WildcardType) { + up = new UnifyPair(left, right, PairOperator.SMALLERDOTWC); + if (((left instanceof ExtendsType) + && (((ExtendsType)left).getExtendedType().getName().equals("java.util.Vector")) + && (((ReferenceType)((ExtendsType)left).getExtendedType()).getTypeParams().iterator().next() instanceof ExtendsType)) || + ((right instanceof ExtendsType) + && (((ExtendsType)right).getExtendedType().getName().equals("java.util.Vector")) + && (((ReferenceType)((ExtendsType)right).getExtendedType()).getTypeParams().iterator().next() instanceof ExtendsType))) + { + System.out.println(""); + } + if (((right instanceof SuperType) && (((SuperType)right).getSuperedType().getName().equals("java.lang.Object"))) + ||((left instanceof SuperType) && (((SuperType)left).getSuperedType().getName().equals("java.lang.Object")))) +{ + System.out.println(""); + } + } + else { + up = new UnifyPair(left, right, PairOperator.SMALLERDOT); + } + TypeUnifyTask unifyTask = new TypeUnifyTask(); + HashSet hs = new HashSet<>(); + hs.add(up); + Set smallerRes = unifyTask.applyTypeUnificationRules(hs, fc); + long smallerLen = smallerRes.stream().filter(x -> !(x.getLhsType() instanceof PlaceholderType && x.getRhsType() instanceof PlaceholderType)).count(); + if (smallerLen == 0) return new Pair<>(-1, smallerRes); + else { + if (left instanceof WildcardType || right instanceof WildcardType) { + up = new UnifyPair(right, left, PairOperator.SMALLERDOTWC); + if (((left instanceof ExtendsType) + && (((ExtendsType)left).getExtendedType().getName().equals("java.util.Vector")) + && (((ReferenceType)((ExtendsType)left).getExtendedType()).getTypeParams().iterator().next() instanceof ExtendsType)) || + ((right instanceof ExtendsType) + && (((ExtendsType)right).getExtendedType().getName().equals("java.util.Vector")) + && (((ReferenceType)((ExtendsType)right).getExtendedType()).getTypeParams().iterator().next() instanceof ExtendsType))) + { + System.out.println(""); + } + if (right instanceof SuperType) + { + System.out.println(""); + } + } + else { + up = new UnifyPair(right, left, PairOperator.SMALLERDOT); + } + //TypeUnifyTask unifyTask = new TypeUnifyTask(); + hs = new HashSet<>(); + hs.add(up); + Set greaterRes = unifyTask.applyTypeUnificationRules(hs, fc); + long greaterLen = greaterRes.stream().filter(x -> !(x.getLhsType() instanceof PlaceholderType && x.getRhsType() instanceof PlaceholderType)).count(); + if (greaterLen == 0) return new Pair<>(1, greaterRes); + else return new Pair<>(0, new HashSet<>()); + } + } + + /* TODO muss noch verifiziert werden PL 2018-03-21 + * (non-Javadoc) + * fuehrt zu Fehlern bei Arrays.sort (contract nicht erfuellt) + * @see com.google.common.collect.Ordering#compare(java.lang.Object, java.lang.Object) + */ + public int compare (Set leftpara, Set rightpara) { + + Set left = new HashSet<>(leftpara); + Set right = new HashSet<>(rightpara); + + /* + //pairop = PairOperator.SMALLERDOTWC; + List al = new ArrayList<>(); + PlaceholderType xx = PlaceholderType.freshPlaceholder(); + al.add(xx); + UnifyType t1 = new ExtendsType(new ReferenceType("Vector", new TypeParams(al))); + + //PlaceholderType yy =new PlaceholderType("yy"); + List alr = new ArrayList<>(); + UnifyType exx = new ExtendsType(xx); + alr.add(exx); + UnifyType t2 = new ExtendsType(new ReferenceType("Vector", new TypeParams(alr))); + + PlaceholderType a = PlaceholderType.freshPlaceholder(); + a.setInnerType(true); + UnifyPair p1 = new UnifyPair(a, t1, PairOperator.SMALLERDOTWC); + PlaceholderType b = PlaceholderType.freshPlaceholder(); + b.setInnerType(true); + UnifyPair p2 = new UnifyPair(b, t2, PairOperator.SMALLERDOTWC); + + List al3 = new ArrayList<>(); + al3.add(a); + + List al4 = new ArrayList<>(); + al4.add(b); + + UnifyPair p3 = new UnifyPair(new PlaceholderType("c"), new ReferenceType("Vector", new TypeParams(al3)), PairOperator.EQUALSDOT); + UnifyPair p4 = new UnifyPair(new PlaceholderType("c"), new ReferenceType("Vector", new TypeParams(al4)), PairOperator.EQUALSDOT); + + right = new HashSet<>(); + right.add(p1); + right.add(p3); + left = new HashSet<>(); + left.add(p2); + left.add(p4); + */ + + + Set lefteq = left.stream() + .filter(x -> (x.getLhsType() instanceof PlaceholderType && x.getPairOp() == PairOperator.EQUALSDOT)) + .collect(Collectors.toCollection(HashSet::new)); + Set righteq = right.stream() + .filter(x -> (x.getLhsType() instanceof PlaceholderType && x.getPairOp() == PairOperator.EQUALSDOT)) + .collect(Collectors.toCollection(HashSet::new)); + Set leftle = left.stream() + .filter(x -> ((x.getLhsType() instanceof PlaceholderType || x.getRhsType() instanceof PlaceholderType) + && x.getPairOp() == PairOperator.SMALLERDOT)) + .collect(Collectors.toCollection(HashSet::new)); + Set rightle = right.stream() + .filter(x -> ((x.getLhsType() instanceof PlaceholderType || x.getRhsType() instanceof PlaceholderType) + && x.getPairOp() == PairOperator.SMALLERDOT)) + .collect(Collectors.toCollection(HashSet::new)); + Set leftlewc = left.stream() + .filter(x -> ((x.getLhsType() instanceof PlaceholderType || x.getRhsType() instanceof PlaceholderType) + && x.getPairOp() == PairOperator.SMALLERDOTWC)) + .collect(Collectors.toCollection(HashSet::new)); + Set rightlewc = right.stream() + .filter(x -> ((x.getLhsType() instanceof PlaceholderType || x.getRhsType() instanceof PlaceholderType) + && x.getPairOp() == PairOperator.SMALLERDOTWC)) + .collect(Collectors.toCollection(HashSet::new)); + //System.out.println(left.toString()); + //Fall 2 + //if (lefteq.iterator().next().getLhsType().getName().equals("AJO")) { + // System.out.print(""); + //} + + //ODER-CONSTRAINT + Set leftBase = left.stream().map(x -> x.getGroundBasePair()).collect(Collectors.toCollection(HashSet::new)); + Set rightBase = right.stream().map(x -> x.getGroundBasePair()).collect(Collectors.toCollection(HashSet::new)); + + Set lefteqOder = left.stream() + .filter(x -> { UnifyPair y = x.getGroundBasePair(); + /*try { + ((FiniteClosure)fc).logFile.write("leftBase: " + leftBase.toString() +"\n"); + ((FiniteClosure)fc).logFile.write("rightBase: " + rightBase.toString() +"\n\n"); + ((FiniteClosure)fc).logFile.write("left: " + left.toString() +"\n"); + ((FiniteClosure)fc).logFile.write("right: " + right.toString() +"\n\n"); + ((FiniteClosure)fc).logFile.write("y: " + y.toString() +"\n"); + ((FiniteClosure)fc).logFile.write("y.getLhsType() : " + y.getLhsType() .toString() +"\n\n"); + ((FiniteClosure)fc).logFile.write("y.getRhsType(): " + y.getRhsType().toString() +"\n"); + ((FiniteClosure)fc).logFile.write("x.getPairOp(): " + x.getPairOp().toString() +"\n\n"); + } + catch (IOException ie) { + } */ + return (y.getLhsType() instanceof PlaceholderType && + !(y.getRhsType() instanceof PlaceholderType) && + x.getPairOp() == PairOperator.EQUALSDOT);}) + .collect(Collectors.toCollection(HashSet::new)); + left.removeAll(lefteqOder); + Set righteqOder = right.stream() + .filter(x -> { UnifyPair y = x.getGroundBasePair(); + return (y.getLhsType() instanceof PlaceholderType && + !(y.getRhsType() instanceof PlaceholderType) && + x.getPairOp() == PairOperator.EQUALSDOT);}) + .collect(Collectors.toCollection(HashSet::new)); + right.removeAll(righteqOder); + Set lefteqRet = left.stream() + .filter(x -> { UnifyPair y = x.getGroundBasePair(); + return (y.getRhsType() instanceof PlaceholderType && + ((PlaceholderType)y.getRhsType()).getOrCons() == (byte)-1);}) + .collect(Collectors.toCollection(HashSet::new)); + left.removeAll(lefteqRet); + Set righteqRet = right.stream() + .filter(x -> { UnifyPair y = x.getGroundBasePair(); + return (y.getRhsType() instanceof PlaceholderType && + ((PlaceholderType)y.getRhsType()).getOrCons() == (byte)-1);}) + .collect(Collectors.toCollection(HashSet::new)); + right.removeAll(righteqRet); + Set leftleOder = left.stream() + .filter(x -> (x.getPairOp() == PairOperator.SMALLERDOT)) + .collect(Collectors.toCollection(HashSet::new)); + Set rightleOder = right.stream() + .filter(x -> (x.getPairOp() == PairOperator.SMALLERDOT)) + .collect(Collectors.toCollection(HashSet::new)); + + /* + synchronized(this) { + try { + ((FiniteClosure)fc).logFile.write("leftBase: " + leftBase.toString() +"\n"); + ((FiniteClosure)fc).logFile.write("rightBase: " + rightBase.toString() +"\n\n"); + ((FiniteClosure)fc).logFile.write("left: " + left.toString() +"\n"); + ((FiniteClosure)fc).logFile.write("right: " + right.toString() +"\n\n"); + ((FiniteClosure)fc).logFile.write("lefteqOder: " + lefteqOder.toString() +"\n"); + ((FiniteClosure)fc).logFile.write("righteqOder: " + righteqOder.toString() +"\n\n"); + ((FiniteClosure)fc).logFile.write("lefteqRet: " + lefteqRet.toString() +"\n"); + ((FiniteClosure)fc).logFile.write("righteqRet: " + righteqRet.toString() +"\n\n"); + ((FiniteClosure)fc).logFile.write("leftleOder: " + leftleOder.toString() +"\n"); + ((FiniteClosure)fc).logFile.write("rightleOder: " + rightleOder.toString() +"\n\n"); + ((FiniteClosure)fc).logFile.flush(); + } + catch (IOException ie) { + } + } + */ + + + Integer compareEq; + if (lefteqOder.size() == 1 && righteqOder.size() == 1 && lefteqRet.size() == 1 && righteqRet.size() == 1) { + Match m = new Match(); + if ((compareEq = compareEq(lefteqOder.iterator().next().getGroundBasePair(), righteqOder.iterator().next().getGroundBasePair())) == -1) { + ArrayList matchList = + rightleOder.stream().map(x -> { + UnifyPair leftElem = leftleOder.stream() + .filter(y -> y.getGroundBasePair().getLhsType().equals(x.getGroundBasePair().getLhsType())) + .findAny().get(); + return new UnifyPair(x.getRhsType(), leftElem.getRhsType(), PairOperator.EQUALSDOT);}) + .collect(Collectors.toCollection(ArrayList::new)); + if (m.match(matchList).isPresent()) { + //try { ((FiniteClosure)fc).logFile.write("result1: -1 \n\n"); } catch (IOException ie) {} + return -1; + } + else { + //try { ((FiniteClosure)fc).logFile.write("result1: 0 \n\n"); } catch (IOException ie) {} + return 0; + } + } else if (compareEq == 1) { + ArrayList matchList = + leftleOder.stream().map(x -> { + UnifyPair rightElem = rightleOder.stream() + .filter(y -> + y.getGroundBasePair().getLhsType().equals(x.getGroundBasePair().getLhsType())) + .findAny().get(); + return new UnifyPair(x.getRhsType(), rightElem.getRhsType(), PairOperator.EQUALSDOT);}) + .collect(Collectors.toCollection(ArrayList::new)); + if (m.match(matchList).isPresent()) { + //try { ((FiniteClosure)fc).logFile.write("result2: 1 \n\n"); } catch (IOException ie) {} + return 1; + } + else { + //try { ((FiniteClosure)fc).logFile.write("result2: 0 \n\n"); } catch (IOException ie) {} + return 0; + } + } else { + /* + synchronized(this) { + try { + ((FiniteClosure)fc).logFile.write("leftBase: " + leftBase.toString() +"\n"); + ((FiniteClosure)fc).logFile.write("rightBase: " + rightBase.toString() +"\n\n"); + ((FiniteClosure)fc).logFile.write("left: " + left.toString() +"\n"); + ((FiniteClosure)fc).logFile.write("right: " + right.toString() +"\n\n"); + ((FiniteClosure)fc).logFile.write("lefteqOder: " + lefteqOder.toString() +"\n"); + ((FiniteClosure)fc).logFile.write("righteqOder: " + righteqOder.toString() +"\n\n"); + ((FiniteClosure)fc).logFile.write("lefteqRet: " + lefteqRet.toString() +"\n"); + ((FiniteClosure)fc).logFile.write("righteqRet: " + righteqRet.toString() +"\n\n"); + ((FiniteClosure)fc).logFile.write("leftleOder: " + leftleOder.toString() +"\n"); + ((FiniteClosure)fc).logFile.write("rightleOder: " + rightleOder.toString() +"\n\n"); + ((FiniteClosure)fc).logFile.write("result3: 0 \n\n"); + ((FiniteClosure)fc).logFile.flush(); + } + catch (IOException ie) { + } + } + */ + return 0; + } + } + + + if (lefteq.size() == 1 && lefteq.iterator().next().getRhsType() instanceof ExtendsType && leftle.size() == 1 && righteq.size() == 0 && rightle.size() == 1) { + return 1; + } + //Fall 2 + if (lefteq.size() == 0 && leftle.size() == 1 && righteq.size() == 1 && righteq.iterator().next().getRhsType() instanceof ExtendsType && rightle.size() == 1) { + return -1; + } + //Fall 3 + if (lefteq.size() == 1 && lefteq.iterator().next().getRhsType() instanceof SuperType && leftle.size() == 1 && righteq.size() == 0 && rightle.size() == 1) { + return -1; + } + //Fall 3 + if (lefteq.size() == 0 && leftle.size() == 1 && righteq.size() == 1 && righteq.iterator().next().getRhsType() instanceof SuperType && rightle.size() == 1) { + return 1; + } + //Fall 5 + if (lefteq.size() == 1 && leftle.size() == 0 && righteq.size() == 1 && rightle.size() == 1) { + return -1; + } + //Fall 5 + if (lefteq.size() == 1 && leftle.size() == 1 && righteq.size() == 1 && rightle.size() == 0) { + return 1; + } + //Fall 5 + if (lefteq.size() == 1 && leftle.size() == 1 && righteq.size() == 1 && rightle.size() == 1) { + return 0; + } + // Nur Paare a =. Theta + if (leftle.size() == 0 && rightle.size() == 0 && leftlewc.size() == 0 && rightlewc.size() ==0) { + Stream lseq = lefteq.stream(); //left.filter(x -> (x.getLhsType() instanceof PlaceholderType && x.getPairOp() == PairOperator.EQUALSDOT)); + Stream rseq = righteq.stream(); //right.filter(x -> (x.getLhsType() instanceof PlaceholderType && x.getPairOp() == PairOperator.EQUALSDOT)); + BinaryOperator> combiner = (x,y) -> { x.putAll(y); return x;}; + HashMap hm = rseq.reduce(new HashMap(), (x, y)-> { x.put(y.getLhsType(),y); return x; }, combiner); + lseq = lseq.filter(x -> !(hm.get(x.getLhsType()) == null));//NOCHMALS UEBERPRUEFEN!!!! + lseq = lseq.filter(x -> !x.equals(hm.get(x.getLhsType()))); //Elemente die gleich sind muessen nicht verglichen werden + Optional si = lseq.map(x -> compareEq(x, hm.get(x.getLhsType()))).reduce((x,y)-> { if (x == y) return x; else return 0; } ); + if (!si.isPresent()) return 0; + else return si.get(); + } + //Fall 1 und 4 + if (lefteq.size() >= 1 && righteq.size() >= 1 && (leftlewc.size() > 0 || rightlewc.size() > 0)) { + if (lefteq.iterator().next().getLhsType().getName().equals("D")) + System.out.print(""); + //Set varsleft = lefteq.stream().map(x -> (PlaceholderType)x.getLhsType()).collect(Collectors.toCollection(HashSet::new)); + //Set varsright = righteq.stream().map(x -> (PlaceholderType)x.getLhsType()).collect(Collectors.toCollection(HashSet::new)); + //filtern des Paares a = Theta, das durch a <. Thata' generiert wurde (nur im Fall 1 relevant) andere Substitutioen werden rausgefiltert + lefteq.removeIf(x -> (x.getBasePair()!=null) && !(x.getLhsType().getName().equals(x.getBasePair().getLhsType().getName()) + ||x.getLhsType().getName().equals(x.getBasePair().getRhsType().getName())));//removeIf(x -> !varsright.contains(x.getLhsType())); + righteq.removeIf(x -> (x.getBasePair()!=null) && !(x.getLhsType().getName().equals(x.getBasePair().getLhsType().getName()) + ||x.getLhsType().getName().equals(x.getBasePair().getRhsType().getName())));//.removeIf(x -> !varsleft.contains(x.getLhsType())); + UnifyPair lseq = lefteq.iterator().next(); + UnifyPair rseq = righteq.iterator().next(); + if (lseq.getRhsType().getName().equals("Object")) { + if (rseq.getRhsType().getName().equals("Object")) return 0; + else return 1; + } + else { + if (rseq.getRhsType().getName().equals("Object")) return -1; + } + if (leftlewc.size() == rightlewc.size()) { + //TODO: Hier wird bei Wildcards nicht das richtige compare aufgerufen PL 18-04-20 + Pair> int_Unifier = compare(lseq.getRhsType(), rseq.getRhsType()); + Unifier uni = new Unifier(); + int_Unifier.getValue().get().forEach(x -> uni.add((PlaceholderType) x.getLhsType(), x.getRhsType())); + if (!lseq.getRhsType().getName().equals(rseq.getRhsType().getName()) + || leftlewc.size() == 0 || rightlewc.size() == 0) return int_Unifier.getKey(); + else { + Set lsleuni = leftlewc.stream().map(x -> uni.apply(x)).collect(Collectors.toCollection(HashSet::new)); + Set rsleuni = rightlewc.stream().map(x -> uni.apply(x)).collect(Collectors.toCollection(HashSet::new)); + BinaryOperator> combiner = (x,y) -> { x.putAll(y); return x;}; + + HashMap hm; + Optional si; + //1. Fall + if (leftlewc.iterator().next().getLhsType() instanceof PlaceholderType) { + hm = rsleuni.stream().reduce(new HashMap(), (x, y)-> { x.put(y.getLhsType(),y); return x; }, combiner); + Stream lslewcstr = lsleuni.stream().filter(x -> !(hm.get(x.getLhsType()) == null)); + si = lslewcstr.map(x -> fc.compare(x.getRhsType(), hm.get(x.getLhsType()).getRhsType(), PairOperator.SMALLERDOTWC)).reduce((x,y)-> { if (x == y) return x; else return 0; } ); + } + //4. Fall + else { + hm = rsleuni.stream().reduce(new HashMap(), (x, y)-> { x.put(y.getRhsType(),y); return x; }, combiner); + Stream lslewcstr = lsleuni.stream().filter(x -> !(hm.get(x.getRhsType()) == null)); + si = lslewcstr.map(x -> fc.compare(x.getLhsType(), hm.get(x.getRhsType()).getLhsType(), PairOperator.SMALLERDOTWC)).reduce((x,y)-> { if (x == y) return x; else return 0; } ); + } + if (!si.isPresent()) return 0; + else return si.get(); + } + } else { + if (leftlewc.size() > 0) { + Set subst; + subst = leftlewc.stream().map(x -> { + if (x.getLhsType() instanceof PlaceholderType) { + return new UnifyPair(x.getLhsType(), x.getRhsType(), PairOperator.EQUALSDOT); + } + else { + return new UnifyPair(x.getRhsType(), x.getLhsType(), PairOperator.EQUALSDOT); + }}).collect(Collectors.toCollection(HashSet::new)); + Unifier uni = new Unifier(); + lseq = uni.apply(lseq); + } + else { + Set subst; + subst = rightlewc.stream().map(x -> { + if (x.getLhsType() instanceof PlaceholderType) { + return new UnifyPair(x.getLhsType(), x.getRhsType(), PairOperator.EQUALSDOT); + } + else { + return new UnifyPair(x.getRhsType(), x.getLhsType(), PairOperator.EQUALSDOT); + }}).collect(Collectors.toCollection(HashSet::new)); + Unifier uni = new Unifier(); + subst.stream().forEach(x -> uni.add((PlaceholderType) x.getLhsType(), x.getRhsType())); + rseq = uni.apply(rseq); + } + return compareEq(lseq, rseq); + } + } + return 0; + } +} + diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/PairOperator.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/PairOperator.java new file mode 100644 index 0000000..54e25b5 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/PairOperator.java @@ -0,0 +1,49 @@ +package de.dhbw.compiler.typeinference.unify.model; + +/** + * Operators of pairs of the unification. + * @author Florian Steurer + */ +public enum PairOperator { + /** + * The smaller operator (T < P) is used to express a subtyping relation between + * T and P for example in the finite closure. It is necessarily true. + */ + SMALLER, + + /** + * The smallerdot operator (T <. P) is used to express a subtyping relation between + * of T and P in a CONSTRAINT during the unification. It is not necessarily true. + */ + SMALLERDOT, + + /** + * The smallernedot operator for arguments (T / ... with the Supertype Number + */ + SMALLERNEQDOT, + + /** + * The smallerdot operator for arguments (T <.? P) is used to express that + * T is an element of smArg(P) (or P is an element of grArg(T)) in a CONSTRAINT + * during the unification. It is not necessarily true. + */ + SMALLERDOTWC, + + /** + * The equalsdot operator (T =. P) is used to express that two types during the unification + * should be equal. It is not necessarily true. + */ + EQUALSDOT; + + @Override + public String toString() { + switch (this) { + case SMALLER: return "<"; + case SMALLERDOT: return "<."; + case SMALLERNEQDOT: return " EXISTING_PLACEHOLDERS = new ArrayList(); + + /** + * Prefix of auto-generated placeholder names. + */ + protected static String nextName = "gen_"; + + /** + * Random number generator used to generate fresh placeholder name. + */ + protected static Random rnd = new Random(43558747548978L); + + /** + * True if this object was auto-generated, false if this object was user-generated. + */ + private final boolean IsGenerated; + + + /** + * isWildcardable gibt an, ob ein Wildcardtyp dem PlaceholderType zugeordnet werden darf + */ + private boolean wildcardable = true; + + /** + * is innerType gibt an, ob der Type des PlaceholderType innerhalb eines Typkonstruktorsverwendet wird + */ + private boolean innerType = false; + + /** + * variance shows the variance of the pair + * 1: contravariant + * -1 covariant + * 0 invariant + * PL 2018-03-21 + */ + private int variance = 0; + + /* + * Fuer Oder-Constraints: + * orCons = 1: Receiver + * orCons = 0: Argument oder kein Oder-Constraint + * orCons = -1: RetType + */ + private byte orCons = 0; + + /** + * Creates a new placeholder type with the specified name. + */ + public PlaceholderType(String name) { + super(name, new TypeParams()); + EXISTING_PLACEHOLDERS.add(name); // Add to list of existing placeholder names + IsGenerated = false; // This type is user generated + } + + + public PlaceholderType(String name, int variance) { + super(name, new TypeParams()); + EXISTING_PLACEHOLDERS.add(name); // Add to list of existing placeholder names + IsGenerated = false; // This type is user generated + this.variance = variance; + } + + /** + * Creates a new placeholdertype + * @param isGenerated true if this placeholder is auto-generated, false if it is user-generated. + */ + protected PlaceholderType(String name, boolean isGenerated) { + super(name, new TypeParams()); + EXISTING_PLACEHOLDERS.add(name); // Add to list of existing placeholder names + IsGenerated = isGenerated; + } + + public UnifyType accept(UnifyTypeVisitor visitor, T ht) { + return visitor.visit(this, ht); + } + + /** + * Creates a fresh placeholder type with a name that does so far not exist. + * A user could later instantiate a type using the same name that is equivalent to this type. + * @return A fresh placeholder type. + */ + public synchronized static PlaceholderType freshPlaceholder() { + String name = nextName + (char) (rnd.nextInt(22) + 97); // Returns random char between 'a' and 'z' + // Add random chars while the name is in use. + while(EXISTING_PLACEHOLDERS.contains(name)) { + name += (char) (rnd.nextInt(22) + 97); // Returns random char between 'a' and 'z' + } + return new PlaceholderType(name, true); + } + + + /** + * True if this placeholder is auto-generated, false if it is user-generated. + */ + public boolean isGenerated() { + return IsGenerated; + } + + public void setVariance(int v) { + variance = v; + } + + public int getVariance() { + return variance; + } + + public void reversVariance() { + if (variance == 1) { + setVariance(-1); + } else { + if (variance == -1) { + setVariance(1); + }} + } + + public void setOrCons(byte i) { + orCons = i; + } + + public byte getOrCons() { + return orCons; + } + + public Boolean isWildcardable() { + return wildcardable; + } + public void disableWildcardtable() { + wildcardable = false; + } + + public void enableWildcardtable() { + wildcardable = true; + } + + public void setWildcardtable(Boolean wildcardable) { + this.wildcardable = wildcardable; + } + + public Boolean isInnerType() { + return innerType; + } + + public void setInnerType(Boolean innerType) { + this.innerType = innerType; + } + + @Override + Set smArg(IFiniteClosure fc, Set fBounded) { + return fc.smArg(this, fBounded); + } + + @Override + Set grArg(IFiniteClosure fc, Set fBounded) { + return fc.grArg(this, fBounded); + } + + @Override + public UnifyType setTypeParams(TypeParams newTp) { + return this; // Placeholders never have params. + } + + @Override + public int hashCode() { + return typeName.hashCode(); + } + + @Override + UnifyType apply(Unifier unif) { + if(unif.hasSubstitute(this)) { + UnifyType ret = unif.getSubstitute(this); + //PL 2018-05-17 Auskommentierung muesste korrekt sein, + //bereits in JavaTXComplier Variancen gesetzt werden. + //ret.accept(new distributeVariance(), this.getVariance()); + return ret; + } + return this; + } + + @Override + public boolean equals(Object obj) { + if(!(obj instanceof PlaceholderType)) + return false; + + return ((PlaceholderType) obj).getName().equals(typeName); + } + + + @Override + public Collection getInvolvedPlaceholderTypes() { + ArrayList ret = new ArrayList<>(); + ret.add(this); + return ret; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/ReferenceType.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/ReferenceType.java new file mode 100644 index 0000000..0d091c2 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/ReferenceType.java @@ -0,0 +1,100 @@ +package de.dhbw.compiler.typeinference.unify.model; + +import java.util.HashMap; +import java.util.Set; + +import de.dhbw.compiler.typeinference.unify.interfaces.IFiniteClosure; +import de.dhbw.compiler.typeinference.unify.interfaces.UnifyTypeVisitor; + +/** + * A reference type e.q. Integer or List. + * @author Florian Steurer + * + */ +public class ReferenceType extends UnifyType { + + /** + * The buffered hashCode + */ + private final int hashCode; + + /** + * gibt an, ob der ReferenceType eine generische Typvariable ist + */ + private final boolean genericTypeVar; + + + public UnifyType accept(UnifyTypeVisitor visitor, T ht) { + return visitor.visit(this, ht); + } + + public ReferenceType(String name, Boolean genericTypeVar) { + super(name, new TypeParams()); + hashCode = 31 + 17 * typeName.hashCode() + 17 * typeParams.hashCode(); + this.genericTypeVar = genericTypeVar; + } + + public ReferenceType(String name, UnifyType... params) { + super(name, new TypeParams(params)); + hashCode = 31 + 17 * typeName.hashCode() + 17 * typeParams.hashCode(); + genericTypeVar = false; + } + + public ReferenceType(String name, TypeParams params) { + super(name, params); + hashCode = 31 + 17 * typeName.hashCode() + 17 * typeParams.hashCode(); + genericTypeVar = false; + } + + public boolean isGenTypeVar () { + return genericTypeVar; + } + + @Override + Set smArg(IFiniteClosure fc, Set fBounded) { + return fc.smArg(this, fBounded); + } + + @Override + Set grArg(IFiniteClosure fc, Set fBounded) { + return fc.grArg(this, fBounded); + } + + @Override + UnifyType apply(Unifier unif) { + TypeParams newParams = typeParams.apply(unif); + + if(newParams.hashCode() == typeParams.hashCode() && newParams.equals(typeParams)) + return this; + + return new ReferenceType(typeName, newParams); + } + + @Override + public UnifyType setTypeParams(TypeParams newTp) { + if(newTp.hashCode() == typeParams.hashCode() && newTp.equals(typeParams)) + return this; // reduced the amount of objects created + return new ReferenceType(typeName, newTp); + } + + @Override + public int hashCode() { + return hashCode; + } + + @Override + public boolean equals(Object obj) { + if(!(obj instanceof ReferenceType)) + return false; + + if(obj.hashCode() != this.hashCode()) + return false; + + ReferenceType other = (ReferenceType) obj; + + if(!other.getName().equals(typeName)) + return false; + + return other.getTypeParams().equals(typeParams); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/SuperType.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/SuperType.java new file mode 100644 index 0000000..436409a --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/SuperType.java @@ -0,0 +1,88 @@ +package de.dhbw.compiler.typeinference.unify.model; + +import java.util.HashMap; +import java.util.Set; + +import de.dhbw.compiler.typeinference.unify.interfaces.IFiniteClosure; +import de.dhbw.compiler.typeinference.unify.interfaces.UnifyTypeVisitor; + +/** + * A super wildcard type e.g. ? super Integer. + * @author Florian Steurer + */ +public final class SuperType extends WildcardType { + + public UnifyType accept(UnifyTypeVisitor visitor, T ht) { + return visitor.visit(this, ht); + } + + /** + * Creates a new instance "? extends superedType" + * @param superedType The type that is supered e.g. Integer in "? super Integer" + */ + public SuperType(UnifyType superedType) { + super("? super " + superedType.getName(), superedType); + } + + /** + * The type that is supered e.g. Integer in "? super Integer" + */ + public UnifyType getSuperedType() { + return wildcardedType; + } + + @Override + public String toString() { + return "? super " + wildcardedType; + } + + /** + * Sets the type parameters of the wildcarded type and returns a new supertype that supers that type. + */ + @Override + public UnifyType setTypeParams(TypeParams newTp) { + UnifyType newType = wildcardedType.setTypeParams(newTp); + if(newType == wildcardedType) + return this; // Reduced the amount of objects created + return new SuperType(wildcardedType.setTypeParams(newTp)); + } + + @Override + Set smArg(IFiniteClosure fc, Set fBounded) { + return fc.smArg(this, fBounded); + } + + @Override + Set grArg(IFiniteClosure fc, Set fBounded) { + return fc.grArg(this, fBounded); + } + + @Override + UnifyType apply(Unifier unif) { + UnifyType newType = wildcardedType.apply(unif); + if(newType.hashCode() == wildcardedType.hashCode() && newType.equals(wildcardedType)) + return this; // Reduced the amount of objects created + return new SuperType(newType); + } + + @Override + public int hashCode() { + /* + * It is important that the prime that is added is different to the prime added in hashCode() of ExtendsType. + * Otherwise ? extends T and ? super T have the same hashCode() for every Type T. + */ + return wildcardedType.hashCode() + 3917; + } + + @Override + public boolean equals(Object obj) { + if(!(obj instanceof SuperType)) + return false; + + if(obj.hashCode() != this.hashCode()) + return false; + + SuperType other = (SuperType) obj; + return other.getSuperedType().equals(wildcardedType); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/TypeParams.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/TypeParams.java new file mode 100644 index 0000000..8c2cd05 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/TypeParams.java @@ -0,0 +1,191 @@ +package de.dhbw.compiler.typeinference.unify.model; + +import java.util.*; + + +/** + * The generic or non-generic parameters of a type e.g. for List + * @author Florian Steurer + */ +public final class TypeParams implements Iterable{ + /** + * The array which backs the type parameters. + */ + private final UnifyType[] typeParams; + + /** + * Hashcode calculation is expensive and must be cached. + */ + private final int hashCode; + + /** + * Creates a new set of type parameters. + * @param types The type parameters. + */ + public TypeParams(List types){ + typeParams = new UnifyType[types.size()]; + for(int i=0;i x instanceof PlaceholderType); + } + + /** + * Returns the number of the type parameters in this object. + * @return number of type parameters, always positive (including 0). + */ + public int size() { + return typeParams.length; + } + + /** + * Returns true if this object has size() of zero, false otherwise. + */ + public boolean empty() { + return typeParams.length == 0; + } + + /** + * Applies a unifier to every parameter in this object. + * @param unif The applied unifier. + * @return A new type parameter object, where the unifier was applied to every parameter. + */ + public TypeParams apply(Unifier unif) { + UnifyType[] newParams = new UnifyType[typeParams.length]; + + // If true, a type was modified and a new typeparams object has to be created. + // Otherwise it is enough to return this object, since it is immutable + // This reduced the needed TypeParams-Instances for the lambda14-Test from + // 130.000 to 30.000 without a decrease in speed. + boolean isNew = false; + + for(int i = 0; i < typeParams.length; i++) { + UnifyType newType = typeParams[i].apply(unif); + newParams[i] = newType; + if(!isNew && (newType.hashCode() != typeParams[i].hashCode() || !newType.equals(typeParams[i]))) + isNew = true; + } + + if(!isNew) + return this; + return new TypeParams(newParams); + } + + /** + * True if the PlaceholderType t is a parameter of this object, or if any parameter + * contains t (arbitrary depth of recursion), false otherwise. + */ + public boolean occurs(PlaceholderType t) { + for(UnifyType p : typeParams) + if(p instanceof PlaceholderType) {//PL 2018-01-31 dangeling else Problem { ... } eingefuegt. + if(p.equals(t)) + return true; + } + else { + if(p.getTypeParams().occurs(t)) + return true; } + return false; + } + + /** + * Returns the i-th parameter of this object. + */ + public UnifyType get(int i) { + return typeParams[i]; + } + + /** + * Returns the parameters of this object. + * PL 2018-03-17 + */ + public UnifyType[] get() { + return typeParams; + } + + /** + * Sets the the type t as the i-th parameter and returns a new object + * that equals this object, except for the i-th type. + */ + public TypeParams set(UnifyType t, int idx) { + // Reduce the creation of new objects for less memory + // Reduced the needed instances of TypeParams in the lambda14-Test from + // 150.000 to 130.000 + if(t.hashCode() == typeParams[idx].hashCode() && t.equals(typeParams[idx])) + return this; + UnifyType[] newparams = Arrays.copyOf(typeParams, typeParams.length); + newparams[idx] = t; + return new TypeParams(newparams); + } + + @Override + public Iterator iterator() { + return Arrays.stream(typeParams).iterator(); + } + + @Override + public int hashCode() { + return hashCode; + } + + @Override + public boolean equals(Object obj) { + if(!(obj instanceof TypeParams)) + return false; + + if(obj.hashCode() != this.hashCode()) + return false; + + TypeParams other = (TypeParams) obj; + + if(other.size() != this.size()) + return false; + + for(int i = 0; i < this.size(); i++){ + //if(this.get(i) == null) + //System.out.print("s"); + } + for(int i = 0; i < this.size(); i++) + if(!(this.get(i).equals(other.get(i)))) + return false; + + return true; + } + + @Override + public String toString() { + String res = ""; + for(UnifyType t : typeParams) + res += t + ","; + return "<" + res.substring(0, res.length()-1) + ">"; + } + + public Collection getInvolvedPlaceholderTypes() { + ArrayList ret = new ArrayList<>(); + for(UnifyType t : typeParams){ + ret.addAll(t.getInvolvedPlaceholderTypes()); + } + return ret; + } +} + diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/Unifier.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/Unifier.java new file mode 100644 index 0000000..3dd0c09 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/Unifier.java @@ -0,0 +1,189 @@ +package de.dhbw.compiler.typeinference.unify.model; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map.Entry; +import java.util.Set; +import java.util.function.Function; + +/** + * A set of substitutions (s -> t) that is an applicable function to types and pairs. + * @author Florian Steurer + */ +public class Unifier implements Function, Iterable> { + + /** + * The set of substitutions that unify a type-term + */ + private HashMap substitutions = new HashMap<>(); + + /** + * Creates a new instance with a single substitution (source -> target). + * @param The type that is replaced + * @param The type that replaces + */ + public Unifier(PlaceholderType source, UnifyType target) { + substitutions.put(source, target); + } + + /** + * Identity function as an "unifier". + */ + protected Unifier() { + + } + + /** + * Creates an unifier that is the identity function (thus has no substitutions). + */ + public static Unifier identity() { + return new Unifier(); + } + + /** + * Adds a substitution to the unifier from (source -> target) + * @param The type that is replaced + * @param The type that replaces + */ + public void add(PlaceholderType source, UnifyType target) { + Unifier tempU = new Unifier(source, target); + // Every new substitution must be applied to previously added substitutions + // otherwise the unifier needs to be applied multiple times to unify two terms + for(PlaceholderType pt : substitutions.keySet()) + substitutions.put(pt, substitutions.get(pt).apply(tempU)); + substitutions.put(source, target); + } + + @Override + public UnifyType apply(UnifyType t) { + return t.apply(this); + } + + /** + * Applies the unifier to the two terms of the pair. + * @return A new pair where the left and right-hand side are applied + */ + public UnifyPair apply(UnifyPair p) { + UnifyType newLhs = this.apply(p.getLhsType()); + UnifyType newRhs = this.apply(p.getRhsType()); + return new UnifyPair(newLhs, newRhs, p.getPairOp()); + } + + /** + * Applies the unifier to the two terms of the pair. + * works only for single subsitution + * @return A new pair where the left and right-hand side are applied + */ + public UnifyPair apply(UnifyPair thisAsPair, UnifyPair p) { + UnifyType newLhs = this.apply(p.getLhsType()); + UnifyType newRhs = this.apply(p.getRhsType()); + //Varianceweitergabe wird nicht benoetigt. + //PlaceholderType lhsph = (PlaceholderType)thisAsPair.getLhsType(); + //if (lhsph.getVariance() != 0) { + // if (p.getLhsType().equals(lhsph)) { + // if (p.getRhsType() instanceof PlaceholderType) { + // ((PlaceholderType)p.getRhsType()).setVariance(lhsph.getVariance()); + // } + // } + // if (p.getRhsType().equals(lhsph)) { + // if (p.getLhsType() instanceof PlaceholderType) { + // ((PlaceholderType)p.getLhsType()).setVariance(lhsph.getVariance()); + // } + // } + //} + if (!(p.getLhsType().equals(newLhs)) || !(p.getRhsType().equals(newRhs))) {//Die Anwendung von this hat was veraendert PL 2018-04-01 + Set suniUnifyPair = new HashSet<>(); + suniUnifyPair.addAll(thisAsPair.getAllSubstitutions()); + suniUnifyPair.add(thisAsPair); + if (p.getLhsType() instanceof PlaceholderType //&& newLhs instanceof PlaceholderType entfernt PL 2018-04-13 + && p.getPairOp() == PairOperator.EQUALSDOT) { + suniUnifyPair.add(p); //p koennte auch subsitution sein + } + return new UnifyPair(newLhs, newRhs, p.getPairOp(), suniUnifyPair, p); + } + return new UnifyPair(newLhs, newRhs, p.getPairOp(), p.getSubstitution(), p.getBasePair(), p.getfBounded(), p.getLocation()); + } + + /** + * Applies the unifier to the left terms of the pair. + * @return A new pair where the left and right-hand side are applied + */ + public UnifyPair applyleft(UnifyPair p) { + return new UnifyPair(this.apply(p.getLhsType()), p.getRhsType(), p.getPairOp()); + } + + /** + * True if the typevariable t will be substituted if the unifier is applied. + * false otherwise. + */ + public boolean hasSubstitute(PlaceholderType t) { + return substitutions.containsKey(t); + } + + /** + * Returns the type that will replace the typevariable t if the unifier is applied. + */ + public UnifyType getSubstitute(PlaceholderType t) { + return substitutions.get(t); + } + + /** + * The number of substitutions in the unifier. If zero, this is the identity function. + */ + public int size() { + return substitutions.size(); + } + + /** + * Garantuees that if there is a substitutions (a -> b) in this unifier, + * a is not an element of the targetParams. Substitutions that do not + * satisfy this condition, are swapped. + */ + public void swapPlaceholderSubstitutions(Iterable targetParams) { + for(UnifyType tph : targetParams) { + if(!(tph instanceof PlaceholderType)) + continue; + // Swap a substitutions (a -> b) if a is an element of the target params. + if(substitutions.containsKey(tph)) { + if((substitutions.get(tph) instanceof PlaceholderType)) { + PlaceholderType newLhs = (PlaceholderType) substitutions.get(tph); + substitutions.remove(tph); + substitutions.put(newLhs, tph); + } + } + } + } + + public void swapPlaceholderSubstitutionsReverse(Iterable sourceParams) { + for(UnifyType tph : sourceParams) { + if(!(tph instanceof PlaceholderType)) + continue; + if(substitutions.containsValue(tph)) { + UnifyType key = substitutions.values().stream().filter(x -> x.equals(tph)).findAny().get(); + if(key instanceof PlaceholderType) { + PlaceholderType newLhs = (PlaceholderType) tph; + substitutions.remove(key); + substitutions.put(newLhs, key); + } + } + } + } + + @Override + public String toString() { + String result = "{ "; + for(Entry entry : substitutions.entrySet()) + result += "(" + entry.getKey() + " -> " + entry.getValue() + "), "; + if(!substitutions.isEmpty()) + result = result.substring(0, result.length()-2); + result += " }"; + return result; + } + + @Override + public Iterator> iterator() { + return substitutions.entrySet().iterator(); + } +} + diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/UnifyPair.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/UnifyPair.java new file mode 100644 index 0000000..9abca69 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/UnifyPair.java @@ -0,0 +1,274 @@ +package de.dhbw.compiler.typeinference.unify.model; + +import com.google.common.collect.ObjectArrays; +import de.dhbw.compiler.parser.SourceLoc; +import de.dhbw.compiler.syntaxtree.type.TypePlaceholder; +import org.antlr.v4.runtime.Token; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; + + +/** + * A pair which contains two types and an operator, e.q. (Integer <. a). + * @author Florian Steurer + */ +public class UnifyPair { + + private SourceLoc location; + + /** + * The type on the left hand side of the pair. + */ + private final UnifyType lhs; + + /** + * The type on the right hand side of the pair. + */ + private final UnifyType rhs; + + /** + * The operator that determines the relation between the left and right hand side type. + */ + private PairOperator pairOp; + + private boolean undefinedPair = false; + + /** + * Unifier/substitute that generated this pair + * PL 2018-03-15 + */ + private Set substitution; + + /** + * Base on which the the unifier is applied + * PL 2018-03-15 + */ + private UnifyPair basePair; + + /** + * For pairs a <. Theta generated in the rule reduceTphSup + * to store the f-Bouned Elements to avoid endless recursion + * PL 2018-03-15 + */ + private Set fBounded = new HashSet<>(); + + private final int hashCode; + + /** + * Creates a new instance of the pair. + * @param lhs The type on the left hand side of the pair. + * @param rhs The type on the right hand side of the pair. + * @param op The operator that determines the relation between the left and right hand side type. + */ + public UnifyPair(UnifyType lhs, UnifyType rhs, PairOperator op) { + this.lhs = lhs; + this.rhs = rhs; + pairOp = op; + substitution = new HashSet<>(); + + // Caching hashcode + 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 uni, UnifyPair base) { + this(lhs, rhs, op, uni, base, new HashSet<>()); + } + + public UnifyPair(UnifyType lhs, UnifyType rhs, PairOperator op, Set uni, UnifyPair base, Set fBounded) { + this(lhs, rhs, op, uni, base, fBounded, null); + } + + public UnifyPair(UnifyType lhs, UnifyType rhs, PairOperator op, Set uni, UnifyPair base, Set fBounded, SourceLoc location) { + this.lhs = lhs; + this.rhs = rhs; + pairOp = op; + substitution = uni; + basePair = base; + this.location = location; + this.fBounded = fBounded; + + // Caching hashcode + hashCode = 17 + 31 * lhs.hashCode() + 31 * rhs.hashCode() + 31 * pairOp.hashCode(); + } + + public SourceLoc getLocation() { + if (location != null) return location; + else if (basePair != null) return basePair.getLocation(); + return null; + } + + /** + * Returns the type on the left hand side of the pair. + */ + public UnifyType getLhsType() { + return lhs; + } + + /** + * Returns the type on the right hand side of the pair. + */ + public UnifyType getRhsType() { + return rhs; + } + + /** + * Returns the operator that determines the relation between the left and right hand side type. + */ + public PairOperator getPairOp() { + return pairOp; + } + + public void setPairOp(PairOperator po) { + pairOp = po; + } + + public void addSubstitutions(Set sup) { + substitution.addAll(sup); + } + + public void setUndefinedPair() { + undefinedPair = true; + } + public Set getSubstitution() { + return new HashSet<>(substitution); + } + + public UnifyPair getBasePair() { + return basePair; + } + public boolean isUndefinedPair() { + return undefinedPair; + } + + public Set getAllSubstitutions () { + Set ret = new HashSet<>(); + ret.addAll(new ArrayList<>(getSubstitution())); + if (basePair != null) { + ret.addAll(new ArrayList<>(basePair.getAllSubstitutions())); + } + return ret; + } + + public Set getThisAndAllBases () { + Set ret = getAllBases(); + ret.add(this); + return ret; + } + public Set getAllBases () { + Set ret = new HashSet<>(); + if (basePair != null) { + ret.add(getBasePair()); + ret.addAll(basePair.getAllBases()); + } + return ret; + } + + public UnifyPair getGroundBasePair () { + if (basePair == null) { + return this; + } + if (basePair.getBasePair() == null) { + return basePair; + } + else { + return basePair.getGroundBasePair(); + } + } + + /** + * wenn in einem Paar bestehend aus 2 Typvariablen eine nicht wildcardtable ist, + * so beide auf nicht wildcardtable setzen + */ + public void disableCondWildcards() { + if (lhs instanceof PlaceholderType && rhs instanceof PlaceholderType + && (!((PlaceholderType)lhs).isWildcardable() || !((PlaceholderType)rhs).isWildcardable())) + { + ((PlaceholderType)lhs).disableWildcardtable(); + ((PlaceholderType)rhs).disableWildcardtable(); + } + + } + + public Boolean wrongWildcard() { + return lhs.wrongWildcard() || rhs.wrongWildcard(); + } + + public Set getfBounded() { + return this.fBounded; + } + + @Override + public boolean equals(Object obj) { + if(!(obj instanceof UnifyPair)) + return false; + + if(obj.hashCode() != this.hashCode()) + return false; + + UnifyPair other = (UnifyPair) obj; + + if (isUndefinedPair()) { + if (other.getBasePair() != basePair || (other.getBasePair() == null && basePair == null)) { + return false; + } + + if (!other.getBasePair().equals(basePair) || + !other.getAllSubstitutions().equals(getAllSubstitutions())) { + return false; + } + } + + + return other.getPairOp() == pairOp + && other.getLhsType().equals(lhs) + && other.getRhsType().equals(rhs); + } + + @Override + public int hashCode() { + return hashCode; + } + + @Override + public String toString() { + String ret = ""; + if (lhs instanceof PlaceholderType) { + ret = new Integer(((PlaceholderType)lhs).getVariance()).toString() + " " + + "WC: " + ((PlaceholderType)lhs).isWildcardable() + + ", IT: " + ((PlaceholderType)lhs).isInnerType(); + } + if (rhs instanceof PlaceholderType) { + ret = ret + ", " + new Integer(((PlaceholderType)rhs).getVariance()).toString() + " " + + "WC: " + ((PlaceholderType)rhs).isWildcardable() + + ", IT: " + ((PlaceholderType)rhs).isInnerType(); + } + var res = "(" + lhs + " " + pairOp + " " + rhs + ", " + ret + ")"; //+ ", [" + getfBounded().toString()+ "])"; + var location = this.getLocation(); + if (location != null) { + res += "@" + location.line() + " in " + location.file(); + } + + return res; + } + + /* + public List getInvolvedPlaceholderTypes() { + ArrayList ret = new ArrayList<>(); + ret.addAll(lhs.getInvolvedPlaceholderTypes()); + ret.addAll(rhs.getInvolvedPlaceholderTypes()); + return ret; + } + */ +} + + diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/UnifyType.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/UnifyType.java new file mode 100644 index 0000000..8b4019e --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/UnifyType.java @@ -0,0 +1,120 @@ +package de.dhbw.compiler.typeinference.unify.model; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Set; + +import de.dhbw.compiler.syntaxtree.StatementVisitor; +import de.dhbw.compiler.typeinference.unify.interfaces.IFiniteClosure; +import de.dhbw.compiler.typeinference.unify.interfaces.UnifyTypeVisitor; + +/** + * Represents a java type. + * @author Florian Steurer + */ +public abstract class UnifyType { + + /** + * The name of the type e.q. "Integer", "? extends Integer" or "List" for (List) + */ + protected final String typeName; + + /** + * The type parameters of the type. + */ + protected final TypeParams typeParams; + + /** + * Creates a new instance + * @param name Name of the type (e.q. List for List, Integer or ? extends Integer) + * @param typeParams Parameters of the type (e.q. for List) + */ + protected UnifyType(String name, TypeParams p) { + typeName = name; + typeParams = p; + } + + + abstract public UnifyType accept(UnifyTypeVisitor visitor, T ht); + + /** + * Returns the name of the type. + * @return The name e.q. List for List, Integer or ? extends Integer + */ + public String getName() { + return typeName; + } + + /** + * The parameters of the type. + * @return Parameters of the type, e.q. for List. + */ + public TypeParams getTypeParams() { + return typeParams; + } + + /** + * Returns a new type that equals this type except for the type parameters. + * @param newTp The type params of the new type. + * @return A new type object. + */ + public abstract UnifyType setTypeParams(TypeParams newTp); + + /** + * Implementation of the visitor-pattern. Returns the set of smArg + * by calling the most specific overload in the FC. + * @param fc The FC that is called. + * @return The set that is smArg(this) + */ + abstract Set smArg(IFiniteClosure fc, Set fBounded); + + /** + * Implementation of the visitor-pattern. Returns the set of grArg + * by calling the most specific overload in the FC. + * @param fc The FC that is called. + * @return The set that is grArg(this) + */ + abstract Set grArg(IFiniteClosure fc, Set fBounded); + + /** + * Applies a unifier to this object. + * @param unif The unifier + * @return A UnifyType, that may or may not be a new object, that has its subtypes substituted. + */ + abstract UnifyType apply(Unifier unif); + + @Override + public String toString() { + String params = ""; + if(typeParams.size() != 0) { + for(UnifyType param : typeParams) + params += param.toString() + ","; + params = "<" + params.substring(0, params.length()-1) + ">"; + } + + return typeName + params; + } + + public Collection getInvolvedPlaceholderTypes() { + ArrayList ret = new ArrayList<>(); + ret.addAll(typeParams.getInvolvedPlaceholderTypes()); + return ret; + } + + public Boolean wrongWildcard() {//default + return false; + } + + @Override + public int hashCode() { + return this.toString().hashCode(); + } + + @Override + public boolean equals(Object obj) { + if(obj == null)return false; + return this.toString().equals(obj.toString()); + } +} \ No newline at end of file diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/WildcardType.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/WildcardType.java new file mode 100644 index 0000000..1e4934d --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/WildcardType.java @@ -0,0 +1,72 @@ +package de.dhbw.compiler.typeinference.unify.model; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * A wildcard type that is either a ExtendsType or a SuperType. + * @author Florian Steurer + */ +public abstract class WildcardType extends UnifyType { + + /** + * The wildcarded type, e.q. Integer for ? extends Integer. Never a wildcard type itself. + */ + protected UnifyType wildcardedType; + + /** + * Creates a new instance. + * @param name The name of the type, e.q. ? extends Integer + * @param wildcardedType The wildcarded type, e.q. Integer for ? extends Integer. Never a wildcard type itself. + */ + protected WildcardType(String name, UnifyType wildcardedType) { + super(name, wildcardedType.getTypeParams()); + this.wildcardedType = wildcardedType; + } + + /** + * Returns the wildcarded type, e.q. Integer for ? extends Integer. + * @return The wildcarded type. Never a wildcard type itself. + */ + public UnifyType getWildcardedType() { + return wildcardedType; + } + + /** + * Returns the type parameters of the WILDCARDED TYPE. + */ + @Override + public TypeParams getTypeParams() { + return wildcardedType.getTypeParams(); + } + + @Override + public Boolean wrongWildcard () {//This is an error + return (wildcardedType instanceof WildcardType); + } + + @Override + public int hashCode() { + return wildcardedType.hashCode() + getName().hashCode() + 17; + } + + @Override + public boolean equals(Object obj) { + if(!(obj instanceof WildcardType)) + return false; + + if(obj.hashCode() != this.hashCode()) + return false; + + WildcardType other = (WildcardType) obj; + return other.getWildcardedType().equals(wildcardedType); + } + + + @Override + public Collection getInvolvedPlaceholderTypes() { + ArrayList ret = new ArrayList<>(); + ret.addAll(wildcardedType.getInvolvedPlaceholderTypes()); + return ret; + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/hashKeyType.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/hashKeyType.java new file mode 100644 index 0000000..958e3ef --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/model/hashKeyType.java @@ -0,0 +1,25 @@ +package de.dhbw.compiler.typeinference.unify.model; + +public class hashKeyType { + UnifyType realType; + + hashKeyType(UnifyType realType) { + this.realType= realType; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof hashKeyType) { + return realType.equals(((hashKeyType)obj).realType); + } + else + { + return false; + } + } + + @Override + public int hashCode() { + return realType.hashCode(); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/visitUnifyTypeVisitor.java b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/visitUnifyTypeVisitor.java new file mode 100644 index 0000000..9693e99 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/typeinference/unify/visitUnifyTypeVisitor.java @@ -0,0 +1,47 @@ +package de.dhbw.compiler.typeinference.unify; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.HashMap; +import java.util.stream.Collectors; + +import de.dhbw.compiler.typeinference.unify.interfaces.UnifyTypeVisitor; +import de.dhbw.compiler.typeinference.unify.model.ExtendsType; +import de.dhbw.compiler.typeinference.unify.model.FunNType; +import de.dhbw.compiler.typeinference.unify.model.PlaceholderType; +import de.dhbw.compiler.typeinference.unify.model.ReferenceType; +import de.dhbw.compiler.typeinference.unify.model.SuperType; +import de.dhbw.compiler.typeinference.unify.model.TypeParams; + +public class visitUnifyTypeVisitor implements UnifyTypeVisitor { + + public ReferenceType visit(ReferenceType refty, T ht) { + return new ReferenceType(refty.getName(), + new TypeParams( + Arrays.stream(refty.getTypeParams().get()) + .map(x -> x.accept(this, ht)) + .collect(Collectors.toCollection(ArrayList::new)))); + } + + public PlaceholderType visit(PlaceholderType phty, T ht) { + return phty; + } + + public FunNType visit(FunNType funnty, T ht) { + return FunNType.getFunNType( + new TypeParams( + Arrays.stream(funnty.getTypeParams().get()) + .map(x -> x.accept(this, ht)) + .collect(Collectors.toCollection(ArrayList::new))) + ); + } + + public SuperType visit(SuperType suty, T ht) { + return new SuperType(suty.getWildcardedType().accept(this, ht)); + } + + public ExtendsType visit(ExtendsType extty, T ht) { + return new ExtendsType(extty.getWildcardedType().accept(this, ht)); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/util/BiRelation.java b/LanguageServer/src/main/java/de/dhbw/compiler/util/BiRelation.java new file mode 100644 index 0000000..acbf9e0 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/util/BiRelation.java @@ -0,0 +1,19 @@ +package de.dhbw.compiler.util; + +import java.util.ArrayList; + +public class BiRelation extends ArrayList>{ + + public void put(X x, Y y) { + this.add(new Pair<>(x,y)); + } + + public void put(Pair p) { + this.add(p); + } + + + public void putAll(BiRelation br) { + this.addAll(br); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/compiler/util/Pair.java b/LanguageServer/src/main/java/de/dhbw/compiler/util/Pair.java new file mode 100644 index 0000000..2996be8 --- /dev/null +++ b/LanguageServer/src/main/java/de/dhbw/compiler/util/Pair.java @@ -0,0 +1,39 @@ +package de.dhbw.compiler.util; + +import java.util.Objects; +import java.util.Optional; + +public class Pair { + private final T key; + private final T1 value; + + public Pair(T a, T1 b) { + this.value = b; + this.key = a; + } + + public Optional getValue() { + return Optional.of(value); + } + + public T getKey() { + return key; + } + + public String toString() { + return "(" + key.toString() + "," + value.toString() + ")\n"; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Pair pair = (Pair) o; + return Objects.equals(key, pair.key) && Objects.equals(value, pair.value); + } + + @Override + public int hashCode() { + return Objects.hash(key, value); + } +} diff --git a/LanguageServer/src/main/java/de/dhbw/parser/Java17Lexer.java b/LanguageServer/src/main/java/de/dhbw/parser/Java17Lexer.java index f34d1b4..0f11004 100644 --- a/LanguageServer/src/main/java/de/dhbw/parser/Java17Lexer.java +++ b/LanguageServer/src/main/java/de/dhbw/parser/Java17Lexer.java @@ -1,9 +1,12 @@ -package de.dhbw.parser;// Generated from /home/ruben/Documents/JavaCompilerCore/src/main/antlr4/de/dhbwstuttgart/parser/antlr/Java17Lexer.g4 by ANTLR 4.13.1 +package de.dhbw.parser;// Generated from C:/Users/ruben/IdeaProjects/JavaCompilerCore/src/main/antlr4/de/dhbwstuttgart/parser/antlr/Java17Lexer.g4 by ANTLR 4.13.1 import org.antlr.v4.runtime.Lexer; import org.antlr.v4.runtime.CharStream; +import org.antlr.v4.runtime.Token; +import org.antlr.v4.runtime.TokenStream; import org.antlr.v4.runtime.*; import org.antlr.v4.runtime.atn.*; import org.antlr.v4.runtime.dfa.DFA; +import org.antlr.v4.runtime.misc.*; @SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast", "CheckReturnValue", "this-escape"}) public class Java17Lexer extends Lexer { diff --git a/LanguageServer/src/main/java/de/dhbw/parser/Java17Parser.java b/LanguageServer/src/main/java/de/dhbw/parser/Java17Parser.java index 4e6a492..6acf021 100644 --- a/LanguageServer/src/main/java/de/dhbw/parser/Java17Parser.java +++ b/LanguageServer/src/main/java/de/dhbw/parser/Java17Parser.java @@ -1,9 +1,12 @@ -package de.dhbw.parser;// Generated from /home/ruben/Documents/JavaCompilerCore/src/main/antlr4/de/dhbwstuttgart/parser/antlr/Java17Parser.g4 by ANTLR 4.13.1 +package de.dhbw.parser;// Generated from C:/Users/ruben/IdeaProjects/JavaCompilerCore/src/main/antlr4/de/dhbwstuttgart/parser/antlr/Java17Parser.g4 by ANTLR 4.13.1 import org.antlr.v4.runtime.atn.*; import org.antlr.v4.runtime.dfa.DFA; import org.antlr.v4.runtime.*; +import org.antlr.v4.runtime.misc.*; import org.antlr.v4.runtime.tree.*; import java.util.List; +import java.util.Iterator; +import java.util.ArrayList; @SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast", "CheckReturnValue"}) public class Java17Parser extends Parser { @@ -621,7 +624,7 @@ public class Java17Parser extends Parser { setState(322); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,7,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { @@ -1268,7 +1271,7 @@ public class Java17Parser extends Parser { setState(391); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,18,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { @@ -1301,7 +1304,7 @@ public class Java17Parser extends Parser { setState(399); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,19,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { @@ -1552,7 +1555,7 @@ public class Java17Parser extends Parser { setState(436); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,26,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { @@ -1627,7 +1630,7 @@ public class Java17Parser extends Parser { setState(442); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,27,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { @@ -2092,7 +2095,7 @@ public class Java17Parser extends Parser { setState(500); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,37,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { @@ -3152,7 +3155,7 @@ public class Java17Parser extends Parser { setState(570); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,49,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { @@ -3538,7 +3541,7 @@ public class Java17Parser extends Parser { setState(610); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,55,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { @@ -3808,7 +3811,7 @@ public class Java17Parser extends Parser { setState(635); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,58,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { @@ -4243,7 +4246,7 @@ public class Java17Parser extends Parser { setState(687); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,66,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { @@ -4337,7 +4340,7 @@ public class Java17Parser extends Parser { setState(705); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,70,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { @@ -4987,7 +4990,7 @@ public class Java17Parser extends Parser { setState(777); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,82,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { @@ -5086,7 +5089,7 @@ public class Java17Parser extends Parser { setState(790); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,85,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { @@ -5184,7 +5187,7 @@ public class Java17Parser extends Parser { setState(803); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,88,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { @@ -5348,7 +5351,7 @@ public class Java17Parser extends Parser { setState(829); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,92,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { @@ -5421,7 +5424,7 @@ public class Java17Parser extends Parser { setState(840); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,93,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { @@ -6202,7 +6205,7 @@ public class Java17Parser extends Parser { setState(903); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,101,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { @@ -6413,7 +6416,7 @@ public class Java17Parser extends Parser { setState(930); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,105,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { @@ -6938,7 +6941,7 @@ public class Java17Parser extends Parser { setState(982); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,113,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { @@ -7624,7 +7627,7 @@ public class Java17Parser extends Parser { setState(1077); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,125,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { @@ -7877,7 +7880,7 @@ public class Java17Parser extends Parser { setState(1093); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,127,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { @@ -8607,7 +8610,7 @@ public class Java17Parser extends Parser { setState(1167); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,137,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { @@ -8830,7 +8833,7 @@ public class Java17Parser extends Parser { setState(1220); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,143,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { @@ -9095,7 +9098,7 @@ public class Java17Parser extends Parser { setState(1253); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,147,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { @@ -9178,7 +9181,7 @@ public class Java17Parser extends Parser { setState(1259); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,148,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { @@ -9704,7 +9707,7 @@ public class Java17Parser extends Parser { setState(1322); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,160,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { @@ -10774,7 +10777,7 @@ public class Java17Parser extends Parser { setState(1377); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,168,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { @@ -10932,7 +10935,7 @@ public class Java17Parser extends Parser { setState(1496); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,180,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { if ( _parseListeners!=null ) triggerExitRuleEvent(); _prevctx = _localctx; @@ -11562,7 +11565,7 @@ public class Java17Parser extends Parser { setState(1514); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,182,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { @@ -11702,7 +11705,7 @@ public class Java17Parser extends Parser { setState(1527); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,185,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { @@ -11727,7 +11730,7 @@ public class Java17Parser extends Parser { setState(1536); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,186,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { @@ -13074,7 +13077,7 @@ public class Java17Parser extends Parser { setState(1659); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,202,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { @@ -13521,7 +13524,7 @@ public class Java17Parser extends Parser { setState(1708); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,210,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { @@ -13541,7 +13544,7 @@ public class Java17Parser extends Parser { setState(1715); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,211,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { @@ -13978,7 +13981,7 @@ public class Java17Parser extends Parser { setState(1752); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,217,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { @@ -14034,7 +14037,7 @@ public class Java17Parser extends Parser { setState(1769); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,220,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { diff --git a/LanguageServer/src/main/java/de/dhbw/parser/Java17ParserBaseListener.java b/LanguageServer/src/main/java/de/dhbw/parser/Java17ParserBaseListener.java index 6d84b8c..925d9ad 100644 --- a/LanguageServer/src/main/java/de/dhbw/parser/Java17ParserBaseListener.java +++ b/LanguageServer/src/main/java/de/dhbw/parser/Java17ParserBaseListener.java @@ -1,4 +1,4 @@ -package de.dhbw.parser;// Generated from /home/ruben/Documents/JavaCompilerCore/src/main/antlr4/de/dhbwstuttgart/parser/antlr/Java17Parser.g4 by ANTLR 4.13.1 +package de.dhbw.parser;// Generated from C:/Users/ruben/IdeaProjects/JavaCompilerCore/src/main/antlr4/de/dhbwstuttgart/parser/antlr/Java17Parser.g4 by ANTLR 4.13.1 import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.tree.ErrorNode; diff --git a/LanguageServer/src/main/java/de/dhbw/parser/Java17ParserBaseVisitor.java b/LanguageServer/src/main/java/de/dhbw/parser/Java17ParserBaseVisitor.java index 6c249c9..281c3b2 100644 --- a/LanguageServer/src/main/java/de/dhbw/parser/Java17ParserBaseVisitor.java +++ b/LanguageServer/src/main/java/de/dhbw/parser/Java17ParserBaseVisitor.java @@ -1,4 +1,4 @@ -package de.dhbw.parser;// Generated from /home/ruben/Documents/JavaCompilerCore/src/main/antlr4/de/dhbwstuttgart/parser/antlr/Java17Parser.g4 by ANTLR 4.13.1 +package de.dhbw.parser;// Generated from C:/Users/ruben/IdeaProjects/JavaCompilerCore/src/main/antlr4/de/dhbwstuttgart/parser/antlr/Java17Parser.g4 by ANTLR 4.13.1 import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor; /** diff --git a/LanguageServer/src/main/java/de/dhbw/parser/Java17ParserListener.java b/LanguageServer/src/main/java/de/dhbw/parser/Java17ParserListener.java index d40068a..276ab4e 100644 --- a/LanguageServer/src/main/java/de/dhbw/parser/Java17ParserListener.java +++ b/LanguageServer/src/main/java/de/dhbw/parser/Java17ParserListener.java @@ -1,4 +1,4 @@ -package de.dhbw.parser;// Generated from /home/ruben/Documents/JavaCompilerCore/src/main/antlr4/de/dhbwstuttgart/parser/antlr/Java17Parser.g4 by ANTLR 4.13.1 +package de.dhbw.parser;// Generated from C:/Users/ruben/IdeaProjects/JavaCompilerCore/src/main/antlr4/de/dhbwstuttgart/parser/antlr/Java17Parser.g4 by ANTLR 4.13.1 import org.antlr.v4.runtime.tree.ParseTreeListener; /** diff --git a/LanguageServer/src/main/java/de/dhbw/parser/Java17ParserVisitor.java b/LanguageServer/src/main/java/de/dhbw/parser/Java17ParserVisitor.java index fe90e75..98b0cc7 100644 --- a/LanguageServer/src/main/java/de/dhbw/parser/Java17ParserVisitor.java +++ b/LanguageServer/src/main/java/de/dhbw/parser/Java17ParserVisitor.java @@ -1,4 +1,4 @@ -package de.dhbw.parser;// Generated from /home/ruben/Documents/JavaCompilerCore/src/main/antlr4/de/dhbwstuttgart/parser/antlr/Java17Parser.g4 by ANTLR 4.13.1 +package de.dhbw.parser;// Generated from C:/Users/ruben/IdeaProjects/JavaCompilerCore/src/main/antlr4/de/dhbwstuttgart/parser/antlr/Java17Parser.g4 by ANTLR 4.13.1 import org.antlr.v4.runtime.tree.ParseTreeVisitor; /**