From 5582872ea524473f2b5f611604c2433019e3345b Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Mon, 10 Jul 2023 01:15:45 +0600 Subject: [PATCH 01/43] added automatic suppression of UNCHECKED_CAST --- backend/src/main/kotlin/io/kabu/backend/generator/Writer.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/src/main/kotlin/io/kabu/backend/generator/Writer.kt b/backend/src/main/kotlin/io/kabu/backend/generator/Writer.kt index c9690c1..283fe4a 100644 --- a/backend/src/main/kotlin/io/kabu/backend/generator/Writer.kt +++ b/backend/src/main/kotlin/io/kabu/backend/generator/Writer.kt @@ -51,6 +51,7 @@ class Writer { .addMember(CodeBlock.of("%S", "FunctionName")) .addMember(CodeBlock.of("%S", "ObjectPropertyName")) .addMember(CodeBlock.of("%S", "MemberVisibilityCanBePrivate")) + .addMember(CodeBlock.of("%S", "UNCHECKED_CAST")) .build() ) From ceaa7f2519b051f01f307dba90d09375d52bc759 Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Tue, 11 Jul 2023 22:07:36 +0600 Subject: [PATCH 02/43] refactoring --- .../io/kabu/backend/analyzer/AnalyzerImpl.kt | 1 - .../backend/analyzer/ParametersRegistry.kt | 22 +++++++++---------- .../kabu/backend/analyzer/handler/Handler.kt | 8 +++---- .../analyzer/handler/IdentifierHandler.kt | 2 +- .../analyzer/handler/OperatorHandler.kt | 4 ++-- .../extension/ExtensionLambdaHandler.kt | 4 ++-- .../AbstractCallableDeclaration.kt | 5 +++-- .../ContextMediatorClassDeclaration.kt | 4 ++-- .../util/TerminalCallableBuilder.kt | 2 +- .../diagnostic/builder/ErrorBuilders.kt | 11 +++++----- .../inout/input/ProcessingInputRenderer.kt | 4 ++-- .../input/method/ContextConstructorMethod.kt | 4 ++-- .../input/method/ContextCreatorMethod.kt | 4 ++-- .../inout/input/method/GlobalPatternMethod.kt | 4 ++-- .../inout/input/method/LocalPatternMethod.kt | 4 ++-- .../kabu/backend/inout/input/method/Method.kt | 4 ++-- .../inout/input/method/PatternMethod.kt | 4 ++-- .../node/ContextMediatorTypeNodeImpl.kt | 4 ++-- .../{EntryParameter.kt => Parameter.kt} | 2 +- .../provider/group/FunDeclarationProviders.kt | 4 ++-- .../group/FunDeclarationProvidersFactory.kt | 3 ++- .../backend/provider/group/RawProviders.kt | 3 ++- .../provider/AbstractWatchedProvider.kt | 5 +---- .../provider/provider/AssignProvider.kt | 5 +---- .../provider/provider/ComparisonProvider.kt | 5 +---- .../provider/provider/HolderProvider.kt | 2 -- .../provider/provider/InclusionProvider.kt | 5 +---- .../io/kabu/backend/integration/TestUtils.kt | 2 -- .../test/PropertyVsTypeConflictTest.kt | 2 +- .../backend/pattern/PatternWithSignature.kt | 7 +++--- .../io/kabu/backend/pattern/Signature.kt | 4 ++-- .../kabu/backend/planner/AnalyzerTestUtils.kt | 6 ++--- .../frontend/ksp/processor/util/TypeUtils.kt | 4 ++-- 33 files changed, 69 insertions(+), 85 deletions(-) rename backend/src/main/kotlin/io/kabu/backend/parameter/{EntryParameter.kt => Parameter.kt} (94%) diff --git a/backend/src/main/kotlin/io/kabu/backend/analyzer/AnalyzerImpl.kt b/backend/src/main/kotlin/io/kabu/backend/analyzer/AnalyzerImpl.kt index 09fae9c..55f1e50 100644 --- a/backend/src/main/kotlin/io/kabu/backend/analyzer/AnalyzerImpl.kt +++ b/backend/src/main/kotlin/io/kabu/backend/analyzer/AnalyzerImpl.kt @@ -136,7 +136,6 @@ class AnalyzerImpl( //todo check: creating different objects for same method parameter val operatorInfoProvider = method.parameters.getOrNull(nextExpectedParameterIndex) ?.takeIf { it.type.isOperatorInfoType } - ?.let { BaseProvider(it.type.toFixedTypeNode(), it.origin) } val right: List = expressions.drop(1) .map { providerOf(it) } diff --git a/backend/src/main/kotlin/io/kabu/backend/analyzer/ParametersRegistry.kt b/backend/src/main/kotlin/io/kabu/backend/analyzer/ParametersRegistry.kt index 5da5cca..e7375c7 100644 --- a/backend/src/main/kotlin/io/kabu/backend/analyzer/ParametersRegistry.kt +++ b/backend/src/main/kotlin/io/kabu/backend/analyzer/ParametersRegistry.kt @@ -4,7 +4,7 @@ import io.kabu.backend.analyzer.handler.lambda.watcher.OperatorInfoTypes.isOpera import io.kabu.backend.diagnostic.builder.sameNamedParametersError import io.kabu.backend.inout.input.method.PatternMethod import io.kabu.backend.node.FixedTypeNode -import io.kabu.backend.parameter.EntryParameter +import io.kabu.backend.parameter.Parameter import io.kabu.backend.parser.IdentifierLeaf import io.kabu.backend.parser.KotlinExpression import io.kabu.backend.util.Constants.RECEIVER_PARAMETER_NAME @@ -15,9 +15,9 @@ class ParametersRegistry( val expression: KotlinExpression ) { - val entryParameters: List = composeEntryParameters() + val parameters: List = composeParameters() .also { validateEntryParameters(it) } - val parametersTypes: Map = entryParameters + val parametersTypes: Map = parameters .groupBy({ it.name }, { it.type.toFixedTypeNode() }) .mapValues { it.value.single() } @@ -25,23 +25,23 @@ class ParametersRegistry( private var operatorInfoParametersUsed = false val strictMethodParametersOrdering get() = operatorInfoParametersUsed - private fun composeEntryParameters(): List { + private fun composeParameters(): List { val receiverParameter = method.receiverType?.let { - EntryParameter(RECEIVER_PARAMETER_NAME, it, method.origin) //todo origin for receiver + Parameter(RECEIVER_PARAMETER_NAME, it, method.origin) //todo origin for receiver } val parameterList = method.parameters.map { - EntryParameter(it.name, it.type, it.origin) + Parameter(it.name, it.type, it.origin) } return listOfNotNull(receiverParameter) + parameterList } - private fun validateEntryParameters(entryParameters: List) { - checkStrictParametersOrdering(entryParameters) + private fun validateEntryParameters(parameters: List) { + checkStrictParametersOrdering(parameters) checkReceiverParameterPresence() - checkForSameNamedParameters(entryParameters) + checkForSameNamedParameters(parameters) } - private fun checkForSameNamedParameters(methodParameters: List) { + private fun checkForSameNamedParameters(methodParameters: List) { val sameNamedParameters = methodParameters .groupBy { it.name } .filter { it.value.size > 1 } @@ -49,7 +49,7 @@ class ParametersRegistry( ?.let { (name, parameters) -> sameNamedParametersError(name, parameters) } } - private fun checkStrictParametersOrdering(methodParameters: List) { + private fun checkStrictParametersOrdering(methodParameters: List) { operatorInfoParametersUsed = methodParameters.any { it.type.isOperatorInfoType } } diff --git a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/Handler.kt b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/Handler.kt index 72cdd3c..46242a4 100644 --- a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/Handler.kt +++ b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/Handler.kt @@ -121,10 +121,10 @@ open class Handler( // creating watched provider of appropriate type val watchedProvider = when(operator) { - is Comparison -> ComparisonProvider(holderTypeNode, evaluatedParameters, analyzer) - is InclusionCheck -> InclusionProvider(holderTypeNode, evaluatedParameters, analyzer) - is ModAssign -> AssignProvider(holderTypeNode, evaluatedParameters, analyzer) - else -> AssignProvider(holderTypeNode, evaluatedParameters, analyzer) + is Comparison -> ComparisonProvider(holderTypeNode, evaluatedParameters) + is InclusionCheck -> InclusionProvider(holderTypeNode, evaluatedParameters) + is ModAssign -> AssignProvider(holderTypeNode, evaluatedParameters) + else -> AssignProvider(holderTypeNode, evaluatedParameters) } return AuxProvider(returningTypeNode, watchedProvider) diff --git a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/IdentifierHandler.kt b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/IdentifierHandler.kt index e41ccf3..67dbfd1 100644 --- a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/IdentifierHandler.kt +++ b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/IdentifierHandler.kt @@ -119,6 +119,6 @@ class IdentifierHandler(analyzer: AnalyzerImpl) : Handler(analyzer) { val functionNode = WrapperPropertyNode(name, holderTypeNode, namespaceNode, funDeclarationProviders) registerNode(functionNode) - return HolderProvider(holderTypeNode, evaluatedParameters, analyzer) + return HolderProvider(holderTypeNode, evaluatedParameters) } } diff --git a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/OperatorHandler.kt b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/OperatorHandler.kt index e87c7a8..7f8ad52 100644 --- a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/OperatorHandler.kt +++ b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/OperatorHandler.kt @@ -193,7 +193,7 @@ class OperatorHandler(analyzer: AnalyzerImpl) : Handler(analyzer) { ) registerNode(functionNode) - return HolderProvider(holderTypeNode, evaluatedParameters, analyzer) + return HolderProvider(holderTypeNode, evaluatedParameters) } private fun createHolderTypeAndProperty( @@ -218,7 +218,7 @@ class OperatorHandler(analyzer: AnalyzerImpl) : Handler(analyzer) { ) registerNode(propertyNode) - return HolderProvider(holderTypeNode, evaluatedParameters, analyzer) + return HolderProvider(holderTypeNode, evaluatedParameters) } private fun createHolderTypeAndIndexedAssignOperator( diff --git a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/extension/ExtensionLambdaHandler.kt b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/extension/ExtensionLambdaHandler.kt index 8510b71..965f916 100644 --- a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/extension/ExtensionLambdaHandler.kt +++ b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/extension/ExtensionLambdaHandler.kt @@ -11,7 +11,7 @@ import io.kabu.backend.node.ContextMediatorTypeNode import io.kabu.backend.node.DerivativeTypeNode import io.kabu.backend.node.factory.node.ContextMediatorTypeNodeImpl import io.kabu.backend.node.namespace.NamespaceNode -import io.kabu.backend.parameter.EntryParameter +import io.kabu.backend.parameter.Parameter import io.kabu.backend.parser.LambdaExpression import io.kabu.backend.processor.MethodsRegistry import io.kabu.backend.provider.provider.ArgumentProvider @@ -48,7 +48,7 @@ class ExtensionLambdaHandler( val contextMediatorTypeNode = ContextMediatorTypeNodeImpl( name = contextMediatorClassSimpleName, namespaceNode = contextMediatorNamespaceNode, - contextProperty = EntryParameter(EXTENSION_CONTEXT_PROPERTY_NAME, extensionContextTypeName), + contextProperty = Parameter(EXTENSION_CONTEXT_PROPERTY_NAME, extensionContextTypeName), ) registerNode(contextMediatorTypeNode) diff --git a/backend/src/main/kotlin/io/kabu/backend/declaration/AbstractCallableDeclaration.kt b/backend/src/main/kotlin/io/kabu/backend/declaration/AbstractCallableDeclaration.kt index a485af5..b34e936 100644 --- a/backend/src/main/kotlin/io/kabu/backend/declaration/AbstractCallableDeclaration.kt +++ b/backend/src/main/kotlin/io/kabu/backend/declaration/AbstractCallableDeclaration.kt @@ -2,6 +2,7 @@ package io.kabu.backend.declaration import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.CodeBlock +import com.squareup.kotlinpoet.TypeName import io.kabu.backend.analyzer.handler.lambda.watcher.OperatorInfoTypes import io.kabu.backend.node.TypeNode import io.kabu.backend.parser.FunctionMustReturn @@ -97,8 +98,8 @@ abstract class AbstractCallableDeclaration : Declaration() { .asCodeBlock() } - private fun getReturnStatementForComparison(operatorInfoType: TypeNode?): String { - return when (operatorInfoType?.typeName) { + private fun getReturnStatementForComparison(operatorInfoType: TypeName?): String { + return when (operatorInfoType) { OperatorInfoTypes.RANKING_COMPARISON_INFO_TYPE -> "return 42" OperatorInfoTypes.STRICTNESS_COMPARISON_INFO_TYPE -> "return 0" else -> "return 42" diff --git a/backend/src/main/kotlin/io/kabu/backend/declaration/classes/ContextMediatorClassDeclaration.kt b/backend/src/main/kotlin/io/kabu/backend/declaration/classes/ContextMediatorClassDeclaration.kt index 4db333a..faa6d16 100644 --- a/backend/src/main/kotlin/io/kabu/backend/declaration/classes/ContextMediatorClassDeclaration.kt +++ b/backend/src/main/kotlin/io/kabu/backend/declaration/classes/ContextMediatorClassDeclaration.kt @@ -8,12 +8,12 @@ import com.squareup.kotlinpoet.TypeSpec import io.kabu.backend.declaration.AbstractTypeDeclaration import io.kabu.backend.declaration.Declaration import io.kabu.backend.generator.addDeclarations -import io.kabu.backend.parameter.EntryParameter +import io.kabu.backend.parameter.Parameter class ContextMediatorClassDeclaration( override val className: ClassName, - val contextProperty: EntryParameter, + val contextProperty: Parameter, ) : AbstractTypeDeclaration() { // for adding declarations on generation code phase diff --git a/backend/src/main/kotlin/io/kabu/backend/declaration/util/TerminalCallableBuilder.kt b/backend/src/main/kotlin/io/kabu/backend/declaration/util/TerminalCallableBuilder.kt index 9b65e10..1d242c2 100644 --- a/backend/src/main/kotlin/io/kabu/backend/declaration/util/TerminalCallableBuilder.kt +++ b/backend/src/main/kotlin/io/kabu/backend/declaration/util/TerminalCallableBuilder.kt @@ -46,7 +46,7 @@ class TerminalCallableBuilder { .findProviders { it is ArgumentProvider } var latestIdentifierParameterIndex = -1 - val providers: List = parametersRegistry.entryParameters.map { signatureParameter -> + val providers: List = parametersRegistry.parameters.map { signatureParameter -> if (signatureParameter.type.isOperatorInfoType) { patternOrderedEnumeration.elementAtOrNull(latestIdentifierParameterIndex + 1) ?.takeIf { it.type.isOperatorInfoType } diff --git a/backend/src/main/kotlin/io/kabu/backend/diagnostic/builder/ErrorBuilders.kt b/backend/src/main/kotlin/io/kabu/backend/diagnostic/builder/ErrorBuilders.kt index 7d4dcb0..02212cf 100644 --- a/backend/src/main/kotlin/io/kabu/backend/diagnostic/builder/ErrorBuilders.kt +++ b/backend/src/main/kotlin/io/kabu/backend/diagnostic/builder/ErrorBuilders.kt @@ -5,20 +5,19 @@ import io.kabu.backend.diagnostic.Origin import io.kabu.backend.diagnostic.diagnosticError import io.kabu.backend.exception.PatternParsingException import io.kabu.backend.inout.input.method.PatternMethod -import io.kabu.backend.parameter.EntryParameter +import io.kabu.backend.parameter.Parameter import io.kabu.backend.parser.Annotation import io.kabu.backend.parser.KotlinExpression import io.kabu.backend.parser.LambdaExpression import io.kabu.backend.parser.NaryExpression import io.kabu.backend.parser.Operator -import io.kabu.backend.provider.provider.BaseProvider import io.kabu.backend.util.Constants.EXTENSION_ANNOTATION import io.kabu.backend.util.Constants.EXTENSION_ANNOTATION_CONTEXT_CREATOR import io.kabu.backend.util.Constants.EXTENSION_ANNOTATION_CONTEXT_PARAMETER import io.kabu.backend.util.Constants.RECEIVER_PARAMETER_NAME -internal fun strictParametersOrderingError(expressionName: String, expectedParameter: EntryParameter): Nothing { +internal fun strictParametersOrderingError(expressionName: String, expectedParameter: Parameter): Nothing { diagnosticError( "Strict method parameters ordering failed on '$expressionName'. Expected '${expectedParameter.name}'", expectedParameter.origin @@ -66,18 +65,18 @@ internal fun extensionAnnotationMissingError(expression: LambdaExpression): Noth ) } -internal fun sameNamedParametersError(name: String, parameters: List): Nothing { +internal fun sameNamedParametersError(name: String, parameters: List): Nothing { diagnosticError("Function contains parameters with same name: '$name'", parameters.mapNotNull { it.origin }) } -internal fun signatureParameterMissingInPatternError(signatureParameter: EntryParameter): Nothing { +internal fun signatureParameterMissingInPatternError(signatureParameter: Parameter): Nothing { diagnosticError( "Signature parameter $signatureParameter is missing in expression pattern", signatureParameter.origin ) } -internal fun signatureParameterMissingError(signatureParameter: EntryParameter): Nothing { +internal fun signatureParameterMissingError(signatureParameter: Parameter): Nothing { diagnosticError( "Signature parameter $signatureParameter not found", signatureParameter.origin diff --git a/backend/src/main/kotlin/io/kabu/backend/inout/input/ProcessingInputRenderer.kt b/backend/src/main/kotlin/io/kabu/backend/inout/input/ProcessingInputRenderer.kt index d7f53e3..b36979a 100644 --- a/backend/src/main/kotlin/io/kabu/backend/inout/input/ProcessingInputRenderer.kt +++ b/backend/src/main/kotlin/io/kabu/backend/inout/input/ProcessingInputRenderer.kt @@ -11,7 +11,7 @@ import io.kabu.backend.inout.input.method.ContextCreatorMethod import io.kabu.backend.inout.input.method.GlobalPatternMethod import io.kabu.backend.inout.input.method.LocalPatternMethod import io.kabu.backend.inout.input.method.Method -import io.kabu.backend.parameter.EntryParameter +import io.kabu.backend.parameter.Parameter val ProcessingInput.dslDefinitionString: String @@ -69,7 +69,7 @@ private fun ContextCreatorMethod.dslString() = when (this) { } } -private fun StringBuilder.appendParameters(parameters: List) { +private fun StringBuilder.appendParameters(parameters: List) { if (parameters.isNotEmpty()) { appendLine("${IND3}parameters(") parameters.forEach { diff --git a/backend/src/main/kotlin/io/kabu/backend/inout/input/method/ContextConstructorMethod.kt b/backend/src/main/kotlin/io/kabu/backend/inout/input/method/ContextConstructorMethod.kt index cc8697e..de37409 100644 --- a/backend/src/main/kotlin/io/kabu/backend/inout/input/method/ContextConstructorMethod.kt +++ b/backend/src/main/kotlin/io/kabu/backend/inout/input/method/ContextConstructorMethod.kt @@ -2,7 +2,7 @@ package io.kabu.backend.inout.input.method import com.squareup.kotlinpoet.TypeName import io.kabu.backend.diagnostic.Origin -import io.kabu.backend.parameter.EntryParameter +import io.kabu.backend.parameter.Parameter import io.kabu.backend.provider.provider.Provider import io.kabu.backend.provider.provider.ProviderContainer @@ -11,7 +11,7 @@ class ContextConstructorMethod( name: String, returnedType: TypeName, receiverType: TypeName?, - parameters: List, + parameters: List, contextName: String, val declaringType: TypeName, origin: Origin diff --git a/backend/src/main/kotlin/io/kabu/backend/inout/input/method/ContextCreatorMethod.kt b/backend/src/main/kotlin/io/kabu/backend/inout/input/method/ContextCreatorMethod.kt index 6a33251..9e023a0 100644 --- a/backend/src/main/kotlin/io/kabu/backend/inout/input/method/ContextCreatorMethod.kt +++ b/backend/src/main/kotlin/io/kabu/backend/inout/input/method/ContextCreatorMethod.kt @@ -2,7 +2,7 @@ package io.kabu.backend.inout.input.method import com.squareup.kotlinpoet.TypeName import io.kabu.backend.diagnostic.Origin -import io.kabu.backend.parameter.EntryParameter +import io.kabu.backend.parameter.Parameter import io.kabu.backend.provider.provider.Provider import io.kabu.backend.provider.provider.ProviderContainer @@ -11,7 +11,7 @@ open class ContextCreatorMethod( name: String, returnedType: TypeName, receiverType: TypeName?, - parameters: List, + parameters: List, val contextName: String, origin: Origin ) : Method( diff --git a/backend/src/main/kotlin/io/kabu/backend/inout/input/method/GlobalPatternMethod.kt b/backend/src/main/kotlin/io/kabu/backend/inout/input/method/GlobalPatternMethod.kt index 72fa805..63f970d 100644 --- a/backend/src/main/kotlin/io/kabu/backend/inout/input/method/GlobalPatternMethod.kt +++ b/backend/src/main/kotlin/io/kabu/backend/inout/input/method/GlobalPatternMethod.kt @@ -2,14 +2,14 @@ package io.kabu.backend.inout.input.method import com.squareup.kotlinpoet.TypeName import io.kabu.backend.diagnostic.Origin -import io.kabu.backend.parameter.EntryParameter +import io.kabu.backend.parameter.Parameter class GlobalPatternMethod( packageName: String, name: String, returnedType: TypeName, receiverType: TypeName?, - parameters: List, + parameters: List, pattern: String, origin: Origin ) : PatternMethod( diff --git a/backend/src/main/kotlin/io/kabu/backend/inout/input/method/LocalPatternMethod.kt b/backend/src/main/kotlin/io/kabu/backend/inout/input/method/LocalPatternMethod.kt index 2280b1d..1d7f7ce 100644 --- a/backend/src/main/kotlin/io/kabu/backend/inout/input/method/LocalPatternMethod.kt +++ b/backend/src/main/kotlin/io/kabu/backend/inout/input/method/LocalPatternMethod.kt @@ -2,14 +2,14 @@ package io.kabu.backend.inout.input.method import com.squareup.kotlinpoet.TypeName import io.kabu.backend.diagnostic.Origin -import io.kabu.backend.parameter.EntryParameter +import io.kabu.backend.parameter.Parameter class LocalPatternMethod( packageName: String, name: String, returnedType: TypeName, receiverType: TypeName?, - parameters: List, + parameters: List, pattern: String, val declaringType: TypeName, origin: Origin diff --git a/backend/src/main/kotlin/io/kabu/backend/inout/input/method/Method.kt b/backend/src/main/kotlin/io/kabu/backend/inout/input/method/Method.kt index fe00cab..9bb5eca 100644 --- a/backend/src/main/kotlin/io/kabu/backend/inout/input/method/Method.kt +++ b/backend/src/main/kotlin/io/kabu/backend/inout/input/method/Method.kt @@ -3,14 +3,14 @@ package io.kabu.backend.inout.input.method import com.squareup.kotlinpoet.TypeName import io.kabu.backend.diagnostic.HasOrigin import io.kabu.backend.diagnostic.Origin -import io.kabu.backend.parameter.EntryParameter +import io.kabu.backend.parameter.Parameter open class Method( val packageName: String, val name: String, open val returnedType: TypeName, val receiverType: TypeName?, - val parameters: List, + val parameters: List, override val origin: Origin ) : HasOrigin { diff --git a/backend/src/main/kotlin/io/kabu/backend/inout/input/method/PatternMethod.kt b/backend/src/main/kotlin/io/kabu/backend/inout/input/method/PatternMethod.kt index 0bb8cbe..9d74f3e 100644 --- a/backend/src/main/kotlin/io/kabu/backend/inout/input/method/PatternMethod.kt +++ b/backend/src/main/kotlin/io/kabu/backend/inout/input/method/PatternMethod.kt @@ -2,14 +2,14 @@ package io.kabu.backend.inout.input.method import com.squareup.kotlinpoet.TypeName import io.kabu.backend.diagnostic.Origin -import io.kabu.backend.parameter.EntryParameter +import io.kabu.backend.parameter.Parameter abstract class PatternMethod( packageName: String, name: String, returnedType: TypeName, receiverType: TypeName?, - parameters: List, + parameters: List, val pattern: String, //todo get origin of pattern annotation as well origin: Origin ) : Method( diff --git a/backend/src/main/kotlin/io/kabu/backend/node/factory/node/ContextMediatorTypeNodeImpl.kt b/backend/src/main/kotlin/io/kabu/backend/node/factory/node/ContextMediatorTypeNodeImpl.kt index ab11376..5503113 100644 --- a/backend/src/main/kotlin/io/kabu/backend/node/factory/node/ContextMediatorTypeNodeImpl.kt +++ b/backend/src/main/kotlin/io/kabu/backend/node/factory/node/ContextMediatorTypeNodeImpl.kt @@ -3,12 +3,12 @@ package io.kabu.backend.node.factory.node import io.kabu.backend.declaration.classes.ContextMediatorClassDeclaration import io.kabu.backend.node.ContextMediatorTypeNode import io.kabu.backend.node.namespace.NamespaceNode -import io.kabu.backend.parameter.EntryParameter +import io.kabu.backend.parameter.Parameter class ContextMediatorTypeNodeImpl( name: String, namespaceNode: NamespaceNode, - private val contextProperty: EntryParameter, + private val contextProperty: Parameter, ) : ContextMediatorTypeNode( name = name, desiredName = null, diff --git a/backend/src/main/kotlin/io/kabu/backend/parameter/EntryParameter.kt b/backend/src/main/kotlin/io/kabu/backend/parameter/Parameter.kt similarity index 94% rename from backend/src/main/kotlin/io/kabu/backend/parameter/EntryParameter.kt rename to backend/src/main/kotlin/io/kabu/backend/parameter/Parameter.kt index c8dc289..9a3bd05 100644 --- a/backend/src/main/kotlin/io/kabu/backend/parameter/EntryParameter.kt +++ b/backend/src/main/kotlin/io/kabu/backend/parameter/Parameter.kt @@ -3,7 +3,7 @@ package io.kabu.backend.parameter import com.squareup.kotlinpoet.TypeName import io.kabu.backend.diagnostic.Origin -class EntryParameter( +class Parameter( val name: String, val type: TypeName, val origin: Origin? = null, diff --git a/backend/src/main/kotlin/io/kabu/backend/provider/group/FunDeclarationProviders.kt b/backend/src/main/kotlin/io/kabu/backend/provider/group/FunDeclarationProviders.kt index 1fc688a..25aced4 100644 --- a/backend/src/main/kotlin/io/kabu/backend/provider/group/FunDeclarationProviders.kt +++ b/backend/src/main/kotlin/io/kabu/backend/provider/group/FunDeclarationProviders.kt @@ -1,8 +1,8 @@ package io.kabu.backend.provider.group +import com.squareup.kotlinpoet.TypeName import io.kabu.backend.diagnostic.builder.unexpectedInvertedOrderingError import io.kabu.backend.integration.NameAndType -import io.kabu.backend.node.TypeNode import io.kabu.backend.provider.provider.NoReceiverProvider import io.kabu.backend.provider.provider.Provider @@ -15,7 +15,7 @@ import io.kabu.backend.provider.provider.Provider class FunDeclarationProviders( val providers: OrderedNamedProviders, val invertedOrdering: Boolean, - val operatorInfoType: TypeNode? = null, //todo revise + val operatorInfoType: TypeName? = null, //todo revise ) { init { diff --git a/backend/src/main/kotlin/io/kabu/backend/provider/group/FunDeclarationProvidersFactory.kt b/backend/src/main/kotlin/io/kabu/backend/provider/group/FunDeclarationProvidersFactory.kt index 604b3e0..616633e 100644 --- a/backend/src/main/kotlin/io/kabu/backend/provider/group/FunDeclarationProvidersFactory.kt +++ b/backend/src/main/kotlin/io/kabu/backend/provider/group/FunDeclarationProvidersFactory.kt @@ -3,6 +3,7 @@ package io.kabu.backend.provider.group import io.kabu.backend.diagnostic.builder.binaryOperatorRequiredForSetterError import io.kabu.backend.diagnostic.builder.unexpectedInvertedOrderingError import io.kabu.backend.provider.provider.Provider +import io.kabu.backend.util.poet.TypeNameUtils.toFixedTypeNode object FunDeclarationProvidersFactory { @@ -40,7 +41,7 @@ object FunDeclarationProvidersFactory { return FunDeclarationProviders( orderedNamesProviders, invertedOrdering, - rawProviders.operatorInfoParameter?.typeNode + rawProviders.operatorInfoParameter?.type ) } diff --git a/backend/src/main/kotlin/io/kabu/backend/provider/group/RawProviders.kt b/backend/src/main/kotlin/io/kabu/backend/provider/group/RawProviders.kt index 4ff9edb..c52d2d1 100644 --- a/backend/src/main/kotlin/io/kabu/backend/provider/group/RawProviders.kt +++ b/backend/src/main/kotlin/io/kabu/backend/provider/group/RawProviders.kt @@ -1,11 +1,12 @@ package io.kabu.backend.provider.group +import io.kabu.backend.parameter.Parameter import io.kabu.backend.provider.provider.Provider /** Parameters obtained from sub-expressions 'as-is' */ class RawProviders( val providersList: List, - val operatorInfoParameter: Provider?, + val operatorInfoParameter: Parameter?, ) { val left: Provider diff --git a/backend/src/main/kotlin/io/kabu/backend/provider/provider/AbstractWatchedProvider.kt b/backend/src/main/kotlin/io/kabu/backend/provider/provider/AbstractWatchedProvider.kt index 159a31f..4980e48 100644 --- a/backend/src/main/kotlin/io/kabu/backend/provider/provider/AbstractWatchedProvider.kt +++ b/backend/src/main/kotlin/io/kabu/backend/provider/provider/AbstractWatchedProvider.kt @@ -1,17 +1,14 @@ package io.kabu.backend.provider.provider -import io.kabu.backend.analyzer.Analyzer import io.kabu.backend.diagnostic.Origin import io.kabu.backend.node.TypeNode -import io.kabu.backend.provider.evaluation.ReplacementProviderWithCode abstract class AbstractWatchedProvider( typeNode: TypeNode, val providers: List, - val analyzer: Analyzer, origin: Origin? = null, -) : HolderProvider(typeNode, providers, analyzer, origin) { +) : HolderProvider(typeNode, providers, origin) { //todo introduce `class VariableName(val value: String)` / `class Code(val value: String)` abstract fun provideCodeForConstructionFromAux(auxName: String): String diff --git a/backend/src/main/kotlin/io/kabu/backend/provider/provider/AssignProvider.kt b/backend/src/main/kotlin/io/kabu/backend/provider/provider/AssignProvider.kt index b7647cd..1ce4ca6 100644 --- a/backend/src/main/kotlin/io/kabu/backend/provider/provider/AssignProvider.kt +++ b/backend/src/main/kotlin/io/kabu/backend/provider/provider/AssignProvider.kt @@ -1,17 +1,14 @@ package io.kabu.backend.provider.provider -import io.kabu.backend.analyzer.Analyzer import io.kabu.backend.node.HolderTypeNode import io.kabu.backend.node.TypeNode -import io.kabu.backend.provider.evaluation.ReplacementProviderWithCode import io.kabu.backend.provider.provider.WatcherLambdaProvider.Companion.STACK_PROPERTY_NAME class AssignProvider( typeNode: TypeNode, providers: List, - analyzer: Analyzer, -) : AbstractWatchedProvider(typeNode, providers, analyzer) { +) : AbstractWatchedProvider(typeNode, providers) { override fun provideCodeForConstructionFromAux(auxName: String): String { val holderClassCanonicalName = (typeNode as HolderTypeNode).className.canonicalName diff --git a/backend/src/main/kotlin/io/kabu/backend/provider/provider/ComparisonProvider.kt b/backend/src/main/kotlin/io/kabu/backend/provider/provider/ComparisonProvider.kt index 6180a5f..634f14c 100644 --- a/backend/src/main/kotlin/io/kabu/backend/provider/provider/ComparisonProvider.kt +++ b/backend/src/main/kotlin/io/kabu/backend/provider/provider/ComparisonProvider.kt @@ -1,19 +1,16 @@ package io.kabu.backend.provider.provider -import io.kabu.backend.analyzer.Analyzer import io.kabu.backend.analyzer.handler.lambda.watcher.OperatorInfoTypes.RANKING_COMPARISON_INFO_TYPE import io.kabu.backend.analyzer.handler.lambda.watcher.OperatorInfoTypes.STRICTNESS_COMPARISON_INFO_TYPE import io.kabu.backend.node.HolderTypeNode import io.kabu.backend.node.TypeNode -import io.kabu.backend.provider.evaluation.ReplacementProviderWithCode import io.kabu.backend.provider.provider.WatcherLambdaProvider.Companion.STACK_PROPERTY_NAME class ComparisonProvider( typeNode: TypeNode, providers: List, - analyzer: Analyzer, -) : AbstractWatchedProvider(typeNode, providers, analyzer) { +) : AbstractWatchedProvider(typeNode, providers) { override fun provideCodeForConstructionFromAux(auxName: String): String { val holderClassCanonicalName = (typeNode as HolderTypeNode).className.canonicalName diff --git a/backend/src/main/kotlin/io/kabu/backend/provider/provider/HolderProvider.kt b/backend/src/main/kotlin/io/kabu/backend/provider/provider/HolderProvider.kt index 348c087..b64484a 100644 --- a/backend/src/main/kotlin/io/kabu/backend/provider/provider/HolderProvider.kt +++ b/backend/src/main/kotlin/io/kabu/backend/provider/provider/HolderProvider.kt @@ -1,7 +1,6 @@ package io.kabu.backend.provider.provider import com.squareup.kotlinpoet.CodeBlock -import io.kabu.backend.analyzer.Analyzer import io.kabu.backend.diagnostic.Origin import io.kabu.backend.legacy.planner.FieldAccessCodeGenerator import io.kabu.backend.legacy.planner.HolderFieldsNamesGenerator.getNameForIndex @@ -14,7 +13,6 @@ import io.kabu.backend.util.decaps open class HolderProvider( typeNode: TypeNode, private val providers: List, - private val analyzer: Analyzer, //todo remove property origin: Origin? = null, ) : BaseProvider(typeNode, origin), Provider { diff --git a/backend/src/main/kotlin/io/kabu/backend/provider/provider/InclusionProvider.kt b/backend/src/main/kotlin/io/kabu/backend/provider/provider/InclusionProvider.kt index 30ceb78..2471df4 100644 --- a/backend/src/main/kotlin/io/kabu/backend/provider/provider/InclusionProvider.kt +++ b/backend/src/main/kotlin/io/kabu/backend/provider/provider/InclusionProvider.kt @@ -1,17 +1,14 @@ package io.kabu.backend.provider.provider -import io.kabu.backend.analyzer.Analyzer import io.kabu.backend.node.HolderTypeNode import io.kabu.backend.node.TypeNode -import io.kabu.backend.provider.evaluation.ReplacementProviderWithCode import io.kabu.backend.provider.provider.WatcherLambdaProvider.Companion.STACK_PROPERTY_NAME class InclusionProvider( typeNode: TypeNode, providers: List, - analyzer: Analyzer, -) : AbstractWatchedProvider(typeNode, providers, analyzer) { +) : AbstractWatchedProvider(typeNode, providers) { override fun provideCodeForConstructionFromAux(auxName: String): String { val holderClassCanonicalName = (typeNode as HolderTypeNode).className.canonicalName diff --git a/backend/src/test/kotlin/io/kabu/backend/integration/TestUtils.kt b/backend/src/test/kotlin/io/kabu/backend/integration/TestUtils.kt index 621dd1a..c8910f3 100644 --- a/backend/src/test/kotlin/io/kabu/backend/integration/TestUtils.kt +++ b/backend/src/test/kotlin/io/kabu/backend/integration/TestUtils.kt @@ -1,8 +1,6 @@ package io.kabu.backend.integration import io.kabu.backend.declaration.Declaration -import io.kabu.backend.integration.NameAndType -import io.kabu.backend.integration.NamedTypeNode import io.kabu.backend.node.FixedTypeNode import io.kabu.backend.node.FunctionNode import io.kabu.backend.node.Node diff --git a/backend/src/test/kotlin/io/kabu/backend/integration/test/PropertyVsTypeConflictTest.kt b/backend/src/test/kotlin/io/kabu/backend/integration/test/PropertyVsTypeConflictTest.kt index 5eb2564..113e4ec 100644 --- a/backend/src/test/kotlin/io/kabu/backend/integration/test/PropertyVsTypeConflictTest.kt +++ b/backend/src/test/kotlin/io/kabu/backend/integration/test/PropertyVsTypeConflictTest.kt @@ -131,7 +131,7 @@ class PropertyVsTypeConflictTest : IntegratorTest() { fun `property with receiver VS fixed type`() { val graph1 = buildAndShowGraph { val pkgNode1 = +pkgNode1() - +fixed("UserType", pkgNode1) //todo fix test + +fixed("UserType", pkgNode1) } val graph2 = buildAndShowGraph { val pkgNode1 = +pkgNode1() diff --git a/backend/src/test/kotlin/io/kabu/backend/pattern/PatternWithSignature.kt b/backend/src/test/kotlin/io/kabu/backend/pattern/PatternWithSignature.kt index 8e43c4b..973e1f5 100644 --- a/backend/src/test/kotlin/io/kabu/backend/pattern/PatternWithSignature.kt +++ b/backend/src/test/kotlin/io/kabu/backend/pattern/PatternWithSignature.kt @@ -8,7 +8,7 @@ import com.squareup.kotlinpoet.STRING import com.squareup.kotlinpoet.TypeName import com.squareup.kotlinpoet.UNIT import io.kabu.backend.analyzer.handler.lambda.watcher.OperatorInfoTypes -import io.kabu.backend.parameter.EntryParameter +import io.kabu.backend.parameter.Parameter class PatternWithSignature(input: String) { @@ -28,7 +28,7 @@ class PatternWithSignature(input: String) { */ private fun parseShortParametersString(shortStringParameters: String): Signature { - fun decode(shortCode: String): EntryParameter { + fun decode(shortCode: String): Parameter { var code = shortCode // nullability @@ -41,7 +41,7 @@ class PatternWithSignature(input: String) { // type val typeName = typeCodeToTypeName(code).copy(nullable = nullable) - return EntryParameter(identifier, typeName) + return Parameter(identifier, typeName) } var str = shortStringParameters @@ -58,7 +58,6 @@ class PatternWithSignature(input: String) { val parametersPart = str val receiver = receiverPart?.trim()?.let(::decode)?.type - //todo orEmpty val params = parametersPart.trim().takeIf { it.isNotEmpty() }?.split(WHITESPACES)?.map(::decode) ?: emptyList() val returns = returnsPart?.trim()?.let(::decode)?.type ?: UNIT diff --git a/backend/src/test/kotlin/io/kabu/backend/pattern/Signature.kt b/backend/src/test/kotlin/io/kabu/backend/pattern/Signature.kt index 13f973b..8fd9fdc 100644 --- a/backend/src/test/kotlin/io/kabu/backend/pattern/Signature.kt +++ b/backend/src/test/kotlin/io/kabu/backend/pattern/Signature.kt @@ -1,11 +1,11 @@ package io.kabu.backend.pattern import com.squareup.kotlinpoet.TypeName -import io.kabu.backend.parameter.EntryParameter +import io.kabu.backend.parameter.Parameter /** Result of parsing the signature string of test string */ data class Signature( val receiverType: TypeName?, - val parameters: List, + val parameters: List, val returnedType: TypeName ) diff --git a/backend/src/test/kotlin/io/kabu/backend/planner/AnalyzerTestUtils.kt b/backend/src/test/kotlin/io/kabu/backend/planner/AnalyzerTestUtils.kt index 463e3f9..cfa0e04 100644 --- a/backend/src/test/kotlin/io/kabu/backend/planner/AnalyzerTestUtils.kt +++ b/backend/src/test/kotlin/io/kabu/backend/planner/AnalyzerTestUtils.kt @@ -2,7 +2,7 @@ package io.kabu.backend.planner import com.squareup.kotlinpoet.TypeName import io.kabu.backend.common.log.InterceptingLogging -import io.kabu.backend.parameter.EntryParameter +import io.kabu.backend.parameter.Parameter import io.kabu.backend.planner.AnalyzerTestUtils.logger import io.kabu.backend.util.Constants @@ -17,8 +17,8 @@ object AnalyzerTestUtils { val logger = InterceptingLogging.logger {} } -fun parametersOf(vararg params: Pair): List { - return params.map { EntryParameter(it.first, it.second) } +fun parametersOf(vararg params: Pair): List { + return params.map { Parameter(it.first, it.second) } } fun completion(vararg parameters: Any?) { diff --git a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/TypeUtils.kt b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/TypeUtils.kt index aa8122e..1885e73 100644 --- a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/TypeUtils.kt +++ b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/TypeUtils.kt @@ -17,7 +17,7 @@ import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy import com.squareup.kotlinpoet.TypeName import io.kabu.backend.exception.PatternProcessingException import io.kabu.backend.inout.input.method.Method -import io.kabu.backend.parameter.EntryParameter +import io.kabu.backend.parameter.Parameter import io.kabu.frontend.ksp.diagnostic.builder.parameterProcessingError @@ -32,7 +32,7 @@ internal fun KSFunctionDeclaration.toMethod(): Method { val name = parameter.name!!.asString() //todo check try { - EntryParameter(name, parameter.type.toTypeName(), parameterOrigin) + Parameter(name, parameter.type.toTypeName(), parameterOrigin) } catch (e: PatternProcessingException) { parameterProcessingError(name, methodName, e, parameterOrigin) } From d0e3d667608cf46e3cce3fce08e724498cfdc11b Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Thu, 13 Jul 2023 00:18:55 +0600 Subject: [PATCH 03/43] implemented origin for function receiver --- .../io/kabu/backend/analyzer/AnalyzerImpl.kt | 2 -- .../backend/analyzer/ParametersRegistry.kt | 9 +++--- .../analyzer/handler/IdentifierHandler.kt | 6 ++-- .../input/method/ContextConstructorMethod.kt | 6 ++-- .../input/method/ContextCreatorMethod.kt | 8 ++--- .../inout/input/method/GlobalPatternMethod.kt | 6 ++-- .../inout/input/method/LocalPatternMethod.kt | 6 ++-- .../kabu/backend/inout/input/method/Method.kt | 6 ++-- .../inout/input/method/PatternMethod.kt | 6 ++-- .../backend/pattern/PatternWithSignature.kt | 5 ++-- .../io/kabu/backend/pattern/Signature.kt | 2 +- .../kabu/backend/planner/AnalyzerAdHocTest.kt | 2 +- .../io/kabu/backend/planner/AnalyzerTest.kt | 2 +- .../detector/BaseConflictDetectorTest.kt | 2 +- .../kotlin/io/kabu/backend/plannerx/XTest.kt | 2 +- .../test/kotlin/io/kabu/backend/r2c/Utils.kt | 10 ++----- .../frontend/ksp/processor/util/TypeUtils.kt | 29 +++++++++++++------ 17 files changed, 57 insertions(+), 52 deletions(-) diff --git a/backend/src/main/kotlin/io/kabu/backend/analyzer/AnalyzerImpl.kt b/backend/src/main/kotlin/io/kabu/backend/analyzer/AnalyzerImpl.kt index 55f1e50..95541a1 100644 --- a/backend/src/main/kotlin/io/kabu/backend/analyzer/AnalyzerImpl.kt +++ b/backend/src/main/kotlin/io/kabu/backend/analyzer/AnalyzerImpl.kt @@ -29,10 +29,8 @@ import io.kabu.backend.parser.PatternString import io.kabu.backend.processor.MethodsRegistry import io.kabu.backend.processor.Options import io.kabu.backend.provider.group.RawProviders -import io.kabu.backend.provider.provider.BaseProvider import io.kabu.backend.provider.provider.Provider import io.kabu.backend.util.Constants -import io.kabu.backend.util.poet.TypeNameUtils.toFixedTypeNode class AnalyzerImpl( diff --git a/backend/src/main/kotlin/io/kabu/backend/analyzer/ParametersRegistry.kt b/backend/src/main/kotlin/io/kabu/backend/analyzer/ParametersRegistry.kt index e7375c7..1e4e578 100644 --- a/backend/src/main/kotlin/io/kabu/backend/analyzer/ParametersRegistry.kt +++ b/backend/src/main/kotlin/io/kabu/backend/analyzer/ParametersRegistry.kt @@ -25,14 +25,13 @@ class ParametersRegistry( private var operatorInfoParametersUsed = false val strictMethodParametersOrdering get() = operatorInfoParametersUsed + //todo simplify private fun composeParameters(): List { - val receiverParameter = method.receiverType?.let { - Parameter(RECEIVER_PARAMETER_NAME, it, method.origin) //todo origin for receiver - } - val parameterList = method.parameters.map { + val receiver = method.receiver + val parameterList = method.parameters.map { //todo unnecessary map? Parameter(it.name, it.type, it.origin) } - return listOfNotNull(receiverParameter) + parameterList + return listOfNotNull(receiver) + parameterList } private fun validateEntryParameters(parameters: List) { diff --git a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/IdentifierHandler.kt b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/IdentifierHandler.kt index 67dbfd1..c07db5a 100644 --- a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/IdentifierHandler.kt +++ b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/IdentifierHandler.kt @@ -103,13 +103,13 @@ class IdentifierHandler(analyzer: AnalyzerImpl) : Handler(analyzer) { private fun createReceiverHolderParameter(name: String): HolderProvider { val method = analyzer.method - val receiverType = method.receiverType //todo use receiverTypeNode + val receiverType = method.receiver?.type //todo use receiverTypeNode ?: diagnosticError("Creating receiver holder type declaration but no receiver type found", method) val receiverTypeNode = receiverType.toFixedTypeNode() - val receiverParameter = ArgumentProvider(receiverTypeNode, Constants.RECEIVER_PARAMETER_NAME) + val receiver = ArgumentProvider(receiverTypeNode, Constants.RECEIVER_PARAMETER_NAME) // Type - val rawProviders = RawProviders(listOf(receiverParameter), null) + val rawProviders = RawProviders(listOf(receiver), null) val funDeclarationProviders = FunDeclarationProvidersFactory.from(rawProviders, invertedOrdering = false) val functionBlockContext = FunctionBlockContext(funDeclarationProviders) val evaluatedParameters = functionBlockContext.doEvaluation() diff --git a/backend/src/main/kotlin/io/kabu/backend/inout/input/method/ContextConstructorMethod.kt b/backend/src/main/kotlin/io/kabu/backend/inout/input/method/ContextConstructorMethod.kt index de37409..6894792 100644 --- a/backend/src/main/kotlin/io/kabu/backend/inout/input/method/ContextConstructorMethod.kt +++ b/backend/src/main/kotlin/io/kabu/backend/inout/input/method/ContextConstructorMethod.kt @@ -10,7 +10,7 @@ class ContextConstructorMethod( packageName: String, name: String, returnedType: TypeName, - receiverType: TypeName?, + receiver: Parameter?, parameters: List, contextName: String, val declaringType: TypeName, @@ -19,7 +19,7 @@ class ContextConstructorMethod( packageName = packageName, name = name, returnedType = returnedType, - receiverType = receiverType, + receiver = receiver, parameters = parameters, contextName = contextName, origin = origin @@ -41,7 +41,7 @@ class ContextConstructorMethod( packageName = packageName, name = name, returnedType = returnedType, - receiverType = receiverType, + receiver = receiver, parameters = parameters, contextName = contextName, declaringType = enclosingTypeName, diff --git a/backend/src/main/kotlin/io/kabu/backend/inout/input/method/ContextCreatorMethod.kt b/backend/src/main/kotlin/io/kabu/backend/inout/input/method/ContextCreatorMethod.kt index 9e023a0..84c65e4 100644 --- a/backend/src/main/kotlin/io/kabu/backend/inout/input/method/ContextCreatorMethod.kt +++ b/backend/src/main/kotlin/io/kabu/backend/inout/input/method/ContextCreatorMethod.kt @@ -10,7 +10,7 @@ open class ContextCreatorMethod( packageName: String, name: String, returnedType: TypeName, - receiverType: TypeName?, + receiver: Parameter?, parameters: List, val contextName: String, origin: Origin @@ -18,9 +18,9 @@ open class ContextCreatorMethod( packageName, name, returnedType, - receiverType, + receiver, parameters, - origin + origin, ) { open fun getInvocationCode(providers: List, providerContainer: ProviderContainer): String { @@ -36,7 +36,7 @@ open class ContextCreatorMethod( packageName = packageName, name = name, returnedType = returnedType, - receiverType = receiverType, + receiver = receiver, parameters = parameters, contextName = contextName, origin = origin diff --git a/backend/src/main/kotlin/io/kabu/backend/inout/input/method/GlobalPatternMethod.kt b/backend/src/main/kotlin/io/kabu/backend/inout/input/method/GlobalPatternMethod.kt index 63f970d..77c8e34 100644 --- a/backend/src/main/kotlin/io/kabu/backend/inout/input/method/GlobalPatternMethod.kt +++ b/backend/src/main/kotlin/io/kabu/backend/inout/input/method/GlobalPatternMethod.kt @@ -8,7 +8,7 @@ class GlobalPatternMethod( packageName: String, name: String, returnedType: TypeName, - receiverType: TypeName?, + receiver: Parameter?, parameters: List, pattern: String, origin: Origin @@ -16,7 +16,7 @@ class GlobalPatternMethod( packageName, name, returnedType, - receiverType, + receiver, parameters, pattern, origin @@ -28,7 +28,7 @@ class GlobalPatternMethod( packageName = packageName, name = name, returnedType = returnedType, - receiverType = receiverType, + receiver = receiver, parameters = parameters, pattern = pattern, origin = origin diff --git a/backend/src/main/kotlin/io/kabu/backend/inout/input/method/LocalPatternMethod.kt b/backend/src/main/kotlin/io/kabu/backend/inout/input/method/LocalPatternMethod.kt index 1d7f7ce..ef8c5dd 100644 --- a/backend/src/main/kotlin/io/kabu/backend/inout/input/method/LocalPatternMethod.kt +++ b/backend/src/main/kotlin/io/kabu/backend/inout/input/method/LocalPatternMethod.kt @@ -8,7 +8,7 @@ class LocalPatternMethod( packageName: String, name: String, returnedType: TypeName, - receiverType: TypeName?, + receiver: Parameter?, parameters: List, pattern: String, val declaringType: TypeName, @@ -17,7 +17,7 @@ class LocalPatternMethod( packageName, name, returnedType, - receiverType, + receiver, parameters, pattern, origin @@ -29,7 +29,7 @@ class LocalPatternMethod( packageName = packageName, name = name, returnedType = returnedType, - receiverType = receiverType, + receiver = receiver, parameters = parameters, pattern = pattern, declaringType = declaringType, diff --git a/backend/src/main/kotlin/io/kabu/backend/inout/input/method/Method.kt b/backend/src/main/kotlin/io/kabu/backend/inout/input/method/Method.kt index 9bb5eca..0a594c8 100644 --- a/backend/src/main/kotlin/io/kabu/backend/inout/input/method/Method.kt +++ b/backend/src/main/kotlin/io/kabu/backend/inout/input/method/Method.kt @@ -9,12 +9,12 @@ open class Method( val packageName: String, val name: String, open val returnedType: TypeName, - val receiverType: TypeName?, + val receiver: Parameter?, val parameters: List, - override val origin: Origin + override val origin: Origin, ) : HasOrigin { - val hasReceiver get() = receiverType != null + val hasReceiver get() = receiver != null override fun toString() = "Method $name ($origin)" } diff --git a/backend/src/main/kotlin/io/kabu/backend/inout/input/method/PatternMethod.kt b/backend/src/main/kotlin/io/kabu/backend/inout/input/method/PatternMethod.kt index 9d74f3e..b5bf9f7 100644 --- a/backend/src/main/kotlin/io/kabu/backend/inout/input/method/PatternMethod.kt +++ b/backend/src/main/kotlin/io/kabu/backend/inout/input/method/PatternMethod.kt @@ -8,7 +8,7 @@ abstract class PatternMethod( packageName: String, name: String, returnedType: TypeName, - receiverType: TypeName?, + receiver: Parameter?, parameters: List, val pattern: String, //todo get origin of pattern annotation as well origin: Origin @@ -16,7 +16,7 @@ abstract class PatternMethod( packageName, name, returnedType, - receiverType, + receiver, parameters, - origin + origin, ) diff --git a/backend/src/test/kotlin/io/kabu/backend/pattern/PatternWithSignature.kt b/backend/src/test/kotlin/io/kabu/backend/pattern/PatternWithSignature.kt index 973e1f5..19872e8 100644 --- a/backend/src/test/kotlin/io/kabu/backend/pattern/PatternWithSignature.kt +++ b/backend/src/test/kotlin/io/kabu/backend/pattern/PatternWithSignature.kt @@ -9,6 +9,7 @@ import com.squareup.kotlinpoet.TypeName import com.squareup.kotlinpoet.UNIT import io.kabu.backend.analyzer.handler.lambda.watcher.OperatorInfoTypes import io.kabu.backend.parameter.Parameter +import io.kabu.backend.util.Constants.RECEIVER_PARAMETER_NAME class PatternWithSignature(input: String) { @@ -57,12 +58,12 @@ class PatternWithSignature(input: String) { if (returnsPart != null) str = str.removeSuffix(returnsPart).dropLast(1) val parametersPart = str - val receiver = receiverPart?.trim()?.let(::decode)?.type + val receiver = receiverPart?.trim()?.let(::decode)?.type?.let { Parameter(RECEIVER_PARAMETER_NAME, it) } val params = parametersPart.trim().takeIf { it.isNotEmpty() }?.split(WHITESPACES)?.map(::decode) ?: emptyList() val returns = returnsPart?.trim()?.let(::decode)?.type ?: UNIT return Signature( - receiverType = receiver, + receiver = receiver, parameters = params, returnedType = returns ) diff --git a/backend/src/test/kotlin/io/kabu/backend/pattern/Signature.kt b/backend/src/test/kotlin/io/kabu/backend/pattern/Signature.kt index 8fd9fdc..9a97108 100644 --- a/backend/src/test/kotlin/io/kabu/backend/pattern/Signature.kt +++ b/backend/src/test/kotlin/io/kabu/backend/pattern/Signature.kt @@ -5,7 +5,7 @@ import io.kabu.backend.parameter.Parameter /** Result of parsing the signature string of test string */ data class Signature( - val receiverType: TypeName?, + val receiver: Parameter?, val parameters: List, val returnedType: TypeName ) diff --git a/backend/src/test/kotlin/io/kabu/backend/planner/AnalyzerAdHocTest.kt b/backend/src/test/kotlin/io/kabu/backend/planner/AnalyzerAdHocTest.kt index 9604f47..66c83cd 100644 --- a/backend/src/test/kotlin/io/kabu/backend/planner/AnalyzerAdHocTest.kt +++ b/backend/src/test/kotlin/io/kabu/backend/planner/AnalyzerAdHocTest.kt @@ -39,7 +39,7 @@ class AnalyzerAdHocTest : Assert() { packageName = targetPackage, name = clientMethod, returnedType = returned, - receiverType = receiver, + receiver = receiver, parameters = parameters, pattern = patternWithSignature.pattern, origin = Origin() diff --git a/backend/src/test/kotlin/io/kabu/backend/planner/AnalyzerTest.kt b/backend/src/test/kotlin/io/kabu/backend/planner/AnalyzerTest.kt index 1b2f73a..b88baab 100644 --- a/backend/src/test/kotlin/io/kabu/backend/planner/AnalyzerTest.kt +++ b/backend/src/test/kotlin/io/kabu/backend/planner/AnalyzerTest.kt @@ -94,7 +94,7 @@ private fun getPlanForPatternWithSignature(patternWithSignature: PatternWithSign packageName = targetPackage, name = clientMethod, returnedType = returned, - receiverType = receiver, + receiver = receiver, parameters = parameters, pattern = patternWithSignature.pattern, origin = Origin() diff --git a/backend/src/test/kotlin/io/kabu/backend/planner/namespace/conflict/detector/BaseConflictDetectorTest.kt b/backend/src/test/kotlin/io/kabu/backend/planner/namespace/conflict/detector/BaseConflictDetectorTest.kt index 64e6d00..db38f51 100644 --- a/backend/src/test/kotlin/io/kabu/backend/planner/namespace/conflict/detector/BaseConflictDetectorTest.kt +++ b/backend/src/test/kotlin/io/kabu/backend/planner/namespace/conflict/detector/BaseConflictDetectorTest.kt @@ -92,7 +92,7 @@ private fun getOutcomeAndOriginString(raw: String): Pair { packageName = TARGET_PACKAGE, name = CLIENT_METHOD, returnedType = returned, - receiverType = receiver, + receiver = receiver, parameters = parameters, pattern = patternWithSignature.pattern, origin = Origin() diff --git a/backend/src/test/kotlin/io/kabu/backend/plannerx/XTest.kt b/backend/src/test/kotlin/io/kabu/backend/plannerx/XTest.kt index e5e6778..7b886b6 100644 --- a/backend/src/test/kotlin/io/kabu/backend/plannerx/XTest.kt +++ b/backend/src/test/kotlin/io/kabu/backend/plannerx/XTest.kt @@ -37,7 +37,7 @@ open class XTest { packageName = "io.kabu.backend.plannerx", name = "completion", returnedType = returned, - receiverType = receiver, + receiver = receiver, parameters = parameters, pattern = patternWithSignature.pattern, origin = Origin() diff --git a/backend/src/test/kotlin/io/kabu/backend/r2c/Utils.kt b/backend/src/test/kotlin/io/kabu/backend/r2c/Utils.kt index fa04038..532d15e 100644 --- a/backend/src/test/kotlin/io/kabu/backend/r2c/Utils.kt +++ b/backend/src/test/kotlin/io/kabu/backend/r2c/Utils.kt @@ -30,12 +30,12 @@ fun completionOutputOf(raw: String, sample: String): String { println("Raw: $raw") val patternWithSignature = PatternWithSignature(raw) - val (receiverType, parameters, returnedType) = patternWithSignature.signature + val (receiver, parameters, returnedType) = patternWithSignature.signature val method = GlobalPatternMethod( packageName = TARGET_PACKAGE, - name = if (receiverType != null) CLIENT_METHOD_WITH_RECEIVER else CLIENT_METHOD, + name = if (receiver != null) CLIENT_METHOD_WITH_RECEIVER else CLIENT_METHOD, returnedType = returnedType, - receiverType = receiverType, + receiver = receiver, parameters = parameters, pattern = patternWithSignature.pattern, origin = unknownOrigin @@ -46,10 +46,6 @@ fun completionOutputOf(raw: String, sample: String): String { accessorObjectIsInSamePackage = true ) ) -// AnalyzerNew(method, namespace, MethodsRegistry(), null, options).analyze() -// println("\n$delimiter\n${namespace.plan}\n$delimiter") -// val scriptGenerated = namespace.writePlanToString() - // --- val nodes = AnalyzerImpl(method, MethodsRegistry(), null, options).analyze() getDiagramOfNodes(nodes) val integrator = Integrator() diff --git a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/TypeUtils.kt b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/TypeUtils.kt index 1885e73..f1ea8e1 100644 --- a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/TypeUtils.kt +++ b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/TypeUtils.kt @@ -15,36 +15,47 @@ import com.squareup.kotlinpoet.LambdaTypeName import com.squareup.kotlinpoet.ParameterSpec import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy import com.squareup.kotlinpoet.TypeName +import io.kabu.backend.diagnostic.Origin import io.kabu.backend.exception.PatternProcessingException import io.kabu.backend.inout.input.method.Method import io.kabu.backend.parameter.Parameter +import io.kabu.backend.util.Constants.RECEIVER_PARAMETER_NAME import io.kabu.frontend.ksp.diagnostic.builder.parameterProcessingError internal fun KSFunctionDeclaration.toMethod(): Method { + + fun createParameter( + name: String, + typeReference: KSTypeReference, + origin: Origin, + methodName: String, + ) = try { + Parameter(name, typeReference.toTypeName(), origin) + } catch (e: PatternProcessingException) { + parameterProcessingError(name, methodName, e, origin) + } + val methodOrigin = originOf(this) val methodName = simpleName.asString() - val receiverType = extensionReceiver?.toTypeName() + val receiver = extensionReceiver + ?.let { createParameter(RECEIVER_PARAMETER_NAME, it, originOf(it, parent = methodOrigin), methodName) } val returnType = returnType?.toTypeName()!! val parameters = parameters.map { parameter -> validateValueParameter(parameter) val parameterOrigin = originOf(parameter, parent = methodOrigin) - val name = parameter.name!!.asString() //todo check + val name = parameter.name!!.asString() - try { - Parameter(name, parameter.type.toTypeName(), parameterOrigin) - } catch (e: PatternProcessingException) { - parameterProcessingError(name, methodName, e, parameterOrigin) - } + createParameter(name, parameter.type, parameterOrigin, methodName) } return Method( packageName = packageName.asString(), name = methodName, returnedType = returnType, - receiverType = receiverType, + receiver = receiver, parameters = parameters, - origin = methodOrigin + origin = methodOrigin, ) } From d9cb3e236771cdd024e0dfd07b6e29e7c589a19a Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Thu, 13 Jul 2023 00:24:35 +0600 Subject: [PATCH 04/43] refactoring --- .../backend/analyzer/ParametersRegistry.kt | 11 +-- .../kabu/backend/analyzer/handler/Handler.kt | 10 +- .../analyzer/handler/IdentifierHandler.kt | 11 +-- .../analyzer/handler/OperatorHandler.kt | 8 +- .../lambda/watcher/WatcherLambdaHandler.kt | 4 +- .../inout/input/ProcessingInputRenderer.kt | 98 ------------------- .../user/legacy/TypeConflictChecker.kt | 6 +- .../IndexedSequentialTypeNameGenerator.kt | 2 +- .../namegen/IndexedTypeNameGenerator.kt | 10 -- .../namegen/PrefixedTypeNameGenerator.kt | 10 ++ .../integration/namegen/TypeNameGenerator.kt | 2 +- .../legacy/TypeNameGeneratorFactory.kt | 4 +- .../{BaseProvider.kt => AbstractProvider.kt} | 2 +- .../provider/provider/ArgumentProvider.kt | 2 +- .../backend/provider/provider/AuxProvider.kt | 2 +- .../provider/provider/EmptyProvider.kt | 2 +- .../provider/ExtensionLambdaProvider.kt | 2 +- .../provider/provider/HolderProvider.kt | 2 +- .../provider/provider/LambdaProvider.kt | 2 +- .../provider/provider/NoReceiverProvider.kt | 2 +- .../provider/WatcherContextProvider.kt | 2 +- .../provider/WatcherLambdaProvider.kt | 2 +- 22 files changed, 45 insertions(+), 151 deletions(-) delete mode 100644 backend/src/main/kotlin/io/kabu/backend/inout/input/ProcessingInputRenderer.kt delete mode 100644 backend/src/main/kotlin/io/kabu/backend/integration/namegen/IndexedTypeNameGenerator.kt create mode 100644 backend/src/main/kotlin/io/kabu/backend/integration/namegen/PrefixedTypeNameGenerator.kt rename backend/src/main/kotlin/io/kabu/backend/provider/provider/{BaseProvider.kt => AbstractProvider.kt} (97%) diff --git a/backend/src/main/kotlin/io/kabu/backend/analyzer/ParametersRegistry.kt b/backend/src/main/kotlin/io/kabu/backend/analyzer/ParametersRegistry.kt index 1e4e578..790520f 100644 --- a/backend/src/main/kotlin/io/kabu/backend/analyzer/ParametersRegistry.kt +++ b/backend/src/main/kotlin/io/kabu/backend/analyzer/ParametersRegistry.kt @@ -16,7 +16,7 @@ class ParametersRegistry( ) { val parameters: List = composeParameters() - .also { validateEntryParameters(it) } + .also { validateParameters(it) } val parametersTypes: Map = parameters .groupBy({ it.name }, { it.type.toFixedTypeNode() }) .mapValues { it.value.single() } @@ -25,16 +25,11 @@ class ParametersRegistry( private var operatorInfoParametersUsed = false val strictMethodParametersOrdering get() = operatorInfoParametersUsed - //todo simplify private fun composeParameters(): List { - val receiver = method.receiver - val parameterList = method.parameters.map { //todo unnecessary map? - Parameter(it.name, it.type, it.origin) - } - return listOfNotNull(receiver) + parameterList + return listOfNotNull(method.receiver) + method.parameters } - private fun validateEntryParameters(parameters: List) { + private fun validateParameters(parameters: List) { checkStrictParametersOrdering(parameters) checkReceiverParameterPresence() checkForSameNamedParameters(parameters) diff --git a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/Handler.kt b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/Handler.kt index 46242a4..202d3e1 100644 --- a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/Handler.kt +++ b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/Handler.kt @@ -4,8 +4,6 @@ import com.squareup.kotlinpoet.BOOLEAN import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.UNIT import com.squareup.kotlinpoet.asClassName -import io.kabu.runtime.InclusionInfo -import io.kabu.runtime.RankingComparisonInfo import io.kabu.backend.analyzer.Analyzer import io.kabu.backend.analyzer.AnalyzerImpl import io.kabu.backend.analyzer.handler.lambda.watcher.CaptureType @@ -27,9 +25,9 @@ import io.kabu.backend.parser.Operator import io.kabu.backend.provider.evaluation.FunctionBlockContext import io.kabu.backend.provider.group.FunDeclarationProvidersFactory import io.kabu.backend.provider.group.RawProviders +import io.kabu.backend.provider.provider.AbstractProvider import io.kabu.backend.provider.provider.AssignProvider import io.kabu.backend.provider.provider.AuxProvider -import io.kabu.backend.provider.provider.BaseProvider import io.kabu.backend.provider.provider.ComparisonProvider import io.kabu.backend.provider.provider.EmptyProvider import io.kabu.backend.provider.provider.InclusionProvider @@ -37,6 +35,8 @@ import io.kabu.backend.provider.provider.OperatorInfoProvider import io.kabu.backend.provider.provider.Provider import io.kabu.backend.util.poet.TypeNameUtils.toFixedTypeNode import io.kabu.backend.util.poet.asFixedTypeName +import io.kabu.runtime.InclusionInfo +import io.kabu.runtime.RankingComparisonInfo open class Handler( @@ -46,7 +46,7 @@ open class Handler( protected fun createHolderTypeAndAssignablePropertyViaWatchedParameter( rawProviders: RawProviders, expression: KotlinExpression - ): BaseProvider { + ): AbstractProvider { val assignExpression = expression.parent as BinaryExpression val assignOperator = assignExpression.operator as Assign @@ -63,7 +63,7 @@ open class Handler( rawProviders: RawProviders, operator: Operator, assignableSuffixExpression: KotlinExpression? - ): BaseProvider { + ): AbstractProvider { val funDeclarationProviders = FunDeclarationProvidersFactory .from(rawProviders, operator.invertedArgumentOrdering) diff --git a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/IdentifierHandler.kt b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/IdentifierHandler.kt index c07db5a..fcdcd3d 100644 --- a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/IdentifierHandler.kt +++ b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/IdentifierHandler.kt @@ -11,17 +11,16 @@ import io.kabu.backend.parser.IdentifierLeaf import io.kabu.backend.provider.evaluation.FunctionBlockContext import io.kabu.backend.provider.group.FunDeclarationProvidersFactory import io.kabu.backend.provider.group.RawProviders +import io.kabu.backend.provider.provider.AbstractProvider import io.kabu.backend.provider.provider.ArgumentProvider -import io.kabu.backend.provider.provider.BaseProvider import io.kabu.backend.provider.provider.EmptyProvider import io.kabu.backend.provider.provider.HolderProvider import io.kabu.backend.provider.provider.NoReceiverProvider import io.kabu.backend.util.Constants -import io.kabu.backend.util.poet.TypeNameUtils.toFixedTypeNode class IdentifierHandler(analyzer: AnalyzerImpl) : Handler(analyzer) { - fun handle(expression: IdentifierLeaf): BaseProvider { + fun handle(expression: IdentifierLeaf): AbstractProvider { val parametersRegistry = analyzer.parametersRegistry val typeNode: FixedTypeNode? = parametersRegistry.parametersTypes[expression.name] return if (typeNode != null) { @@ -49,7 +48,7 @@ class IdentifierHandler(analyzer: AnalyzerImpl) : Handler(analyzer) { ) } - private fun createProperty(expression: IdentifierLeaf): BaseProvider { + private fun createProperty(expression: IdentifierLeaf): AbstractProvider { val parametersRegistry = analyzer.parametersRegistry if (parametersRegistry.receiverCatchIsNecessary) { @@ -102,10 +101,8 @@ class IdentifierHandler(analyzer: AnalyzerImpl) : Handler(analyzer) { } private fun createReceiverHolderParameter(name: String): HolderProvider { - val method = analyzer.method - val receiverType = method.receiver?.type //todo use receiverTypeNode + val receiverTypeNode = analyzer.parametersRegistry.parametersTypes[Constants.RECEIVER_PARAMETER_NAME] ?: diagnosticError("Creating receiver holder type declaration but no receiver type found", method) - val receiverTypeNode = receiverType.toFixedTypeNode() val receiver = ArgumentProvider(receiverTypeNode, Constants.RECEIVER_PARAMETER_NAME) // Type diff --git a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/OperatorHandler.kt b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/OperatorHandler.kt index 7f8ad52..2926772 100644 --- a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/OperatorHandler.kt +++ b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/OperatorHandler.kt @@ -21,7 +21,7 @@ import io.kabu.backend.parser.UnaryExpression import io.kabu.backend.provider.evaluation.FunctionBlockContext import io.kabu.backend.provider.group.FunDeclarationProvidersFactory import io.kabu.backend.provider.group.RawProviders -import io.kabu.backend.provider.provider.BaseProvider +import io.kabu.backend.provider.provider.AbstractProvider import io.kabu.backend.provider.provider.EmptyProvider import io.kabu.backend.provider.provider.HolderProvider import io.kabu.backend.provider.provider.Provider @@ -133,7 +133,7 @@ class OperatorHandler(analyzer: AnalyzerImpl) : Handler(analyzer) { private fun createTerminalIndexedAssignOperator( rawProviders: RawProviders, expression: NaryExpression - ): BaseProvider { + ): AbstractProvider { val assigningParameter = providerOf((expression.parent as BinaryExpression).children[1]) // combining providers for "set" operator @@ -162,7 +162,7 @@ class OperatorHandler(analyzer: AnalyzerImpl) : Handler(analyzer) { private fun createTerminalAssignableProperty( rawProviders: RawProviders, expression: BinaryExpression, - ): BaseProvider { + ): AbstractProvider { val propertyName = (expression.right as IdentifierLeaf).name val receiverProvider = rawProviders.providersList[0] val assigningProvider = providerOf((expression.parent as BinaryExpression).children[1]) @@ -224,7 +224,7 @@ class OperatorHandler(analyzer: AnalyzerImpl) : Handler(analyzer) { private fun createHolderTypeAndIndexedAssignOperator( rawProviders: RawProviders, expression: NaryExpression - ): BaseProvider { + ): AbstractProvider { val assigningParameter = providerOf((expression.parent as BinaryExpression).children[1]) // combining providers for "set" operator diff --git a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/WatcherLambdaHandler.kt b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/WatcherLambdaHandler.kt index 552b6d5..3d5486d 100644 --- a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/WatcherLambdaHandler.kt +++ b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/WatcherLambdaHandler.kt @@ -19,14 +19,14 @@ import io.kabu.backend.parser.Indexing import io.kabu.backend.parser.LambdaExpression import io.kabu.backend.parser.NaryExpression import io.kabu.backend.provider.group.FunDeclarationProvidersFactory -import io.kabu.backend.provider.provider.BaseProvider +import io.kabu.backend.provider.provider.AbstractProvider import io.kabu.backend.provider.provider.ScopingLambdaProvider import io.kabu.backend.provider.provider.WatcherContextProvider import io.kabu.backend.provider.provider.WatcherLambdaProvider class WatcherLambdaHandler(analyzer: AnalyzerImpl) : Handler(analyzer) { - fun handle(expression: LambdaExpression): BaseProvider { + fun handle(expression: LambdaExpression): AbstractProvider { val watcherLambda = analyzer.currentWatcherLambda!! // examining the first statement of lambda diff --git a/backend/src/main/kotlin/io/kabu/backend/inout/input/ProcessingInputRenderer.kt b/backend/src/main/kotlin/io/kabu/backend/inout/input/ProcessingInputRenderer.kt deleted file mode 100644 index b36979a..0000000 --- a/backend/src/main/kotlin/io/kabu/backend/inout/input/ProcessingInputRenderer.kt +++ /dev/null @@ -1,98 +0,0 @@ -package io.kabu.backend.inout.input - -import com.squareup.kotlinpoet.BOOLEAN -import com.squareup.kotlinpoet.ClassName -import com.squareup.kotlinpoet.INT -import com.squareup.kotlinpoet.STRING -import com.squareup.kotlinpoet.TypeName -import com.squareup.kotlinpoet.UNIT -import io.kabu.backend.inout.input.method.ContextConstructorMethod -import io.kabu.backend.inout.input.method.ContextCreatorMethod -import io.kabu.backend.inout.input.method.GlobalPatternMethod -import io.kabu.backend.inout.input.method.LocalPatternMethod -import io.kabu.backend.inout.input.method.Method -import io.kabu.backend.parameter.Parameter - - -val ProcessingInput.dslDefinitionString: String - get() = buildString { - appendLine(""" - override val processingInput = ProcessingInput( - ${IND1}generatedSourcesRoot = "", // can be anything - """.trimIndent()) - appendLine("${IND1}globalPatterns = listOf(") - globalPatterns - .joinToString("$IND2,\n") { it.dslString() } - .let { append(it) } - appendLine("$IND1),") - - appendLine("${IND1}localPatterns = listOf(") - localPatterns - .joinToString("$IND2,\n") { it.dslString() } - .let { append(it) } - appendLine("$IND1),") - - appendLine("${IND1}contextCreators = listOf(") - contextCreators - .joinToString("$IND2,\n") { it.dslString() } - .let { append(it) } - appendLine("$IND1)") - - appendLine(")") - } - -private fun Method.buildForMethodOfType(type: String, typeSpecificStrings: StringBuilder.()->Unit) = buildString { - appendLine("""${IND2}"$name" - $type(basePackage) {""") - typeSpecificStrings() - appendLine("""${IND3}returns = ${returnedType.simplify()} """) - - appendParameters(parameters) - appendLine("${IND2}}") -} - -private fun GlobalPatternMethod.dslString() = buildForMethodOfType("globalPattern") { - appendLine("""${IND3}pattern = "$pattern" """) -} - -private fun LocalPatternMethod.dslString() = buildForMethodOfType("localPattern") { - appendLine("""${IND3}pattern = "$pattern" """) - appendLine("""${IND3}declaringType = ${declaringType.simplify()} """) -} - -private fun ContextCreatorMethod.dslString() = when (this) { - is ContextConstructorMethod -> buildForMethodOfType("contextConstructor") { - appendLine("""${IND3}contextName = "$contextName" """) - appendLine("""${IND3}declaringType = ${declaringType.simplify()} """) - } - else -> buildForMethodOfType("contextCreator") { - appendLine("""${IND3}contextName = "$contextName" """) - } -} - -private fun StringBuilder.appendParameters(parameters: List) { - if (parameters.isNotEmpty()) { - appendLine("${IND3}parameters(") - parameters.forEach { - appendLine("""$IND4"${it.name}" / ${it.type.simplify()},""") - } - appendLine("$IND3)") - } -} - -private fun TypeName.simplify(): String { - if (this !is ClassName) return "" - return when (this) { - UNIT -> "UNIT" - INT -> "INT" - BOOLEAN -> "BOOLEAN" - STRING -> "STRING" - else -> "!\"$simpleName\"" - } -} - -private fun ind(i: Int) = buildString { repeat(i) { append(" ") } } - -private val IND1 = ind(1) -private val IND2 = ind(2) -private val IND3 = ind(3) -private val IND4 = ind(4) diff --git a/backend/src/main/kotlin/io/kabu/backend/integration/detector/user/legacy/TypeConflictChecker.kt b/backend/src/main/kotlin/io/kabu/backend/integration/detector/user/legacy/TypeConflictChecker.kt index 134e05d..2891a1c 100644 --- a/backend/src/main/kotlin/io/kabu/backend/integration/detector/user/legacy/TypeConflictChecker.kt +++ b/backend/src/main/kotlin/io/kabu/backend/integration/detector/user/legacy/TypeConflictChecker.kt @@ -7,7 +7,7 @@ import com.squareup.kotlinpoet.asTypeName import io.kabu.backend.diagnostic.diagnosticError import io.kabu.backend.integration.detector.user.legacy.types.StandardMethod import io.kabu.backend.integration.detector.user.legacy.types.StandardProperty -import io.kabu.backend.provider.provider.BaseProvider +import io.kabu.backend.provider.provider.AbstractProvider import io.kabu.backend.util.fromJSON import io.kabu.backend.util.poet.RegularSerializedType import io.kabu.backend.util.poet.SerializedType @@ -55,14 +55,14 @@ open class TypeConflictChecker(private val klass: KClass<*>) : ConflictChecker() operatorFunctionName == standardMethod.name && parametersAreCompatible( standardMethod.parameterTypes, - parametersWithoutReceiver as List + parametersWithoutReceiver as List ) } } private fun parametersAreCompatible( standardFunctionParameters: List, - requestedOperatorParameters: List, + requestedOperatorParameters: List, ): Boolean { return standardFunctionParameters.size == requestedOperatorParameters.size && standardFunctionParameters.zip(requestedOperatorParameters) diff --git a/backend/src/main/kotlin/io/kabu/backend/integration/namegen/IndexedSequentialTypeNameGenerator.kt b/backend/src/main/kotlin/io/kabu/backend/integration/namegen/IndexedSequentialTypeNameGenerator.kt index 97c7055..08a0cf8 100644 --- a/backend/src/main/kotlin/io/kabu/backend/integration/namegen/IndexedSequentialTypeNameGenerator.kt +++ b/backend/src/main/kotlin/io/kabu/backend/integration/namegen/IndexedSequentialTypeNameGenerator.kt @@ -1,7 +1,7 @@ package io.kabu.backend.integration.namegen class IndexedSequentialTypeNameGenerator( - private val typeNameGenerator: IndexedTypeNameGenerator, + private val typeNameGenerator: TypeNameGenerator, ) : SequentialTypeNameGenerator { private var index = 1 diff --git a/backend/src/main/kotlin/io/kabu/backend/integration/namegen/IndexedTypeNameGenerator.kt b/backend/src/main/kotlin/io/kabu/backend/integration/namegen/IndexedTypeNameGenerator.kt deleted file mode 100644 index f1917fe..0000000 --- a/backend/src/main/kotlin/io/kabu/backend/integration/namegen/IndexedTypeNameGenerator.kt +++ /dev/null @@ -1,10 +0,0 @@ -package io.kabu.backend.integration.namegen - -class IndexedTypeNameGenerator(private val prefix: String) : TypeNameGenerator { - - override fun generateTypeName(attempt: Int): String { - require(attempt >= 0) - return if (attempt == 0) prefix - else prefix + attempt - } -} diff --git a/backend/src/main/kotlin/io/kabu/backend/integration/namegen/PrefixedTypeNameGenerator.kt b/backend/src/main/kotlin/io/kabu/backend/integration/namegen/PrefixedTypeNameGenerator.kt new file mode 100644 index 0000000..ec3c1f3 --- /dev/null +++ b/backend/src/main/kotlin/io/kabu/backend/integration/namegen/PrefixedTypeNameGenerator.kt @@ -0,0 +1,10 @@ +package io.kabu.backend.integration.namegen + +class PrefixedTypeNameGenerator(private val prefix: String) : TypeNameGenerator { + + override fun generateTypeName(counter: Int): String { + require(counter >= 0) + return if (counter == 0) prefix + else prefix + counter + } +} diff --git a/backend/src/main/kotlin/io/kabu/backend/integration/namegen/TypeNameGenerator.kt b/backend/src/main/kotlin/io/kabu/backend/integration/namegen/TypeNameGenerator.kt index 956090b..a918ea8 100644 --- a/backend/src/main/kotlin/io/kabu/backend/integration/namegen/TypeNameGenerator.kt +++ b/backend/src/main/kotlin/io/kabu/backend/integration/namegen/TypeNameGenerator.kt @@ -3,5 +3,5 @@ package io.kabu.backend.integration.namegen interface TypeNameGenerator { - fun generateTypeName(attempt: Int): String + fun generateTypeName(counter: Int): String } diff --git a/backend/src/main/kotlin/io/kabu/backend/legacy/TypeNameGeneratorFactory.kt b/backend/src/main/kotlin/io/kabu/backend/legacy/TypeNameGeneratorFactory.kt index 6fc0080..88238b5 100644 --- a/backend/src/main/kotlin/io/kabu/backend/legacy/TypeNameGeneratorFactory.kt +++ b/backend/src/main/kotlin/io/kabu/backend/legacy/TypeNameGeneratorFactory.kt @@ -1,12 +1,12 @@ package io.kabu.backend.legacy import io.kabu.backend.integration.namegen.IndexedSequentialTypeNameGenerator -import io.kabu.backend.integration.namegen.IndexedTypeNameGenerator +import io.kabu.backend.integration.namegen.PrefixedTypeNameGenerator import io.kabu.backend.integration.namegen.SequentialTypeNameGenerator object TypeNameGeneratorFactory { fun create(): SequentialTypeNameGenerator = - IndexedSequentialTypeNameGenerator(IndexedTypeNameGenerator("H")) + IndexedSequentialTypeNameGenerator(PrefixedTypeNameGenerator("H")) } diff --git a/backend/src/main/kotlin/io/kabu/backend/provider/provider/BaseProvider.kt b/backend/src/main/kotlin/io/kabu/backend/provider/provider/AbstractProvider.kt similarity index 97% rename from backend/src/main/kotlin/io/kabu/backend/provider/provider/BaseProvider.kt rename to backend/src/main/kotlin/io/kabu/backend/provider/provider/AbstractProvider.kt index 199bea4..ef38487 100644 --- a/backend/src/main/kotlin/io/kabu/backend/provider/provider/BaseProvider.kt +++ b/backend/src/main/kotlin/io/kabu/backend/provider/provider/AbstractProvider.kt @@ -12,7 +12,7 @@ import io.kabu.backend.util.poet.TypeNameUtils.shorten * * @property type type of the runtime object */ -open class BaseProvider( //todo abstract? +abstract class AbstractProvider( override var typeNode: TypeNode, override val origin: Origin? = null, ): Provider { diff --git a/backend/src/main/kotlin/io/kabu/backend/provider/provider/ArgumentProvider.kt b/backend/src/main/kotlin/io/kabu/backend/provider/provider/ArgumentProvider.kt index 058fbf7..026db7b 100644 --- a/backend/src/main/kotlin/io/kabu/backend/provider/provider/ArgumentProvider.kt +++ b/backend/src/main/kotlin/io/kabu/backend/provider/provider/ArgumentProvider.kt @@ -8,7 +8,7 @@ open class ArgumentProvider( typeNode: TypeNode, val originalName: String, // name defined by user origin: Origin? = null, -) : BaseProvider(typeNode, origin) { +) : AbstractProvider(typeNode, origin) { override val isUseful: Boolean = true diff --git a/backend/src/main/kotlin/io/kabu/backend/provider/provider/AuxProvider.kt b/backend/src/main/kotlin/io/kabu/backend/provider/provider/AuxProvider.kt index 677f670..dce218b 100644 --- a/backend/src/main/kotlin/io/kabu/backend/provider/provider/AuxProvider.kt +++ b/backend/src/main/kotlin/io/kabu/backend/provider/provider/AuxProvider.kt @@ -14,7 +14,7 @@ class AuxProvider( typeNode: TypeNode, private val watchedProvider: AbstractWatchedProvider, origin: Origin? = null, -) : BaseProvider(typeNode, origin) { +) : AbstractProvider(typeNode, origin) { override val childrenProviders: List = listOf(watchedProvider) diff --git a/backend/src/main/kotlin/io/kabu/backend/provider/provider/EmptyProvider.kt b/backend/src/main/kotlin/io/kabu/backend/provider/provider/EmptyProvider.kt index 90204f9..1e633a3 100644 --- a/backend/src/main/kotlin/io/kabu/backend/provider/provider/EmptyProvider.kt +++ b/backend/src/main/kotlin/io/kabu/backend/provider/provider/EmptyProvider.kt @@ -10,7 +10,7 @@ import io.kabu.backend.util.poet.TypeNameUtils.toFixedTypeNode class EmptyProvider( typeNode: TypeNode, origin: Origin? = null, -) : BaseProvider(typeNode, origin) { +) : AbstractProvider(typeNode, origin) { constructor() : this(ANY.toFixedTypeNode()) diff --git a/backend/src/main/kotlin/io/kabu/backend/provider/provider/ExtensionLambdaProvider.kt b/backend/src/main/kotlin/io/kabu/backend/provider/provider/ExtensionLambdaProvider.kt index 4eb0aec..54a841b 100644 --- a/backend/src/main/kotlin/io/kabu/backend/provider/provider/ExtensionLambdaProvider.kt +++ b/backend/src/main/kotlin/io/kabu/backend/provider/provider/ExtensionLambdaProvider.kt @@ -12,7 +12,7 @@ import io.kabu.backend.util.poet.asCodeBlock class ExtensionLambdaProvider( typeNode: TypeNode, - returningProvider: BaseProvider, //todo don't need? //todo rename + returningProvider: AbstractProvider, //todo don't need? //todo rename val contextMediatorTypeNode: TypeNode, val contextCreatorDefinition: ContextCreatorDefinition, val destinationParameterTypeNode: TypeNode, diff --git a/backend/src/main/kotlin/io/kabu/backend/provider/provider/HolderProvider.kt b/backend/src/main/kotlin/io/kabu/backend/provider/provider/HolderProvider.kt index b64484a..1e6bcaf 100644 --- a/backend/src/main/kotlin/io/kabu/backend/provider/provider/HolderProvider.kt +++ b/backend/src/main/kotlin/io/kabu/backend/provider/provider/HolderProvider.kt @@ -14,7 +14,7 @@ open class HolderProvider( typeNode: TypeNode, private val providers: List, origin: Origin? = null, -) : BaseProvider(typeNode, origin), Provider { +) : AbstractProvider(typeNode, origin), Provider { private val fields: OrderedNamedProviders = OrderedNamedProviders().apply { this@HolderProvider.providers.forEachIndexed { index, provider -> register(provider, getNameForIndex(index)) } diff --git a/backend/src/main/kotlin/io/kabu/backend/provider/provider/LambdaProvider.kt b/backend/src/main/kotlin/io/kabu/backend/provider/provider/LambdaProvider.kt index ef07a74..b0910cf 100644 --- a/backend/src/main/kotlin/io/kabu/backend/provider/provider/LambdaProvider.kt +++ b/backend/src/main/kotlin/io/kabu/backend/provider/provider/LambdaProvider.kt @@ -12,7 +12,7 @@ open class LambdaProvider( val returningProvider: Provider, val analyzer: Analyzer, origin: Origin? = null, -) : BaseProvider(typeNode, origin) { +) : AbstractProvider(typeNode, origin) { override fun generateName(): String { return returningProvider.generateName() + "Lambda" diff --git a/backend/src/main/kotlin/io/kabu/backend/provider/provider/NoReceiverProvider.kt b/backend/src/main/kotlin/io/kabu/backend/provider/provider/NoReceiverProvider.kt index dc778dd..6b5ec12 100644 --- a/backend/src/main/kotlin/io/kabu/backend/provider/provider/NoReceiverProvider.kt +++ b/backend/src/main/kotlin/io/kabu/backend/provider/provider/NoReceiverProvider.kt @@ -8,4 +8,4 @@ import io.kabu.backend.util.poet.TypeNameUtils.toFixedTypeNode * - may be used as first provider of FunDeclarationParameters to indicate absence of function/property receiver * - does not turn into 'this' by transformation to FunDeclarationParameters */ -class NoReceiverProvider : BaseProvider(ANY.toFixedTypeNode()) +class NoReceiverProvider : AbstractProvider(ANY.toFixedTypeNode()) diff --git a/backend/src/main/kotlin/io/kabu/backend/provider/provider/WatcherContextProvider.kt b/backend/src/main/kotlin/io/kabu/backend/provider/provider/WatcherContextProvider.kt index c3e457f..480bf67 100644 --- a/backend/src/main/kotlin/io/kabu/backend/provider/provider/WatcherContextProvider.kt +++ b/backend/src/main/kotlin/io/kabu/backend/provider/provider/WatcherContextProvider.kt @@ -13,7 +13,7 @@ class WatcherContextProvider( private val childProvider: Provider, private val analyzer: Analyzer, origin: Origin? = null, -) : BaseProvider(typeNode, origin), Provider { +) : AbstractProvider(typeNode, origin), Provider { override fun generateName(): String { return typeNode.name.decaps() diff --git a/backend/src/main/kotlin/io/kabu/backend/provider/provider/WatcherLambdaProvider.kt b/backend/src/main/kotlin/io/kabu/backend/provider/provider/WatcherLambdaProvider.kt index 9831ba7..b8331f0 100644 --- a/backend/src/main/kotlin/io/kabu/backend/provider/provider/WatcherLambdaProvider.kt +++ b/backend/src/main/kotlin/io/kabu/backend/provider/provider/WatcherLambdaProvider.kt @@ -16,7 +16,7 @@ class WatcherLambdaProvider( val watcherContextProvider: WatcherContextProvider, val analyzer: Analyzer, origin: Origin? = null, -) : BaseProvider(typeNode, origin) { +) : AbstractProvider(typeNode, origin) { override fun generateName(): String { return watcherContextProvider.generateName() + "Lambda" From 741a74b29775c9c887cac0418d8d64167c60860d Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Thu, 13 Jul 2023 00:54:47 +0600 Subject: [PATCH 05/43] mandatory origins for parameters --- .../handler/lambda/extension/ExtensionLambdaHandler.kt | 4 +++- .../io/kabu/backend/diagnostic/builder/ErrorBuilders.kt | 2 +- .../src/main/kotlin/io/kabu/backend/parameter/Parameter.kt | 4 ++-- .../kotlin/io/kabu/backend/pattern/PatternWithSignature.kt | 6 ++++-- .../kotlin/io/kabu/backend/planner/AnalyzerTestUtils.kt | 6 ------ 5 files changed, 10 insertions(+), 12 deletions(-) diff --git a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/extension/ExtensionLambdaHandler.kt b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/extension/ExtensionLambdaHandler.kt index 965f916..58b5fdd 100644 --- a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/extension/ExtensionLambdaHandler.kt +++ b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/extension/ExtensionLambdaHandler.kt @@ -4,6 +4,7 @@ import com.squareup.kotlinpoet.LambdaTypeName import com.squareup.kotlinpoet.UNIT import io.kabu.backend.analyzer.Analyzer import io.kabu.backend.analyzer.AnalyzerImpl +import io.kabu.backend.diagnostic.Origin import io.kabu.backend.diagnostic.builder.extensionAnnotationMissingError import io.kabu.backend.diagnostic.builder.unknownFunctionParameterNameError import io.kabu.backend.inout.input.method.PatternMethod @@ -48,7 +49,8 @@ class ExtensionLambdaHandler( val contextMediatorTypeNode = ContextMediatorTypeNodeImpl( name = contextMediatorClassSimpleName, namespaceNode = contextMediatorNamespaceNode, - contextProperty = Parameter(EXTENSION_CONTEXT_PROPERTY_NAME, extensionContextTypeName), + //todo Origin() && Parameter ? + contextProperty = Parameter(EXTENSION_CONTEXT_PROPERTY_NAME, extensionContextTypeName, Origin()), ) registerNode(contextMediatorTypeNode) diff --git a/backend/src/main/kotlin/io/kabu/backend/diagnostic/builder/ErrorBuilders.kt b/backend/src/main/kotlin/io/kabu/backend/diagnostic/builder/ErrorBuilders.kt index 02212cf..e9e7482 100644 --- a/backend/src/main/kotlin/io/kabu/backend/diagnostic/builder/ErrorBuilders.kt +++ b/backend/src/main/kotlin/io/kabu/backend/diagnostic/builder/ErrorBuilders.kt @@ -66,7 +66,7 @@ internal fun extensionAnnotationMissingError(expression: LambdaExpression): Noth } internal fun sameNamedParametersError(name: String, parameters: List): Nothing { - diagnosticError("Function contains parameters with same name: '$name'", parameters.mapNotNull { it.origin }) + diagnosticError("Function contains parameters with same name: '$name'", parameters.map { it.origin }) } internal fun signatureParameterMissingInPatternError(signatureParameter: Parameter): Nothing { diff --git a/backend/src/main/kotlin/io/kabu/backend/parameter/Parameter.kt b/backend/src/main/kotlin/io/kabu/backend/parameter/Parameter.kt index 9a3bd05..3f7a387 100644 --- a/backend/src/main/kotlin/io/kabu/backend/parameter/Parameter.kt +++ b/backend/src/main/kotlin/io/kabu/backend/parameter/Parameter.kt @@ -6,10 +6,10 @@ import io.kabu.backend.diagnostic.Origin class Parameter( val name: String, val type: TypeName, - val origin: Origin? = null, + val origin: Origin, ) { override fun toString(): String { - val sourceLocationPart = origin?.sourceLocation?.toString()?.let { " ($it)" } ?: "" + val sourceLocationPart = origin.sourceLocation?.toString()?.let { " ($it)" } ?: "" return "'$name: $type'$sourceLocationPart" } } diff --git a/backend/src/test/kotlin/io/kabu/backend/pattern/PatternWithSignature.kt b/backend/src/test/kotlin/io/kabu/backend/pattern/PatternWithSignature.kt index 19872e8..259aed3 100644 --- a/backend/src/test/kotlin/io/kabu/backend/pattern/PatternWithSignature.kt +++ b/backend/src/test/kotlin/io/kabu/backend/pattern/PatternWithSignature.kt @@ -8,6 +8,7 @@ import com.squareup.kotlinpoet.STRING import com.squareup.kotlinpoet.TypeName import com.squareup.kotlinpoet.UNIT import io.kabu.backend.analyzer.handler.lambda.watcher.OperatorInfoTypes +import io.kabu.backend.diagnostic.Origin import io.kabu.backend.parameter.Parameter import io.kabu.backend.util.Constants.RECEIVER_PARAMETER_NAME @@ -42,7 +43,7 @@ class PatternWithSignature(input: String) { // type val typeName = typeCodeToTypeName(code).copy(nullable = nullable) - return Parameter(identifier, typeName) + return Parameter(identifier, typeName, Origin(excerpt = shortCode)) } var str = shortStringParameters @@ -58,7 +59,8 @@ class PatternWithSignature(input: String) { if (returnsPart != null) str = str.removeSuffix(returnsPart).dropLast(1) val parametersPart = str - val receiver = receiverPart?.trim()?.let(::decode)?.type?.let { Parameter(RECEIVER_PARAMETER_NAME, it) } + val receiver = receiverPart?.trim()?.let(::decode)?.type + ?.let { Parameter(RECEIVER_PARAMETER_NAME, it, Origin(excerpt = receiverPart)) } val params = parametersPart.trim().takeIf { it.isNotEmpty() }?.split(WHITESPACES)?.map(::decode) ?: emptyList() val returns = returnsPart?.trim()?.let(::decode)?.type ?: UNIT diff --git a/backend/src/test/kotlin/io/kabu/backend/planner/AnalyzerTestUtils.kt b/backend/src/test/kotlin/io/kabu/backend/planner/AnalyzerTestUtils.kt index cfa0e04..568ca45 100644 --- a/backend/src/test/kotlin/io/kabu/backend/planner/AnalyzerTestUtils.kt +++ b/backend/src/test/kotlin/io/kabu/backend/planner/AnalyzerTestUtils.kt @@ -1,8 +1,6 @@ package io.kabu.backend.planner -import com.squareup.kotlinpoet.TypeName import io.kabu.backend.common.log.InterceptingLogging -import io.kabu.backend.parameter.Parameter import io.kabu.backend.planner.AnalyzerTestUtils.logger import io.kabu.backend.util.Constants @@ -17,10 +15,6 @@ object AnalyzerTestUtils { val logger = InterceptingLogging.logger {} } -fun parametersOf(vararg params: Pair): List { - return params.map { Parameter(it.first, it.second) } -} - fun completion(vararg parameters: Any?) { logger.info { "completion: ${parameters.joinToString()}" } } From 43f6241197cd36d1f99c803030dab0024f343123 Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Wed, 12 Jul 2023 02:05:09 +0600 Subject: [PATCH 06/43] implemented @Context annotation --- README.md | 12 ++++-- .../main/kotlin/io/kabu/annotation/Context.kt | 10 +++++ doc/patternExtension.md | 11 +++-- .../ksp/processor/KspFrontendProcessor.kt | 20 ++++++++- .../kabu/frontend/ksp/processor/util/Utils.kt | 11 +++-- .../builder/ContextCreatorFunctionBuilder.kt | 38 ++++++++++++++-- .../processor/BaseKspFrontendProcessorTest.kt | 2 +- .../test1/ContextAnnotationTest.kt | 43 +++++++++++++++++++ ...AnnotationAndContextCreatorConflictTest.kt | 35 +++++++++++++++ .../complex/nested/ifelse/IfElseTest.kt | 6 +-- .../ksp/processor/simple/SimpleContextTest.kt | 16 +++---- 11 files changed, 176 insertions(+), 28 deletions(-) create mode 100644 annotation/src/main/kotlin/io/kabu/annotation/Context.kt create mode 100644 frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/complex/contextParametrization/contextAnnotation/test1/ContextAnnotationTest.kt create mode 100644 frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/complex/contextParametrization/contextAnnotation/test2/ContextAnnotationAndContextCreatorConflictTest.kt diff --git a/README.md b/README.md index 0e0f494..73a3861 100644 --- a/README.md +++ b/README.md @@ -218,7 +218,8 @@ data class FootballTeam( val trophies: List ) -class PlayersBuilder @ContextCreator("playersBuilder") constructor() { +@Context("playersBuilder") +class PlayersBuilder { val players = mutableListOf() @LocalPattern("name - number") @@ -227,7 +228,8 @@ class PlayersBuilder @ContextCreator("playersBuilder") constructor() { } } -class FootballTeamBuilder @ContextCreator("footballTeamBuilder") constructor() { +@Context("footballTeamBuilder") +class FootballTeamBuilder { val trophies = mutableListOf() var isChampion = false @@ -282,7 +284,8 @@ fun main() { ```kotlin // Example-009 -class Actions @ContextCreator("actions") constructor() { +@Context("actions") +class Actions { val trueActions = mutableListOf<() -> Unit>() val falseActions = mutableListOf<() -> Unit>() @@ -474,7 +477,8 @@ An *extension point* defines a lambda based scope in which multiple operations f // Example-009 // context class -class Actions @ContextCreator("actions") constructor() { +@Context("actions") +class Actions { val trueActions = mutableListOf<() -> Unit>() val falseActions = mutableListOf<() -> Unit>() diff --git a/annotation/src/main/kotlin/io/kabu/annotation/Context.kt b/annotation/src/main/kotlin/io/kabu/annotation/Context.kt new file mode 100644 index 0000000..5eca29c --- /dev/null +++ b/annotation/src/main/kotlin/io/kabu/annotation/Context.kt @@ -0,0 +1,10 @@ +package io.kabu.annotation + +import kotlin.annotation.AnnotationRetention.SOURCE +import kotlin.annotation.AnnotationTarget.CLASS + +@Retention(SOURCE) +@Target(CLASS) +annotation class Context( + val contextName: String +) diff --git a/doc/patternExtension.md b/doc/patternExtension.md index 2c43498..dbef882 100644 --- a/doc/patternExtension.md +++ b/doc/patternExtension.md @@ -57,6 +57,9 @@ Context creator: - must be annotated with `@ContextCreator` annotation - may have parameters +### `@Context` annotation +`@Context` annotation placed on a class means that primary constructor of this class acts as *context creator*. This is a shortcut to marking primary constructor with `@ContextCreator` annotation. + ## Unbounded and recursive extensions nesting Local patterns can have their own extension points, so building complex DSLs with arbitrary depth of extensions nesting is possible. Recursive (and transitively recursive) extensions nesting is possible too because local pattens can have extension points bound to the same context class. @@ -85,7 +88,7 @@ jsonObject { ## Steps to define an extension point 1. Choose a *context name* (following the rules for identifier name). It may relate to a context class name. 2. Create a *context class* containing functions marked with `@LocalPattern`, which constitute a set of allowed operations inside a lambda. -3. Define at least one way to create the *context class*. Mark it with a `@ContextCreator` annotation and specify chosen *context name*. +3. Define at least one way to create the *context class*. Mark it with a `@ContextCreator` annotation and specify chosen *context name*. Or mark the context class with `@Context` annotation if primary constructor will act as context creator. 4. Mark an empty lambda with `@Extend` annotation inside a pattern. Specify required parameters of the annotation. ### Example @@ -147,7 +150,8 @@ data class FootballTeam( val trophies: List ) -class PlayersBuilder @ContextCreator("playersBuilder") constructor() { +@Context("playersBuilder") +class PlayersBuilder { val players = mutableListOf() @LocalPattern("name - number") @@ -156,7 +160,8 @@ class PlayersBuilder @ContextCreator("playersBuilder") constructor() { } } -class FootballTeamBuilder @ContextCreator("footballTeamBuilder") constructor() { +@Context("footballTeamBuilder") +class FootballTeamBuilder { val trophies = mutableListOf() var isChampion = false diff --git a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/KspFrontendProcessor.kt b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/KspFrontendProcessor.kt index b02c8bd..9353c45 100755 --- a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/KspFrontendProcessor.kt +++ b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/KspFrontendProcessor.kt @@ -7,7 +7,9 @@ import com.google.devtools.ksp.processing.SymbolProcessor import com.google.devtools.ksp.processing.SymbolProcessorEnvironment import com.google.devtools.ksp.processing.SymbolProcessorProvider import com.google.devtools.ksp.symbol.KSAnnotated +import com.google.devtools.ksp.symbol.KSClassDeclaration import com.google.devtools.ksp.symbol.KSFunctionDeclaration +import io.kabu.annotation.Context import io.kabu.annotation.ContextCreator import io.kabu.annotation.Pattern import io.kabu.annotation.LocalPattern @@ -37,11 +39,14 @@ class KspFrontendProcessor( override fun process(resolver: Resolver): List { openLogging() try { + val contextCreators = getContextCreatorMethods(resolver) + + getContextCreatorMethodsFromContextClasses(resolver) + val processingInput = ProcessingInput( fileWriter = KspFileWriter(codeGenerator), globalPatterns = getGlobalPatternMethods(resolver), localPatterns = getLocalPatternMethods(resolver), - contextCreators = getContextCreatorMethods(resolver) + contextCreators = contextCreators, ) val backendProcessor = BackendProcessor(Options.fromPartial(parseOptions(options))) @@ -76,6 +81,19 @@ class KspFrontendProcessor( return result } + private fun getContextCreatorMethodsFromContextClasses(resolver: Resolver): List { + val typesDeclarations = resolver + .getSymbolsWithAnnotation(Context::class.qualifiedName!!) + .filterIsInstance() + .toList() + + val result = typesDeclarations.map { type -> + ContextCreatorFunctionBuilder().build(type) + } + + return result + } + private fun getLocalPatternMethods(resolver: Resolver): List { val functionDeclarations = resolver .getSymbolsWithAnnotation(LocalPattern::class.qualifiedName!!) diff --git a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/Utils.kt b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/Utils.kt index 840ea79..37d6340 100644 --- a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/Utils.kt +++ b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/Utils.kt @@ -1,14 +1,14 @@ package io.kabu.frontend.ksp.processor.util import com.google.devtools.ksp.symbol.FileLocation +import com.google.devtools.ksp.symbol.KSAnnotated import com.google.devtools.ksp.symbol.KSDeclaration -import com.google.devtools.ksp.symbol.KSFunctionDeclaration import com.google.devtools.ksp.symbol.KSNode import com.google.devtools.ksp.symbol.KSTypeArgument import com.google.devtools.ksp.symbol.KSValueParameter -import io.kabu.backend.diagnostic.diagnosticError import io.kabu.backend.diagnostic.FileSourceLocation import io.kabu.backend.diagnostic.Origin +import io.kabu.backend.diagnostic.diagnosticError import io.kabu.frontend.ksp.diagnostic.builder.notSupportedError internal fun areNotSupported(clause: Boolean = true, ksNode: KSNode? = null, message: () -> String) { @@ -41,8 +41,11 @@ internal fun originOf(ksNode: KSNode, parent: Origin? = null): Origin { return Origin(excerpt = excerpt, sourceLocation = sourceLocation, parent = parent) } -internal inline fun KSFunctionDeclaration.getAnnotation() = - annotations.single { +internal inline fun KSAnnotated.getAnnotation() = + getAnnotationOrNull()!! + +internal inline fun KSAnnotated.getAnnotationOrNull() = + annotations.singleOrNull { val annotationQualifiedName = it.annotationType.resolve().declaration.qualifiedName?.asString() annotationQualifiedName == T::class.qualifiedName } diff --git a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/builder/ContextCreatorFunctionBuilder.kt b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/builder/ContextCreatorFunctionBuilder.kt index 1bc76a3..2467ebd 100644 --- a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/builder/ContextCreatorFunctionBuilder.kt +++ b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/builder/ContextCreatorFunctionBuilder.kt @@ -4,27 +4,57 @@ import com.google.devtools.ksp.isConstructor import com.google.devtools.ksp.symbol.FunctionKind import com.google.devtools.ksp.symbol.KSClassDeclaration import com.google.devtools.ksp.symbol.KSFunctionDeclaration +import io.kabu.annotation.Context import io.kabu.annotation.ContextCreator +import io.kabu.backend.diagnostic.diagnosticError import io.kabu.backend.inout.input.method.ContextConstructorMethod.Companion.toContextConstructorMethod import io.kabu.backend.inout.input.method.ContextCreatorMethod import io.kabu.backend.inout.input.method.ContextCreatorMethod.Companion.toContextCreatorMethod import io.kabu.frontend.ksp.processor.util.areNotSupported import io.kabu.frontend.ksp.processor.util.builder.validator.ContextClassFoundByAnnotatedConstructorValidator import io.kabu.frontend.ksp.processor.util.getAnnotation +import io.kabu.frontend.ksp.processor.util.getAnnotationOrNull +import io.kabu.frontend.ksp.processor.util.originOf import io.kabu.frontend.ksp.processor.util.toMethod import io.kabu.frontend.ksp.processor.util.toTypeName class ContextCreatorFunctionBuilder : AbstractFunctionBuilder() { - override fun build(function: KSFunctionDeclaration): ContextCreatorMethod { - val role = ContextCreator::class.simpleName!! - validateFunction(function, role) + fun build(classDeclaration: KSClassDeclaration): ContextCreatorMethod { + val primaryConstructor = classDeclaration.primaryConstructor + ?: diagnosticError("Type '$classDeclaration' does not have primary constructor", originOf(classDeclaration)) + + if (primaryConstructor.getAnnotationOrNull() != null) { + diagnosticError( + "Primary constructor of @${Context::class.java.simpleName}-annotated type '$classDeclaration' " + + "can not have @${ContextCreator::class.java.simpleName} annotation", originOf(classDeclaration) + ) + } + + val contextAnnotation = classDeclaration.getAnnotation() + val contextName = contextAnnotation.arguments + .single { it.name?.asString() == Context::contextName.name } //todo error if 'name' is missing + .value as String + return buildContextCreatorMethod(primaryConstructor, contextName) + } + + override fun build(function: KSFunctionDeclaration): ContextCreatorMethod { val contextCreatorAnnotation = function.getAnnotation() val contextName = contextCreatorAnnotation.arguments - .single { it.name?.asString() == ContextCreator::contextName.name }//todo error if 'name' is missing + .single { it.name?.asString() == ContextCreator::contextName.name } //todo error if 'name' is missing .value as String + return buildContextCreatorMethod(function, contextName) + } + + private fun buildContextCreatorMethod( + function: KSFunctionDeclaration, + contextName: String, + ): ContextCreatorMethod { + val role = ContextCreator::class.simpleName!! + validateFunction(function, role) + return if (function.isConstructor()) { val classDeclaration = function.parentDeclaration as KSClassDeclaration diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/BaseKspFrontendProcessorTest.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/BaseKspFrontendProcessorTest.kt index d8ef28c..e2718d5 100644 --- a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/BaseKspFrontendProcessorTest.kt +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/BaseKspFrontendProcessorTest.kt @@ -237,12 +237,12 @@ operator fun String.minus(result: TestCase.ScriptResult) = TestCase(this.trimInd import io.kabu.annotation.Pattern import io.kabu.annotation.LocalPattern import io.kabu.annotation.ContextCreator + import io.kabu.annotation.Context // lines below are for future imports or other declarations to fix line numbers used in tests - // end of common part """ diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/complex/contextParametrization/contextAnnotation/test1/ContextAnnotationTest.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/complex/contextParametrization/contextAnnotation/test1/ContextAnnotationTest.kt new file mode 100644 index 0000000..b2a641c --- /dev/null +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/complex/contextParametrization/contextAnnotation/test1/ContextAnnotationTest.kt @@ -0,0 +1,43 @@ +@file:Suppress("UNUSED_PARAMETER") + +package io.kabu.frontend.ksp.processor.complex.contextParametrization.contextAnnotation.test1 + +import io.kabu.frontend.ksp.processor.BaseKspFrontendProcessorTest +import io.kabu.frontend.ksp.processor.TestCase.ScriptResult.Termination +import io.kabu.frontend.ksp.processor.minus +import io.kabu.frontend.ksp.processor.sample +import org.junit.Test + + +class ContextAnnotationTest : BaseKspFrontendProcessorTest() { + + @Test + fun test() = compileAndCheckAndRun( + """ + + @Context("someClass") + class SomeClass(val i: Int) { + + private val pairs = mutableListOf>() + + @LocalPattern("name - number") + fun foo(name: String, number: Int) { + pairs.add("${'$'}name" to number + i) + } + + override fun toString() = "SomeClass(pairs=${'$'}pairs)" + } + + @Pattern("i @Extend(context = someClass(i), parameter = arg) {}") + fun bar(i: Int, arg: SomeClass) { + print(arg) + } + + """, + sample(""" + 2 { + "aaa" - 3 + } + """) - Termination("SomeClass(pairs=[(aaa, 5)])") + ) +} diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/complex/contextParametrization/contextAnnotation/test2/ContextAnnotationAndContextCreatorConflictTest.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/complex/contextParametrization/contextAnnotation/test2/ContextAnnotationAndContextCreatorConflictTest.kt new file mode 100644 index 0000000..3118ac9 --- /dev/null +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/complex/contextParametrization/contextAnnotation/test2/ContextAnnotationAndContextCreatorConflictTest.kt @@ -0,0 +1,35 @@ +@file:Suppress("UNUSED_PARAMETER") + +package io.kabu.frontend.ksp.processor.complex.contextParametrization.contextAnnotation.test2 + +import io.kabu.frontend.ksp.processor.BaseKspFrontendProcessorTest +import org.junit.Test + + +class ContextAnnotationAndContextCreatorConflictTest : BaseKspFrontendProcessorTest() { + + @Test + fun test() = compileAndCheck( + """ + @Context("someClass") + class SomeClass @ContextCreator("someClass") constructor(val i: Int) { + + private val pairs = mutableListOf>() + + @LocalPattern("name - number") + fun foo(name: String, number: Int) { + pairs.add("${'$'}name" to number + i) + } + + override fun toString() = "SomeClass(pairs=${'$'}pairs)" + } + + @Pattern("i @Extend(context = someClass(i), parameter = arg) {}") + fun bar(i: Int, arg: SomeClass) { + print(arg) + } + + """) { + assertCompilationError(15, "Primary constructor of", "can not have @ContextCreator annotation") + } +} diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/complex/nested/ifelse/IfElseTest.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/complex/nested/ifelse/IfElseTest.kt index 4724198..4edcd01 100644 --- a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/complex/nested/ifelse/IfElseTest.kt +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/complex/nested/ifelse/IfElseTest.kt @@ -11,7 +11,7 @@ class IfElseTest : BaseKspFrontendProcessorTest() { @Test fun test() = compileAndCheckAndRun( """ - class Context @ContextCreator("context") constructor() { + class Ctx @ContextCreator("context") constructor() { val trueActions = mutableListOf<() -> Unit>() val falseActions = mutableListOf<() -> Unit>() @@ -36,12 +36,12 @@ class IfElseTest : BaseKspFrontendProcessorTest() { } @Pattern("condition @Extend(context = context(), parameter = context) {}") - fun ifElse(condition: Boolean, context: Context) { + fun ifElse(condition: Boolean, context: Ctx) { (if (condition) context.trueActions else context.falseActions).forEach { it() } } @Pattern("condition Yoda said @Extend(context = context(), parameter = context) {}") - fun yodaIfElse(condition: Boolean, context: Context) = ifElse(condition, context) + fun yodaIfElse(condition: Boolean, context: Ctx) = ifElse(condition, context) """, sample(""" diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/simple/SimpleContextTest.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/simple/SimpleContextTest.kt index 3f77f51..1d8e862 100644 --- a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/simple/SimpleContextTest.kt +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/simple/SimpleContextTest.kt @@ -13,11 +13,11 @@ class SimpleContextTest : BaseKspFrontendProcessorTest() { fun `pattern extension does not fail`() = compileAndCheckAndRun( """ @Pattern("i % @Extend(context = ctx(), parameter = context) {}") - fun foo(i: Int, context: Context) { + fun foo(i: Int, context: Ctx) { print(i) } - class Context @ContextCreator("ctx") constructor() { + class Ctx @ContextCreator("ctx") constructor() { @LocalPattern("s * count") fun str(count: Int, s: String): String { @@ -34,11 +34,11 @@ class SimpleContextTest : BaseKspFrontendProcessorTest() { fun `simple extension`() = compileAndCheckAndRun( """ @Pattern("i % @Extend(context = ctx(), parameter = context) {}") - fun foo(i: Int, context: Context) { + fun foo(i: Int, context: Ctx) { print("${'$'}i, ${'$'}{context.result}") } - class Context @ContextCreator("ctx") constructor() { + class Ctx @ContextCreator("ctx") constructor() { var result: String? = null @LocalPattern("s * count") @@ -56,11 +56,11 @@ class SimpleContextTest : BaseKspFrontendProcessorTest() { fun `extension point inside watcher lambda`() = compileAndCheckAndRun( """ @Pattern("i % { b - @Extend(context = ctx(), parameter = context) {} }") - fun foo(i: Int, b: Boolean, context: Context) { + fun foo(i: Int, b: Boolean, context: Ctx) { print("${'$'}i, ${'$'}b, ${'$'}{context.result}") } - class Context @ContextCreator("ctx") constructor() { + class Ctx @ContextCreator("ctx") constructor() { var result: String? = null @LocalPattern("s * count") @@ -78,11 +78,11 @@ class SimpleContextTest : BaseKspFrontendProcessorTest() { fun `conflicts inside context mediator, context mediator inside watcher lambda`() = compileAndCheckAndRun( """ @Pattern("i % { @Extend(context = ctx(), parameter = context) {} }") - fun foo(i: Int, context: Context) { + fun foo(i: Int, context: Ctx) { print("${'$'}i, ${'$'}{context.result}") } - class Context @ContextCreator("ctx") constructor() { + class Ctx @ContextCreator("ctx") constructor() { var result: String = "" @LocalPattern("a / b + c / d") From e85e6ac4a9726e001e31df0060ec195c4cc9844e Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Fri, 14 Jul 2023 00:34:31 +0600 Subject: [PATCH 07/43] mediator classes are placed into package level namespace --- .../handler/lambda/extension/ExtensionLambdaHandler.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/extension/ExtensionLambdaHandler.kt b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/extension/ExtensionLambdaHandler.kt index 58b5fdd..b9a4b74 100644 --- a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/extension/ExtensionLambdaHandler.kt +++ b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/extension/ExtensionLambdaHandler.kt @@ -42,8 +42,7 @@ class ExtensionLambdaHandler( analyzer.methodsRegistry.getExtensionContextType(extensionContextCreatorDefinition.name) val extensionContextTypeNode = extensionContextTypeName.toFixedTypeNode() - //todo namespaceNode.getRoot() - mediator classes don't belong to particular pattern - val contextMediatorNamespaceNode = namespaceNode + val contextMediatorNamespaceNode = namespaceNode.getRoot() val contextMediatorClassSimpleName = contextMediatorNamespaceNode.typeNameGenerator.generateNextTypeName() val contextMediatorTypeNode = ContextMediatorTypeNodeImpl( From 3207bddb554c4838a727c233144642483fec73f3 Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Fri, 14 Jul 2023 21:43:47 +0600 Subject: [PATCH 08/43] added guard counter into topological sort algorithm --- backend/src/main/kotlin/io/kabu/backend/node/nodesUtils.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backend/src/main/kotlin/io/kabu/backend/node/nodesUtils.kt b/backend/src/main/kotlin/io/kabu/backend/node/nodesUtils.kt index 75d4a30..243384a 100644 --- a/backend/src/main/kotlin/io/kabu/backend/node/nodesUtils.kt +++ b/backend/src/main/kotlin/io/kabu/backend/node/nodesUtils.kt @@ -2,9 +2,11 @@ package io.kabu.backend.node fun sortTopologically(graph: Set): List { + var counter = 0 val remainingNodes = graph.toMutableList() val resolvedNodes = mutableListOf() while (remainingNodes.isNotEmpty()) { + if (counter++ > 100_000) error("Topological sort went into infinite loop, remaining nodes: $remainingNodes") val iterator = remainingNodes.iterator() while (iterator.hasNext()) { val node = iterator.next() From 9fe43200c0e87a208da17a62d8cf109a7f2b6ed4 Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Fri, 14 Jul 2023 22:33:14 +0600 Subject: [PATCH 09/43] local patterns handling moved to a separate step --- .../extension/ExtensionLambdaHandler.kt | 21 +---- .../io/kabu/backend/integration/Integrator.kt | 2 + ...AndPackageNodeUniversalConflictResolver.kt | 9 +- .../backend/processor/BackendProcessor.kt | 86 ++++++++++++++++++- .../kabu/backend/processor/MethodsRegistry.kt | 15 ++++ 5 files changed, 112 insertions(+), 21 deletions(-) diff --git a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/extension/ExtensionLambdaHandler.kt b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/extension/ExtensionLambdaHandler.kt index b9a4b74..896c36c 100644 --- a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/extension/ExtensionLambdaHandler.kt +++ b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/extension/ExtensionLambdaHandler.kt @@ -4,21 +4,17 @@ import com.squareup.kotlinpoet.LambdaTypeName import com.squareup.kotlinpoet.UNIT import io.kabu.backend.analyzer.Analyzer import io.kabu.backend.analyzer.AnalyzerImpl -import io.kabu.backend.diagnostic.Origin import io.kabu.backend.diagnostic.builder.extensionAnnotationMissingError import io.kabu.backend.diagnostic.builder.unknownFunctionParameterNameError import io.kabu.backend.inout.input.method.PatternMethod import io.kabu.backend.node.ContextMediatorTypeNode import io.kabu.backend.node.DerivativeTypeNode -import io.kabu.backend.node.factory.node.ContextMediatorTypeNodeImpl import io.kabu.backend.node.namespace.NamespaceNode -import io.kabu.backend.parameter.Parameter import io.kabu.backend.parser.LambdaExpression import io.kabu.backend.processor.MethodsRegistry import io.kabu.backend.provider.provider.ArgumentProvider import io.kabu.backend.provider.provider.ExtensionLambdaProvider import io.kabu.backend.util.Constants.EXTENSION_ANNOTATION -import io.kabu.backend.util.Constants.EXTENSION_CONTEXT_PROPERTY_NAME import io.kabu.backend.util.poet.TypeNameUtils.toFixedTypeNode class ExtensionLambdaHandler( @@ -42,20 +38,9 @@ class ExtensionLambdaHandler( analyzer.methodsRegistry.getExtensionContextType(extensionContextCreatorDefinition.name) val extensionContextTypeNode = extensionContextTypeName.toFixedTypeNode() - val contextMediatorNamespaceNode = namespaceNode.getRoot() - - val contextMediatorClassSimpleName = contextMediatorNamespaceNode.typeNameGenerator.generateNextTypeName() - val contextMediatorTypeNode = ContextMediatorTypeNodeImpl( - name = contextMediatorClassSimpleName, - namespaceNode = contextMediatorNamespaceNode, - //todo Origin() && Parameter ? - contextProperty = Parameter(EXTENSION_CONTEXT_PROPERTY_NAME, extensionContextTypeName, Origin()), - ) - registerNode(contextMediatorTypeNode) - - val localPatternMethods = analyzer.methodsRegistry.getLocalPatternMethods(extensionContextTypeName) - localPatternMethods.forEach { - analyzeMethod(it, contextMediatorTypeNode, analyzer.methodsRegistry, EXTENSION_CONTEXT_PROPERTY_NAME) + val contextMediatorTypeNode = methodsRegistry.getContextMediatorTypeNode(extensionContextTypeName).also { node -> + registerNode(node) + node.dependencies.forEach { registerNode(it) } //todo not recursive yet } val returningTypeNode = DerivativeTypeNode(namespaceNode, mutableListOf(contextMediatorTypeNode)) { deps -> diff --git a/backend/src/main/kotlin/io/kabu/backend/integration/Integrator.kt b/backend/src/main/kotlin/io/kabu/backend/integration/Integrator.kt index 0887033..72985eb 100644 --- a/backend/src/main/kotlin/io/kabu/backend/integration/Integrator.kt +++ b/backend/src/main/kotlin/io/kabu/backend/integration/Integrator.kt @@ -31,6 +31,8 @@ class Integrator { fun integrate(graph: Set, removeIrrelevant: Boolean = true) { val sortedNodes = sortTopologically(graph) sortedNodes.forEach { node -> + if (node in integrated) return@forEach // skipping already integrated nodes + println("Integrating: '$node'") val conflictingNode = findConflictingNode(node) diff --git a/backend/src/main/kotlin/io/kabu/backend/integration/resolver/PackageNodeAndPackageNodeUniversalConflictResolver.kt b/backend/src/main/kotlin/io/kabu/backend/integration/resolver/PackageNodeAndPackageNodeUniversalConflictResolver.kt index 5ba1f5e..da4fa6f 100644 --- a/backend/src/main/kotlin/io/kabu/backend/integration/resolver/PackageNodeAndPackageNodeUniversalConflictResolver.kt +++ b/backend/src/main/kotlin/io/kabu/backend/integration/resolver/PackageNodeAndPackageNodeUniversalConflictResolver.kt @@ -8,7 +8,7 @@ import io.kabu.backend.node.PackageNode * Resolves conflict when integrating a PackageNode */ @Suppress("MaxLineLength") -class PackageNodeAndPackageNodeUniversalConflictResolver(private val integrator: Integrator): ConflictResolver { +class PackageNodeAndPackageNodeUniversalConflictResolver(private val integrator: Integrator) : ConflictResolver { override fun resolve(node1: Node, node2: Node) { node1 as PackageNode; node2 as PackageNode @@ -21,5 +21,12 @@ class PackageNodeAndPackageNodeUniversalConflictResolver(private val integrator: val conflicting = integrator.integratedOf(node1, node2) integrator.rewireNodes(current, conflicting) + + // rewiring accessor objects + val currentAccessorObjectNode = current.accessorObjectNode + val conflictingAccessorObjectNode = conflicting.accessorObjectNode + if (currentAccessorObjectNode != null && conflictingAccessorObjectNode == null) { + conflicting.accessorObjectNode = currentAccessorObjectNode + } } } diff --git a/backend/src/main/kotlin/io/kabu/backend/processor/BackendProcessor.kt b/backend/src/main/kotlin/io/kabu/backend/processor/BackendProcessor.kt index f188a45..f9d4a05 100644 --- a/backend/src/main/kotlin/io/kabu/backend/processor/BackendProcessor.kt +++ b/backend/src/main/kotlin/io/kabu/backend/processor/BackendProcessor.kt @@ -1,15 +1,29 @@ package io.kabu.backend.processor +import com.squareup.kotlinpoet.ClassName +import com.squareup.kotlinpoet.ParameterizedTypeName +import com.squareup.kotlinpoet.TypeName +import io.kabu.annotation.LocalPattern import io.kabu.annotation.Pattern import io.kabu.backend.analyzer.AnalyzerImpl import io.kabu.backend.common.log.InterceptingLogging +import io.kabu.backend.diagnostic.Origin +import io.kabu.backend.diagnostic.diagnosticError import io.kabu.backend.exception.PatternProcessingException import io.kabu.backend.generator.Generator import io.kabu.backend.inout.input.ProcessingInput +import io.kabu.backend.inout.input.method.ContextCreatorMethod import io.kabu.backend.inout.input.method.GlobalPatternMethod +import io.kabu.backend.inout.input.method.PatternMethod import io.kabu.backend.inout.output.ProcessingOutput import io.kabu.backend.integration.Integrator +import io.kabu.backend.node.Node import io.kabu.backend.node.Nodes +import io.kabu.backend.node.PackageNode +import io.kabu.backend.node.factory.node.ContextMediatorTypeNodeImpl +import io.kabu.backend.node.namespace.NamespaceNode +import io.kabu.backend.parameter.Parameter +import io.kabu.backend.util.Constants class BackendProcessor(private val options: Options = Options.DEFAULT) { @@ -28,10 +42,13 @@ class BackendProcessor(private val options: Options = Options.DEFAULT) { } private fun processInternally(processingInput: ProcessingInput) { - val globalPatternMethods = processingInput.globalPatterns val methodsRegistry = MethodsRegistry(processingInput) - val integrator = Integrator() + + val nodesForExtensionContexts = analyzeContextCreators(processingInput.contextCreators, methodsRegistry) + integrator.integrate(nodesForExtensionContexts) + + val globalPatternMethods = processingInput.globalPatterns globalPatternMethods.forEach { val nodes = analyzeGlobalPatternMethod(it, methodsRegistry) integrator.integrate(nodes) @@ -41,6 +58,71 @@ class BackendProcessor(private val options: Options = Options.DEFAULT) { generator.writeCode(integrator.integrated, processingInput.fileWriter) } + private fun analyzeContextCreators( + contextCreators: List, + methodsRegistry: MethodsRegistry, + ) : Nodes { + val extensionContextTypes = contextCreators.map { it.returnedType }.distinct() + + val nodes = extensionContextTypes.flatMap { extensionContextTypeName -> + analyzeContextType(extensionContextTypeName, methodsRegistry) + } + + return Nodes().apply { + nodes.forEach(this::add) + } + } + + private fun analyzeContextType( + extensionContextTypeName: TypeName, + methodsRegistry: MethodsRegistry, + ): List { + logger.info { "Handling extension context type: $extensionContextTypeName" } + + val packageName = when (extensionContextTypeName) { + is ClassName -> extensionContextTypeName.packageName + is ParameterizedTypeName -> extensionContextTypeName.rawType.packageName + else -> diagnosticError("Unsupported extension context type: $extensionContextTypeName") + } + + val packageNode = PackageNode(packageName) + val contextMediatorClassSimpleName = packageNode.typeNameGenerator.generateNextTypeName() + val contextMediatorTypeNode = ContextMediatorTypeNodeImpl( + name = contextMediatorClassSimpleName, + namespaceNode = packageNode, + //todo Origin() && Parameter ? + contextProperty = Parameter(Constants.EXTENSION_CONTEXT_PROPERTY_NAME, extensionContextTypeName, Origin()), + ) + + methodsRegistry.registerContextMediatorTypeNode(extensionContextTypeName, contextMediatorTypeNode) + + val localPatternMethods = methodsRegistry.getLocalPatternMethods(extensionContextTypeName) + val nodesForLocalPatterns = localPatternMethods.flatMap { + analyzeLocalPatternMethod( + method = it, + contextMediatorTypeNode = contextMediatorTypeNode, + methodsRegistry = methodsRegistry, + ) + } + + return listOf(packageNode, contextMediatorTypeNode) + nodesForLocalPatterns + } + + private fun analyzeLocalPatternMethod( + method: PatternMethod, + contextMediatorTypeNode: NamespaceNode, + methodsRegistry: MethodsRegistry, + ) : Nodes { + logger.info { "Analyzing ${LocalPattern::class.simpleName} method: $method" } + return AnalyzerImpl( + method = method, + methodsRegistry = methodsRegistry, + contextPropertyName = Constants.EXTENSION_CONTEXT_PROPERTY_NAME, //todo rm + options = options, + contextMediatorNamespaceNode = contextMediatorTypeNode //todo inconsistency in names + ).analyze() + } + private fun analyzeGlobalPatternMethod( method: GlobalPatternMethod, methodsRegistry: MethodsRegistry diff --git a/backend/src/main/kotlin/io/kabu/backend/processor/MethodsRegistry.kt b/backend/src/main/kotlin/io/kabu/backend/processor/MethodsRegistry.kt index 91a653d..7bdacef 100644 --- a/backend/src/main/kotlin/io/kabu/backend/processor/MethodsRegistry.kt +++ b/backend/src/main/kotlin/io/kabu/backend/processor/MethodsRegistry.kt @@ -6,12 +6,27 @@ import io.kabu.backend.diagnostic.diagnosticError import io.kabu.backend.inout.input.ProcessingInput import io.kabu.backend.inout.input.method.ContextCreatorMethod import io.kabu.backend.inout.input.method.LocalPatternMethod +import io.kabu.backend.node.TypeNode class MethodsRegistry(processingInput: ProcessingInput? = null) { private val localPatterns: Map> // registry of LocalPattern methods private val contextCreators: List // registry of ContextCreator + //todo not registry responsibility + private val map: MutableMap = mutableMapOf() + + fun registerContextMediatorTypeNode(extensionContextTypeName: TypeName, contextMediatorTypeNode: TypeNode) { + if (extensionContextTypeName in map) { + error("Duplicate context mediator registration for: $extensionContextTypeName") + } + map[extensionContextTypeName] = contextMediatorTypeNode + } + + fun getContextMediatorTypeNode(extensionContextTypeName: TypeName): TypeNode { + return map[extensionContextTypeName]!! + } + init { if (processingInput != null) { contextCreators = validateContextCreators(processingInput.contextCreators) From 6b5c12a54708249a3e382c12c860373cb3131aac Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Sun, 16 Jul 2023 15:13:12 +0600 Subject: [PATCH 10/43] refactoring --- .../AbstractCallableDeclaration.kt | 25 +++++++------------ 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/backend/src/main/kotlin/io/kabu/backend/declaration/AbstractCallableDeclaration.kt b/backend/src/main/kotlin/io/kabu/backend/declaration/AbstractCallableDeclaration.kt index b34e936..8d72a8c 100644 --- a/backend/src/main/kotlin/io/kabu/backend/declaration/AbstractCallableDeclaration.kt +++ b/backend/src/main/kotlin/io/kabu/backend/declaration/AbstractCallableDeclaration.kt @@ -12,27 +12,13 @@ import io.kabu.backend.provider.group.FunDeclarationProviders import io.kabu.backend.provider.provider.WatcherLambdaProvider.Companion.STACK_PROPERTY_NAME import io.kabu.backend.util.poet.asCodeBlock -//todo DRY abstract class AbstractCallableDeclaration : Declaration() { protected fun getCallableStatements( funDeclarationProviders: FunDeclarationProviders, returningClassName: ClassName, ): CodeBlock { - val functionBlockContext = FunctionBlockContext(funDeclarationProviders) - functionBlockContext.doEvaluation() - - val statements1 = functionBlockContext.joinAllStatements() - val statements2 = run { - val allParameters = functionBlockContext.actualProvidersProvider.childrenProviders - .joinToString { functionBlockContext.getCodeForActualProvider(it) } - "return %T($allParameters)" - } - - return listOf(statements1, statements2) - .filter { it.isNotBlank() } - .joinToString("\n") - .asCodeBlock(returningClassName) + return getCodeBlockForReturn(funDeclarationProviders, returningClassName) } protected fun getCallableStatements( @@ -50,6 +36,13 @@ abstract class AbstractCallableDeclaration : Declaration() { private fun codeBlockForGeneratedTypeNode( funDeclarationProviders: FunDeclarationProviders, returnTypeNode: TypeNode, + ): CodeBlock { + return getCodeBlockForReturn(funDeclarationProviders, returnTypeNode.typeName) + } + + private fun getCodeBlockForReturn( + funDeclarationProviders: FunDeclarationProviders, + returningTypeName: TypeName, ): CodeBlock { val functionBlockContext = FunctionBlockContext(funDeclarationProviders) functionBlockContext.doEvaluation() @@ -64,7 +57,7 @@ abstract class AbstractCallableDeclaration : Declaration() { return listOf(statements1, statements2) .filter { it.isNotBlank() } .joinToString("\n") - .asCodeBlock(returnTypeNode.typeName) + .asCodeBlock(returningTypeName) } private fun codeBlockForFixedTypeNode( From b5f8a0a602ced455e6d26288be8e86ba260d5114 Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Sun, 16 Jul 2023 19:59:53 +0600 Subject: [PATCH 11/43] updated baseline --- detekt/detekt-baseline.xml | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/detekt/detekt-baseline.xml b/detekt/detekt-baseline.xml index f3c454d..63b1195 100644 --- a/detekt/detekt-baseline.xml +++ b/detekt/detekt-baseline.xml @@ -3,7 +3,7 @@ CyclomaticComplexMethod:GraphVisualizer.kt$GraphVisualizer$fun generateMermaidDiagramAsFlowchart( nodes: Set<Node>, styling: Boolean = true, title: String? = null, ): String - CyclomaticComplexMethod:Handler.kt$Handler$protected fun createWatchedParameter( rawProviders: RawProviders, operator: Operator, assignableSuffixExpression: KotlinExpression? ): BaseProvider + CyclomaticComplexMethod:Handler.kt$Handler$protected fun createWatchedParameter( rawProviders: RawProviders, operator: Operator, assignableSuffixExpression: KotlinExpression? ): AbstractProvider CyclomaticComplexMethod:OperatorHandler.kt$OperatorHandler$fun handle(expression: OperatorExpression): Provider CyclomaticComplexMethod:PatternParser.kt$PatternParser$private fun visit(tree: ParseTree): KotlinExpression CyclomaticComplexMethod:PatternParser.kt$PatternParser$private fun visitBinaryOperator(context: ParseTree): BinaryOperator @@ -21,21 +21,21 @@ LongMethod:JsonObjectBuilderTest.kt$JsonObjectBuilderTest$@Test fun test() LongMethod:ParserSuccessTest.kt$PatternParserTestParameterized.Companion$@JvmStatic @Parameterized.Parameters fun data() LongMethod:PatternParser.kt$PatternParser$private fun visit(tree: ParseTree): KotlinExpression - LongParameterList:ContextConstructorMethod.kt$ContextConstructorMethod$( packageName: String, name: String, returnedType: TypeName, receiverType: TypeName?, parameters: List<EntryParameter>, contextName: String, val declaringType: TypeName, origin: Origin ) - LongParameterList:ContextCreatorMethod.kt$ContextCreatorMethod$( packageName: String, name: String, returnedType: TypeName, receiverType: TypeName?, parameters: List<EntryParameter>, val contextName: String, origin: Origin ) - LongParameterList:ExtensionLambdaProvider.kt$ExtensionLambdaProvider$( typeNode: TypeNode, returningProvider: BaseProvider, //todo don't need? //todo rename val contextMediatorTypeNode: TypeNode, val contextCreatorDefinition: ContextCreatorDefinition, val destinationParameterTypeNode: TypeNode, analyzer: Analyzer, origin: Origin? = null, ) - LongParameterList:GlobalPatternMethod.kt$GlobalPatternMethod$( packageName: String, name: String, returnedType: TypeName, receiverType: TypeName?, parameters: List<EntryParameter>, pattern: String, origin: Origin ) - LongParameterList:LocalPatternMethod.kt$LocalPatternMethod$( packageName: String, name: String, returnedType: TypeName, receiverType: TypeName?, parameters: List<EntryParameter>, pattern: String, val declaringType: TypeName, origin: Origin ) - LongParameterList:PatternMethod.kt$PatternMethod$( packageName: String, name: String, returnedType: TypeName, receiverType: TypeName?, parameters: List<EntryParameter>, val pattern: String, //todo get origin of pattern annotation as well origin: Origin ) + LongParameterList:ContextConstructorMethod.kt$ContextConstructorMethod$( packageName: String, name: String, returnedType: TypeName, receiver: Parameter?, parameters: List<Parameter>, contextName: String, val declaringType: TypeName, origin: Origin ) + LongParameterList:ContextCreatorMethod.kt$ContextCreatorMethod$( packageName: String, name: String, returnedType: TypeName, receiver: Parameter?, parameters: List<Parameter>, val contextName: String, origin: Origin ) + LongParameterList:ExtensionLambdaProvider.kt$ExtensionLambdaProvider$( typeNode: TypeNode, returningProvider: AbstractProvider, //todo don't need? //todo rename val contextMediatorTypeNode: TypeNode, val contextCreatorDefinition: ContextCreatorDefinition, val destinationParameterTypeNode: TypeNode, analyzer: Analyzer, origin: Origin? = null, ) + LongParameterList:GlobalPatternMethod.kt$GlobalPatternMethod$( packageName: String, name: String, returnedType: TypeName, receiver: Parameter?, parameters: List<Parameter>, pattern: String, origin: Origin ) + LongParameterList:LocalPatternMethod.kt$LocalPatternMethod$( packageName: String, name: String, returnedType: TypeName, receiver: Parameter?, parameters: List<Parameter>, pattern: String, val declaringType: TypeName, origin: Origin ) + LongParameterList:PatternMethod.kt$PatternMethod$( packageName: String, name: String, returnedType: TypeName, receiver: Parameter?, parameters: List<Parameter>, val pattern: String, //todo get origin of pattern annotation as well origin: Origin ) MagicNumber:PatternParser.kt$PatternParser$3 - MagicNumber:ProcessingInputRenderer.kt$3 - MagicNumber:ProcessingInputRenderer.kt$4 + MagicNumber:nodesUtils.kt$100_000 MatchingDeclarationName:ContextConstructorAloneTest.kt$ContextConstructorTest : BaseKspFrontendProcessorTest + MaxLineLength:ExtensionLambdaHandler.kt$ExtensionLambdaHandler$val MaxLineLength:OperatorHandler.kt$OperatorHandler$val rawProvidersOfAssign = RawProviders(rawProviders.providersList + assigningParameter, operatorInfoParameter = null) MemberNameEqualsClassName:OperatorInfoTypes.kt$OperatorInfoTypes$private val operatorInfoTypes = listOf( EQUALITY_INFO_TYPE, INCLUSION_INFO_TYPE, RANKING_COMPARISON_INFO_TYPE, STRICTNESS_COMPARISON_INFO_TYPE, ) PrintStackTrace:KspFrontendProcessor.kt$KspFrontendProcessor$e ReturnCount:FunctionAndFunctionUniversalConflictResolver.kt$FunctionAndFunctionUniversalConflictResolver$private fun returnTypesAreMergeable(current: FunctionNode, conflicting: FunctionNode): Boolean - ReturnCount:IdentifierHandler.kt$IdentifierHandler$private fun createProperty(expression: IdentifierLeaf): BaseProvider + ReturnCount:IdentifierHandler.kt$IdentifierHandler$private fun createProperty(expression: IdentifierLeaf): AbstractProvider ReturnCount:KspFrontendProcessor.kt$KspFrontendProcessor$override fun process(resolver: Resolver): List<KSAnnotated> ReturnCount:LambdaHandler.kt$LambdaHandler$fun handle(expression: LambdaExpression): Provider ReturnCount:OperatorHandler.kt$OperatorHandler$fun handle(expression: OperatorExpression): Provider @@ -52,6 +52,7 @@ TooManyFunctions:TypeConflictChecker.kt$TypeConflictChecker : ConflictChecker UnnecessaryAbstractClass:SimpleScript.kt$SimpleScript$SimpleScript UnusedPrivateMember:BaseKspFrontendProcessorTest.kt$BaseKspFrontendProcessorTest$private fun KotlinCompilation.Result.kspGeneratedSources(): List<File> + UnusedPrivateMember:ExtensionLambdaHandler.kt$ExtensionLambdaHandler$private fun analyzeMethod( method: PatternMethod, contextMediatorNamespaceNode: NamespaceNode, methodsRegistry: MethodsRegistry, contextPropertyName: String? ) UnusedPrivateMember:FunctionStaticUserCodeConflictDetector.kt$FunctionStaticUserCodeConflictDetector$node: FunctionNode UnusedPrivateMember:PropertyStaticUserCodeConflictDetector.kt$PropertyStaticUserCodeConflictDetector$node: PropertyNode UnusedPrivateMember:TypeStaticUserCodeConflictDetector.kt$TypeStaticUserCodeConflictDetector$node: TypeNode From c3a19e056f699753b2c54024b82b1b032866d86b Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Sun, 16 Jul 2023 23:40:03 +0600 Subject: [PATCH 12/43] dependencies: kotlinpoet:1.14.2 --- .../functions/AbstractFunctionDeclaration.kt | 2 +- .../io/kabu/backend/generator/Generator.kt | 4 ++-- .../io/kabu/backend/generator/Writer.kt | 23 +++++++++++++++++-- .../kabu/backend/planner/AnalyzerAdHocTest.kt | 2 +- .../kabu/backend/plannerx/GenerationTest.kt | 2 +- .../test/kotlin/io/kabu/backend/r2c/Utils.kt | 2 +- dependencies.gradle | 2 +- 7 files changed, 28 insertions(+), 9 deletions(-) diff --git a/backend/src/main/kotlin/io/kabu/backend/declaration/functions/AbstractFunctionDeclaration.kt b/backend/src/main/kotlin/io/kabu/backend/declaration/functions/AbstractFunctionDeclaration.kt index 5933508..f4d886c 100644 --- a/backend/src/main/kotlin/io/kabu/backend/declaration/functions/AbstractFunctionDeclaration.kt +++ b/backend/src/main/kotlin/io/kabu/backend/declaration/functions/AbstractFunctionDeclaration.kt @@ -23,7 +23,7 @@ abstract class AbstractFunctionDeclaration : AbstractCallableDeclaration() { isHelper: Boolean = false, //todo up ): FunSpec { return FunSpec.builder(name).apply { - addModifiers(if (isHelper) KModifier.PRIVATE else KModifier.PUBLIC) + if (isHelper) addModifiers(KModifier.PRIVATE) when { isInfix -> addModifiers(KModifier.INFIX) !isHelper -> addModifiers(KModifier.OPERATOR) diff --git a/backend/src/main/kotlin/io/kabu/backend/generator/Generator.kt b/backend/src/main/kotlin/io/kabu/backend/generator/Generator.kt index 6a22b2c..6d3492d 100644 --- a/backend/src/main/kotlin/io/kabu/backend/generator/Generator.kt +++ b/backend/src/main/kotlin/io/kabu/backend/generator/Generator.kt @@ -12,7 +12,7 @@ import io.kabu.backend.node.WatcherContextTypeNode import io.kabu.backend.node.sortTopologically -class Generator { +class Generator(private val testMode: Boolean = false) { private val filename: String = "Generated" fun writeCode(nodes: Set, writer: FileWriter) { @@ -48,7 +48,7 @@ class Generator { val gatheredDeclarations = gatherDeclarationsForNodes(unwrittenNodes, writtenNodes) val declarations = gatheredDeclarations.declarations - return Writer().composeFileForDeclarations(packageNode.name, declarations) + return Writer(testMode).composeFileForDeclarations(packageNode.name, declarations) } private fun getDeclarationsForNode(node: Node): GatheredDeclarations { diff --git a/backend/src/main/kotlin/io/kabu/backend/generator/Writer.kt b/backend/src/main/kotlin/io/kabu/backend/generator/Writer.kt index 283fe4a..e52283e 100644 --- a/backend/src/main/kotlin/io/kabu/backend/generator/Writer.kt +++ b/backend/src/main/kotlin/io/kabu/backend/generator/Writer.kt @@ -11,11 +11,22 @@ import io.kabu.backend.declaration.objects.AccessorObjectDeclaration import io.kabu.backend.declaration.properties.AbstractPropertyDeclaration import io.kabu.backend.util.Constants.RUNTIME_PACKAGE -class Writer { +class Writer(private val testMode: Boolean = false) { fun composeFileForDeclarations(packageName: String, declarations: List): String { val fileSpec = buildFileSpec(packageName, declarations) - return fileSpec.toString() + return removePublicModifier(fileSpec.toString()) + } + + private fun removePublicModifier(source: String): String { + if (!testMode) return source + + var result = source.replace(operatorFunRegex, "operator") + result = result.replace(infixFunRegex, "infix") + result = result.replace(classRegex, "class") + result = result.replace(objectRegex, "object") + result = result.replace(valRegex, "val") + return result } private fun buildFileSpec(packageName: String, declarations: List): FileSpec { @@ -58,6 +69,14 @@ class Writer { addDeclarations(declarations) }.build() } + + private companion object { + val operatorFunRegex = Regex("public operator") + val infixFunRegex = Regex("public infix") + val classRegex = Regex("public class") + val objectRegex = Regex("public object") + val valRegex = Regex("public val") + } } internal fun TypeSpec.Builder.addDeclarations(declarations: List) { diff --git a/backend/src/test/kotlin/io/kabu/backend/planner/AnalyzerAdHocTest.kt b/backend/src/test/kotlin/io/kabu/backend/planner/AnalyzerAdHocTest.kt index 66c83cd..0719baf 100644 --- a/backend/src/test/kotlin/io/kabu/backend/planner/AnalyzerAdHocTest.kt +++ b/backend/src/test/kotlin/io/kabu/backend/planner/AnalyzerAdHocTest.kt @@ -47,7 +47,7 @@ class AnalyzerAdHocTest : Assert() { val options = Options.DEFAULT.copy(hideInternalProperties = false, accessorObjectIsInSamePackage = true) val nodes = AnalyzerImpl(method, MethodsRegistry(), null, options).analyze() val integrated = Integrator().apply { integrate(nodes) }.integrated - val codeForPackage = Generator().getCodeForPackage(integrated, method.packageName) + val codeForPackage = Generator(testMode = true).getCodeForPackage(integrated, method.packageName) SimpleFileWriter(TEST_GENERATED_DIR).writeFile(method.packageName, filename, codeForPackage) } catch (e: PatternProcessingException) { logger.error(e) { "${e.localizedMessage}\n${e.diagnostic}" } diff --git a/backend/src/test/kotlin/io/kabu/backend/plannerx/GenerationTest.kt b/backend/src/test/kotlin/io/kabu/backend/plannerx/GenerationTest.kt index 9ed1df5..42f14fa 100644 --- a/backend/src/test/kotlin/io/kabu/backend/plannerx/GenerationTest.kt +++ b/backend/src/test/kotlin/io/kabu/backend/plannerx/GenerationTest.kt @@ -9,7 +9,7 @@ import org.junit.Test class GenerationTest : XTest() { - private val generator = Generator() + private val generator = Generator(testMode = true) @Test fun test() { diff --git a/backend/src/test/kotlin/io/kabu/backend/r2c/Utils.kt b/backend/src/test/kotlin/io/kabu/backend/r2c/Utils.kt index 532d15e..7b81482 100644 --- a/backend/src/test/kotlin/io/kabu/backend/r2c/Utils.kt +++ b/backend/src/test/kotlin/io/kabu/backend/r2c/Utils.kt @@ -50,7 +50,7 @@ fun completionOutputOf(raw: String, sample: String): String { getDiagramOfNodes(nodes) val integrator = Integrator() integrator.integrate(nodes, removeIrrelevant = false) - val scriptGenerated = Generator().getCodeForPackage(integrator.integrated, method.packageName) + val scriptGenerated = Generator(testMode = true).getCodeForPackage(integrator.integrated, method.packageName) // --- val scriptString = scriptGenerated + diff --git a/dependencies.gradle b/dependencies.gradle index 3da2b84..bca4117 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -23,7 +23,7 @@ ext.deps = [ ], "ksp" : "com.google.devtools.ksp:symbol-processing-api:$kspVersion", "antlrRuntime": "org.antlr:antlr4-runtime:4.11.1", // https://mvnrepository.com/artifact/org.antlr/antlr4-runtime - "kotlinPoet" : "com.squareup:kotlinpoet:1.6.0", + "kotlinPoet" : "com.squareup:kotlinpoet:1.14.2", "jackson" : "com.fasterxml.jackson.module:jackson-module-kotlin:2.11.0", "textTree" : "org.barfuin.texttree:text-tree:2.1.2", ] From 197fb83e276adc74e56d95b9d8b1c38fda98cbc9 Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Sun, 16 Jul 2023 23:47:51 +0600 Subject: [PATCH 13/43] dependencies: added kotlinpoet-ksp:1.14.2 --- backend/build.gradle | 3 ++- dependencies.gradle | 10 +++++++--- frontend/ksp/processor/build.gradle | 3 ++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/backend/build.gradle b/backend/build.gradle index 3dad3b5..836e5c8 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -19,7 +19,8 @@ dependencies { implementation deps.kotlin.stdlib implementation deps.kotlin.reflect implementation deps.antlrRuntime - implementation deps.kotlinPoet + implementation deps.kotlinPoet.kotlinPoet + implementation deps.kotlinPoet.kotlinPoetKsp implementation deps.logging.simple api deps.logging.api implementation deps.jackson diff --git a/dependencies.gradle b/dependencies.gradle index bca4117..008e4c1 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -1,4 +1,5 @@ def kctVersion = "1.5.0" +def kotlinPoetVersion = "1.14.2" ext.deps = [ "kotlin" : [ @@ -18,12 +19,15 @@ ext.deps = [ "kctKsp": "com.github.tschuchortdev:kotlin-compile-testing-ksp:$kctVersion", ], "logging" : [ - "simple" : "org.slf4j:slf4j-simple:1.7.9", - "api": "io.github.microutils:kotlin-logging:1.7.6", + "simple": "org.slf4j:slf4j-simple:1.7.9", + "api" : "io.github.microutils:kotlin-logging:1.7.6", + ], + "kotlinPoet" : [ + "kotlinPoet" : "com.squareup:kotlinpoet:$kotlinPoetVersion", + "kotlinPoetKsp": "com.squareup:kotlinpoet-ksp:$kotlinPoetVersion", ], "ksp" : "com.google.devtools.ksp:symbol-processing-api:$kspVersion", "antlrRuntime": "org.antlr:antlr4-runtime:4.11.1", // https://mvnrepository.com/artifact/org.antlr/antlr4-runtime - "kotlinPoet" : "com.squareup:kotlinpoet:1.14.2", "jackson" : "com.fasterxml.jackson.module:jackson-module-kotlin:2.11.0", "textTree" : "org.barfuin.texttree:text-tree:2.1.2", ] diff --git a/frontend/ksp/processor/build.gradle b/frontend/ksp/processor/build.gradle index 2b6d50d..94d0e0b 100644 --- a/frontend/ksp/processor/build.gradle +++ b/frontend/ksp/processor/build.gradle @@ -19,7 +19,8 @@ dependencies { implementation deps.kotlin.stdlib implementation deps.ksp - implementation deps.kotlinPoet + implementation deps.kotlinPoet.kotlinPoet + implementation deps.kotlinPoet.kotlinPoetKsp testImplementation deps.kct.kct testImplementation deps.kct.kctKsp From 6c9f8bc6302321069d580bca440621e09dcf917c Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Mon, 17 Jul 2023 01:21:49 +0600 Subject: [PATCH 14/43] migration to KotlinPoet's toTypeName --- .../frontend/ksp/processor/util/TypeUtils.kt | 64 ++++++------------- .../builder/ContextCreatorFunctionBuilder.kt | 6 +- .../builder/LocalPatternFunctionBuilder.kt | 6 +- 3 files changed, 29 insertions(+), 47 deletions(-) diff --git a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/TypeUtils.kt b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/TypeUtils.kt index f1ea8e1..4e4ae45 100644 --- a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/TypeUtils.kt +++ b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/TypeUtils.kt @@ -9,12 +9,8 @@ import com.google.devtools.ksp.symbol.KSTypeReference import com.google.devtools.ksp.symbol.KSValueParameter import com.google.devtools.ksp.symbol.Modifier import com.google.devtools.ksp.symbol.Variance -import com.squareup.kotlinpoet.ClassName -import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.LambdaTypeName -import com.squareup.kotlinpoet.ParameterSpec -import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy -import com.squareup.kotlinpoet.TypeName +import com.squareup.kotlinpoet.ksp.toTypeName +import com.squareup.kotlinpoet.ksp.toTypeParameterResolver import io.kabu.backend.diagnostic.Origin import io.kabu.backend.exception.PatternProcessingException import io.kabu.backend.inout.input.method.Method @@ -24,6 +20,9 @@ import io.kabu.frontend.ksp.diagnostic.builder.parameterProcessingError internal fun KSFunctionDeclaration.toMethod(): Method { + val typeParameterResolver = typeParameters.toTypeParameterResolver() + val methodOrigin = originOf(this) + val methodName = simpleName.asString() fun createParameter( name: String, @@ -31,16 +30,16 @@ internal fun KSFunctionDeclaration.toMethod(): Method { origin: Origin, methodName: String, ) = try { - Parameter(name, typeReference.toTypeName(), origin) + typeReference.validate() + Parameter(name, typeReference.toTypeName(typeParameterResolver), origin) } catch (e: PatternProcessingException) { parameterProcessingError(name, methodName, e, origin) } - val methodOrigin = originOf(this) - val methodName = simpleName.asString() val receiver = extensionReceiver ?.let { createParameter(RECEIVER_PARAMETER_NAME, it, originOf(it, parent = methodOrigin), methodName) } - val returnType = returnType?.toTypeName()!! + val returnType = returnType?.toTypeName(typeParameterResolver)!! + .also { returnType?.validate() } val parameters = parameters.map { parameter -> validateValueParameter(parameter) val parameterOrigin = originOf(parameter, parent = methodOrigin) @@ -59,51 +58,30 @@ internal fun KSFunctionDeclaration.toMethod(): Method { ) } -internal fun KSTypeReference.toTypeName(): TypeName { +internal fun KSTypeReference.validate() { val type = resolve() validateType(type) - + (element as? KSCallableReference)?.let { callableReference -> validateCallableReference(callableReference) - val typeName = LambdaTypeName.get( - receiver = callableReference.receiverType?.toTypeName(), - parameters = callableReference.functionParameters.map { - validateValueParameter(it) - - val modifiers = mutableListOf().apply { - if (it.isVararg) add(KModifier.VARARG) - } - - ParameterSpec(name = it.name?.asString() ?: "", type = it.type.toTypeName(), modifiers) - }, - returnType = callableReference.returnType.toTypeName() - ) - - return if (type.isMarkedNullable) { - typeName.copy(nullable = true) - } else typeName + callableReference.receiverType?.validate() + callableReference.functionParameters.forEach { + validateValueParameter(it) + it.type.validate() + } + callableReference.returnType.validate() } // assuming interface or class below - return type.toTypeName() + type.validate() } -internal fun KSType.toTypeName(): TypeName { +internal fun KSType.validate() { validateType(this) - - val className = ClassName(declaration.packageName.asString(), declaration.simpleName.asString()) - val typeName = if (arguments.isEmpty()) className else { - className.parameterizedBy( - arguments.map { typeArgument -> - validateTypeArgument(typeArgument) - typeArgument.type!!.toTypeName() - } - ) + arguments.forEach { typeArgument -> + validateTypeArgument(typeArgument) } - return if (isMarkedNullable) { - typeName.copy(nullable = true) - } else typeName } internal fun validateTypeArgument(typeArgument: KSTypeArgument) { diff --git a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/builder/ContextCreatorFunctionBuilder.kt b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/builder/ContextCreatorFunctionBuilder.kt index 2467ebd..7640b51 100644 --- a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/builder/ContextCreatorFunctionBuilder.kt +++ b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/builder/ContextCreatorFunctionBuilder.kt @@ -4,6 +4,7 @@ import com.google.devtools.ksp.isConstructor import com.google.devtools.ksp.symbol.FunctionKind import com.google.devtools.ksp.symbol.KSClassDeclaration import com.google.devtools.ksp.symbol.KSFunctionDeclaration +import com.squareup.kotlinpoet.ksp.toTypeName import io.kabu.annotation.Context import io.kabu.annotation.ContextCreator import io.kabu.backend.diagnostic.diagnosticError @@ -16,7 +17,7 @@ import io.kabu.frontend.ksp.processor.util.getAnnotation import io.kabu.frontend.ksp.processor.util.getAnnotationOrNull import io.kabu.frontend.ksp.processor.util.originOf import io.kabu.frontend.ksp.processor.util.toMethod -import io.kabu.frontend.ksp.processor.util.toTypeName +import io.kabu.frontend.ksp.processor.util.validate class ContextCreatorFunctionBuilder : AbstractFunctionBuilder() { @@ -64,7 +65,8 @@ class ContextCreatorFunctionBuilder : AbstractFunctionBuilder() { @@ -34,7 +35,8 @@ class LocalPatternFunctionBuilder : AbstractFunctionBuilder( val declaringType = classDeclaration .asStarProjectedType() //todo highlight generic nuances intentionally - .toTypeName() + .also { it.validate() } + .toTypeName() //todo val typeParameterResolver = typeParameters.toTypeParameterResolver() return function.toMethod().toLocalPatternMethod(declaringType, pattern) } From aff92a893debf828786efd9ff583891442ae579b Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Wed, 19 Jul 2023 00:34:18 +0600 Subject: [PATCH 15/43] support for parameterized functions --- .../classes/HolderClassDeclaration.kt | 9 +++++-- .../functions/AbstractFunctionDeclaration.kt | 6 +++++ .../node/factory/node/HolderTypeNodeImpl.kt | 2 +- .../main/kotlin/io/kabu/backend/node/node.kt | 19 +++++++++++++- .../kabu/backend/util/poet/TypeNameUtils.kt | 25 +++++++++++++++++++ .../frontend/ksp/processor/util/TypeUtils.kt | 8 +++--- .../util/builder/AbstractFunctionBuilder.kt | 3 --- 7 files changed, 61 insertions(+), 11 deletions(-) diff --git a/backend/src/main/kotlin/io/kabu/backend/declaration/classes/HolderClassDeclaration.kt b/backend/src/main/kotlin/io/kabu/backend/declaration/classes/HolderClassDeclaration.kt index 682f723..093ab2b 100644 --- a/backend/src/main/kotlin/io/kabu/backend/declaration/classes/HolderClassDeclaration.kt +++ b/backend/src/main/kotlin/io/kabu/backend/declaration/classes/HolderClassDeclaration.kt @@ -11,17 +11,21 @@ import io.kabu.backend.declaration.AbstractTypeDeclaration import io.kabu.backend.integration.NameAndType import io.kabu.backend.integration.NamedTypeNode import io.kabu.backend.legacy.planner.HolderFieldsNamesGenerator.rename +import io.kabu.backend.node.HolderTypeNode import io.kabu.backend.node.ObjectTypeNode import io.kabu.backend.node.TypeNode import io.kabu.backend.node.namespace.NamespaceNode class HolderClassDeclaration( - override val className: ClassName, + val typeNode: HolderTypeNode, fieldTypes: List, val parentTypeName: TypeName? = null, private val namespaceNode: NamespaceNode ) : AbstractTypeDeclaration() { + override val className: ClassName + get() = typeNode.className + private val fields: List = run { val nameAndTypes: List = fieldTypes.map { NamedTypeNode("", it) } @@ -45,7 +49,8 @@ class HolderClassDeclaration( } }.build() - return TypeSpec.classBuilder(className).apply { + return TypeSpec.classBuilder(typeNode.className).apply { + addTypeVariables(typeNode.gatherTypeVariableNames()) parentTypeName?.let { superclass(it) } addModifiers(KModifier.PUBLIC) primaryConstructor(constructor).apply { diff --git a/backend/src/main/kotlin/io/kabu/backend/declaration/functions/AbstractFunctionDeclaration.kt b/backend/src/main/kotlin/io/kabu/backend/declaration/functions/AbstractFunctionDeclaration.kt index f4d886c..fd83a23 100644 --- a/backend/src/main/kotlin/io/kabu/backend/declaration/functions/AbstractFunctionDeclaration.kt +++ b/backend/src/main/kotlin/io/kabu/backend/declaration/functions/AbstractFunctionDeclaration.kt @@ -6,6 +6,7 @@ import com.squareup.kotlinpoet.KModifier import com.squareup.kotlinpoet.TypeName import io.kabu.backend.declaration.AbstractCallableDeclaration import io.kabu.backend.provider.group.OrderedNamedProviders +import io.kabu.backend.util.poet.gatherTypeVariableNames abstract class AbstractFunctionDeclaration : AbstractCallableDeclaration() { @@ -23,6 +24,11 @@ abstract class AbstractFunctionDeclaration : AbstractCallableDeclaration() { isHelper: Boolean = false, //todo up ): FunSpec { return FunSpec.builder(name).apply { + val typeVariableNames = returnType.gatherTypeVariableNames() + + receiverType?.gatherTypeVariableNames().orEmpty() + + providers.providers.flatMap { it.type.gatherTypeVariableNames() } + addTypeVariables(typeVariableNames.toSet()) + if (isHelper) addModifiers(KModifier.PRIVATE) when { isInfix -> addModifiers(KModifier.INFIX) diff --git a/backend/src/main/kotlin/io/kabu/backend/node/factory/node/HolderTypeNodeImpl.kt b/backend/src/main/kotlin/io/kabu/backend/node/factory/node/HolderTypeNodeImpl.kt index fc7f7c3..2a964c2 100644 --- a/backend/src/main/kotlin/io/kabu/backend/node/factory/node/HolderTypeNodeImpl.kt +++ b/backend/src/main/kotlin/io/kabu/backend/node/factory/node/HolderTypeNodeImpl.kt @@ -18,7 +18,7 @@ class HolderTypeNodeImpl( @Suppress("UNCHECKED_CAST") private fun getHolderClassDeclaration() = HolderClassDeclaration( - className = className, + typeNode = this, fieldTypes = fieldTypes, parentTypeName = null, namespaceNode = namespaceNode!!, diff --git a/backend/src/main/kotlin/io/kabu/backend/node/node.kt b/backend/src/main/kotlin/io/kabu/backend/node/node.kt index 8d7d65d..d85d441 100644 --- a/backend/src/main/kotlin/io/kabu/backend/node/node.kt +++ b/backend/src/main/kotlin/io/kabu/backend/node/node.kt @@ -2,7 +2,9 @@ package io.kabu.backend.node import com.squareup.kotlinpoet.ClassName +import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy import com.squareup.kotlinpoet.TypeName +import com.squareup.kotlinpoet.TypeVariableName import io.kabu.backend.declaration.Declaration import io.kabu.backend.integration.NameAndType import io.kabu.backend.legacy.TypeNameGeneratorFactory @@ -10,6 +12,7 @@ import io.kabu.backend.node.namespace.ClassNamespaceNode import io.kabu.backend.node.namespace.NamespaceNode import io.kabu.backend.node.namespace.PackageNamespaceNode import io.kabu.backend.provider.group.FunDeclarationProviders +import io.kabu.backend.util.poet.gatherTypeVariableNames interface Node { @@ -179,12 +182,26 @@ open class HolderTypeNode( .mapTo(mutableListOf()) { it } .apply { namespaceNode?.let { add(it) } } + //todo rn rawClassName val className: ClassName get() = namespaceNode!!.composeClassName(name) //todo className vs typeName override val typeName: TypeName - get() = className + get() = composeTypeName() + + private fun composeTypeName(): TypeName { + val typeVariableNames = gatherTypeVariableNames() + return if (typeVariableNames.isEmpty()) className else { + className.parameterizedBy(typeVariableNames) + } + } + + fun gatherTypeVariableNames(): List { + return fieldTypes.flatMap { + it.typeName.gatherTypeVariableNames() + }.toSet().toList() + } init { updateLinks() diff --git a/backend/src/main/kotlin/io/kabu/backend/util/poet/TypeNameUtils.kt b/backend/src/main/kotlin/io/kabu/backend/util/poet/TypeNameUtils.kt index 6bb8639..ee9b586 100644 --- a/backend/src/main/kotlin/io/kabu/backend/util/poet/TypeNameUtils.kt +++ b/backend/src/main/kotlin/io/kabu/backend/util/poet/TypeNameUtils.kt @@ -1,9 +1,12 @@ package io.kabu.backend.util.poet import com.squareup.kotlinpoet.ClassName +import com.squareup.kotlinpoet.Dynamic import com.squareup.kotlinpoet.LambdaTypeName import com.squareup.kotlinpoet.ParameterizedTypeName import com.squareup.kotlinpoet.TypeName +import com.squareup.kotlinpoet.TypeVariableName +import com.squareup.kotlinpoet.WildcardTypeName import io.kabu.backend.node.FixedTypeNode @@ -27,3 +30,25 @@ object TypeNameUtils { private val packageNamesRegex = Regex("\\w+\\.") } + +fun TypeName.gatherTypeVariableNames(): Collection { + + fun Iterable.gatherTypeVariableNames(): Collection { + return flatMap { it.gatherTypeVariableNames() } + } + + //todo RECURSIVE BOUNDS NOT HANDLED!!! + return when (this) { + is TypeVariableName -> bounds.gatherTypeVariableNames() + this + is ParameterizedTypeName -> typeArguments.gatherTypeVariableNames() + is WildcardTypeName -> inTypes.gatherTypeVariableNames() + outTypes.gatherTypeVariableNames() + is LambdaTypeName -> { + parameters.map { it.type }.gatherTypeVariableNames() + + returnType.gatherTypeVariableNames() + + receiver?.gatherTypeVariableNames().orEmpty() + } + + is ClassName -> emptyList() + Dynamic -> emptyList() + } +} diff --git a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/TypeUtils.kt b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/TypeUtils.kt index 4e4ae45..eb2ca8b 100644 --- a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/TypeUtils.kt +++ b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/TypeUtils.kt @@ -85,10 +85,10 @@ internal fun KSType.validate() { } internal fun validateTypeArgument(typeArgument: KSTypeArgument) { - areNotSupported(typeArgument.variance == Variance.CONTRAVARIANT, typeArgument) { - "Contravariant type arguments" - } // tested - areNotSupported(typeArgument.variance == Variance.COVARIANT, typeArgument) { "Covariant type arguments" } // tested +// areNotSupported(typeArgument.variance == Variance.CONTRAVARIANT, typeArgument) { // supported +// "Contravariant type arguments" +// } // tested +// areNotSupported(typeArgument.variance == Variance.COVARIANT, typeArgument) { "Covariant type arguments" } // supported areNotSupported(typeArgument.variance == Variance.STAR, typeArgument) { "Star projections" } // tested } diff --git a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/builder/AbstractFunctionBuilder.kt b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/builder/AbstractFunctionBuilder.kt index 7b5c07e..22cb6be 100644 --- a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/builder/AbstractFunctionBuilder.kt +++ b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/builder/AbstractFunctionBuilder.kt @@ -43,9 +43,6 @@ abstract class AbstractFunctionBuilder { areNotSupported(function.isPrivate(), function) { "Private functions as $role" } // tested areNotSupported(function.isProtected(), function) { "Protected functions as $role" } // tested areNotSupported(function.isAbstract, function) { "Abstract functions as $role" } // tested - areNotSupported(function.typeParameters.isNotEmpty(), function) { - "Functions with type parameters as $role" - } // tested areNotSupported(function.isActual, function) { "Functions with 'actual' keyword as $role" } areNotSupported(function.isExpect, function) { "Functions with 'expect' keyword as $role" } notSupportedFunctionModifiers( From d43373cca7db993516d00aedf3e6b64562ebb6ba Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Fri, 21 Jul 2023 01:05:52 +0600 Subject: [PATCH 16/43] tests --- .../supported/GlobalPatternFunctionsSupportedTest.kt | 11 +++++++++++ .../GlobalPatternFunctionsNotSupportedTest.kt | 11 ----------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/supported/GlobalPatternFunctionsSupportedTest.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/supported/GlobalPatternFunctionsSupportedTest.kt index 700efa7..923b74d 100644 --- a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/supported/GlobalPatternFunctionsSupportedTest.kt +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/supported/GlobalPatternFunctionsSupportedTest.kt @@ -17,4 +17,15 @@ class GlobalPatternFunctionsSupportedTest : BaseKspFrontendProcessorTest() { ) { assertOk() } + + @Test + fun `parameterized function`() = compileAndCheck( + """ + @Pattern("!bar") + fun func(bar: T) { + } + """ + ) { + assertOk() + } } diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/unsupported/GlobalPatternFunctionsNotSupportedTest.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/unsupported/GlobalPatternFunctionsNotSupportedTest.kt index 15d50ae..d4db365 100644 --- a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/unsupported/GlobalPatternFunctionsNotSupportedTest.kt +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/unsupported/GlobalPatternFunctionsNotSupportedTest.kt @@ -190,15 +190,4 @@ class GlobalPatternFunctionsNotSupportedTest : BaseKspFrontendProcessorTest() { ) { assertCompilationError(17, "Tailrec functions as $role aren't supported yet", "\"findFixPoint\"") } - - @Test - fun `parameterized function not supported`() = compileAndCheck( - """ - @Pattern("!bar") - fun func(bar: T) { - } - """ - ) { - assertCompilationError(15, "Functions with type parameters as $role aren't supported yet", "\"func\"") - } } From 9cfc50190ec744058e2445bfad7a6a7f95750583 Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Fri, 21 Jul 2023 01:09:58 +0600 Subject: [PATCH 17/43] refactoring --- .../backend/declaration/classes/HolderClassDeclaration.kt | 4 ++-- backend/src/main/kotlin/io/kabu/backend/node/node.kt | 8 +++----- .../io/kabu/backend/provider/provider/AssignProvider.kt | 2 +- .../kabu/backend/provider/provider/ComparisonProvider.kt | 2 +- .../kabu/backend/provider/provider/InclusionProvider.kt | 2 +- 5 files changed, 8 insertions(+), 10 deletions(-) diff --git a/backend/src/main/kotlin/io/kabu/backend/declaration/classes/HolderClassDeclaration.kt b/backend/src/main/kotlin/io/kabu/backend/declaration/classes/HolderClassDeclaration.kt index 093ab2b..461cec9 100644 --- a/backend/src/main/kotlin/io/kabu/backend/declaration/classes/HolderClassDeclaration.kt +++ b/backend/src/main/kotlin/io/kabu/backend/declaration/classes/HolderClassDeclaration.kt @@ -24,7 +24,7 @@ class HolderClassDeclaration( ) : AbstractTypeDeclaration() { override val className: ClassName - get() = typeNode.className + get() = typeNode.rawClassName private val fields: List = run { val nameAndTypes: List = fieldTypes.map { NamedTypeNode("", it) } @@ -49,7 +49,7 @@ class HolderClassDeclaration( } }.build() - return TypeSpec.classBuilder(typeNode.className).apply { + return TypeSpec.classBuilder(typeNode.rawClassName).apply { addTypeVariables(typeNode.gatherTypeVariableNames()) parentTypeName?.let { superclass(it) } addModifiers(KModifier.PUBLIC) diff --git a/backend/src/main/kotlin/io/kabu/backend/node/node.kt b/backend/src/main/kotlin/io/kabu/backend/node/node.kt index d85d441..07ba9ce 100644 --- a/backend/src/main/kotlin/io/kabu/backend/node/node.kt +++ b/backend/src/main/kotlin/io/kabu/backend/node/node.kt @@ -182,18 +182,16 @@ open class HolderTypeNode( .mapTo(mutableListOf()) { it } .apply { namespaceNode?.let { add(it) } } - //todo rn rawClassName - val className: ClassName + val rawClassName: ClassName get() = namespaceNode!!.composeClassName(name) - //todo className vs typeName override val typeName: TypeName get() = composeTypeName() private fun composeTypeName(): TypeName { val typeVariableNames = gatherTypeVariableNames() - return if (typeVariableNames.isEmpty()) className else { - className.parameterizedBy(typeVariableNames) + return if (typeVariableNames.isEmpty()) rawClassName else { + rawClassName.parameterizedBy(typeVariableNames) } } diff --git a/backend/src/main/kotlin/io/kabu/backend/provider/provider/AssignProvider.kt b/backend/src/main/kotlin/io/kabu/backend/provider/provider/AssignProvider.kt index 1ce4ca6..a2a9521 100644 --- a/backend/src/main/kotlin/io/kabu/backend/provider/provider/AssignProvider.kt +++ b/backend/src/main/kotlin/io/kabu/backend/provider/provider/AssignProvider.kt @@ -11,7 +11,7 @@ class AssignProvider( ) : AbstractWatchedProvider(typeNode, providers) { override fun provideCodeForConstructionFromAux(auxName: String): String { - val holderClassCanonicalName = (typeNode as HolderTypeNode).className.canonicalName + val holderClassCanonicalName = (typeNode as HolderTypeNode).rawClassName.canonicalName //todo use FieldAccessCodeGenerator(analyzer).generateFieldAccessorCode(selfName!!, privateFieldName) diff --git a/backend/src/main/kotlin/io/kabu/backend/provider/provider/ComparisonProvider.kt b/backend/src/main/kotlin/io/kabu/backend/provider/provider/ComparisonProvider.kt index 634f14c..ea2215f 100644 --- a/backend/src/main/kotlin/io/kabu/backend/provider/provider/ComparisonProvider.kt +++ b/backend/src/main/kotlin/io/kabu/backend/provider/provider/ComparisonProvider.kt @@ -13,7 +13,7 @@ class ComparisonProvider( ) : AbstractWatchedProvider(typeNode, providers) { override fun provideCodeForConstructionFromAux(auxName: String): String { - val holderClassCanonicalName = (typeNode as HolderTypeNode).className.canonicalName + val holderClassCanonicalName = (typeNode as HolderTypeNode).rawClassName.canonicalName //todo do safeCast method to bring right exceptions to the user //todo make holder creation through CodeBlock(%T, className) diff --git a/backend/src/main/kotlin/io/kabu/backend/provider/provider/InclusionProvider.kt b/backend/src/main/kotlin/io/kabu/backend/provider/provider/InclusionProvider.kt index 2471df4..05a72f1 100644 --- a/backend/src/main/kotlin/io/kabu/backend/provider/provider/InclusionProvider.kt +++ b/backend/src/main/kotlin/io/kabu/backend/provider/provider/InclusionProvider.kt @@ -11,7 +11,7 @@ class InclusionProvider( ) : AbstractWatchedProvider(typeNode, providers) { override fun provideCodeForConstructionFromAux(auxName: String): String { - val holderClassCanonicalName = (typeNode as HolderTypeNode).className.canonicalName + val holderClassCanonicalName = (typeNode as HolderTypeNode).rawClassName.canonicalName //todo use FieldAccessCodeGenerator(analyzer).generateFieldAccessorCode(selfName!!, privateFieldName) From 632601c7b380b854b634963dc4d96f204f7a8f08 Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Fri, 21 Jul 2023 02:20:21 +0600 Subject: [PATCH 18/43] improved logging --- .../declaration/util/TerminalCallableBuilder.kt | 7 ++++++- .../kotlin/io/kabu/backend/generator/Generator.kt | 2 +- .../io/kabu/backend/integration/Integrator.kt | 14 ++++++++------ .../backend/integration/render/GraphVisualizer.kt | 6 ++++-- ...FunctionAndFunctionUniversalConflictResolver.kt | 9 ++++----- .../GeneratedClassTypeNodeConflictResolver.kt | 6 ++++++ ...PropertyAndPropertyUniversalConflictResolver.kt | 7 +++---- .../TypeAndPropertyUniversalConflictResolver.kt | 5 +++++ .../src/main/kotlin/io/kabu/backend/node/node.kt | 7 ++++++- .../io/kabu/backend/processor/MethodsRegistry.kt | 2 +- .../backend/integration/test/IntegratorTest.kt | 13 +++++++++---- .../io/kabu/backend/plannerx/GenerationTest.kt | 1 - .../test/kotlin/io/kabu/backend/plannerx/XTest.kt | 4 ++-- .../src/test/kotlin/io/kabu/backend/r2c/Utils.kt | 7 ++----- 14 files changed, 57 insertions(+), 33 deletions(-) diff --git a/backend/src/main/kotlin/io/kabu/backend/declaration/util/TerminalCallableBuilder.kt b/backend/src/main/kotlin/io/kabu/backend/declaration/util/TerminalCallableBuilder.kt index 1d242c2..c3d8c37 100644 --- a/backend/src/main/kotlin/io/kabu/backend/declaration/util/TerminalCallableBuilder.kt +++ b/backend/src/main/kotlin/io/kabu/backend/declaration/util/TerminalCallableBuilder.kt @@ -5,6 +5,7 @@ import com.squareup.kotlinpoet.UNIT import io.kabu.backend.analyzer.Analyzer import io.kabu.backend.analyzer.AnalyzerImpl import io.kabu.backend.analyzer.handler.lambda.watcher.OperatorInfoTypes.isOperatorInfoType +import io.kabu.backend.common.log.InterceptingLogging import io.kabu.backend.diagnostic.builder.couldNotRetrieveReceiverValueError import io.kabu.backend.diagnostic.builder.signatureParameterMissingError import io.kabu.backend.diagnostic.builder.signatureParameterMissingInPatternError @@ -24,7 +25,7 @@ class TerminalCallableBuilder { functionBlockContext: FunctionBlockContext, requiredReturnStatement: String?, ): CodeBlock { - println(renderProviderTree(functionBlockContext.actualProvidersProvider)) + logger.debug { renderProviderTree(functionBlockContext.actualProvidersProvider) } val providers: List = gatherRequiredProviders(analyzer, functionBlockContext.actualProvidersProvider) @@ -114,4 +115,8 @@ class TerminalCallableBuilder { .joinToString(separator = "\n") .asCodeBlock() } + + private companion object { + val logger = InterceptingLogging.logger {} + } } diff --git a/backend/src/main/kotlin/io/kabu/backend/generator/Generator.kt b/backend/src/main/kotlin/io/kabu/backend/generator/Generator.kt index 6d3492d..843249d 100644 --- a/backend/src/main/kotlin/io/kabu/backend/generator/Generator.kt +++ b/backend/src/main/kotlin/io/kabu/backend/generator/Generator.kt @@ -97,7 +97,7 @@ class Generator(private val testMode: Boolean = false) { val unwrittenIterator = unwrittenNodes.iterator() while (unwrittenIterator.hasNext()) { val node = unwrittenIterator.next() - logger.debug { "Checking node: $node" } + logger.trace { "Checking node: $node" } val hasNoUnwrittenDependencies = node.dependencies.none { it in unwrittenNodes } if (hasNoUnwrittenDependencies) { val gatheredDeclarations = getDeclarationsForNode(node) diff --git a/backend/src/main/kotlin/io/kabu/backend/integration/Integrator.kt b/backend/src/main/kotlin/io/kabu/backend/integration/Integrator.kt index 72985eb..c9b0cd8 100644 --- a/backend/src/main/kotlin/io/kabu/backend/integration/Integrator.kt +++ b/backend/src/main/kotlin/io/kabu/backend/integration/Integrator.kt @@ -1,12 +1,12 @@ package io.kabu.backend.integration +import io.kabu.backend.common.log.InterceptingLogging import io.kabu.backend.exception.UnresolvedConflictException import io.kabu.backend.integration.detector.FunctionConflictDetector import io.kabu.backend.integration.detector.PackageConflictDetector import io.kabu.backend.integration.detector.PropertyConflictDetector import io.kabu.backend.integration.detector.TypeConflictDetector import io.kabu.backend.integration.detector.UserCodeConflictDetector -import io.kabu.backend.integration.render.GraphVisualizer.Companion.visualize import io.kabu.backend.integration.resolver.UniversalConflictResolver import io.kabu.backend.node.FunctionNode import io.kabu.backend.node.HolderTypeNode @@ -33,19 +33,17 @@ class Integrator { sortedNodes.forEach { node -> if (node in integrated) return@forEach // skipping already integrated nodes - println("Integrating: '$node'") + logger.debug { "Integrating: '$node'" } val conflictingNode = findConflictingNode(node) if (conflictingNode != null) { - println("Resolving conflict with '$conflictingNode'") + logger.debug { "Resolving conflict with '$conflictingNode'" } resolveConflict(node, conflictingNode) } else { - println("No conflicts with generated code") resolvePossibleConflictWithUserCode(node) integrateNode(node) } - visualize(integrated) validateLinks() } @@ -137,7 +135,7 @@ class Integrator { private fun removeIrrelevantNodes() { val irrelevantNodes = integrated.filter { isIrrelevantNode(it) }.toSet() - println("Irrelevant nodes: $irrelevantNodes") + logger.debug { "Irrelevant nodes: $irrelevantNodes" } integrated.removeAll(irrelevantNodes) } @@ -204,4 +202,8 @@ class Integrator { CLASS_INTERFACE_OBJECT_PROPERTY, FUNCTION, } + + private companion object { + val logger = InterceptingLogging.logger {} + } } diff --git a/backend/src/main/kotlin/io/kabu/backend/integration/render/GraphVisualizer.kt b/backend/src/main/kotlin/io/kabu/backend/integration/render/GraphVisualizer.kt index 5027dca..c4d1fd2 100644 --- a/backend/src/main/kotlin/io/kabu/backend/integration/render/GraphVisualizer.kt +++ b/backend/src/main/kotlin/io/kabu/backend/integration/render/GraphVisualizer.kt @@ -1,5 +1,6 @@ package io.kabu.backend.integration.render +import io.kabu.backend.common.log.InterceptingLogging import io.kabu.backend.node.FunctionNode import io.kabu.backend.node.HolderTypeNode import io.kabu.backend.node.Node @@ -221,14 +222,15 @@ class GraphVisualizer { ) companion object { + private val logger = InterceptingLogging.logger {} private const val ONLINE_MERMAID_RENDERER_BASE_URL = "http://localhost" fun visualize(nodes: Set, title: String? = null) { val titleText = title?.let { "$title :" }.orEmpty() GraphVisualizer().run { val mermaidDiagram = generateMermaidDiagramAsFlowchart(nodes, title = title) - println(titleText + getMermaidRenderLink(mermaidDiagram)) - println(mermaidDiagram) + logger.debug { titleText + getMermaidRenderLink(mermaidDiagram) } + logger.debug(mermaidDiagram) } } } diff --git a/backend/src/main/kotlin/io/kabu/backend/integration/resolver/FunctionAndFunctionUniversalConflictResolver.kt b/backend/src/main/kotlin/io/kabu/backend/integration/resolver/FunctionAndFunctionUniversalConflictResolver.kt index 901894b..fda9ead 100644 --- a/backend/src/main/kotlin/io/kabu/backend/integration/resolver/FunctionAndFunctionUniversalConflictResolver.kt +++ b/backend/src/main/kotlin/io/kabu/backend/integration/resolver/FunctionAndFunctionUniversalConflictResolver.kt @@ -29,6 +29,8 @@ class FunctionAndFunctionUniversalConflictResolver(private val integrator: Integ val current = integrator.notIntegratedOf(node1, node2) if (!isResolvable(current, conflicting)) integrator.unresolvedConflictError(current, conflicting) + visualize(integrator.integrated, "Before conflict resolving") + conflicting.parameters.forEachIndexed { index, nameAndType -> val correspondingNameAndType = current.parameters[index] if (nameAndType.name != correspondingNameAndType.name) { @@ -38,16 +40,13 @@ class FunctionAndFunctionUniversalConflictResolver(private val integrator: Integ val parameterNames = renameClashingParametersNames(conflicting.parameters.map { it.name }) conflicting.parameters.forEachIndexed { index, nameAndType -> nameAndType.name = parameterNames[index] } - visualize(integrator.integrated, "Before rewire") - integrator.validateLinks() - integrator.rewireNodes(current, conflicting) - visualize(integrator.integrated, "After functions rewire") integrator.validateLinks() integrator.rewireNodes(current.returnTypeNode, conflicting.returnTypeNode) - visualize(integrator.integrated, "After return types rewire") integrator.validateLinks() + + visualize(integrator.integrated, "After conflict resolving") } private fun generalizeName(typeNode: TypeNode): String { diff --git a/backend/src/main/kotlin/io/kabu/backend/integration/resolver/GeneratedClassTypeNodeConflictResolver.kt b/backend/src/main/kotlin/io/kabu/backend/integration/resolver/GeneratedClassTypeNodeConflictResolver.kt index c545e56..5ce98d1 100644 --- a/backend/src/main/kotlin/io/kabu/backend/integration/resolver/GeneratedClassTypeNodeConflictResolver.kt +++ b/backend/src/main/kotlin/io/kabu/backend/integration/resolver/GeneratedClassTypeNodeConflictResolver.kt @@ -1,6 +1,7 @@ package io.kabu.backend.integration.resolver import io.kabu.backend.integration.Integrator +import io.kabu.backend.integration.render.GraphVisualizer.Companion.visualize import io.kabu.backend.node.GeneratedTypeNode import io.kabu.backend.node.Node @@ -21,6 +22,9 @@ open class GeneratedClassTypeNodeConflictResolver( private fun resolveConflict(node1: GeneratedTypeNode, node2: GeneratedTypeNode) { val current = integrator.notIntegratedOf(node1, node2) val conflicting = integrator.integratedOf(node1, node2) + + visualize(integrator.integrated, "Before conflict resolving") + when { current.desiredName == null -> { current.name = integrator.pickAvailableTypeName(current.namespaceNode!!, conflicting.name) @@ -34,5 +38,7 @@ open class GeneratedClassTypeNodeConflictResolver( else -> integrator.unresolvedConflictError(current, conflicting) } + + visualize(integrator.integrated, "After conflict resolving") } } diff --git a/backend/src/main/kotlin/io/kabu/backend/integration/resolver/PropertyAndPropertyUniversalConflictResolver.kt b/backend/src/main/kotlin/io/kabu/backend/integration/resolver/PropertyAndPropertyUniversalConflictResolver.kt index 1d3e0e9..2f1aa7a 100644 --- a/backend/src/main/kotlin/io/kabu/backend/integration/resolver/PropertyAndPropertyUniversalConflictResolver.kt +++ b/backend/src/main/kotlin/io/kabu/backend/integration/resolver/PropertyAndPropertyUniversalConflictResolver.kt @@ -23,16 +23,15 @@ class PropertyAndPropertyUniversalConflictResolver(private val integrator: Integ val current = integrator.notIntegratedOf(node1, node2) if (!isResolvable(current, conflicting)) integrator.unresolvedConflictError(current, conflicting) - visualize(integrator.integrated, "Before rewire") - integrator.validateLinks() + visualize(integrator.integrated, "Before conflict resolving") integrator.rewireNodes(current, conflicting) - visualize(integrator.integrated, "After functions rewire") integrator.validateLinks() integrator.rewireNodes(current.returnTypeNode, conflicting.returnTypeNode) - visualize(integrator.integrated, "After return types rewire") integrator.validateLinks() + + visualize(integrator.integrated, "After conflict resolving") } private fun isResolvable(current: PropertyNode, conflicting: PropertyNode): Boolean { diff --git a/backend/src/main/kotlin/io/kabu/backend/integration/resolver/TypeAndPropertyUniversalConflictResolver.kt b/backend/src/main/kotlin/io/kabu/backend/integration/resolver/TypeAndPropertyUniversalConflictResolver.kt index f2fb16f..c434990 100644 --- a/backend/src/main/kotlin/io/kabu/backend/integration/resolver/TypeAndPropertyUniversalConflictResolver.kt +++ b/backend/src/main/kotlin/io/kabu/backend/integration/resolver/TypeAndPropertyUniversalConflictResolver.kt @@ -1,6 +1,7 @@ package io.kabu.backend.integration.resolver import io.kabu.backend.integration.Integrator +import io.kabu.backend.integration.render.GraphVisualizer.Companion.visualize import io.kabu.backend.node.FixedTypeNode import io.kabu.backend.node.GeneratedTypeNode import io.kabu.backend.node.Node @@ -30,7 +31,11 @@ class TypeAndPropertyUniversalConflictResolver(private val integrator: Integrato integrator.unresolvedConflictError(generatedTypeNode, propertyNode) } + visualize(integrator.integrated, "Before conflict resolving") + generatedTypeNode.name = integrator.pickAvailableTypeName(generatedTypeNode.namespaceNode!!, propertyNode.name) integrator.integrated.add(integrator.notIntegratedOf(generatedTypeNode, propertyNode)) + + visualize(integrator.integrated, "After conflict resolving") } } diff --git a/backend/src/main/kotlin/io/kabu/backend/node/node.kt b/backend/src/main/kotlin/io/kabu/backend/node/node.kt index 07ba9ce..04dca0b 100644 --- a/backend/src/main/kotlin/io/kabu/backend/node/node.kt +++ b/backend/src/main/kotlin/io/kabu/backend/node/node.kt @@ -5,6 +5,7 @@ import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy import com.squareup.kotlinpoet.TypeName import com.squareup.kotlinpoet.TypeVariableName +import io.kabu.backend.common.log.InterceptingLogging import io.kabu.backend.declaration.Declaration import io.kabu.backend.integration.NameAndType import io.kabu.backend.legacy.TypeNameGeneratorFactory @@ -32,9 +33,13 @@ interface AbstractNode : Node { it.derivativeNodes.add(this) } } catch (e: Exception) { - println(e) + logger.error("Links inconsistency in node '$this'", e) } } + + private companion object { + val logger = InterceptingLogging.logger {} + } } //========== diff --git a/backend/src/main/kotlin/io/kabu/backend/processor/MethodsRegistry.kt b/backend/src/main/kotlin/io/kabu/backend/processor/MethodsRegistry.kt index 7bdacef..f833753 100644 --- a/backend/src/main/kotlin/io/kabu/backend/processor/MethodsRegistry.kt +++ b/backend/src/main/kotlin/io/kabu/backend/processor/MethodsRegistry.kt @@ -43,7 +43,7 @@ class MethodsRegistry(processingInput: ProcessingInput? = null) { return when { groupedByExtensionContextType.isEmpty() -> - diagnosticError("No context creator for context name $contextName.") + diagnosticError("Context creator for context name '$contextName' not found.") groupedByExtensionContextType.size > 1 -> diagnosticError( "Context creators for one context name '$contextName' must have the same return type\n " + diff --git a/backend/src/test/kotlin/io/kabu/backend/integration/test/IntegratorTest.kt b/backend/src/test/kotlin/io/kabu/backend/integration/test/IntegratorTest.kt index bbe549f..20b617e 100644 --- a/backend/src/test/kotlin/io/kabu/backend/integration/test/IntegratorTest.kt +++ b/backend/src/test/kotlin/io/kabu/backend/integration/test/IntegratorTest.kt @@ -1,5 +1,6 @@ package io.kabu.backend.integration.test +import io.kabu.backend.common.log.InterceptingLogging import io.kabu.backend.integration.Integrator import io.kabu.backend.integration.render.GraphVisualizer import io.kabu.backend.node.Node @@ -16,8 +17,8 @@ open class IntegratorTest { val visualizer = GraphVisualizer() val styledDiagram = visualizer.generateMermaidDiagramAsFlowchart(integrator.integrated, styling = true) val unStyledDiagram = visualizer.generateMermaidDiagramAsFlowchart(integrator.integrated, styling = false) - println(visualizer.getMermaidRenderLink(styledDiagram)) - println(unStyledDiagram) + logger.debug { visualizer.getMermaidRenderLink(styledDiagram) } + logger.debug { unStyledDiagram } return unStyledDiagram } @@ -31,13 +32,17 @@ open class IntegratorTest { private fun showDiagram(nodes: Set, styling: Boolean = true) { val visualizer = GraphVisualizer() val diagram = visualizer.generateMermaidDiagramAsFlowchart(nodes, styling) - println(visualizer.getMermaidRenderLink(diagram)) - println(diagram) + logger.debug { visualizer.getMermaidRenderLink(diagram) } + logger.debug { diagram } } protected infix fun String.assertEq(actual: String) { assertEquals(this.trimIndent() + "\n", actual) } + + private companion object { + val logger = InterceptingLogging.logger {} + } } class GraphBuilder { diff --git a/backend/src/test/kotlin/io/kabu/backend/plannerx/GenerationTest.kt b/backend/src/test/kotlin/io/kabu/backend/plannerx/GenerationTest.kt index 42f14fa..6a6ced4 100644 --- a/backend/src/test/kotlin/io/kabu/backend/plannerx/GenerationTest.kt +++ b/backend/src/test/kotlin/io/kabu/backend/plannerx/GenerationTest.kt @@ -19,7 +19,6 @@ class GenerationTest : XTest() { private fun testPattern(patternWithSignature: String) { // analyze method + pattern val nodes = analyzePatternWithSignature(patternWithSignature) - getDiagramOfNodes(nodes) // integrate nodes val integrator = Integrator() diff --git a/backend/src/test/kotlin/io/kabu/backend/plannerx/XTest.kt b/backend/src/test/kotlin/io/kabu/backend/plannerx/XTest.kt index 7b886b6..493c5be 100644 --- a/backend/src/test/kotlin/io/kabu/backend/plannerx/XTest.kt +++ b/backend/src/test/kotlin/io/kabu/backend/plannerx/XTest.kt @@ -56,8 +56,8 @@ open class XTest { val visualizer = GraphVisualizer() val styledDiagram = visualizer.generateMermaidDiagramAsFlowchart(nodes, styling = true) val unStyledDiagram = visualizer.generateMermaidDiagramAsFlowchart(nodes, styling = false) - println(visualizer.getMermaidRenderLink(styledDiagram)) - println(unStyledDiagram) + logger.debug { visualizer.getMermaidRenderLink(styledDiagram) } + logger.debug { unStyledDiagram } return unStyledDiagram } } diff --git a/backend/src/test/kotlin/io/kabu/backend/r2c/Utils.kt b/backend/src/test/kotlin/io/kabu/backend/r2c/Utils.kt index 7b81482..6a012b7 100644 --- a/backend/src/test/kotlin/io/kabu/backend/r2c/Utils.kt +++ b/backend/src/test/kotlin/io/kabu/backend/r2c/Utils.kt @@ -7,7 +7,6 @@ import io.kabu.backend.generator.Generator import io.kabu.backend.inout.input.method.GlobalPatternMethod import io.kabu.backend.integration.Integrator import io.kabu.backend.pattern.PatternWithSignature -import io.kabu.backend.plannerx.XTest.Companion.getDiagramOfNodes import io.kabu.backend.processor.MethodsRegistry import io.kabu.backend.processor.Options import io.kabu.backend.processor.PartialOptions @@ -27,7 +26,7 @@ fun Any?.completionWithReceiver(vararg parameters: Any?) { } fun completionOutputOf(raw: String, sample: String): String { - println("Raw: $raw") + logger.debug("Raw: $raw") val patternWithSignature = PatternWithSignature(raw) val (receiver, parameters, returnedType) = patternWithSignature.signature @@ -47,7 +46,6 @@ fun completionOutputOf(raw: String, sample: String): String { ) ) val nodes = AnalyzerImpl(method, MethodsRegistry(), null, options).analyze() - getDiagramOfNodes(nodes) val integrator = Integrator() integrator.integrate(nodes, removeIrrelevant = false) val scriptGenerated = Generator(testMode = true).getCodeForPackage(integrator.integrated, method.packageName) @@ -83,14 +81,13 @@ fun completionOutputOf(raw: String, sample: String): String { } Assert.assertTrue(res is ResultWithDiagnostics.Success) } - println(out) + logger.debug(out) return out } private const val CLIENT_METHOD = "completion" private const val CLIENT_METHOD_WITH_RECEIVER = "completionWithReceiver" private const val TARGET_PACKAGE = "$BACKEND_PACKAGE.r2c" -private const val FILENAME = "Generated" private const val DELIMITER = "=================================================" val unknownOrigin = Origin() private val logger = InterceptingLogging.logger {} From f4a566e8b48f442e9e50513b971373ec76ff368f Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Sat, 22 Jul 2023 16:45:23 +0600 Subject: [PATCH 19/43] removed Overriding.translation --- .../io/kabu/backend/parser/Operators.kt | 56 ++++++++----------- 1 file changed, 23 insertions(+), 33 deletions(-) diff --git a/backend/src/main/kotlin/io/kabu/backend/parser/Operators.kt b/backend/src/main/kotlin/io/kabu/backend/parser/Operators.kt index c152cdd..7431c6f 100644 --- a/backend/src/main/kotlin/io/kabu/backend/parser/Operators.kt +++ b/backend/src/main/kotlin/io/kabu/backend/parser/Operators.kt @@ -11,12 +11,10 @@ import io.kabu.backend.parser.Arity.UNARY /** * @property function overridable function name (by convention) - * @property translation actual compiler translation * @property mustReturn what the translation function must return, if FREE - no restrictions */ data class Overriding( val function: String, - val translation: String? = null, val mustReturn: FunctionMustReturn = FunctionMustReturn.FREE ) @@ -77,7 +75,7 @@ class Call(origin: Origin) : NaryOperator( symbol = "call", priority = 15, expressionType = EvaluatedExpressionType.FREE, - overriding = Overriding("invoke", "a.invoke(parametersList)"), + overriding = Overriding("invoke"), origin = origin ) @@ -85,7 +83,7 @@ class Indexing(origin: Origin) : NaryOperator( symbol = "index", priority = 15, expressionType = EvaluatedExpressionType.FREE, - overriding = Overriding("get", "a.get(parametersList)"), + overriding = Overriding("get"), origin = origin ) @@ -106,14 +104,14 @@ sealed class UnaryPostfix( class PlusPlusPostfix(origin: Origin) : UnaryPostfix( symbol = "++", expressionType = EvaluatedExpressionType.FREE, - overriding = Overriding("inc", "a.inc()", FunctionMustReturn.ASSIGNABLE), + overriding = Overriding("inc", FunctionMustReturn.ASSIGNABLE), origin = origin ) class MinusMinusPostfix(origin: Origin) : UnaryPostfix( symbol = "--", expressionType = EvaluatedExpressionType.FREE, - overriding = Overriding("dec", "a.dec()", FunctionMustReturn.ASSIGNABLE), + overriding = Overriding("dec", FunctionMustReturn.ASSIGNABLE), origin = origin ) } @@ -135,35 +133,35 @@ sealed class UnaryPrefix( class UnaryMinus(origin: Origin) : UnaryPrefix( symbol = "-", expressionType = EvaluatedExpressionType.FREE, - overriding = Overriding("unaryMinus", "a.unaryMinus()"), + overriding = Overriding("unaryMinus"), origin = origin ) class UnaryPlus(origin: Origin) : UnaryPrefix( symbol = "+", expressionType = EvaluatedExpressionType.FREE, - overriding = Overriding("unaryPlus", "a.unaryPlus()"), + overriding = Overriding("unaryPlus"), origin = origin ) class PlusPlusPrefix(origin: Origin) : UnaryPrefix( symbol = "++", expressionType = EvaluatedExpressionType.FREE, - overriding = Overriding("inc", "a.inc()", FunctionMustReturn.ASSIGNABLE), + overriding = Overriding("inc", FunctionMustReturn.ASSIGNABLE), origin = origin ) class MinusMinusPrefix(origin: Origin) : UnaryPrefix( symbol = "--", expressionType = EvaluatedExpressionType.FREE, - overriding = Overriding("dec", "a.dec()", FunctionMustReturn.ASSIGNABLE), + overriding = Overriding("dec", FunctionMustReturn.ASSIGNABLE), origin = origin ) class Not(origin: Origin) : UnaryPrefix( symbol = "!", expressionType = EvaluatedExpressionType.FREE, - overriding = Overriding("not", "a.not()"), + overriding = Overriding("not"), origin = origin ) } @@ -190,21 +188,21 @@ sealed class Multiplicative( class Multiply(origin: Origin) : Multiplicative( symbol = "*", expressionType = EvaluatedExpressionType.FREE, - overriding = Overriding("times", "a.times(b)"), + overriding = Overriding("times"), origin = origin ) class Divide(origin: Origin) : Multiplicative( symbol = "/", expressionType = EvaluatedExpressionType.FREE, - overriding = Overriding("div", "a.div(b)"), + overriding = Overriding("div"), origin = origin ) class Remainder(origin: Origin) : Multiplicative( symbol = "%", expressionType = EvaluatedExpressionType.FREE, - overriding = Overriding("rem", "a.rem(b)"), + overriding = Overriding("rem"), origin = origin ) } @@ -221,14 +219,14 @@ sealed class Additive( class BinaryPlus(origin: Origin) : Additive( symbol = "+", expressionType = EvaluatedExpressionType.FREE, - overriding = Overriding("plus", "a.plus(b)"), + overriding = Overriding("plus"), origin = origin ) class BinaryMinus(origin: Origin) : Additive( symbol = "-", expressionType = EvaluatedExpressionType.FREE, - overriding = Overriding("minus", "a.minus(b)"), + overriding = Overriding("minus"), origin = origin ) } @@ -239,7 +237,7 @@ class RangeTo(origin: Origin) : BinaryOperator( symbol = "..", priority = 10, expressionType = EvaluatedExpressionType.FREE, - overriding = Overriding("rangeTo", "a.rangeTo(b)"), + overriding = Overriding("rangeTo"), origin = origin ) @@ -247,7 +245,7 @@ class RangeUntil(origin: Origin) : BinaryOperator( symbol = "..<", priority = 10, expressionType = EvaluatedExpressionType.FREE, - overriding = Overriding("rangeUntil", "a.rangeUntil(b)"), + overriding = Overriding("rangeUntil"), origin = origin ) @@ -260,7 +258,7 @@ class InfixFunction( symbol = symbol, priority = 9, expressionType = EvaluatedExpressionType.FREE, - overriding = Overriding(symbol, "a.$symbol(b)"), + overriding = Overriding(symbol), origin = origin ) @@ -282,7 +280,6 @@ sealed class InclusionCheck( expressionType = EvaluatedExpressionType.BOOLEAN, overriding = Overriding( function = "contains", - translation = "b.contains(a)", mustReturn = FunctionMustReturn.BOOLEAN ), origin = origin @@ -295,7 +292,6 @@ sealed class InclusionCheck( expressionType = EvaluatedExpressionType.BOOLEAN, overriding = Overriding( function = "contains", - translation = "!b.contains(a)", mustReturn = FunctionMustReturn.BOOLEAN ), origin = origin @@ -321,7 +317,6 @@ sealed class Comparison( expressionType = EvaluatedExpressionType.BOOLEAN, overriding = Overriding( function = "compareTo", - translation = "a.compareTo(b) < 0", mustReturn = FunctionMustReturn.INT, ), origin = origin @@ -332,7 +327,6 @@ sealed class Comparison( expressionType = EvaluatedExpressionType.BOOLEAN, overriding = Overriding( function = "compareTo", - translation = "a.compareTo(b) > 0", mustReturn = FunctionMustReturn.INT, ), origin = origin @@ -343,7 +337,6 @@ sealed class Comparison( expressionType = EvaluatedExpressionType.BOOLEAN, overriding = Overriding( function = "compareTo", - translation = "a.compareTo(b) <= 0", mustReturn = FunctionMustReturn.INT, ), origin = origin @@ -354,7 +347,6 @@ sealed class Comparison( expressionType = EvaluatedExpressionType.BOOLEAN, overriding = Overriding( function = "compareTo", - translation = "a.compareTo(b) >= 0", mustReturn = FunctionMustReturn.INT, ), origin = origin @@ -379,7 +371,6 @@ sealed class Equality( expressionType = EvaluatedExpressionType.BOOLEAN, overriding = Overriding( function = "equals", - translation = "a?.equals(b) ?: (b === null)", mustReturn = FunctionMustReturn.BOOLEAN, ), origin = origin @@ -390,7 +381,6 @@ sealed class Equality( expressionType = EvaluatedExpressionType.BOOLEAN, overriding = Overriding( function = "equals", - translation = "!(a?.equals(b) ?: (b === null))", mustReturn = FunctionMustReturn.BOOLEAN, ), origin = origin @@ -430,35 +420,35 @@ sealed class ModAssign( class PlusAssign(origin: Origin) : ModAssign( symbol = "+=", expressionType = EvaluatedExpressionType.NONE, - overriding = Overriding("plusAssign", "a.plusAssign(b)", FunctionMustReturn.UNIT), + overriding = Overriding("plusAssign", FunctionMustReturn.UNIT), origin = origin ) class MinusAssign(origin: Origin) : ModAssign( symbol = "-=", expressionType = EvaluatedExpressionType.NONE, - overriding = Overriding("minusAssign", "a.minusAssign(b)", FunctionMustReturn.UNIT), + overriding = Overriding("minusAssign", FunctionMustReturn.UNIT), origin = origin ) class MultiplyAssign(origin: Origin) : ModAssign( symbol = "*=", expressionType = EvaluatedExpressionType.NONE, - overriding = Overriding("timesAssign", "a.timesAssign(b)", FunctionMustReturn.UNIT), + overriding = Overriding("timesAssign", FunctionMustReturn.UNIT), origin = origin ) class DivideAssign(origin: Origin) : ModAssign( symbol = "/=", expressionType = EvaluatedExpressionType.NONE, - overriding = Overriding("divAssign", "a.divAssign(b)", FunctionMustReturn.UNIT), + overriding = Overriding("divAssign", FunctionMustReturn.UNIT), origin = origin ) class RemainderAssign(origin: Origin) : ModAssign( symbol = "%=", expressionType = EvaluatedExpressionType.NONE, - overriding = Overriding("remAssign", "a.remAssign(b)", FunctionMustReturn.UNIT), + overriding = Overriding("remAssign", FunctionMustReturn.UNIT), origin = origin ) } @@ -467,6 +457,6 @@ class Assign(origin: Origin) : BinaryOperator( symbol = "=", priority = 1, expressionType = EvaluatedExpressionType.NONE, - overriding = Overriding("set", "", FunctionMustReturn.UNIT), + overriding = Overriding("set", FunctionMustReturn.UNIT), origin = origin ) From 5e89216bd4c5af79080bebd0bfd53044308d687c Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Sat, 22 Jul 2023 17:17:33 +0600 Subject: [PATCH 20/43] refactored Overriding --- .../kabu/backend/analyzer/handler/Handler.kt | 4 +- .../backend/analyzer/handler/HandlerUtils.kt | 2 +- .../analyzer/handler/OperatorHandler.kt | 6 +- .../lambda/watcher/WatcherLambdaHandler.kt | 2 +- .../user/legacy/types/LambdaTypeChecker.kt | 2 +- .../io/kabu/backend/parser/Operators.kt | 57 +++++++++---------- 6 files changed, 34 insertions(+), 39 deletions(-) diff --git a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/Handler.kt b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/Handler.kt index 202d3e1..6380603 100644 --- a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/Handler.kt +++ b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/Handler.kt @@ -65,7 +65,7 @@ open class Handler( assignableSuffixExpression: KotlinExpression? ): AbstractProvider { val funDeclarationProviders = FunDeclarationProvidersFactory - .from(rawProviders, operator.invertedArgumentOrdering) + .from(rawProviders, operator.overriding.invertedArgumentOrdering) val functionBlockContext = FunctionBlockContext(funDeclarationProviders) //todo not adding operator info provider here! @@ -108,7 +108,7 @@ open class Handler( // registering capture type for operation val returningTypeNode = expressionReturnedTypeOf(operator.expressionType)!!.toFixedTypeNode() val translationReturnedTypeNode = - (if (operator is Assign) UNIT else operator.overriding!!.mustReturn.asFixedTypeName()).toFixedTypeNode() + (if (operator is Assign) UNIT else operator.overriding.mustReturn.asFixedTypeName()).toFixedTypeNode() val captureType = CaptureType( operator = operator, funDeclarationProviders = funDeclarationProviders, diff --git a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/HandlerUtils.kt b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/HandlerUtils.kt index 34ee837..6892ade 100644 --- a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/HandlerUtils.kt +++ b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/HandlerUtils.kt @@ -14,7 +14,7 @@ internal val KotlinExpression.isTerminal: Boolean internal val LambdaExpression.canBeLambdaWithReceiver: Boolean get() { val parentExpressionHasInvertedArgumentOrdering = (parent as? OperatorExpression) - ?.operator?.invertedArgumentOrdering + ?.operator?.overriding?.invertedArgumentOrdering ?: false val lambdaIsTheFirstChild = indexInParent == 0 diff --git a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/OperatorHandler.kt b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/OperatorHandler.kt index 2926772..9f94f30 100644 --- a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/OperatorHandler.kt +++ b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/OperatorHandler.kt @@ -117,7 +117,7 @@ class OperatorHandler(analyzer: AnalyzerImpl) : Handler(analyzer) { validateApplicability(expression.operator, analyzer, rawProviders) val funDeclarationProviders = FunDeclarationProvidersFactory - .from(rawProviders, expression.operator.invertedArgumentOrdering) + .from(rawProviders, expression.operator.overriding.invertedArgumentOrdering) val terminalFunction = TerminalFunctionNode( funDeclarationProviders = funDeclarationProviders, @@ -145,7 +145,7 @@ class OperatorHandler(analyzer: AnalyzerImpl) : Handler(analyzer) { val funDeclarationProviders = FunDeclarationProvidersFactory.from( rawProvidersOfAssign, - assignOperator.invertedArgumentOrdering + assignOperator.overriding.invertedArgumentOrdering ) val functionNode = TerminalFunctionNode( @@ -176,7 +176,7 @@ class OperatorHandler(analyzer: AnalyzerImpl) : Handler(analyzer) { ): HolderProvider { val funDeclarationProviders = FunDeclarationProvidersFactory.from( rawProviders, - expression.operator.invertedArgumentOrdering + expression.operator.overriding.invertedArgumentOrdering ) val functionBlockContext = FunctionBlockContext(funDeclarationProviders) diff --git a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/WatcherLambdaHandler.kt b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/WatcherLambdaHandler.kt index 3d5486d..362f54b 100644 --- a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/WatcherLambdaHandler.kt +++ b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/WatcherLambdaHandler.kt @@ -166,7 +166,7 @@ class WatcherLambdaHandler(analyzer: AnalyzerImpl) : Handler(analyzer) { val rawProviders = captureType.rawProviders!! val funDeclarationProviders = FunDeclarationProvidersFactory.from( rawProviders, - captureType.operator.invertedArgumentOrdering, + captureType.operator.overriding.invertedArgumentOrdering, forSetter = true ) diff --git a/backend/src/main/kotlin/io/kabu/backend/integration/detector/user/legacy/types/LambdaTypeChecker.kt b/backend/src/main/kotlin/io/kabu/backend/integration/detector/user/legacy/types/LambdaTypeChecker.kt index cb7b5fd..9780541 100644 --- a/backend/src/main/kotlin/io/kabu/backend/integration/detector/user/legacy/types/LambdaTypeChecker.kt +++ b/backend/src/main/kotlin/io/kabu/backend/integration/detector/user/legacy/types/LambdaTypeChecker.kt @@ -17,7 +17,7 @@ class LambdaTypeChecker : TypeConflictChecker(Function::class) { // forbid '{ ... }()' patterns if (request.operator is Call && request.rawProviders.right.isEmpty()) { - ownTypeConflict(request, request.operator.overriding!!.function) + ownTypeConflict(request, request.operator.overriding.function!!) } } } diff --git a/backend/src/main/kotlin/io/kabu/backend/parser/Operators.kt b/backend/src/main/kotlin/io/kabu/backend/parser/Operators.kt index 7431c6f..d902afb 100644 --- a/backend/src/main/kotlin/io/kabu/backend/parser/Operators.kt +++ b/backend/src/main/kotlin/io/kabu/backend/parser/Operators.kt @@ -12,34 +12,31 @@ import io.kabu.backend.parser.Arity.UNARY /** * @property function overridable function name (by convention) * @property mustReturn what the translation function must return, if FREE - no restrictions + * @property invertedArgumentOrdering if there is difference between argument ordering in use site of operator + * and its translation */ data class Overriding( - val function: String, - val mustReturn: FunctionMustReturn = FunctionMustReturn.FREE + val function: String?, + val mustReturn: FunctionMustReturn = FunctionMustReturn.FREE, + val invertedArgumentOrdering: Boolean = false, ) /** - * Descendants can possibly be used in a resulting code. - * Only those operators implemented that support overriding in some way + * Operator of Kotlin tree. * * @property expressionType type of this operator expression in usage site - * @property invertedArgumentOrdering if there is difference between argument ordering in use site of operator - * and its translation */ sealed class Operator( //todo rename to OperatorType, or use ParsedOperator(OperatorType, origin) in KotlinExpression ? val symbol: String, val priority: Int, val arity: Arity, val expressionType: EvaluatedExpressionType = EvaluatedExpressionType.FREE, - val overriding: Overriding? = null, + val overriding: Overriding, //todo remove as we should not mix **type** of an operator and actual parsed operator (with origin) ? override val origin: Origin ) : HasOrigin { - /** If there is difference between argument ordering in use site of operator and its translation */ - open val invertedArgumentOrdering: Boolean = false - - fun getFunctionNameOrThrow(): String = overriding?.function + fun getFunctionNameOrThrow(): String = overriding.function ?: diagnosticError("Operator $this is not supported", this) override fun toString() = this::class.simpleName ?: "Operator" @@ -49,7 +46,7 @@ sealed class UnaryOperator( symbol: String, priority: Int, expressionType: EvaluatedExpressionType = EvaluatedExpressionType.FREE, - overriding: Overriding? = null, + overriding: Overriding, origin: Origin, ) : Operator(symbol, priority, UNARY, expressionType, overriding, origin) @@ -57,7 +54,7 @@ sealed class BinaryOperator( symbol: String, priority: Int, expressionType: EvaluatedExpressionType = EvaluatedExpressionType.FREE, - overriding: Overriding? = null, + overriding: Overriding, origin: Origin ) : Operator(symbol, priority, BINARY, expressionType, overriding, origin) @@ -65,7 +62,7 @@ sealed class NaryOperator( symbol: String, priority: Int, expressionType: EvaluatedExpressionType, - overriding: Overriding? = null, + overriding: Overriding, origin: Origin ) : Operator(symbol, priority, NARY, expressionType, overriding, origin) @@ -90,7 +87,7 @@ class Indexing(origin: Origin) : NaryOperator( sealed class UnaryPostfix( symbol: String, expressionType: EvaluatedExpressionType, - overriding: Overriding? = null, + overriding: Overriding, origin: Origin ) : UnaryOperator(symbol, 15, expressionType, overriding, origin) { @@ -116,7 +113,7 @@ sealed class UnaryPostfix( ) } -class Access(origin: Origin) : BinaryOperator(".", 15, origin = origin) +class Access(origin: Origin) : BinaryOperator(".", 15, overriding = Overriding(null), origin = origin) //object SafeAccess : BinaryOperator("?.", 15), NotSupported //object Question : BinaryOperator("?", 15), NotSupported @@ -126,7 +123,7 @@ class Access(origin: Origin) : BinaryOperator(".", 15, origin = origin) sealed class UnaryPrefix( symbol: String, expressionType: EvaluatedExpressionType, - overriding: Overriding? = null, + overriding: Overriding, origin: Origin ) : UnaryOperator(symbol, 14, expressionType, overriding, origin) { @@ -181,7 +178,7 @@ sealed class UnaryPrefix( sealed class Multiplicative( symbol: String, expressionType: EvaluatedExpressionType, - overriding: Overriding? = null, + overriding: Overriding, origin: Origin ) : BinaryOperator(symbol, 12, expressionType, overriding, origin) { @@ -212,7 +209,7 @@ sealed class Multiplicative( sealed class Additive( symbol: String, expressionType: EvaluatedExpressionType, - overriding: Overriding? = null, + overriding: Overriding, origin: Origin ) : BinaryOperator(symbol, 11, expressionType, overriding, origin) { @@ -271,7 +268,7 @@ class InfixFunction( sealed class InclusionCheck( symbol: String, expressionType: EvaluatedExpressionType, - overriding: Overriding? = null, + overriding: Overriding, origin: Origin ) : BinaryOperator(symbol, 7, expressionType, overriding, origin) { @@ -280,24 +277,22 @@ sealed class InclusionCheck( expressionType = EvaluatedExpressionType.BOOLEAN, overriding = Overriding( function = "contains", - mustReturn = FunctionMustReturn.BOOLEAN + mustReturn = FunctionMustReturn.BOOLEAN, + invertedArgumentOrdering = true, ), origin = origin - ) { - override val invertedArgumentOrdering = true - } + ) class NotIn(origin: Origin) : InclusionCheck( symbol = "!in", expressionType = EvaluatedExpressionType.BOOLEAN, overriding = Overriding( function = "contains", - mustReturn = FunctionMustReturn.BOOLEAN + mustReturn = FunctionMustReturn.BOOLEAN, + invertedArgumentOrdering = true, ), origin = origin - ) { - override val invertedArgumentOrdering = true - } + ) } // object Is : NamedCheck("is"), NotSupported @@ -308,7 +303,7 @@ sealed class InclusionCheck( sealed class Comparison( symbol: String, expressionType: EvaluatedExpressionType, - overriding: Overriding? = null, + overriding: Overriding, origin: Origin ) : BinaryOperator(symbol, 6, expressionType, overriding, origin) { @@ -358,7 +353,7 @@ sealed class Comparison( sealed class Equality( symbol: String, expressionType: EvaluatedExpressionType, - overriding: Overriding?, + overriding: Overriding, origin: Origin ) : BinaryOperator(symbol, 5, expressionType, overriding, origin) { /* @@ -404,7 +399,7 @@ sealed class Equality( sealed class ModAssign( symbol: String, expressionType: EvaluatedExpressionType, - overriding: Overriding? = null, + overriding: Overriding, origin: Origin ) : BinaryOperator(symbol, 1, expressionType, overriding, origin) { From aeb1729a80bce91eaea79d8c949f0e751a2e87bc Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Sat, 22 Jul 2023 17:26:24 +0600 Subject: [PATCH 21/43] refactoring --- .../analyzer/handler/lambda/watcher/WatcherLambda.kt | 4 ++-- .../backend/declaration/AbstractCallableDeclaration.kt | 5 ++--- .../backend/declaration/functions/FunctionDeclaration.kt | 2 +- .../declaration/functions/TerminalFunctionDeclaration.kt | 8 +++----- .../detector/user/legacy/TypeConflictChecker.kt | 2 +- .../detector/user/legacy/types/StringTypeChecker.kt | 2 +- .../src/main/kotlin/io/kabu/backend/parser/Operators.kt | 9 ++------- 7 files changed, 12 insertions(+), 20 deletions(-) diff --git a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/WatcherLambda.kt b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/WatcherLambda.kt index 6a82709..856b34c 100644 --- a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/WatcherLambda.kt +++ b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/WatcherLambda.kt @@ -40,7 +40,7 @@ class WatcherLambda(val watcherContextTypeNode: WatcherContextTypeNode) { //todo exact types match (ignoring type parameters)! return captureTypes.size == groupTypes.size && captureTypes.zip(groupTypes).all { it.first == it.second } && - captureType.operator.overriding?.function == group.operator.overriding?.function + captureType.operator.overriding.function == group.operator.overriding.function } } @@ -54,7 +54,7 @@ class CaptureTypeGroup( ) { fun getBaseNameForDeclarations(): String { - val namePart = operator.overriding?.function ?: "func" + val namePart = operator.overriding.function ?: "func" val argsPart = buildString { funDeclarationProviders.providersList.forEach { append(it.type.toString().replace(illegalKotlinIdentifierSymbol, "_")) diff --git a/backend/src/main/kotlin/io/kabu/backend/declaration/AbstractCallableDeclaration.kt b/backend/src/main/kotlin/io/kabu/backend/declaration/AbstractCallableDeclaration.kt index 8d72a8c..6bcbe12 100644 --- a/backend/src/main/kotlin/io/kabu/backend/declaration/AbstractCallableDeclaration.kt +++ b/backend/src/main/kotlin/io/kabu/backend/declaration/AbstractCallableDeclaration.kt @@ -26,7 +26,7 @@ abstract class AbstractCallableDeclaration : Declaration() { funDeclarationProviders: FunDeclarationProviders, returnTypeNode: TypeNode, ): CodeBlock { - return if (operator.overriding?.mustReturn == FunctionMustReturn.FREE) { + return if (operator.overriding.mustReturn == FunctionMustReturn.FREE) { codeBlockForGeneratedTypeNode(funDeclarationProviders, returnTypeNode) } else { codeBlockForFixedTypeNode(funDeclarationProviders, operator) @@ -76,13 +76,12 @@ abstract class AbstractCallableDeclaration : Declaration() { val statements2 = actualValues.joinToString(";") { "$STACK_PROPERTY_NAME.push($it)" } // returning necessary value - val statements3 = when (operator.overriding?.mustReturn) { + val statements3 = when (operator.overriding.mustReturn) { FunctionMustReturn.FREE -> TODO() FunctionMustReturn.ASSIGNABLE -> TODO() FunctionMustReturn.BOOLEAN -> "return true" FunctionMustReturn.INT -> getReturnStatementForComparison(funDeclarationProviders.operatorInfoType) FunctionMustReturn.UNIT -> "" - null -> TODO() } return listOf(statements1, statements2, statements3) diff --git a/backend/src/main/kotlin/io/kabu/backend/declaration/functions/FunctionDeclaration.kt b/backend/src/main/kotlin/io/kabu/backend/declaration/functions/FunctionDeclaration.kt index 9a0b7c3..db32a99 100644 --- a/backend/src/main/kotlin/io/kabu/backend/declaration/functions/FunctionDeclaration.kt +++ b/backend/src/main/kotlin/io/kabu/backend/declaration/functions/FunctionDeclaration.kt @@ -20,7 +20,7 @@ class FunctionDeclaration( val functionName: String get() = when (kind) { is RegularFunctionNodeKind.HelperFunction -> kind.name - else -> operator.getFunctionNameOrThrow() + else -> operator.overriding.function!! } override fun generateFunSpec(): FunSpec { diff --git a/backend/src/main/kotlin/io/kabu/backend/declaration/functions/TerminalFunctionDeclaration.kt b/backend/src/main/kotlin/io/kabu/backend/declaration/functions/TerminalFunctionDeclaration.kt index 6728b35..bb4f9b6 100644 --- a/backend/src/main/kotlin/io/kabu/backend/declaration/functions/TerminalFunctionDeclaration.kt +++ b/backend/src/main/kotlin/io/kabu/backend/declaration/functions/TerminalFunctionDeclaration.kt @@ -24,12 +24,12 @@ open class TerminalFunctionDeclaration( //todo abstract in base? val functionName: String - get() = operator.getFunctionNameOrThrow() + get() = operator.overriding.function!! val returnedType: TypeName get() = when { operator is Assign -> UNIT - operator.overriding!!.mustReturn != FunctionMustReturn.FREE -> { + operator.overriding.mustReturn != FunctionMustReturn.FREE -> { operator.overriding.mustReturn.asFixedTypeName() } @@ -57,15 +57,13 @@ open class TerminalFunctionDeclaration( ) } - private fun getRequiredByOperatorReturnStatement(operator: Operator) = when (operator.overriding?.mustReturn) { + private fun getRequiredByOperatorReturnStatement(operator: Operator) = when (operator.overriding.mustReturn) { FunctionMustReturn.BOOLEAN -> "return true" FunctionMustReturn.INT -> "return 42" FunctionMustReturn.FREE, FunctionMustReturn.ASSIGNABLE, FunctionMustReturn.UNIT, -> null - - null -> null } override fun toString(): String { diff --git a/backend/src/main/kotlin/io/kabu/backend/integration/detector/user/legacy/TypeConflictChecker.kt b/backend/src/main/kotlin/io/kabu/backend/integration/detector/user/legacy/TypeConflictChecker.kt index 2891a1c..d666947 100644 --- a/backend/src/main/kotlin/io/kabu/backend/integration/detector/user/legacy/TypeConflictChecker.kt +++ b/backend/src/main/kotlin/io/kabu/backend/integration/detector/user/legacy/TypeConflictChecker.kt @@ -48,7 +48,7 @@ open class TypeConflictChecker(private val klass: KClass<*>) : ConflictChecker() } private fun findFirstClashingFunction(request: OperatorDeclarationRequest): StandardMethod? { - val operatorFunctionName = request.operator.overriding?.function + val operatorFunctionName = request.operator.overriding.function val parametersWithoutReceiver = request.rawProviders.providersList.drop(1) return functions.find { standardMethod -> diff --git a/backend/src/main/kotlin/io/kabu/backend/integration/detector/user/legacy/types/StringTypeChecker.kt b/backend/src/main/kotlin/io/kabu/backend/integration/detector/user/legacy/types/StringTypeChecker.kt index 92c67a1..996208e 100644 --- a/backend/src/main/kotlin/io/kabu/backend/integration/detector/user/legacy/types/StringTypeChecker.kt +++ b/backend/src/main/kotlin/io/kabu/backend/integration/detector/user/legacy/types/StringTypeChecker.kt @@ -11,7 +11,7 @@ class StringTypeChecker : TypeConflictChecker(String::class) { super.check(request) if (request.operator is Additive.BinaryPlus) { - val conflictingStandardMethod = functions.single { it.name == request.operator.overriding!!.function } + val conflictingStandardMethod = functions.single { it.name == request.operator.overriding.function!! } ownTypeConflict(request, conflictingStandardMethod) } } diff --git a/backend/src/main/kotlin/io/kabu/backend/parser/Operators.kt b/backend/src/main/kotlin/io/kabu/backend/parser/Operators.kt index d902afb..9222a02 100644 --- a/backend/src/main/kotlin/io/kabu/backend/parser/Operators.kt +++ b/backend/src/main/kotlin/io/kabu/backend/parser/Operators.kt @@ -4,7 +4,6 @@ package io.kabu.backend.parser import io.kabu.backend.diagnostic.HasOrigin import io.kabu.backend.diagnostic.Origin -import io.kabu.backend.diagnostic.diagnosticError import io.kabu.backend.parser.Arity.BINARY import io.kabu.backend.parser.Arity.NARY import io.kabu.backend.parser.Arity.UNARY @@ -26,19 +25,15 @@ data class Overriding( * * @property expressionType type of this operator expression in usage site */ -sealed class Operator( //todo rename to OperatorType, or use ParsedOperator(OperatorType, origin) in KotlinExpression ? +sealed class Operator( val symbol: String, val priority: Int, val arity: Arity, val expressionType: EvaluatedExpressionType = EvaluatedExpressionType.FREE, val overriding: Overriding, - //todo remove as we should not mix **type** of an operator and actual parsed operator (with origin) ? - override val origin: Origin + override val origin: Origin //todo mixing type of operator and parsed operator (with origin)? ) : HasOrigin { - fun getFunctionNameOrThrow(): String = overriding.function - ?: diagnosticError("Operator $this is not supported", this) - override fun toString() = this::class.simpleName ?: "Operator" } From 5286c4f5caa7b858879f839423aa8cc268bd8764 Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Sat, 22 Jul 2023 19:06:30 +0600 Subject: [PATCH 22/43] refactored LeftHandSideOfAssign --- .../kabu/backend/analyzer/handler/Handler.kt | 19 ++++++++-- .../analyzer/handler/OperatorHandler.kt | 5 ++- .../handler/lambda/watcher/CaptureType.kt | 5 +-- .../lambda/watcher/LeftHandSideOfAssign.kt | 21 ++++++++++ .../handler/lambda/watcher/WatcherLambda.kt | 7 +--- .../lambda/watcher/WatcherLambdaHandler.kt | 38 +++++-------------- 6 files changed, 53 insertions(+), 42 deletions(-) create mode 100644 backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/LeftHandSideOfAssign.kt diff --git a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/Handler.kt b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/Handler.kt index 6380603..7c473f1 100644 --- a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/Handler.kt +++ b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/Handler.kt @@ -7,6 +7,7 @@ import com.squareup.kotlinpoet.asClassName import io.kabu.backend.analyzer.Analyzer import io.kabu.backend.analyzer.AnalyzerImpl import io.kabu.backend.analyzer.handler.lambda.watcher.CaptureType +import io.kabu.backend.analyzer.handler.lambda.watcher.LeftHandSideOfAssign import io.kabu.backend.diagnostic.builder.watcherLambdaMissingError import io.kabu.backend.node.FixedTypeNode import io.kabu.backend.node.HolderTypeNode @@ -14,10 +15,12 @@ import io.kabu.backend.node.TypeNode import io.kabu.backend.node.factory.node.HolderTypeNodeImpl import io.kabu.backend.node.factory.node.TerminalAssignablePropertyNode import io.kabu.backend.node.factory.node.TerminalReadOnlyPropertyNode +import io.kabu.backend.parser.Access import io.kabu.backend.parser.Assign import io.kabu.backend.parser.BinaryExpression import io.kabu.backend.parser.Comparison import io.kabu.backend.parser.EvaluatedExpressionType +import io.kabu.backend.parser.IdentifierLeaf import io.kabu.backend.parser.InclusionCheck import io.kabu.backend.parser.KotlinExpression import io.kabu.backend.parser.ModAssign @@ -56,13 +59,23 @@ open class Handler( val rawProvidersOfAssign = RawProviders(listOf(rawProviders.providersList[0], assigningProvider), operatorInfoParameter = null) - return createWatchedParameter(rawProvidersOfAssign, assignOperator, expression) + val leftHandSideOfAssign = when { + expression is IdentifierLeaf -> + LeftHandSideOfAssign.StandaloneProperty(expression.name) + + expression is BinaryExpression && expression.operator is Access -> + LeftHandSideOfAssign.ObjectProperty((expression.right as IdentifierLeaf).name) + + else -> error("Unknown type of ${LeftHandSideOfAssign::class.simpleName}") + } + + return createWatchedParameter(rawProvidersOfAssign, assignOperator, leftHandSideOfAssign) } protected fun createWatchedParameter( rawProviders: RawProviders, operator: Operator, - assignableSuffixExpression: KotlinExpression? + leftHandSideOfAssign: LeftHandSideOfAssign? ): AbstractProvider { val funDeclarationProviders = FunDeclarationProvidersFactory .from(rawProviders, operator.overriding.invertedArgumentOrdering) @@ -113,7 +126,7 @@ open class Handler( operator = operator, funDeclarationProviders = funDeclarationProviders, returnTypeNode = translationReturnedTypeNode, - assignableSuffixExpression = assignableSuffixExpression, + leftHandSideOfAssign = leftHandSideOfAssign, rawProviders = rawProviders, ) val watcherLambda = analyzer.currentWatcherLambda ?: watcherLambdaMissingError(operator) diff --git a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/OperatorHandler.kt b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/OperatorHandler.kt index 9f94f30..b131f22 100644 --- a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/OperatorHandler.kt +++ b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/OperatorHandler.kt @@ -3,6 +3,7 @@ package io.kabu.backend.analyzer.handler import com.squareup.kotlinpoet.UNIT import io.kabu.backend.analyzer.Analyzer import io.kabu.backend.analyzer.AnalyzerImpl +import io.kabu.backend.analyzer.handler.lambda.watcher.LeftHandSideOfAssign import io.kabu.backend.diagnostic.diagnosticError import io.kabu.backend.node.factory.node.RegularFunctionNode import io.kabu.backend.node.factory.node.TerminalFunctionNode @@ -62,7 +63,7 @@ class OperatorHandler(analyzer: AnalyzerImpl) : Handler(analyzer) { } if (!operatorCanReturnAnything) { - return createWatchedParameter(rawParameters, expression.operator, assignableSuffixExpression = null) + return createWatchedParameter(rawParameters, expression.operator, leftHandSideOfAssign = null) } if (expression.operator !is Access) { @@ -231,6 +232,6 @@ class OperatorHandler(analyzer: AnalyzerImpl) : Handler(analyzer) { val rawProvidersOfAssign = RawProviders(rawProviders.providersList + assigningParameter, operatorInfoParameter = null) val assignOperator = (expression.parent as BinaryExpression).operator as Assign - return createWatchedParameter(rawProvidersOfAssign, assignOperator, expression) + return createWatchedParameter(rawProvidersOfAssign, assignOperator, LeftHandSideOfAssign.Indexing) } } diff --git a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/CaptureType.kt b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/CaptureType.kt index f15321d..e1e271c 100644 --- a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/CaptureType.kt +++ b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/CaptureType.kt @@ -1,7 +1,6 @@ package io.kabu.backend.analyzer.handler.lambda.watcher import io.kabu.backend.node.TypeNode -import io.kabu.backend.parser.KotlinExpression import io.kabu.backend.parser.Operator import io.kabu.backend.provider.group.FunDeclarationProviders import io.kabu.backend.provider.group.RawProviders @@ -11,7 +10,7 @@ class CaptureType( val operator: Operator, val funDeclarationProviders: FunDeclarationProviders, val returnTypeNode: TypeNode, - // in case of operator==Assign, tells us about actual accessor expression: (Access|Index) - val assignableSuffixExpression: KotlinExpression? = null, //todo get rid of KExpression, use class/enum instead? + val leftHandSideOfAssign: LeftHandSideOfAssign? = null, val rawProviders: RawProviders? = null ) + diff --git a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/LeftHandSideOfAssign.kt b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/LeftHandSideOfAssign.kt new file mode 100644 index 0000000..f62ebcb --- /dev/null +++ b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/LeftHandSideOfAssign.kt @@ -0,0 +1,21 @@ +package io.kabu.backend.analyzer.handler.lambda.watcher + +/** + * Represents information about left hand side of assign operation + */ +sealed class LeftHandSideOfAssign { + /** + * @property name - "x" for assign expression "x = z" + */ + data class StandaloneProperty(val name: String): LeftHandSideOfAssign() + + /** + * @property name - "y" for assign expression "x.y = z" + */ + data class ObjectProperty(val name: String): LeftHandSideOfAssign() + + /** + * "x[y] = z" + */ + data object Indexing : LeftHandSideOfAssign() +} diff --git a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/WatcherLambda.kt b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/WatcherLambda.kt index 856b34c..bdaa785 100644 --- a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/WatcherLambda.kt +++ b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/WatcherLambda.kt @@ -2,7 +2,6 @@ package io.kabu.backend.analyzer.handler.lambda.watcher import io.kabu.backend.node.TypeNode import io.kabu.backend.node.WatcherContextTypeNode -import io.kabu.backend.parser.KotlinExpression import io.kabu.backend.parser.Operator import io.kabu.backend.provider.group.FunDeclarationProviders import io.kabu.backend.util.Constants @@ -25,7 +24,7 @@ class WatcherLambda(val watcherContextTypeNode: WatcherContextTypeNode) { captureType.operator, captureType.funDeclarationProviders, captureType.returnTypeNode, - captureType.assignableSuffixExpression, + captureType.leftHandSideOfAssign, ) captureTypeGroups[group] = mutableListOf() } @@ -48,9 +47,7 @@ class CaptureTypeGroup( val operator: Operator, val funDeclarationProviders: FunDeclarationProviders, val returnTypeNode: TypeNode, //todo revise? -// // in case of operator==Assign, tells us about actual accessor expression: (Access|Index) - val assignableSuffixExpression: KotlinExpression?, -// val rawProviders: RawProviders? = null + val leftHandSideOfAssign: LeftHandSideOfAssign?, ) { fun getBaseNameForDeclarations(): String { diff --git a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/WatcherLambdaHandler.kt b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/WatcherLambdaHandler.kt index 362f54b..f665b5e 100644 --- a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/WatcherLambdaHandler.kt +++ b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/WatcherLambdaHandler.kt @@ -11,13 +11,8 @@ import io.kabu.backend.node.factory.node.AssignablePropertyNode import io.kabu.backend.node.factory.node.DispatcherCallsCounterPropertyNode import io.kabu.backend.node.factory.node.RegularFunctionNode import io.kabu.backend.node.factory.node.util.RegularFunctionNodeKind -import io.kabu.backend.parser.Access import io.kabu.backend.parser.Assign -import io.kabu.backend.parser.BinaryExpression -import io.kabu.backend.parser.IdentifierLeaf -import io.kabu.backend.parser.Indexing import io.kabu.backend.parser.LambdaExpression -import io.kabu.backend.parser.NaryExpression import io.kabu.backend.provider.group.FunDeclarationProvidersFactory import io.kabu.backend.provider.provider.AbstractProvider import io.kabu.backend.provider.provider.ScopingLambdaProvider @@ -72,27 +67,12 @@ class WatcherLambdaHandler(analyzer: AnalyzerImpl) : Handler(analyzer) { captureTypes: MutableList, ) { val operator = group.operator - val assignableSuffixExpression = group.assignableSuffixExpression + val leftHandSideOfAssign = group.leftHandSideOfAssign - when { - operator is Assign && assignableSuffixExpression is IdentifierLeaf -> { - // x = z - handleBinaryAssign(captureTypes) - } - - operator is Assign && (assignableSuffixExpression as? BinaryExpression)?.operator is Access -> { - // x.y = z - handleBinaryAssign(captureTypes) - } - - operator is Assign && (assignableSuffixExpression as? NaryExpression)?.operator is Indexing -> { - // x[y] = z - handleRegularCapture(captureTypes, group) - } - - else -> { - handleRegularCapture(captureTypes, group) - } + if (operator is Assign && leftHandSideOfAssign !is LeftHandSideOfAssign.Indexing) { + handleBinaryAssign(captureTypes) + } else { + handleRegularCapture(captureTypes, group) } } @@ -157,10 +137,10 @@ class WatcherLambdaHandler(analyzer: AnalyzerImpl) : Handler(analyzer) { private fun handleBinaryAssign(captureTypes: List) { val captureType = captureTypes.single() - val name = when (val suffix = captureType.assignableSuffixExpression) { - is IdentifierLeaf -> suffix.name // x = z - is BinaryExpression -> (suffix.right as IdentifierLeaf).name // x.y = z - else -> error("Unknown type of assignableSuffixExpression: $suffix") + val name = when (val leftHandSide = captureType.leftHandSideOfAssign) { + is LeftHandSideOfAssign.StandaloneProperty -> leftHandSide.name + is LeftHandSideOfAssign.ObjectProperty -> leftHandSide.name + else -> error("Unknown type of ${LeftHandSideOfAssign::class.simpleName}: $leftHandSide") } val rawProviders = captureType.rawProviders!! From c99528f01bca01cd7862669d0b9cb48955053f56 Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Sat, 22 Jul 2023 21:46:49 +0600 Subject: [PATCH 23/43] refactoring --- .../lambda/watcher/WatcherLambdaHandler.kt | 3 +-- .../properties/AbstractPropertyDeclaration.kt | 3 +-- ...eTypeAndDerivativeTypeConflictResolver.kt} | 4 +-- .../FixedTypeAndFixedTypeConflictResolver.kt | 10 +++++++ ...peAndFixedTypeUniversalConflictResolver.kt | 24 ----------------- ...=> FunctionAndFunctionConflictResolver.kt} | 2 +- ...edTypeAndGeneratedTypeConflictResolver.kt} | 2 +- ...t => PackageAndPackageConflictResolver.kt} | 2 +- ...=> PropertyAndPropertyConflictResolver.kt} | 2 +- ....kt => TypeAndPropertyConflictResolver.kt} | 2 +- .../resolver/UniversalConflictResolver.kt | 27 ++++++++++--------- .../main/kotlin/io/kabu/backend/node/node.kt | 3 ++- .../provider/provider/ComparisonProvider.kt | 12 ++++----- .../provider/ScopingLambdaProvider.kt | 4 +-- .../provider/WatcherLambdaProvider.kt | 1 - .../planner/parameter/TestProviders.kt | 2 +- .../ksp/diagnostic/builder/ErrorBuilders.kt | 2 +- .../processor/BaseKspFrontendProcessorTest.kt | 13 +++------ ...dByAnnotatedConstructorNotSupportedTest.kt | 2 +- 19 files changed, 50 insertions(+), 70 deletions(-) rename backend/src/main/kotlin/io/kabu/backend/integration/resolver/{DerivativeTypeAndDerivativeTypeNodeConflictResolver.kt => DerivativeTypeAndDerivativeTypeConflictResolver.kt} (74%) create mode 100644 backend/src/main/kotlin/io/kabu/backend/integration/resolver/FixedTypeAndFixedTypeConflictResolver.kt delete mode 100644 backend/src/main/kotlin/io/kabu/backend/integration/resolver/FixedTypeAndFixedTypeUniversalConflictResolver.kt rename backend/src/main/kotlin/io/kabu/backend/integration/resolver/{FunctionAndFunctionUniversalConflictResolver.kt => FunctionAndFunctionConflictResolver.kt} (96%) rename backend/src/main/kotlin/io/kabu/backend/integration/resolver/{GeneratedClassTypeNodeConflictResolver.kt => GeneratedTypeAndGeneratedTypeConflictResolver.kt} (96%) rename backend/src/main/kotlin/io/kabu/backend/integration/resolver/{PackageNodeAndPackageNodeUniversalConflictResolver.kt => PackageAndPackageConflictResolver.kt} (89%) rename backend/src/main/kotlin/io/kabu/backend/integration/resolver/{PropertyAndPropertyUniversalConflictResolver.kt => PropertyAndPropertyConflictResolver.kt} (96%) rename backend/src/main/kotlin/io/kabu/backend/integration/resolver/{TypeAndPropertyUniversalConflictResolver.kt => TypeAndPropertyConflictResolver.kt} (93%) diff --git a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/WatcherLambdaHandler.kt b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/WatcherLambdaHandler.kt index f665b5e..5b1085f 100644 --- a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/WatcherLambdaHandler.kt +++ b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/WatcherLambdaHandler.kt @@ -49,13 +49,12 @@ class WatcherLambdaHandler(analyzer: AnalyzerImpl) : Handler(analyzer) { ScopingLambdaProvider( typeNode = typeNode, returningProvider = returningProvider, - watcherContextTypeNode = watcherContextTypeNode, + contextTypeNode = watcherContextTypeNode, analyzer = analyzer ) } else { WatcherLambdaProvider( typeNode = typeNode, - returnType = returningProvider, watcherContextProvider = WatcherContextProvider(watcherContextTypeNode, returningProvider, analyzer), analyzer = analyzer ) diff --git a/backend/src/main/kotlin/io/kabu/backend/declaration/properties/AbstractPropertyDeclaration.kt b/backend/src/main/kotlin/io/kabu/backend/declaration/properties/AbstractPropertyDeclaration.kt index 4826f03..998e0e6 100644 --- a/backend/src/main/kotlin/io/kabu/backend/declaration/properties/AbstractPropertyDeclaration.kt +++ b/backend/src/main/kotlin/io/kabu/backend/declaration/properties/AbstractPropertyDeclaration.kt @@ -81,8 +81,7 @@ abstract class AbstractPropertyDeclaration : AbstractCallableDeclaration() { val errorMessage = "The property can be used in an assign operation only" getter( FunSpec.getterBuilder() - //todo '\n' is here because of broken KotlinPoet generation - .addCode(CodeBlock.of("throw %T(%S)\n", NotImplementedError::class, errorMessage)) + .addCode(CodeBlock.of("throw %T(%S)", NotImplementedError::class, errorMessage)) .addAnnotation( AnnotationSpec.builder(Deprecated::class) .addMember("\"$errorMessage\", level = DeprecationLevel.ERROR") diff --git a/backend/src/main/kotlin/io/kabu/backend/integration/resolver/DerivativeTypeAndDerivativeTypeNodeConflictResolver.kt b/backend/src/main/kotlin/io/kabu/backend/integration/resolver/DerivativeTypeAndDerivativeTypeConflictResolver.kt similarity index 74% rename from backend/src/main/kotlin/io/kabu/backend/integration/resolver/DerivativeTypeAndDerivativeTypeNodeConflictResolver.kt rename to backend/src/main/kotlin/io/kabu/backend/integration/resolver/DerivativeTypeAndDerivativeTypeConflictResolver.kt index b61f825..a45da9d 100644 --- a/backend/src/main/kotlin/io/kabu/backend/integration/resolver/DerivativeTypeAndDerivativeTypeNodeConflictResolver.kt +++ b/backend/src/main/kotlin/io/kabu/backend/integration/resolver/DerivativeTypeAndDerivativeTypeConflictResolver.kt @@ -7,7 +7,7 @@ import io.kabu.backend.node.Node /** * Resolves conflict when integrating a HolderTypeNode */ -class DerivativeTypeAndDerivativeTypeNodeConflictResolver(private val integrator: Integrator): ConflictResolver { +class DerivativeTypeAndDerivativeTypeConflictResolver(private val integrator: Integrator): ConflictResolver { override fun resolve(node1: Node, node2: Node) { node1 as DerivativeTypeNode; node2 as DerivativeTypeNode @@ -17,6 +17,6 @@ class DerivativeTypeAndDerivativeTypeNodeConflictResolver(private val integrator private fun resolveConflict(node1: DerivativeTypeNode, node2: DerivativeTypeNode) { val current = integrator.notIntegratedOf(node1, node2) - integrator.integrateNode(current) //todo not resolving but coexisting + integrator.integrateNode(current) // not resolving but coexisting } } diff --git a/backend/src/main/kotlin/io/kabu/backend/integration/resolver/FixedTypeAndFixedTypeConflictResolver.kt b/backend/src/main/kotlin/io/kabu/backend/integration/resolver/FixedTypeAndFixedTypeConflictResolver.kt new file mode 100644 index 0000000..cf95110 --- /dev/null +++ b/backend/src/main/kotlin/io/kabu/backend/integration/resolver/FixedTypeAndFixedTypeConflictResolver.kt @@ -0,0 +1,10 @@ +package io.kabu.backend.integration.resolver + +import io.kabu.backend.integration.Integrator +import io.kabu.backend.integration.resolver.common.RewiringConflictResolver + +/** + * Resolves conflict between FixedTypeNode-s + */ +class FixedTypeAndFixedTypeConflictResolver(private val integrator: Integrator) : + RewiringConflictResolver(integrator) diff --git a/backend/src/main/kotlin/io/kabu/backend/integration/resolver/FixedTypeAndFixedTypeUniversalConflictResolver.kt b/backend/src/main/kotlin/io/kabu/backend/integration/resolver/FixedTypeAndFixedTypeUniversalConflictResolver.kt deleted file mode 100644 index 97dba9a..0000000 --- a/backend/src/main/kotlin/io/kabu/backend/integration/resolver/FixedTypeAndFixedTypeUniversalConflictResolver.kt +++ /dev/null @@ -1,24 +0,0 @@ -package io.kabu.backend.integration.resolver - -import io.kabu.backend.integration.Integrator -import io.kabu.backend.node.FixedTypeNode -import io.kabu.backend.node.Node - -/** - * Resolves conflict when integrating a HolderTypeNode - */ -class FixedTypeAndFixedTypeUniversalConflictResolver(private val integrator: Integrator): ConflictResolver { - - override fun resolve(node1: Node, node2: Node) { - node1 as FixedTypeNode; node2 as FixedTypeNode - - resolveConflict(node1, node2) - } - - private fun resolveConflict(node1: FixedTypeNode, node2: FixedTypeNode) { - val current = integrator.notIntegratedOf(node1, node2) - val conflicting = integrator.integratedOf(node1, node2) - - integrator.rewireNodes(current, conflicting) - } -} diff --git a/backend/src/main/kotlin/io/kabu/backend/integration/resolver/FunctionAndFunctionUniversalConflictResolver.kt b/backend/src/main/kotlin/io/kabu/backend/integration/resolver/FunctionAndFunctionConflictResolver.kt similarity index 96% rename from backend/src/main/kotlin/io/kabu/backend/integration/resolver/FunctionAndFunctionUniversalConflictResolver.kt rename to backend/src/main/kotlin/io/kabu/backend/integration/resolver/FunctionAndFunctionConflictResolver.kt index fda9ead..7ebfad5 100644 --- a/backend/src/main/kotlin/io/kabu/backend/integration/resolver/FunctionAndFunctionUniversalConflictResolver.kt +++ b/backend/src/main/kotlin/io/kabu/backend/integration/resolver/FunctionAndFunctionConflictResolver.kt @@ -15,7 +15,7 @@ import io.kabu.backend.util.decaps * Resolves FunctionNode-FunctionNode conflict (both ways) */ @Suppress("UNUSED_PARAMETER") -class FunctionAndFunctionUniversalConflictResolver(private val integrator: Integrator): ConflictResolver { +class FunctionAndFunctionConflictResolver(private val integrator: Integrator): ConflictResolver { override fun resolve(node1: Node, node2: Node) { node1 as FunctionNode diff --git a/backend/src/main/kotlin/io/kabu/backend/integration/resolver/GeneratedClassTypeNodeConflictResolver.kt b/backend/src/main/kotlin/io/kabu/backend/integration/resolver/GeneratedTypeAndGeneratedTypeConflictResolver.kt similarity index 96% rename from backend/src/main/kotlin/io/kabu/backend/integration/resolver/GeneratedClassTypeNodeConflictResolver.kt rename to backend/src/main/kotlin/io/kabu/backend/integration/resolver/GeneratedTypeAndGeneratedTypeConflictResolver.kt index 5ce98d1..1cd63fd 100644 --- a/backend/src/main/kotlin/io/kabu/backend/integration/resolver/GeneratedClassTypeNodeConflictResolver.kt +++ b/backend/src/main/kotlin/io/kabu/backend/integration/resolver/GeneratedTypeAndGeneratedTypeConflictResolver.kt @@ -9,7 +9,7 @@ import io.kabu.backend.node.Node * Resolves GeneratedTypeNode-GeneratedTypeNode conflicts for classes */ //todo introduce GeneratedClassTypeNode and remove children -open class GeneratedClassTypeNodeConflictResolver( +open class GeneratedTypeAndGeneratedTypeConflictResolver( private val integrator: Integrator, ) : ConflictResolver { diff --git a/backend/src/main/kotlin/io/kabu/backend/integration/resolver/PackageNodeAndPackageNodeUniversalConflictResolver.kt b/backend/src/main/kotlin/io/kabu/backend/integration/resolver/PackageAndPackageConflictResolver.kt similarity index 89% rename from backend/src/main/kotlin/io/kabu/backend/integration/resolver/PackageNodeAndPackageNodeUniversalConflictResolver.kt rename to backend/src/main/kotlin/io/kabu/backend/integration/resolver/PackageAndPackageConflictResolver.kt index da4fa6f..9847f19 100644 --- a/backend/src/main/kotlin/io/kabu/backend/integration/resolver/PackageNodeAndPackageNodeUniversalConflictResolver.kt +++ b/backend/src/main/kotlin/io/kabu/backend/integration/resolver/PackageAndPackageConflictResolver.kt @@ -8,7 +8,7 @@ import io.kabu.backend.node.PackageNode * Resolves conflict when integrating a PackageNode */ @Suppress("MaxLineLength") -class PackageNodeAndPackageNodeUniversalConflictResolver(private val integrator: Integrator) : ConflictResolver { +class PackageAndPackageConflictResolver(private val integrator: Integrator) : ConflictResolver { override fun resolve(node1: Node, node2: Node) { node1 as PackageNode; node2 as PackageNode diff --git a/backend/src/main/kotlin/io/kabu/backend/integration/resolver/PropertyAndPropertyUniversalConflictResolver.kt b/backend/src/main/kotlin/io/kabu/backend/integration/resolver/PropertyAndPropertyConflictResolver.kt similarity index 96% rename from backend/src/main/kotlin/io/kabu/backend/integration/resolver/PropertyAndPropertyUniversalConflictResolver.kt rename to backend/src/main/kotlin/io/kabu/backend/integration/resolver/PropertyAndPropertyConflictResolver.kt index 2f1aa7a..c8c52d0 100644 --- a/backend/src/main/kotlin/io/kabu/backend/integration/resolver/PropertyAndPropertyUniversalConflictResolver.kt +++ b/backend/src/main/kotlin/io/kabu/backend/integration/resolver/PropertyAndPropertyConflictResolver.kt @@ -11,7 +11,7 @@ import io.kabu.backend.node.PropertyNode * Resolves PropertyNode-PropertyNode conflict (both ways) */ @Suppress("UNUSED_PARAMETER") -class PropertyAndPropertyUniversalConflictResolver(private val integrator: Integrator): ConflictResolver { +class PropertyAndPropertyConflictResolver(private val integrator: Integrator): ConflictResolver { override fun resolve(node1: Node, node2: Node) { node1 as PropertyNode; node2 as PropertyNode diff --git a/backend/src/main/kotlin/io/kabu/backend/integration/resolver/TypeAndPropertyUniversalConflictResolver.kt b/backend/src/main/kotlin/io/kabu/backend/integration/resolver/TypeAndPropertyConflictResolver.kt similarity index 93% rename from backend/src/main/kotlin/io/kabu/backend/integration/resolver/TypeAndPropertyUniversalConflictResolver.kt rename to backend/src/main/kotlin/io/kabu/backend/integration/resolver/TypeAndPropertyConflictResolver.kt index c434990..66086c3 100644 --- a/backend/src/main/kotlin/io/kabu/backend/integration/resolver/TypeAndPropertyUniversalConflictResolver.kt +++ b/backend/src/main/kotlin/io/kabu/backend/integration/resolver/TypeAndPropertyConflictResolver.kt @@ -11,7 +11,7 @@ import io.kabu.backend.node.TypeNode /** * Resolves TypeNode-PropertyNode conflict (both ways) */ -class TypeAndPropertyUniversalConflictResolver(private val integrator: Integrator) : ConflictResolver { +class TypeAndPropertyConflictResolver(private val integrator: Integrator) : ConflictResolver { override fun resolve(node1: Node, node2: Node) { val typeNode = node1 as TypeNode diff --git a/backend/src/main/kotlin/io/kabu/backend/integration/resolver/UniversalConflictResolver.kt b/backend/src/main/kotlin/io/kabu/backend/integration/resolver/UniversalConflictResolver.kt index 914d091..4cc856a 100644 --- a/backend/src/main/kotlin/io/kabu/backend/integration/resolver/UniversalConflictResolver.kt +++ b/backend/src/main/kotlin/io/kabu/backend/integration/resolver/UniversalConflictResolver.kt @@ -22,22 +22,23 @@ class UniversalConflictResolver(private val integrator: Integrator): ConflictRes @Suppress("MaxLineLength") private val resolvers: Map = mapOf( - Pair(PackageNode::class, PackageNode::class) to ::PackageNodeAndPackageNodeUniversalConflictResolver, - Pair(TypeNode::class, PropertyNode::class) to ::TypeAndPropertyUniversalConflictResolver, - Pair(FunctionNode::class, FunctionNode::class) to ::FunctionAndFunctionUniversalConflictResolver, + Pair(PackageNode::class, PackageNode::class) to ::PackageAndPackageConflictResolver, + Pair(TypeNode::class, PropertyNode::class) to ::TypeAndPropertyConflictResolver, + Pair(FunctionNode::class, FunctionNode::class) to ::FunctionAndFunctionConflictResolver, // generated classes - Pair(ContextMediatorTypeNode::class, ContextMediatorTypeNode::class) to ::GeneratedClassTypeNodeConflictResolver, - Pair(ContextMediatorTypeNode::class, HolderTypeNode::class) to ::GeneratedClassTypeNodeConflictResolver, - Pair(ContextMediatorTypeNode::class, WatcherContextTypeNode::class) to ::GeneratedClassTypeNodeConflictResolver, - Pair(HolderTypeNode::class, HolderTypeNode::class) to ::GeneratedClassTypeNodeConflictResolver, - Pair(HolderTypeNode::class, WatcherContextTypeNode::class) to ::GeneratedClassTypeNodeConflictResolver, - Pair(WatcherContextTypeNode::class, WatcherContextTypeNode::class) to ::GeneratedClassTypeNodeConflictResolver, - - Pair(PropertyNode::class, PropertyNode::class) to ::PropertyAndPropertyUniversalConflictResolver, + Pair(ContextMediatorTypeNode::class, ContextMediatorTypeNode::class) to ::GeneratedTypeAndGeneratedTypeConflictResolver, + Pair(ContextMediatorTypeNode::class, HolderTypeNode::class) to ::GeneratedTypeAndGeneratedTypeConflictResolver, + Pair(ContextMediatorTypeNode::class, WatcherContextTypeNode::class) to ::GeneratedTypeAndGeneratedTypeConflictResolver, + Pair(HolderTypeNode::class, HolderTypeNode::class) to ::GeneratedTypeAndGeneratedTypeConflictResolver, + Pair(HolderTypeNode::class, WatcherContextTypeNode::class) to ::GeneratedTypeAndGeneratedTypeConflictResolver, + Pair(WatcherContextTypeNode::class, WatcherContextTypeNode::class) to ::GeneratedTypeAndGeneratedTypeConflictResolver, + + // other + Pair(PropertyNode::class, PropertyNode::class) to ::PropertyAndPropertyConflictResolver, Pair(AccessorObjectTypeNode::class, AccessorObjectTypeNode::class) to ::AccessorObjectAndAccessorObjectConflictResolver, - Pair(FixedTypeNode::class, FixedTypeNode::class) to ::FixedTypeAndFixedTypeUniversalConflictResolver, - Pair(DerivativeTypeNode::class, DerivativeTypeNode::class) to ::DerivativeTypeAndDerivativeTypeNodeConflictResolver, + Pair(FixedTypeNode::class, FixedTypeNode::class) to ::FixedTypeAndFixedTypeConflictResolver, + Pair(DerivativeTypeNode::class, DerivativeTypeNode::class) to ::DerivativeTypeAndDerivativeTypeConflictResolver, ) override fun resolve(node1: Node, node2: Node) { diff --git a/backend/src/main/kotlin/io/kabu/backend/node/node.kt b/backend/src/main/kotlin/io/kabu/backend/node/node.kt index 04dca0b..dc0a483 100644 --- a/backend/src/main/kotlin/io/kabu/backend/node/node.kt +++ b/backend/src/main/kotlin/io/kabu/backend/node/node.kt @@ -88,7 +88,8 @@ class FixedTypeNode( } override fun toString(): String { - return "${className()}: ${namespaceRecursiveName()}/$name" + val namespacePart = namespaceRecursiveName()?.let { "$it/" }.orEmpty() + return "${className()}: $namespacePart$name" } init { diff --git a/backend/src/main/kotlin/io/kabu/backend/provider/provider/ComparisonProvider.kt b/backend/src/main/kotlin/io/kabu/backend/provider/provider/ComparisonProvider.kt index ea2215f..0ac464c 100644 --- a/backend/src/main/kotlin/io/kabu/backend/provider/provider/ComparisonProvider.kt +++ b/backend/src/main/kotlin/io/kabu/backend/provider/provider/ComparisonProvider.kt @@ -20,15 +20,15 @@ class ComparisonProvider( val code = buildString { append("$auxName.let{aux->") - val providerInfoProvider = providers.single { it is OperatorInfoProvider } - val providerInfoProviderIndex = providers.indexOf(providerInfoProvider) + val operatorInfoProvider = providers.single { it is OperatorInfoProvider } + val operatorInfoProviderIndex = providers.indexOf(operatorInfoProvider) for (i in providers.size - 1 downTo 0) { - if (i == providerInfoProviderIndex) continue + if (i == operatorInfoProviderIndex) continue append("val v$i=$STACK_PROPERTY_NAME.pop() as ${providers[i].type};") } - append("val v$providerInfoProviderIndex=") - when (providerInfoProvider.type) { + append("val v$operatorInfoProviderIndex=") + when (val type = operatorInfoProvider.type) { RANKING_COMPARISON_INFO_TYPE -> { append("if(aux)RankingComparisonInfo.GREATER else RankingComparisonInfo.LESS;") } @@ -37,7 +37,7 @@ class ComparisonProvider( append("if(aux)StrictnessComparisonInfo.RELAXED else StrictnessComparisonInfo.STRICT;") } - else -> TODO() + else -> error("Unknown operator info type: $type") } append("$holderClassCanonicalName(") val holderArguments = List(providers.size) { index -> "v$index" }.joinToString(",") diff --git a/backend/src/main/kotlin/io/kabu/backend/provider/provider/ScopingLambdaProvider.kt b/backend/src/main/kotlin/io/kabu/backend/provider/provider/ScopingLambdaProvider.kt index 2f62c9c..9f78c35 100644 --- a/backend/src/main/kotlin/io/kabu/backend/provider/provider/ScopingLambdaProvider.kt +++ b/backend/src/main/kotlin/io/kabu/backend/provider/provider/ScopingLambdaProvider.kt @@ -11,7 +11,7 @@ import io.kabu.backend.util.poet.asCodeBlock class ScopingLambdaProvider( typeNode: TypeNode, returningProvider: Provider, - val watcherContextTypeNode: TypeNode, //todo watcher VS scoping + val contextTypeNode: TypeNode, analyzer: Analyzer, origin: Origin? = null, ) : LambdaProvider(typeNode, returningProvider, analyzer, origin) { @@ -23,7 +23,7 @@ class ScopingLambdaProvider( ): RetrievalWay? { if (provider !== returningProvider) return null - val contextClassName = (watcherContextTypeNode.typeName as ClassName).canonicalName + val contextClassName = (contextTypeNode.typeName as ClassName).canonicalName return RetrievalWay("with($contextClassName()){${selfName!!}()}".asCodeBlock(), isReentrant = false) } } diff --git a/backend/src/main/kotlin/io/kabu/backend/provider/provider/WatcherLambdaProvider.kt b/backend/src/main/kotlin/io/kabu/backend/provider/provider/WatcherLambdaProvider.kt index b8331f0..c1bad35 100644 --- a/backend/src/main/kotlin/io/kabu/backend/provider/provider/WatcherLambdaProvider.kt +++ b/backend/src/main/kotlin/io/kabu/backend/provider/provider/WatcherLambdaProvider.kt @@ -12,7 +12,6 @@ import io.kabu.backend.util.poet.asCodeBlock class WatcherLambdaProvider( typeNode: TypeNode, - val returnType: Provider, //todo unused? val watcherContextProvider: WatcherContextProvider, val analyzer: Analyzer, origin: Origin? = null, diff --git a/backend/src/test/kotlin/io/kabu/backend/planner/parameter/TestProviders.kt b/backend/src/test/kotlin/io/kabu/backend/planner/parameter/TestProviders.kt index e037de1..c9df3c0 100644 --- a/backend/src/test/kotlin/io/kabu/backend/planner/parameter/TestProviders.kt +++ b/backend/src/test/kotlin/io/kabu/backend/planner/parameter/TestProviders.kt @@ -19,7 +19,7 @@ interface TestProvider : Provider { @Suppress("UNUSED_PARAMETER") override var typeNode: TypeNode - get() = TODO("Not yet implemented") + get() = error("Not implemented") set(value) {} override fun getReplacementWay(context: FunctionBlockContext, forName: String): ReplacementProviderWithCode? { diff --git a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/diagnostic/builder/ErrorBuilders.kt b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/diagnostic/builder/ErrorBuilders.kt index dc2dd3c..761e1d0 100644 --- a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/diagnostic/builder/ErrorBuilders.kt +++ b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/diagnostic/builder/ErrorBuilders.kt @@ -6,7 +6,7 @@ import io.kabu.backend.exception.PatternProcessingException internal fun unexpectedLocalPatternError(origin: Origin, parentOrigin: Origin?): Nothing { diagnosticError( - "LocalPattern methods must be enclosed in a class/interface/object", //todo object? + "LocalPattern methods must be enclosed in a class/interface", origin, parentOrigin ) } diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/BaseKspFrontendProcessorTest.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/BaseKspFrontendProcessorTest.kt index e2718d5..ea4a1a8 100644 --- a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/BaseKspFrontendProcessorTest.kt +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/BaseKspFrontendProcessorTest.kt @@ -166,8 +166,6 @@ open class BaseKspFrontendProcessorTest { logger.debug { "Running script for '$sampleScript'" } val projectRoot = "../../../" val mainKtsLib = "${projectRoot}frontend/ksp/testing/lib/kotlin-main-kts-1.9.0.jar" -// val runtimeClassFiles = "${projectRoot}runtime/build/libs/runtime-1.0-SNAPSHOT.jar" -// val annotationClassFiles = "${projectRoot}annotation/build/libs/annotation-1.0-SNAPSHOT.jar" val runtimeClassFiles = "${projectRoot}runtime/build/classes/kotlin/main" val annotationClassFiles = "${projectRoot}annotation/build/classes/kotlin/main" val classFiles = "${projectRoot}frontend/ksp/processor/build/ksptesting/classes" @@ -175,18 +173,15 @@ open class BaseKspFrontendProcessorTest { val file = File.createTempFile("sample", ".main.kts").apply { writeText(KOTLIN_TEST_FILE_PREFIX + sampleScript + KOTLIN_TEST_FILE_SUFFIX) } - val process = ProcessBuilder("kotlin", "-cp", classpath, file.absolutePath).apply { -// redirectOutput(Redirect.INHERIT) -// redirectError(Redirect.INHERIT) - }.start() - if (process.waitFor() != 0) { + val process = ProcessBuilder("kotlin", "-cp", classpath, file.absolutePath).start() + return if (process.waitFor() != 0) { val errOutput = process.errorStream.bufferedReader().readText() System.err.println(errOutput) - return "" + "" } else { val processOutput = process.inputStream.bufferedReader().readText() System.out.println(processOutput) - return processOutput + processOutput } } diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/unsupported/ContextClassFoundByAnnotatedConstructorNotSupportedTest.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/unsupported/ContextClassFoundByAnnotatedConstructorNotSupportedTest.kt index c698823..737e1c9 100644 --- a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/unsupported/ContextClassFoundByAnnotatedConstructorNotSupportedTest.kt +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/unsupported/ContextClassFoundByAnnotatedConstructorNotSupportedTest.kt @@ -9,7 +9,7 @@ import org.junit.Test */ class ContextClassFoundByAnnotatedConstructorNotSupportedTest : BaseKspFrontendProcessorTest() { - private val role = "Context" //todo role = "Context created by constructor" + private val role = "Context" // KIND From 491a0e95dc682372eea3e38b7199b686130583ba Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Sat, 22 Jul 2023 23:36:12 +0600 Subject: [PATCH 24/43] removed useless comments --- .../io/kabu/backend/integration/render/GraphVisualizer.kt | 1 - .../io/kabu/backend/provider/provider/EmptyProvider.kt | 3 --- .../backend/provider/provider/WatcherContextProvider.kt | 3 --- backend/src/main/kotlin/io/kabu/backend/util/JsonUtils.kt | 6 ------ backend/src/test/kotlin/io/kabu/backend/r2c/JsonUtils.kt | 6 ------ .../src/test/kotlin/io/kabu/backend/r2c/scripting/host.kt | 6 +++--- .../io/kabu/frontend/ksp/processor/KspFrontendProcessor.kt | 3 +-- .../io/kabu/frontend/ksp/processor/supported/SingleTest.kt | 3 +-- 8 files changed, 5 insertions(+), 26 deletions(-) diff --git a/backend/src/main/kotlin/io/kabu/backend/integration/render/GraphVisualizer.kt b/backend/src/main/kotlin/io/kabu/backend/integration/render/GraphVisualizer.kt index c4d1fd2..1346b9f 100644 --- a/backend/src/main/kotlin/io/kabu/backend/integration/render/GraphVisualizer.kt +++ b/backend/src/main/kotlin/io/kabu/backend/integration/render/GraphVisualizer.kt @@ -36,7 +36,6 @@ class GraphVisualizer { if (styling) { appendLine("direction BT") } -// appendLine("%%{init: {\"flowchart\": {\"defaultRenderer\": \"elk\"}} }%%") if (title != null) { appendLine("___TITLE___[[${fixPaddings(title)}]]") diff --git a/backend/src/main/kotlin/io/kabu/backend/provider/provider/EmptyProvider.kt b/backend/src/main/kotlin/io/kabu/backend/provider/provider/EmptyProvider.kt index 1e633a3..2364f5b 100644 --- a/backend/src/main/kotlin/io/kabu/backend/provider/provider/EmptyProvider.kt +++ b/backend/src/main/kotlin/io/kabu/backend/provider/provider/EmptyProvider.kt @@ -17,7 +17,4 @@ class EmptyProvider( override fun generateName(): String { return typeNode.name.decaps() } - -// override fun getEvaluationRequirement(): Provider.EvaluationRequirement = -// Provider.EvaluationRequirement.MANDATORY //todo rethink to evaluate "empty lambdas" and not pass them } diff --git a/backend/src/main/kotlin/io/kabu/backend/provider/provider/WatcherContextProvider.kt b/backend/src/main/kotlin/io/kabu/backend/provider/provider/WatcherContextProvider.kt index 480bf67..d262ece 100644 --- a/backend/src/main/kotlin/io/kabu/backend/provider/provider/WatcherContextProvider.kt +++ b/backend/src/main/kotlin/io/kabu/backend/provider/provider/WatcherContextProvider.kt @@ -29,9 +29,6 @@ class WatcherContextProvider( ): RetrievalWay? { if (provider !== childProvider) return null -// val privateFieldName = fields[provider] -// val code = FieldAccessCodeGenerator(analyzer).generateFieldAccessorCode(selfName!!, privateFieldName) - val code = "(${selfName!!}.stack.pop() as ${provider.type})" return RetrievalWay(CodeBlock.of(code), isReentrant = false) } diff --git a/backend/src/main/kotlin/io/kabu/backend/util/JsonUtils.kt b/backend/src/main/kotlin/io/kabu/backend/util/JsonUtils.kt index 60f9b24..6303576 100644 --- a/backend/src/main/kotlin/io/kabu/backend/util/JsonUtils.kt +++ b/backend/src/main/kotlin/io/kabu/backend/util/JsonUtils.kt @@ -16,12 +16,6 @@ private val objectMapper: ObjectMapper by lazy { ObjectMapper() .registerModule(KotlinModule()) .setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY) -// .setSerializationInclusion(JsonInclude.Include.NON_NULL) -// .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) -// .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) -// .registerModule(KotlinModule()) -// .registerModule(JsonOrgModule()) - } private val objectWriter by lazy { diff --git a/backend/src/test/kotlin/io/kabu/backend/r2c/JsonUtils.kt b/backend/src/test/kotlin/io/kabu/backend/r2c/JsonUtils.kt index bffb418..7fad861 100644 --- a/backend/src/test/kotlin/io/kabu/backend/r2c/JsonUtils.kt +++ b/backend/src/test/kotlin/io/kabu/backend/r2c/JsonUtils.kt @@ -16,12 +16,6 @@ private val objectMapper: ObjectMapper by lazy { ObjectMapper() .registerModule(KotlinModule()) .setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY) -// .setSerializationInclusion(JsonInclude.Include.NON_NULL) -// .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) -// .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) -// .registerModule(KotlinModule()) -// .registerModule(JsonOrgModule()) - } private val objectWriter by lazy { diff --git a/backend/src/test/kotlin/io/kabu/backend/r2c/scripting/host.kt b/backend/src/test/kotlin/io/kabu/backend/r2c/scripting/host.kt index 2700215..e86ae92 100644 --- a/backend/src/test/kotlin/io/kabu/backend/r2c/scripting/host.kt +++ b/backend/src/test/kotlin/io/kabu/backend/r2c/scripting/host.kt @@ -43,12 +43,12 @@ private fun scriptCompilationConfiguration(): ScriptCompilationConfiguration = "annotation", ) // variant 2: try to extract current classpath and use it for the compilation without filtering -// dependenciesFromCurrentContext(wholeClasspath = true) + //dependenciesFromCurrentContext(wholeClasspath = true) // variant 3: try to extract a classpath from a particular classloader (or Thread.contextClassLoader by default) // filtering as in the variant 1 is supported too -// dependenciesFromClassloader(classLoader = SimpleScript::class.java.classLoader, wholeClasspath = true) + //dependenciesFromClassloader(classLoader = SimpleScript::class.java.classLoader, wholeClasspath = true) // variant 4: explicit classpath -// updateClasspath(listOf(File("/path/to/jar"))) + //updateClasspath(listOf(File("/path/to/jar"))) } compilerOptions.append("-language-version=1.8", "-opt-in=kotlin.ExperimentalStdlibApi") } diff --git a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/KspFrontendProcessor.kt b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/KspFrontendProcessor.kt index 9353c45..e16a90e 100755 --- a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/KspFrontendProcessor.kt +++ b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/KspFrontendProcessor.kt @@ -11,8 +11,8 @@ import com.google.devtools.ksp.symbol.KSClassDeclaration import com.google.devtools.ksp.symbol.KSFunctionDeclaration import io.kabu.annotation.Context import io.kabu.annotation.ContextCreator -import io.kabu.annotation.Pattern import io.kabu.annotation.LocalPattern +import io.kabu.annotation.Pattern import io.kabu.backend.common.log.InterceptingLogging import io.kabu.backend.common.log.LogSink import io.kabu.backend.diagnostic.Diagnostic @@ -153,7 +153,6 @@ class KspFrontendProcessor( class KspFrontendProcessorProvider : SymbolProcessorProvider { override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor { -// environment.logger.warn("Creating a processor") return KspFrontendProcessor(environment.codeGenerator, environment.options, environment.logger) } } diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/supported/SingleTest.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/supported/SingleTest.kt index 9613108..bfe7917 100644 --- a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/supported/SingleTest.kt +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/supported/SingleTest.kt @@ -11,8 +11,7 @@ class SingleTest : BaseKspFrontendProcessorTest() { """ class A -// @Pattern("!par") // temp - ok, notemp - ok - @Pattern("foo + par") //todo temp - error, notemp - ok + @Pattern("foo + par") fun f(par: A){ } From a15d3ce6fe710ef60a2b60a417b38831c9ebf05d Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Sat, 22 Jul 2023 23:39:17 +0600 Subject: [PATCH 25/43] refactoring --- .../lambda/watcher/CaptureTypeGroup.kt | 30 +++++++++++++++++++ .../handler/lambda/watcher/WatcherLambda.kt | 28 ----------------- .../AbstractCallableDeclaration.kt | 4 +-- .../provider/evaluation/EvaluationHelper.kt | 2 +- .../evaluation/FunctionBlockContext.kt | 6 ++-- 5 files changed, 35 insertions(+), 35 deletions(-) create mode 100644 backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/CaptureTypeGroup.kt diff --git a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/CaptureTypeGroup.kt b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/CaptureTypeGroup.kt new file mode 100644 index 0000000..476e0be --- /dev/null +++ b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/CaptureTypeGroup.kt @@ -0,0 +1,30 @@ +package io.kabu.backend.analyzer.handler.lambda.watcher + +import io.kabu.backend.node.TypeNode +import io.kabu.backend.parser.Operator +import io.kabu.backend.provider.group.FunDeclarationProviders +import io.kabu.backend.util.Constants + +class CaptureTypeGroup( + val operator: Operator, + val funDeclarationProviders: FunDeclarationProviders, + val returnTypeNode: TypeNode, //todo revise? + val leftHandSideOfAssign: LeftHandSideOfAssign?, +) { + + fun getBaseNameForDeclarations(): String { + val namePart = operator.overriding.function ?: "func" + val argsPart = buildString { + funDeclarationProviders.providersList.forEach { + append(it.type.toString().replace(illegalKotlinIdentifierSymbol, "_")) + append("_") + } + } + val projectPart = Constants.PROJECT_BASE_PACKAGE.replace(".", "_") + return listOf(projectPart, namePart, argsPart).joinToString("__") + } + + private companion object { + val illegalKotlinIdentifierSymbol = Regex("[^A-Za-z0-9_]") + } +} diff --git a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/WatcherLambda.kt b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/WatcherLambda.kt index bdaa785..3dc4381 100644 --- a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/WatcherLambda.kt +++ b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/WatcherLambda.kt @@ -1,10 +1,6 @@ package io.kabu.backend.analyzer.handler.lambda.watcher -import io.kabu.backend.node.TypeNode import io.kabu.backend.node.WatcherContextTypeNode -import io.kabu.backend.parser.Operator -import io.kabu.backend.provider.group.FunDeclarationProviders -import io.kabu.backend.util.Constants class WatcherLambda(val watcherContextTypeNode: WatcherContextTypeNode) { @@ -42,27 +38,3 @@ class WatcherLambda(val watcherContextTypeNode: WatcherContextTypeNode) { captureType.operator.overriding.function == group.operator.overriding.function } } - -class CaptureTypeGroup( - val operator: Operator, - val funDeclarationProviders: FunDeclarationProviders, - val returnTypeNode: TypeNode, //todo revise? - val leftHandSideOfAssign: LeftHandSideOfAssign?, -) { - - fun getBaseNameForDeclarations(): String { - val namePart = operator.overriding.function ?: "func" - val argsPart = buildString { - funDeclarationProviders.providersList.forEach { - append(it.type.toString().replace(illegalKotlinIdentifierSymbol, "_")) - append("_") - } - } - val projectPart = Constants.PROJECT_BASE_PACKAGE.replace(".", "_") - return listOf(projectPart, namePart, argsPart).joinToString("__") - } - - private companion object { - val illegalKotlinIdentifierSymbol = Regex("[^A-Za-z0-9_]") - } -} diff --git a/backend/src/main/kotlin/io/kabu/backend/declaration/AbstractCallableDeclaration.kt b/backend/src/main/kotlin/io/kabu/backend/declaration/AbstractCallableDeclaration.kt index 6bcbe12..634085b 100644 --- a/backend/src/main/kotlin/io/kabu/backend/declaration/AbstractCallableDeclaration.kt +++ b/backend/src/main/kotlin/io/kabu/backend/declaration/AbstractCallableDeclaration.kt @@ -50,7 +50,7 @@ abstract class AbstractCallableDeclaration : Declaration() { val statements1 = functionBlockContext.joinAllStatements() val statements2 = run { val allParameters = functionBlockContext.actualProvidersProvider.childrenProviders - .joinToString { functionBlockContext.getCodeForActualProvider(it) } + .joinToString { functionBlockContext.getCodeForProvider(it) } "return %T($allParameters)" } @@ -72,7 +72,7 @@ abstract class AbstractCallableDeclaration : Declaration() { // saving val actualValues = functionBlockContext.actualProvidersProvider.childrenProviders - .map { functionBlockContext.getCodeForActualProvider(it) } + .map { functionBlockContext.getCodeForProvider(it) } val statements2 = actualValues.joinToString(";") { "$STACK_PROPERTY_NAME.push($it)" } // returning necessary value diff --git a/backend/src/main/kotlin/io/kabu/backend/provider/evaluation/EvaluationHelper.kt b/backend/src/main/kotlin/io/kabu/backend/provider/evaluation/EvaluationHelper.kt index cca9872..8d42103 100644 --- a/backend/src/main/kotlin/io/kabu/backend/provider/evaluation/EvaluationHelper.kt +++ b/backend/src/main/kotlin/io/kabu/backend/provider/evaluation/EvaluationHelper.kt @@ -65,7 +65,7 @@ object EvaluationHelper { provider: Provider, ): ProviderInfo? { var evaluationStatements: String? = null - var providerName = functionBlockContext.getCodeForActualProvider(provider) + var providerName = functionBlockContext.getCodeForProvider(provider) var replacementProvider = provider val replacementWay = provider.getReplacementWay(context = functionBlockContext, providerName) diff --git a/backend/src/main/kotlin/io/kabu/backend/provider/evaluation/FunctionBlockContext.kt b/backend/src/main/kotlin/io/kabu/backend/provider/evaluation/FunctionBlockContext.kt index 3bc284d..cb3523d 100644 --- a/backend/src/main/kotlin/io/kabu/backend/provider/evaluation/FunctionBlockContext.kt +++ b/backend/src/main/kotlin/io/kabu/backend/provider/evaluation/FunctionBlockContext.kt @@ -34,12 +34,10 @@ class FunctionBlockContext( fun registerActualProvider(provider: Provider, name: String, statements: List) { _allStatements += statements actualProviders.register(provider, name) - //todo mb losing non-actual providers names in allProviders... allProviders.register(provider, name) } - //todo rn getCodeForProvider - fun getCodeForActualProvider(provider: Provider): String { + fun getCodeForProvider(provider: Provider): String { return actualProvidersProvider .getChildRetrievalWay(selfName = null, provider, actualProvidersProvider)!!.codeBlock.toString() } @@ -76,7 +74,7 @@ class FunctionBlockContext( private fun getReplacement(provider: Provider): Replacement { val name = nextVarName() - val code = getCodeForActualProvider(provider) + val code = getCodeForProvider(provider) val statements = "val $name = $code" return Replacement(provider, name, statements) } From 9ea0de37251dae9f0a3a5d0d5bc5a1d38cfb1d2d Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Sun, 23 Jul 2023 01:49:17 +0600 Subject: [PATCH 26/43] implemented lambda label parsing (added tests) --- .../kotlin/io/kabu/backend/parser/KotlinTree.kt | 9 +++++++-- .../kotlin/io/kabu/backend/parser/PatternParser.kt | 13 +++++++------ .../kotlin/io/kabu/backend/ParserSuccessTest.kt | 8 +++++++- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/backend/src/main/kotlin/io/kabu/backend/parser/KotlinTree.kt b/backend/src/main/kotlin/io/kabu/backend/parser/KotlinTree.kt index 1ba592a..89f4f2b 100644 --- a/backend/src/main/kotlin/io/kabu/backend/parser/KotlinTree.kt +++ b/backend/src/main/kotlin/io/kabu/backend/parser/KotlinTree.kt @@ -1,8 +1,8 @@ package io.kabu.backend.parser import io.kabu.backend.diagnostic.HasOrigin -import io.kabu.backend.diagnostic.diagnosticError import io.kabu.backend.diagnostic.Origin +import io.kabu.backend.diagnostic.diagnosticError sealed class KotlinExpression : HasOrigin { @@ -41,11 +41,16 @@ class IdentifierLeaf( class LambdaExpression( val expressions: List, val annotations: List, + val label: String?, override val origin: Origin ) : KotlinExpression() { override var parent: KotlinExpression? = null override val children = expressions - override fun toString() = "(${annotations.let { if (it.isNotEmpty()) "@$it " else "" }}lambda $expressions)" + override fun toString(): String { + val annotationsPart = annotations.let { if (it.isNotEmpty()) "@$it " else "" } + val labelPart = label?.let { "$it@ " }.orEmpty() + return "(${annotationsPart}${labelPart}lambda $expressions)" + } override fun toExcerptsString(): String { val annotationsPart = annotations.let { if (it.isNotEmpty()) "@$it " else "" } //todo annotations excerpts val expressionsPart = expressions.map { it.toExcerptsString() } diff --git a/backend/src/main/kotlin/io/kabu/backend/parser/PatternParser.kt b/backend/src/main/kotlin/io/kabu/backend/parser/PatternParser.kt index 4e4b84f..dc3718b 100644 --- a/backend/src/main/kotlin/io/kabu/backend/parser/PatternParser.kt +++ b/backend/src/main/kotlin/io/kabu/backend/parser/PatternParser.kt @@ -138,11 +138,12 @@ class PatternParser( val annotations = gatherAnnotations(tree.annotation()) val lambdaLiteral = tree.lambdaLiteral() val expressions = visitStatements(lambdaLiteral.statements()) - LambdaExpression(expressions, annotations, originOf(tree)) + val label = tree.label()?.simpleIdentifier()?.Identifier()?.symbol?.text + LambdaExpression(expressions, annotations, label, originOf(tree)) } is LambdaLiteralContext -> { val expressions = visitStatements(tree.statements()) - LambdaExpression(expressions, emptyList(), originOf(tree)) + LambdaExpression(expressions, emptyList(), null, originOf(tree)) } is ParenthesizedExpressionContext -> { visit(tree.expression()) @@ -166,9 +167,9 @@ class PatternParser( it.singleAnnotation()?.unescapedAnnotation()?.let { add(it) } it.multiAnnotation()?.unescapedAnnotation()?.let { addAll(it) } } - }.map { - val userType = it.userType() - val constructorInvocation = it.constructorInvocation() + }.map { annotationContext -> + val userType = annotationContext.userType() + val constructorInvocation = annotationContext.constructorInvocation() when { userType != null -> { val name = identifierTextOf(userType) @@ -186,7 +187,7 @@ class PatternParser( } Annotation(name, arguments) } - else -> error("Annotation has invalid format: ${it.text}") + else -> error("Annotation has invalid format: ${annotationContext.text}") } } } diff --git a/backend/src/test/kotlin/io/kabu/backend/ParserSuccessTest.kt b/backend/src/test/kotlin/io/kabu/backend/ParserSuccessTest.kt index b6929ed..40dfa9c 100644 --- a/backend/src/test/kotlin/io/kabu/backend/ParserSuccessTest.kt +++ b/backend/src/test/kotlin/io/kabu/backend/ParserSuccessTest.kt @@ -4,9 +4,9 @@ import io.kabu.backend.common.log.InterceptingLogging import io.kabu.backend.diagnostic.FileSourceLocation import io.kabu.backend.diagnostic.Origin import io.kabu.backend.diagnostic.builder.patternParsingError +import io.kabu.backend.exception.PatternParsingException import io.kabu.backend.parser.KotlinExpression import io.kabu.backend.parser.PatternParser -import io.kabu.backend.exception.PatternParsingException import io.kabu.backend.parser.PatternString import org.junit.Assert import org.junit.Test @@ -212,6 +212,12 @@ class PatternParserTestParameterized(val raw: String, val parsed: String) : Asse "! @Ann() {}" to "(! (@[Ann()] lambda []))", "xxx yyy @A {}" to "(xxx `yyy` (@[A()] lambda []))", + // lambda label + "xxx yyy label@ {}" to "(xxx `yyy` (label@ lambda []))", + "b @Abc lll@ { }" to "(b call [(@[Abc()] lll@ lambda [])])", + "b @[Abc Def] label1@ { }" to "(b call [(@[Abc(), Def()] label1@ lambda [])])", + "b @Abc @Def label2@ { }" to "(b call [(@[Abc(), Def()] label2@ lambda [])])", + "c" to "c" ).map { arrayOf(it.first, it.second) } } From e95bb7d6ebcfd20807d137c92cc36db0b4eccd66 Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Sun, 23 Jul 2023 01:53:30 +0600 Subject: [PATCH 27/43] refactoring --- .../io/kabu/backend/analyzer/Analyzer.kt | 2 +- .../io/kabu/backend/analyzer/AnalyzerImpl.kt | 3 ++- .../extension/ExtensionLambdaHandler.kt | 21 ------------------- .../AbstractCallableDeclaration.kt | 6 ++++-- .../classes/HolderClassDeclaration.kt | 2 +- .../functions/AbstractFunctionDeclaration.kt | 2 +- .../util/TerminalCallableBuilder.kt | 6 +++--- .../common/RewiringConflictResolver.kt | 2 +- .../main/kotlin/io/kabu/backend/node/node.kt | 1 - .../io/kabu/backend/parser/PatternParser.kt | 2 +- .../backend/processor/BackendProcessor.kt | 2 -- .../kabu/backend/processor/MethodsRegistry.kt | 7 +------ .../provider/render/ProviderTreeRendering.kt | 2 +- .../kabu/backend/util/poet/TypeNameUtils.kt | 4 ++++ .../kabu/backend/planner/AnalyzerAdHocTest.kt | 2 +- .../io/kabu/backend/planner/AnalyzerTest.kt | 2 +- .../detector/BaseConflictDetectorTest.kt | 4 ++-- .../kotlin/io/kabu/backend/plannerx/XTest.kt | 2 +- .../test/kotlin/io/kabu/backend/r2c/Utils.kt | 2 +- doc/img/logo_kabu.svg | 19 ++++++++--------- 20 files changed, 35 insertions(+), 58 deletions(-) diff --git a/backend/src/main/kotlin/io/kabu/backend/analyzer/Analyzer.kt b/backend/src/main/kotlin/io/kabu/backend/analyzer/Analyzer.kt index c87e9da..d455fa3 100644 --- a/backend/src/main/kotlin/io/kabu/backend/analyzer/Analyzer.kt +++ b/backend/src/main/kotlin/io/kabu/backend/analyzer/Analyzer.kt @@ -20,7 +20,7 @@ interface Analyzer { val methodsRegistry: MethodsRegistry - val contextPropertyName: String? + val isLocalPattern: Boolean val namespaceNode: NamespaceNode diff --git a/backend/src/main/kotlin/io/kabu/backend/analyzer/AnalyzerImpl.kt b/backend/src/main/kotlin/io/kabu/backend/analyzer/AnalyzerImpl.kt index 95541a1..cbfa3c7 100644 --- a/backend/src/main/kotlin/io/kabu/backend/analyzer/AnalyzerImpl.kt +++ b/backend/src/main/kotlin/io/kabu/backend/analyzer/AnalyzerImpl.kt @@ -36,7 +36,6 @@ import io.kabu.backend.util.Constants class AnalyzerImpl( override val method: PatternMethod, override val methodsRegistry: MethodsRegistry, - override val contextPropertyName: String?, val options: Options, private val contextMediatorNamespaceNode: NamespaceNode? = null, ) : Analyzer { @@ -56,6 +55,8 @@ class AnalyzerImpl( } catch (e: PatternParsingException) { patternParsingError(e) } + override val isLocalPattern: Boolean + get() = contextMediatorNamespaceNode != null val parametersRegistry = ParametersRegistry(method, expression) diff --git a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/extension/ExtensionLambdaHandler.kt b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/extension/ExtensionLambdaHandler.kt index 896c36c..ac69a84 100644 --- a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/extension/ExtensionLambdaHandler.kt +++ b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/extension/ExtensionLambdaHandler.kt @@ -6,12 +6,9 @@ import io.kabu.backend.analyzer.Analyzer import io.kabu.backend.analyzer.AnalyzerImpl import io.kabu.backend.diagnostic.builder.extensionAnnotationMissingError import io.kabu.backend.diagnostic.builder.unknownFunctionParameterNameError -import io.kabu.backend.inout.input.method.PatternMethod import io.kabu.backend.node.ContextMediatorTypeNode import io.kabu.backend.node.DerivativeTypeNode -import io.kabu.backend.node.namespace.NamespaceNode import io.kabu.backend.parser.LambdaExpression -import io.kabu.backend.processor.MethodsRegistry import io.kabu.backend.provider.provider.ArgumentProvider import io.kabu.backend.provider.provider.ExtensionLambdaProvider import io.kabu.backend.util.Constants.EXTENSION_ANNOTATION @@ -57,22 +54,4 @@ class ExtensionLambdaHandler( analyzer = analyzer, ) } - - private fun analyzeMethod( - method: PatternMethod, - contextMediatorNamespaceNode: NamespaceNode, - methodsRegistry: MethodsRegistry, - contextPropertyName: String? - ) { - val nodes = AnalyzerImpl( - method = method, - methodsRegistry = methodsRegistry, - contextPropertyName = contextPropertyName, - options = analyzer.options, - contextMediatorNamespaceNode = contextMediatorNamespaceNode - ).analyze() - nodes.forEach { - registerNode(it) - } - } } diff --git a/backend/src/main/kotlin/io/kabu/backend/declaration/AbstractCallableDeclaration.kt b/backend/src/main/kotlin/io/kabu/backend/declaration/AbstractCallableDeclaration.kt index 634085b..89af6ef 100644 --- a/backend/src/main/kotlin/io/kabu/backend/declaration/AbstractCallableDeclaration.kt +++ b/backend/src/main/kotlin/io/kabu/backend/declaration/AbstractCallableDeclaration.kt @@ -77,8 +77,10 @@ abstract class AbstractCallableDeclaration : Declaration() { // returning necessary value val statements3 = when (operator.overriding.mustReturn) { - FunctionMustReturn.FREE -> TODO() - FunctionMustReturn.ASSIGNABLE -> TODO() + FunctionMustReturn.FREE, + FunctionMustReturn.ASSIGNABLE, + -> error("Incompatible FunctionMustReturn(${operator.overriding.mustReturn}) for fixed returned type") + FunctionMustReturn.BOOLEAN -> "return true" FunctionMustReturn.INT -> getReturnStatementForComparison(funDeclarationProviders.operatorInfoType) FunctionMustReturn.UNIT -> "" diff --git a/backend/src/main/kotlin/io/kabu/backend/declaration/classes/HolderClassDeclaration.kt b/backend/src/main/kotlin/io/kabu/backend/declaration/classes/HolderClassDeclaration.kt index 461cec9..291eb4d 100644 --- a/backend/src/main/kotlin/io/kabu/backend/declaration/classes/HolderClassDeclaration.kt +++ b/backend/src/main/kotlin/io/kabu/backend/declaration/classes/HolderClassDeclaration.kt @@ -69,7 +69,7 @@ class HolderClassDeclaration( } } - if (accessorClassName != null) { + if (fieldsHidingEnabled) { fields.forEach { addProperty( PropertySpec.builder(it.name, it.typeNode.typeName).apply { diff --git a/backend/src/main/kotlin/io/kabu/backend/declaration/functions/AbstractFunctionDeclaration.kt b/backend/src/main/kotlin/io/kabu/backend/declaration/functions/AbstractFunctionDeclaration.kt index fd83a23..755c27f 100644 --- a/backend/src/main/kotlin/io/kabu/backend/declaration/functions/AbstractFunctionDeclaration.kt +++ b/backend/src/main/kotlin/io/kabu/backend/declaration/functions/AbstractFunctionDeclaration.kt @@ -21,7 +21,7 @@ abstract class AbstractFunctionDeclaration : AbstractCallableDeclaration() { receiverType: TypeName? = null, isInfix: Boolean = false, codeBlock: CodeBlock, - isHelper: Boolean = false, //todo up + isHelper: Boolean = false, ): FunSpec { return FunSpec.builder(name).apply { val typeVariableNames = returnType.gatherTypeVariableNames() + diff --git a/backend/src/main/kotlin/io/kabu/backend/declaration/util/TerminalCallableBuilder.kt b/backend/src/main/kotlin/io/kabu/backend/declaration/util/TerminalCallableBuilder.kt index c3d8c37..05ee65b 100644 --- a/backend/src/main/kotlin/io/kabu/backend/declaration/util/TerminalCallableBuilder.kt +++ b/backend/src/main/kotlin/io/kabu/backend/declaration/util/TerminalCallableBuilder.kt @@ -15,6 +15,7 @@ import io.kabu.backend.provider.provider.ArgumentProvider import io.kabu.backend.provider.provider.Provider import io.kabu.backend.provider.provider.ProviderContainer import io.kabu.backend.provider.render.renderProviderTree +import io.kabu.backend.util.Constants.EXTENSION_CONTEXT_PROPERTY_NAME import io.kabu.backend.util.poet.asCodeBlock @@ -75,14 +76,13 @@ class TerminalCallableBuilder { retrievalWay.codeBlock.toString() //todo ignoring reentrant!!! } - val contextPropertyName = analyzer.contextPropertyName val evaluationStatements = functionBlockContext.joinAllStatements() val method = analyzer.method val methodName = method.name val receiverExists = method.hasReceiver val returningUnit = method.returnedType == UNIT - val terminatingLocalPatternMethod = contextPropertyName != null + val terminatingLocalPatternMethod = analyzer.isLocalPattern if (receiverExists || terminatingLocalPatternMethod) { if (receiverExists == terminatingLocalPatternMethod) { diagnosticError("Member functions with receiver aren't supported", method) @@ -90,7 +90,7 @@ class TerminalCallableBuilder { val (receiver, callParameters) = if (receiverExists) { codes.first() to codes.drop(1) } else { - contextPropertyName to codes + EXTENSION_CONTEXT_PROPERTY_NAME to codes } val names = callParameters.joinToString() return if (returningUnit) { diff --git a/backend/src/main/kotlin/io/kabu/backend/integration/resolver/common/RewiringConflictResolver.kt b/backend/src/main/kotlin/io/kabu/backend/integration/resolver/common/RewiringConflictResolver.kt index 77f9104..c2cb128 100644 --- a/backend/src/main/kotlin/io/kabu/backend/integration/resolver/common/RewiringConflictResolver.kt +++ b/backend/src/main/kotlin/io/kabu/backend/integration/resolver/common/RewiringConflictResolver.kt @@ -7,7 +7,7 @@ import io.kabu.backend.node.Node /** * Resolves conflict by rewiring nodes (swap current node with already integrated). */ -open class RewiringConflictResolver(private val integrator: Integrator): ConflictResolver { //todo find duplicates +open class RewiringConflictResolver(private val integrator: Integrator): ConflictResolver { override fun resolve(node1: Node, node2: Node) { val current = integrator.notIntegratedOf(node1, node2) diff --git a/backend/src/main/kotlin/io/kabu/backend/node/node.kt b/backend/src/main/kotlin/io/kabu/backend/node/node.kt index dc0a483..2b40049 100644 --- a/backend/src/main/kotlin/io/kabu/backend/node/node.kt +++ b/backend/src/main/kotlin/io/kabu/backend/node/node.kt @@ -156,7 +156,6 @@ open class ObjectTypeNode( val className: ClassName get() = namespaceNode!!.composeClassName(name) - //todo className vs typeName override val typeName: TypeName get() = className diff --git a/backend/src/main/kotlin/io/kabu/backend/parser/PatternParser.kt b/backend/src/main/kotlin/io/kabu/backend/parser/PatternParser.kt index dc3718b..e7c95c1 100644 --- a/backend/src/main/kotlin/io/kabu/backend/parser/PatternParser.kt +++ b/backend/src/main/kotlin/io/kabu/backend/parser/PatternParser.kt @@ -125,7 +125,7 @@ class PatternParser( getLeftAssociativeTreeOfOperationList(tree, { comparison(it) }, { equalityOperator(it) }) } is AssignmentContext -> { - require(tree.childCount == 3) //todo can be many of them + require(tree.childCount == 3) val operator = visitBinaryOperator(tree.getChild(1)) val left = visit(tree.assignableExpression() ?: tree.directlyAssignableExpression()) val right = visit(tree.expression()) diff --git a/backend/src/main/kotlin/io/kabu/backend/processor/BackendProcessor.kt b/backend/src/main/kotlin/io/kabu/backend/processor/BackendProcessor.kt index f9d4a05..d1ca96d 100644 --- a/backend/src/main/kotlin/io/kabu/backend/processor/BackendProcessor.kt +++ b/backend/src/main/kotlin/io/kabu/backend/processor/BackendProcessor.kt @@ -117,7 +117,6 @@ class BackendProcessor(private val options: Options = Options.DEFAULT) { return AnalyzerImpl( method = method, methodsRegistry = methodsRegistry, - contextPropertyName = Constants.EXTENSION_CONTEXT_PROPERTY_NAME, //todo rm options = options, contextMediatorNamespaceNode = contextMediatorTypeNode //todo inconsistency in names ).analyze() @@ -131,7 +130,6 @@ class BackendProcessor(private val options: Options = Options.DEFAULT) { return AnalyzerImpl( method = method, methodsRegistry = methodsRegistry, - contextPropertyName = null, options = options ).analyze() } diff --git a/backend/src/main/kotlin/io/kabu/backend/processor/MethodsRegistry.kt b/backend/src/main/kotlin/io/kabu/backend/processor/MethodsRegistry.kt index f833753..018012f 100644 --- a/backend/src/main/kotlin/io/kabu/backend/processor/MethodsRegistry.kt +++ b/backend/src/main/kotlin/io/kabu/backend/processor/MethodsRegistry.kt @@ -7,6 +7,7 @@ import io.kabu.backend.inout.input.ProcessingInput import io.kabu.backend.inout.input.method.ContextCreatorMethod import io.kabu.backend.inout.input.method.LocalPatternMethod import io.kabu.backend.node.TypeNode +import io.kabu.backend.util.poet.TypeNameUtils.isAssignableTo class MethodsRegistry(processingInput: ProcessingInput? = null) { @@ -96,10 +97,4 @@ class MethodsRegistry(processingInput: ProcessingInput? = null) { ): Map> { return localPatternMethods.groupBy { it.declaringType } } - -} - -//todo move to TypeName utils? -internal infix fun TypeName.isAssignableTo(other: TypeName): Boolean { - return this == other // todo consider inheritance } diff --git a/backend/src/main/kotlin/io/kabu/backend/provider/render/ProviderTreeRendering.kt b/backend/src/main/kotlin/io/kabu/backend/provider/render/ProviderTreeRendering.kt index 44a559e..387fea8 100644 --- a/backend/src/main/kotlin/io/kabu/backend/provider/render/ProviderTreeRendering.kt +++ b/backend/src/main/kotlin/io/kabu/backend/provider/render/ProviderTreeRendering.kt @@ -51,7 +51,7 @@ private fun Provider.toNode(): Node = object : Node { is ArgumentProvider -> "Identifier (${provider.originalName})" is EmptyProvider -> "Empty" is AuxProvider -> "Aux" - else -> TODO() + else -> error("Unknown provider type: $provider") } override fun getChildren(): List = this@toNode.childrenProviders.map(Provider::toNode) diff --git a/backend/src/main/kotlin/io/kabu/backend/util/poet/TypeNameUtils.kt b/backend/src/main/kotlin/io/kabu/backend/util/poet/TypeNameUtils.kt index ee9b586..3aade30 100644 --- a/backend/src/main/kotlin/io/kabu/backend/util/poet/TypeNameUtils.kt +++ b/backend/src/main/kotlin/io/kabu/backend/util/poet/TypeNameUtils.kt @@ -28,6 +28,10 @@ object TypeNameUtils { return base.replace(packageNamesRegex, "") } + infix fun TypeName.isAssignableTo(other: TypeName): Boolean { + return this == other // todo consider inheritance + } + private val packageNamesRegex = Regex("\\w+\\.") } diff --git a/backend/src/test/kotlin/io/kabu/backend/planner/AnalyzerAdHocTest.kt b/backend/src/test/kotlin/io/kabu/backend/planner/AnalyzerAdHocTest.kt index 0719baf..cf7f5e7 100644 --- a/backend/src/test/kotlin/io/kabu/backend/planner/AnalyzerAdHocTest.kt +++ b/backend/src/test/kotlin/io/kabu/backend/planner/AnalyzerAdHocTest.kt @@ -45,7 +45,7 @@ class AnalyzerAdHocTest : Assert() { origin = Origin() ) val options = Options.DEFAULT.copy(hideInternalProperties = false, accessorObjectIsInSamePackage = true) - val nodes = AnalyzerImpl(method, MethodsRegistry(), null, options).analyze() + val nodes = AnalyzerImpl(method, MethodsRegistry(), options).analyze() val integrated = Integrator().apply { integrate(nodes) }.integrated val codeForPackage = Generator(testMode = true).getCodeForPackage(integrated, method.packageName) SimpleFileWriter(TEST_GENERATED_DIR).writeFile(method.packageName, filename, codeForPackage) diff --git a/backend/src/test/kotlin/io/kabu/backend/planner/AnalyzerTest.kt b/backend/src/test/kotlin/io/kabu/backend/planner/AnalyzerTest.kt index b88baab..e490521 100644 --- a/backend/src/test/kotlin/io/kabu/backend/planner/AnalyzerTest.kt +++ b/backend/src/test/kotlin/io/kabu/backend/planner/AnalyzerTest.kt @@ -104,5 +104,5 @@ private fun getPlanForPatternWithSignature(patternWithSignature: PatternWithSign hideInternalProperties = false, accessorObjectIsInSamePackage = true, ) - return AnalyzerImpl(method, MethodsRegistry(), null, options).analyze() + return AnalyzerImpl(method, MethodsRegistry(), options).analyze() } diff --git a/backend/src/test/kotlin/io/kabu/backend/planner/namespace/conflict/detector/BaseConflictDetectorTest.kt b/backend/src/test/kotlin/io/kabu/backend/planner/namespace/conflict/detector/BaseConflictDetectorTest.kt index db38f51..fa21af6 100644 --- a/backend/src/test/kotlin/io/kabu/backend/planner/namespace/conflict/detector/BaseConflictDetectorTest.kt +++ b/backend/src/test/kotlin/io/kabu/backend/planner/namespace/conflict/detector/BaseConflictDetectorTest.kt @@ -1,12 +1,12 @@ package io.kabu.backend.planner.namespace.conflict.detector -import io.kabu.backend.pattern.PatternWithSignature import io.kabu.backend.analyzer.AnalyzerImpl import io.kabu.backend.common.log.InterceptingLogging import io.kabu.backend.diagnostic.Origin import io.kabu.backend.exception.PatternProcessingException import io.kabu.backend.inout.input.method.GlobalPatternMethod import io.kabu.backend.integration.detector.user.legacy.detector.KotlinLangConflictDetector +import io.kabu.backend.pattern.PatternWithSignature import io.kabu.backend.processor.MethodsRegistry import io.kabu.backend.processor.Options import io.kabu.backend.util.Constants.BACKEND_PACKAGE @@ -99,7 +99,7 @@ private fun getOutcomeAndOriginString(raw: String): Pair { ) return try { - AnalyzerImpl(method, MethodsRegistry(), null, Options.DEFAULT).analyze() + AnalyzerImpl(method, MethodsRegistry(), Options.DEFAULT).analyze() "ok" to "" } catch (e: PatternProcessingException) { "fail" to (e.diagnostic.sourceCodeDetails?.trim() ?: "") diff --git a/backend/src/test/kotlin/io/kabu/backend/plannerx/XTest.kt b/backend/src/test/kotlin/io/kabu/backend/plannerx/XTest.kt index 493c5be..5dc11c3 100644 --- a/backend/src/test/kotlin/io/kabu/backend/plannerx/XTest.kt +++ b/backend/src/test/kotlin/io/kabu/backend/plannerx/XTest.kt @@ -44,7 +44,7 @@ open class XTest { ) val options = Options.DEFAULT.copy(hideInternalProperties = false, accessorObjectIsInSamePackage = true) - return AnalyzerImpl(method, MethodsRegistry(), null, options).analyze() + return AnalyzerImpl(method, MethodsRegistry(), options).analyze() } catch (e: PatternProcessingException) { logger.error(e) { "${e.localizedMessage}\n${e.diagnostic}" } diff --git a/backend/src/test/kotlin/io/kabu/backend/r2c/Utils.kt b/backend/src/test/kotlin/io/kabu/backend/r2c/Utils.kt index 6a012b7..fabf012 100644 --- a/backend/src/test/kotlin/io/kabu/backend/r2c/Utils.kt +++ b/backend/src/test/kotlin/io/kabu/backend/r2c/Utils.kt @@ -45,7 +45,7 @@ fun completionOutputOf(raw: String, sample: String): String { accessorObjectIsInSamePackage = true ) ) - val nodes = AnalyzerImpl(method, MethodsRegistry(), null, options).analyze() + val nodes = AnalyzerImpl(method, MethodsRegistry(), options).analyze() val integrator = Integrator() integrator.integrate(nodes, removeIrrelevant = false) val scriptGenerated = Generator(testMode = true).getCodeForPackage(integrator.integrated, method.packageName) diff --git a/doc/img/logo_kabu.svg b/doc/img/logo_kabu.svg index da3f377..a07ff42 100644 --- a/doc/img/logo_kabu.svg +++ b/doc/img/logo_kabu.svg @@ -1,12 +1,11 @@ - + + stroke-width="8.962371322224001" stroke="#6230a3"/> + fill="#6230a3"/> + class="wordmark-text-0" + id="text-0"/> @@ -31,8 +30,8 @@ height="21.008469135802468" data-palette-color="#ffffff"> + class="slogan-text-1" + id="text-1"/> From 88102cb8d26c6b0ede19a7e92e54d816dcfb39f1 Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Sun, 23 Jul 2023 03:12:46 +0600 Subject: [PATCH 28/43] fixed TypeParametersTest tests --- .../ksp/processor/TypeParametersTest.kt | 28 ++++++------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/TypeParametersTest.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/TypeParametersTest.kt index fb46596..b9d7bdb 100644 --- a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/TypeParametersTest.kt +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/TypeParametersTest.kt @@ -22,36 +22,24 @@ class TypeParametersTest : BaseKspFrontendProcessorTest() { } @Test - fun `unsupported contravariance`() = compileAndCheck( + fun `supported contravariance`() = compileAndCheck( """ - class A - - @Pattern("foo @Extend(context = bar(), parameter = par) {}") - fun f(par: A){ + @Pattern("foo + par") + fun f(par: List){ } """ ) { - assertCompilationError() - assertExpectedMessage("Error while processing parameter 'par' of function 'f': " + - "Contravariant type arguments aren't supported yet") - assertExpectedLineNumber(17) - assertExpectedMessage("\"par\"") + assertOk() } @Test - fun `unsupported covariance`() = compileAndCheck( + fun `supported covariance`() = compileAndCheck( """ - class A - - @Pattern("foo @Extend(context = bar(), parameter = par) {}") - fun f(par: A){ + @Pattern("foo + par") + fun f(par: List){ } """ ) { - assertCompilationError() - assertExpectedMessage("Error while processing parameter 'par' of function 'f': " + - "Covariant type arguments aren't supported yet") - assertExpectedLineNumber(17) - assertExpectedMessage("\"par\"") + assertOk() } } From 849ba2afee1646e8b1fe5dae985f01a98cba3ef6 Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Mon, 24 Jul 2023 23:50:59 +0600 Subject: [PATCH 29/43] refactored OperatorInfoTypes --- .../lambda/watcher/OperatorInfoTypes.kt | 37 ++++++++----------- .../AbstractCallableDeclaration.kt | 8 ++-- .../provider/provider/ComparisonProvider.kt | 9 +++-- .../backend/pattern/PatternWithSignature.kt | 14 ++++--- 4 files changed, 34 insertions(+), 34 deletions(-) diff --git a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/OperatorInfoTypes.kt b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/OperatorInfoTypes.kt index 5ec0dc9..eca8565 100644 --- a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/OperatorInfoTypes.kt +++ b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/OperatorInfoTypes.kt @@ -1,29 +1,22 @@ package io.kabu.backend.analyzer.handler.lambda.watcher -import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.TypeName -import io.kabu.backend.util.Constants.RUNTIME_PACKAGE +import com.squareup.kotlinpoet.asTypeName +import io.kabu.runtime.EqualityInfo +import io.kabu.runtime.InclusionInfo +import io.kabu.runtime.RankingComparisonInfo +import io.kabu.runtime.StrictnessComparisonInfo -object OperatorInfoTypes { //todo can we get them from KClass directly? +object OperatorInfoTypes { - /** see [io.kabu.runtime.EqualityInfo] */ - val EQUALITY_INFO_TYPE = ClassName(RUNTIME_PACKAGE, "EqualityInfo") - - /** see [io.kabu.runtime.InclusionInfo] */ - val INCLUSION_INFO_TYPE = ClassName(RUNTIME_PACKAGE, "InclusionInfo") + val TypeName.isOperatorInfoType get() = this in OPERATOR_INFO_TYPES - /** see [io.kabu.runtime.RankingComparisonInfo] */ - val RANKING_COMPARISON_INFO_TYPE = ClassName(RUNTIME_PACKAGE, "RankingComparisonInfo") - - /** see [io.kabu.runtime.StrictnessComparisonInfo] */ - val STRICTNESS_COMPARISON_INFO_TYPE = ClassName(RUNTIME_PACKAGE, "StrictnessComparisonInfo") - - val TypeName.isOperatorInfoType get() = this in operatorInfoTypes - - private val operatorInfoTypes = listOf( - EQUALITY_INFO_TYPE, - INCLUSION_INFO_TYPE, - RANKING_COMPARISON_INFO_TYPE, - STRICTNESS_COMPARISON_INFO_TYPE, - ) + private val OPERATOR_INFO_TYPES = listOf( + EqualityInfo::class, + InclusionInfo::class, + RankingComparisonInfo::class, + StrictnessComparisonInfo::class, + ).map { + it.asTypeName() + } } diff --git a/backend/src/main/kotlin/io/kabu/backend/declaration/AbstractCallableDeclaration.kt b/backend/src/main/kotlin/io/kabu/backend/declaration/AbstractCallableDeclaration.kt index 89af6ef..8404732 100644 --- a/backend/src/main/kotlin/io/kabu/backend/declaration/AbstractCallableDeclaration.kt +++ b/backend/src/main/kotlin/io/kabu/backend/declaration/AbstractCallableDeclaration.kt @@ -3,7 +3,7 @@ package io.kabu.backend.declaration import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.CodeBlock import com.squareup.kotlinpoet.TypeName -import io.kabu.backend.analyzer.handler.lambda.watcher.OperatorInfoTypes +import com.squareup.kotlinpoet.asTypeName import io.kabu.backend.node.TypeNode import io.kabu.backend.parser.FunctionMustReturn import io.kabu.backend.parser.Operator @@ -11,6 +11,8 @@ import io.kabu.backend.provider.evaluation.FunctionBlockContext import io.kabu.backend.provider.group.FunDeclarationProviders import io.kabu.backend.provider.provider.WatcherLambdaProvider.Companion.STACK_PROPERTY_NAME import io.kabu.backend.util.poet.asCodeBlock +import io.kabu.runtime.RankingComparisonInfo +import io.kabu.runtime.StrictnessComparisonInfo abstract class AbstractCallableDeclaration : Declaration() { @@ -94,8 +96,8 @@ abstract class AbstractCallableDeclaration : Declaration() { private fun getReturnStatementForComparison(operatorInfoType: TypeName?): String { return when (operatorInfoType) { - OperatorInfoTypes.RANKING_COMPARISON_INFO_TYPE -> "return 42" - OperatorInfoTypes.STRICTNESS_COMPARISON_INFO_TYPE -> "return 0" + RankingComparisonInfo::class.asTypeName() -> "return 42" + StrictnessComparisonInfo::class.asTypeName() -> "return 0" else -> "return 42" } } diff --git a/backend/src/main/kotlin/io/kabu/backend/provider/provider/ComparisonProvider.kt b/backend/src/main/kotlin/io/kabu/backend/provider/provider/ComparisonProvider.kt index 0ac464c..feefc84 100644 --- a/backend/src/main/kotlin/io/kabu/backend/provider/provider/ComparisonProvider.kt +++ b/backend/src/main/kotlin/io/kabu/backend/provider/provider/ComparisonProvider.kt @@ -1,10 +1,11 @@ package io.kabu.backend.provider.provider -import io.kabu.backend.analyzer.handler.lambda.watcher.OperatorInfoTypes.RANKING_COMPARISON_INFO_TYPE -import io.kabu.backend.analyzer.handler.lambda.watcher.OperatorInfoTypes.STRICTNESS_COMPARISON_INFO_TYPE +import com.squareup.kotlinpoet.asTypeName import io.kabu.backend.node.HolderTypeNode import io.kabu.backend.node.TypeNode import io.kabu.backend.provider.provider.WatcherLambdaProvider.Companion.STACK_PROPERTY_NAME +import io.kabu.runtime.RankingComparisonInfo +import io.kabu.runtime.StrictnessComparisonInfo class ComparisonProvider( @@ -29,11 +30,11 @@ class ComparisonProvider( append("val v$operatorInfoProviderIndex=") when (val type = operatorInfoProvider.type) { - RANKING_COMPARISON_INFO_TYPE -> { + RankingComparisonInfo::class.asTypeName() -> { append("if(aux)RankingComparisonInfo.GREATER else RankingComparisonInfo.LESS;") } - STRICTNESS_COMPARISON_INFO_TYPE -> { + StrictnessComparisonInfo::class.asTypeName() -> { append("if(aux)StrictnessComparisonInfo.RELAXED else StrictnessComparisonInfo.STRICT;") } diff --git a/backend/src/test/kotlin/io/kabu/backend/pattern/PatternWithSignature.kt b/backend/src/test/kotlin/io/kabu/backend/pattern/PatternWithSignature.kt index 259aed3..f561735 100644 --- a/backend/src/test/kotlin/io/kabu/backend/pattern/PatternWithSignature.kt +++ b/backend/src/test/kotlin/io/kabu/backend/pattern/PatternWithSignature.kt @@ -7,10 +7,14 @@ import com.squareup.kotlinpoet.LambdaTypeName import com.squareup.kotlinpoet.STRING import com.squareup.kotlinpoet.TypeName import com.squareup.kotlinpoet.UNIT -import io.kabu.backend.analyzer.handler.lambda.watcher.OperatorInfoTypes +import com.squareup.kotlinpoet.asTypeName import io.kabu.backend.diagnostic.Origin import io.kabu.backend.parameter.Parameter import io.kabu.backend.util.Constants.RECEIVER_PARAMETER_NAME +import io.kabu.runtime.EqualityInfo +import io.kabu.runtime.InclusionInfo +import io.kabu.runtime.RankingComparisonInfo +import io.kabu.runtime.StrictnessComparisonInfo class PatternWithSignature(input: String) { @@ -91,10 +95,10 @@ class PatternWithSignature(input: String) { "fi" to LambdaTypeName.get(returnType = INT), "fb" to LambdaTypeName.get(returnType = BOOLEAN), "fs" to LambdaTypeName.get(returnType = STRING), - "rank" to OperatorInfoTypes.RANKING_COMPARISON_INFO_TYPE, - "strict" to OperatorInfoTypes.STRICTNESS_COMPARISON_INFO_TYPE, - "incl" to OperatorInfoTypes.INCLUSION_INFO_TYPE, - "equal" to OperatorInfoTypes.EQUALITY_INFO_TYPE, + "rank" to RankingComparisonInfo::class.asTypeName(), + "strict" to StrictnessComparisonInfo::class.asTypeName(), + "incl" to InclusionInfo::class.asTypeName(), + "equal" to EqualityInfo::class.asTypeName(), ) } } From 076fc49664f36c714144fa59796ca386d38e5726 Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Tue, 25 Jul 2023 01:20:11 +0600 Subject: [PATCH 30/43] refactoring --- .../analyzer/handler/lambda/watcher/CaptureTypeGroup.kt | 2 +- .../backend/declaration/functions/FunctionDeclaration.kt | 5 +++-- .../io/kabu/backend/integration/render/GraphVisualizer.kt | 2 +- backend/src/main/kotlin/io/kabu/backend/node/node.kt | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/CaptureTypeGroup.kt b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/CaptureTypeGroup.kt index 476e0be..66e6cce 100644 --- a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/CaptureTypeGroup.kt +++ b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/watcher/CaptureTypeGroup.kt @@ -8,7 +8,7 @@ import io.kabu.backend.util.Constants class CaptureTypeGroup( val operator: Operator, val funDeclarationProviders: FunDeclarationProviders, - val returnTypeNode: TypeNode, //todo revise? + val returnTypeNode: TypeNode, val leftHandSideOfAssign: LeftHandSideOfAssign?, ) { diff --git a/backend/src/main/kotlin/io/kabu/backend/declaration/functions/FunctionDeclaration.kt b/backend/src/main/kotlin/io/kabu/backend/declaration/functions/FunctionDeclaration.kt index db32a99..9db3d23 100644 --- a/backend/src/main/kotlin/io/kabu/backend/declaration/functions/FunctionDeclaration.kt +++ b/backend/src/main/kotlin/io/kabu/backend/declaration/functions/FunctionDeclaration.kt @@ -8,6 +8,7 @@ import io.kabu.backend.parser.InfixFunction import io.kabu.backend.parser.Operator import io.kabu.backend.provider.group.FunDeclarationProviders import io.kabu.backend.util.poet.asCodeBlock +import io.kabu.runtime.exception.PatternEvaluationException class FunctionDeclaration( @@ -54,9 +55,9 @@ class FunctionDeclaration( appendLine(" $index -> $callCode") } - appendLine(" else -> TODO()") //todo todo throw proper exception + appendLine(" else -> throw %T(%S)") appendLine("}") - }.asCodeBlock() + }.asCodeBlock(PatternEvaluationException::class, "Wrong counter index ($$counterName)") } override fun toString(): String { diff --git a/backend/src/main/kotlin/io/kabu/backend/integration/render/GraphVisualizer.kt b/backend/src/main/kotlin/io/kabu/backend/integration/render/GraphVisualizer.kt index 1346b9f..d6f5598 100644 --- a/backend/src/main/kotlin/io/kabu/backend/integration/render/GraphVisualizer.kt +++ b/backend/src/main/kotlin/io/kabu/backend/integration/render/GraphVisualizer.kt @@ -110,7 +110,7 @@ class GraphVisualizer { appendLine("") } nodes.forEach { node -> - node.dependencies.distinct().forEach { dependency -> //todo make dependencies a set + node.dependencies.distinct().forEach { dependency -> val link = if (dependency == node.namespaceNode) "-.->" else "-->" appendLine("${names[node]?.id} $link ${names[dependency]?.id}") } diff --git a/backend/src/main/kotlin/io/kabu/backend/node/node.kt b/backend/src/main/kotlin/io/kabu/backend/node/node.kt index 2b40049..eab3003 100644 --- a/backend/src/main/kotlin/io/kabu/backend/node/node.kt +++ b/backend/src/main/kotlin/io/kabu/backend/node/node.kt @@ -19,7 +19,7 @@ import io.kabu.backend.util.poet.gatherTypeVariableNames interface Node { var namespaceNode: NamespaceNode? val name: String - val dependencies: Iterable + val dependencies: Iterable //todo make dependencies a set val derivativeNodes: MutableSet fun createDeclarations(): List fun replaceDependency(replaced: Node, replaceBy: Node) From 83a42819cbc20fb69045d2b89ec8f30fb57a21a8 Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Tue, 25 Jul 2023 23:52:49 +0600 Subject: [PATCH 31/43] fixed toTypeName for functional types --- .../ksp/processor/util/PoetReplacements.kt | 38 +++++++++++++++++++ .../frontend/ksp/processor/util/TypeUtils.kt | 1 - 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/PoetReplacements.kt diff --git a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/PoetReplacements.kt b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/PoetReplacements.kt new file mode 100644 index 0000000..2d08a16 --- /dev/null +++ b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/PoetReplacements.kt @@ -0,0 +1,38 @@ +package io.kabu.frontend.ksp.processor.util + +import com.google.devtools.ksp.symbol.KSCallableReference +import com.google.devtools.ksp.symbol.KSTypeReference +import com.squareup.kotlinpoet.KModifier +import com.squareup.kotlinpoet.LambdaTypeName +import com.squareup.kotlinpoet.ParameterSpec +import com.squareup.kotlinpoet.TypeName +import com.squareup.kotlinpoet.ksp.TypeParameterResolver +import com.squareup.kotlinpoet.ksp.toTypeName as toTypeNameByKotlinPoet + +fun KSTypeReference.toTypeName( + typeParamResolver: TypeParameterResolver = TypeParameterResolver.EMPTY, +): TypeName { + val type = resolve() + + (element as? KSCallableReference)?.let { callableReference -> + validateCallableReference(callableReference) + + val typeName = LambdaTypeName.get( + receiver = callableReference.receiverType?.toTypeName(typeParamResolver), + parameters = callableReference.functionParameters.map { + validateValueParameter(it) + + val modifiers = mutableListOf().apply { + if (it.isVararg) add(KModifier.VARARG) + } + + ParameterSpec(name = it.name?.asString() ?: "", type = it.type.toTypeName(typeParamResolver), modifiers) + }, + returnType = callableReference.returnType.toTypeName(typeParamResolver) + ) + + return typeName.copy(nullable = type.isMarkedNullable) + } + + return toTypeNameByKotlinPoet(typeParamResolver) +} diff --git a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/TypeUtils.kt b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/TypeUtils.kt index eb2ca8b..ed9099a 100644 --- a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/TypeUtils.kt +++ b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/TypeUtils.kt @@ -9,7 +9,6 @@ import com.google.devtools.ksp.symbol.KSTypeReference import com.google.devtools.ksp.symbol.KSValueParameter import com.google.devtools.ksp.symbol.Modifier import com.google.devtools.ksp.symbol.Variance -import com.squareup.kotlinpoet.ksp.toTypeName import com.squareup.kotlinpoet.ksp.toTypeParameterResolver import io.kabu.backend.diagnostic.Origin import io.kabu.backend.exception.PatternProcessingException From 4ea00b5cfce41eabb1c328bea3cdcfacea6fe5c0 Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Wed, 26 Jul 2023 00:29:01 +0600 Subject: [PATCH 32/43] refactoring --- .../ksp/processor/util/MethodCreationUtils.kt | 51 ++++++++++++++++++ ...Replacements.kt => TypeConversionUtils.kt} | 17 +++--- .../{TypeUtils.kt => TypeValidationUtils.kt} | 52 ------------------- .../kabu/frontend/ksp/processor/util/Utils.kt | 5 ++ .../builder/ContextCreatorFunctionBuilder.kt | 4 +- .../builder/LocalPatternFunctionBuilder.kt | 4 +- 6 files changed, 71 insertions(+), 62 deletions(-) create mode 100644 frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/MethodCreationUtils.kt rename frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/{PoetReplacements.kt => TypeConversionUtils.kt} (68%) rename frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/{TypeUtils.kt => TypeValidationUtils.kt} (57%) diff --git a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/MethodCreationUtils.kt b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/MethodCreationUtils.kt new file mode 100644 index 0000000..a2e8f7f --- /dev/null +++ b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/MethodCreationUtils.kt @@ -0,0 +1,51 @@ +package io.kabu.frontend.ksp.processor.util + +import com.google.devtools.ksp.symbol.KSFunctionDeclaration +import com.google.devtools.ksp.symbol.KSTypeReference +import com.squareup.kotlinpoet.ksp.toTypeParameterResolver +import io.kabu.backend.diagnostic.Origin +import io.kabu.backend.exception.PatternProcessingException +import io.kabu.backend.inout.input.method.Method +import io.kabu.backend.parameter.Parameter +import io.kabu.backend.util.Constants.RECEIVER_PARAMETER_NAME +import io.kabu.frontend.ksp.diagnostic.builder.parameterProcessingError + + +internal fun KSFunctionDeclaration.toMethod(): Method { + val typeParameterResolver = typeParameters.toTypeParameterResolver() + val methodOrigin = originOf(this) + val methodName = simpleName.asString() + + fun createParameter( + name: String, + typeReference: KSTypeReference, + origin: Origin, + methodName: String, + ) = try { + typeReference.validate() + Parameter(name, typeReference.asTypeName(typeParameterResolver), origin) + } catch (e: PatternProcessingException) { + parameterProcessingError(name, methodName, e, origin) + } + + val receiver = extensionReceiver + ?.let { createParameter(RECEIVER_PARAMETER_NAME, it, originOf(it, parent = methodOrigin), methodName) } + val returnType = returnType?.asTypeName(typeParameterResolver)!! + .also { returnType?.validate() } + val parameters = parameters.map { parameter -> + validateValueParameter(parameter) + val parameterOrigin = originOf(parameter, parent = methodOrigin) + val name = parameter.name!!.asString() + + createParameter(name, parameter.type, parameterOrigin, methodName) + } + + return Method( + packageName = packageName.asString(), + name = methodName, + returnedType = returnType, + receiver = receiver, + parameters = parameters, + origin = methodOrigin, + ) +} diff --git a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/PoetReplacements.kt b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/TypeConversionUtils.kt similarity index 68% rename from frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/PoetReplacements.kt rename to frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/TypeConversionUtils.kt index 2d08a16..a34a662 100644 --- a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/PoetReplacements.kt +++ b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/TypeConversionUtils.kt @@ -1,15 +1,16 @@ package io.kabu.frontend.ksp.processor.util import com.google.devtools.ksp.symbol.KSCallableReference +import com.google.devtools.ksp.symbol.KSType import com.google.devtools.ksp.symbol.KSTypeReference import com.squareup.kotlinpoet.KModifier import com.squareup.kotlinpoet.LambdaTypeName import com.squareup.kotlinpoet.ParameterSpec import com.squareup.kotlinpoet.TypeName import com.squareup.kotlinpoet.ksp.TypeParameterResolver -import com.squareup.kotlinpoet.ksp.toTypeName as toTypeNameByKotlinPoet +import com.squareup.kotlinpoet.ksp.toTypeName -fun KSTypeReference.toTypeName( +internal fun KSTypeReference.asTypeName( typeParamResolver: TypeParameterResolver = TypeParameterResolver.EMPTY, ): TypeName { val type = resolve() @@ -18,7 +19,7 @@ fun KSTypeReference.toTypeName( validateCallableReference(callableReference) val typeName = LambdaTypeName.get( - receiver = callableReference.receiverType?.toTypeName(typeParamResolver), + receiver = callableReference.receiverType?.asTypeName(typeParamResolver), parameters = callableReference.functionParameters.map { validateValueParameter(it) @@ -26,13 +27,17 @@ fun KSTypeReference.toTypeName( if (it.isVararg) add(KModifier.VARARG) } - ParameterSpec(name = it.name?.asString() ?: "", type = it.type.toTypeName(typeParamResolver), modifiers) + ParameterSpec(name = it.name?.asString() ?: "", type = it.type.asTypeName(typeParamResolver), modifiers) }, - returnType = callableReference.returnType.toTypeName(typeParamResolver) + returnType = callableReference.returnType.asTypeName(typeParamResolver) ) return typeName.copy(nullable = type.isMarkedNullable) } - return toTypeNameByKotlinPoet(typeParamResolver) + return toTypeName(typeParamResolver) } + +internal fun KSType.asTypeName( + typeParamResolver: TypeParameterResolver = TypeParameterResolver.EMPTY, +): TypeName = toTypeName(typeParamResolver) diff --git a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/TypeUtils.kt b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/TypeValidationUtils.kt similarity index 57% rename from frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/TypeUtils.kt rename to frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/TypeValidationUtils.kt index ed9099a..b191f85 100644 --- a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/TypeUtils.kt +++ b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/TypeValidationUtils.kt @@ -1,61 +1,11 @@ package io.kabu.frontend.ksp.processor.util import com.google.devtools.ksp.symbol.KSCallableReference -import com.google.devtools.ksp.symbol.KSClassDeclaration -import com.google.devtools.ksp.symbol.KSFunctionDeclaration import com.google.devtools.ksp.symbol.KSType import com.google.devtools.ksp.symbol.KSTypeArgument import com.google.devtools.ksp.symbol.KSTypeReference import com.google.devtools.ksp.symbol.KSValueParameter -import com.google.devtools.ksp.symbol.Modifier import com.google.devtools.ksp.symbol.Variance -import com.squareup.kotlinpoet.ksp.toTypeParameterResolver -import io.kabu.backend.diagnostic.Origin -import io.kabu.backend.exception.PatternProcessingException -import io.kabu.backend.inout.input.method.Method -import io.kabu.backend.parameter.Parameter -import io.kabu.backend.util.Constants.RECEIVER_PARAMETER_NAME -import io.kabu.frontend.ksp.diagnostic.builder.parameterProcessingError - - -internal fun KSFunctionDeclaration.toMethod(): Method { - val typeParameterResolver = typeParameters.toTypeParameterResolver() - val methodOrigin = originOf(this) - val methodName = simpleName.asString() - - fun createParameter( - name: String, - typeReference: KSTypeReference, - origin: Origin, - methodName: String, - ) = try { - typeReference.validate() - Parameter(name, typeReference.toTypeName(typeParameterResolver), origin) - } catch (e: PatternProcessingException) { - parameterProcessingError(name, methodName, e, origin) - } - - val receiver = extensionReceiver - ?.let { createParameter(RECEIVER_PARAMETER_NAME, it, originOf(it, parent = methodOrigin), methodName) } - val returnType = returnType?.toTypeName(typeParameterResolver)!! - .also { returnType?.validate() } - val parameters = parameters.map { parameter -> - validateValueParameter(parameter) - val parameterOrigin = originOf(parameter, parent = methodOrigin) - val name = parameter.name!!.asString() - - createParameter(name, parameter.type, parameterOrigin, methodName) - } - - return Method( - packageName = packageName.asString(), - name = methodName, - returnedType = returnType, - receiver = receiver, - parameters = parameters, - origin = methodOrigin, - ) -} internal fun KSTypeReference.validate() { val type = resolve() @@ -110,5 +60,3 @@ internal fun validateType(type: KSType) { internal fun validateCallableReference(callableReference: KSCallableReference) { // validation is provided by validation of function constituting parts: receiver, parameters, returned type } - -internal val KSClassDeclaration.isInner get() = Modifier.INNER in modifiers diff --git a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/Utils.kt b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/Utils.kt index 37d6340..700a348 100644 --- a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/Utils.kt +++ b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/Utils.kt @@ -2,10 +2,12 @@ package io.kabu.frontend.ksp.processor.util import com.google.devtools.ksp.symbol.FileLocation import com.google.devtools.ksp.symbol.KSAnnotated +import com.google.devtools.ksp.symbol.KSClassDeclaration import com.google.devtools.ksp.symbol.KSDeclaration import com.google.devtools.ksp.symbol.KSNode import com.google.devtools.ksp.symbol.KSTypeArgument import com.google.devtools.ksp.symbol.KSValueParameter +import com.google.devtools.ksp.symbol.Modifier import io.kabu.backend.diagnostic.FileSourceLocation import io.kabu.backend.diagnostic.Origin import io.kabu.backend.diagnostic.diagnosticError @@ -49,3 +51,6 @@ internal inline fun KSAnnotated.getAnnotationOrNull() = val annotationQualifiedName = it.annotationType.resolve().declaration.qualifiedName?.asString() annotationQualifiedName == T::class.qualifiedName } + +internal val KSClassDeclaration.isInner get() = + Modifier.INNER in modifiers diff --git a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/builder/ContextCreatorFunctionBuilder.kt b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/builder/ContextCreatorFunctionBuilder.kt index 7640b51..3e71896 100644 --- a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/builder/ContextCreatorFunctionBuilder.kt +++ b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/builder/ContextCreatorFunctionBuilder.kt @@ -4,7 +4,6 @@ import com.google.devtools.ksp.isConstructor import com.google.devtools.ksp.symbol.FunctionKind import com.google.devtools.ksp.symbol.KSClassDeclaration import com.google.devtools.ksp.symbol.KSFunctionDeclaration -import com.squareup.kotlinpoet.ksp.toTypeName import io.kabu.annotation.Context import io.kabu.annotation.ContextCreator import io.kabu.backend.diagnostic.diagnosticError @@ -12,6 +11,7 @@ import io.kabu.backend.inout.input.method.ContextConstructorMethod.Companion.toC import io.kabu.backend.inout.input.method.ContextCreatorMethod import io.kabu.backend.inout.input.method.ContextCreatorMethod.Companion.toContextCreatorMethod import io.kabu.frontend.ksp.processor.util.areNotSupported +import io.kabu.frontend.ksp.processor.util.asTypeName import io.kabu.frontend.ksp.processor.util.builder.validator.ContextClassFoundByAnnotatedConstructorValidator import io.kabu.frontend.ksp.processor.util.getAnnotation import io.kabu.frontend.ksp.processor.util.getAnnotationOrNull @@ -66,7 +66,7 @@ class ContextCreatorFunctionBuilder : AbstractFunctionBuilder( val declaringType = classDeclaration .asStarProjectedType() //todo highlight generic nuances intentionally .also { it.validate() } - .toTypeName() //todo val typeParameterResolver = typeParameters.toTypeParameterResolver() + .asTypeName() //todo val typeParameterResolver = typeParameters.toTypeParameterResolver() return function.toMethod().toLocalPatternMethod(declaringType, pattern) } From cabab265faf77d6d7e163bf2b12f15eed7793b8b Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Wed, 26 Jul 2023 00:32:59 +0600 Subject: [PATCH 33/43] tweaked logging --- .../kotlin/io/kabu/backend/processor/BackendProcessor.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/src/main/kotlin/io/kabu/backend/processor/BackendProcessor.kt b/backend/src/main/kotlin/io/kabu/backend/processor/BackendProcessor.kt index d1ca96d..ba6f347 100644 --- a/backend/src/main/kotlin/io/kabu/backend/processor/BackendProcessor.kt +++ b/backend/src/main/kotlin/io/kabu/backend/processor/BackendProcessor.kt @@ -77,7 +77,7 @@ class BackendProcessor(private val options: Options = Options.DEFAULT) { extensionContextTypeName: TypeName, methodsRegistry: MethodsRegistry, ): List { - logger.info { "Handling extension context type: $extensionContextTypeName" } + logger.debug { "Handling extension context type: $extensionContextTypeName" } val packageName = when (extensionContextTypeName) { is ClassName -> extensionContextTypeName.packageName @@ -113,7 +113,7 @@ class BackendProcessor(private val options: Options = Options.DEFAULT) { contextMediatorTypeNode: NamespaceNode, methodsRegistry: MethodsRegistry, ) : Nodes { - logger.info { "Analyzing ${LocalPattern::class.simpleName} method: $method" } + logger.debug { "Analyzing ${LocalPattern::class.simpleName} method: $method" } return AnalyzerImpl( method = method, methodsRegistry = methodsRegistry, @@ -126,7 +126,7 @@ class BackendProcessor(private val options: Options = Options.DEFAULT) { method: GlobalPatternMethod, methodsRegistry: MethodsRegistry ): Nodes { - logger.info { "Analyzing ${Pattern::class.simpleName} method: $method" } + logger.debug { "Analyzing ${Pattern::class.simpleName} method: $method" } return AnalyzerImpl( method = method, methodsRegistry = methodsRegistry, From 597a9a59390b3c73605f05776af24bcf6366a495 Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Tue, 25 Jul 2023 02:29:29 +0600 Subject: [PATCH 34/43] refactoring --- .../processor/BaseKspFrontendProcessorTest.kt | 26 ------------------- 1 file changed, 26 deletions(-) diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/BaseKspFrontendProcessorTest.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/BaseKspFrontendProcessorTest.kt index ea4a1a8..1499198 100644 --- a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/BaseKspFrontendProcessorTest.kt +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/BaseKspFrontendProcessorTest.kt @@ -48,15 +48,6 @@ open class BaseKspFrontendProcessorTest { if (!file.deleteRecursively()) error("ERROR: temp dir deletion failed: ${path.toAbsolutePath()}") } - protected fun compileAndCheckWithoutSyntaxHighlight( - code: String, - block: KotlinCompilation.Result.() -> Unit, - ) { - val kotlinSource = createKotlinFile(code) - val compilationResult = compile(kspWithCompilation = false, kotlinSource, emptyJavaSourceFile()) - compilationResult.block() - } - protected fun compileAndCheck( @Language("kotlin", prefix = KOTLIN_TEST_FILE_PREFIX, suffix = KOTLIN_TEST_FILE_SUFFIX) code: String, block: KotlinCompilation.Result.() -> Unit, @@ -91,18 +82,6 @@ open class BaseKspFrontendProcessorTest { this.kspWithCompilation = kspWithCompilation }.compile() - private fun KotlinCompilation.Result.kspGeneratedSources(): List { - val kspWorkingDir = workingDir.resolve("ksp") - val kspGeneratedDir = kspWorkingDir.resolve("sources") - val kotlinGeneratedDir = kspGeneratedDir.resolve("kotlin") - val javaGeneratedDir = kspGeneratedDir.resolve("java") - return kotlinGeneratedDir.walk().toList() + - javaGeneratedDir.walk().toList() - } - - private val KotlinCompilation.Result.workingDir: File - get() = checkNotNull(outputDirectory.parentFile) - private fun createKotlinFile( @Language("kotlin", prefix = KOTLIN_TEST_FILE_PREFIX, suffix = KOTLIN_TEST_FILE_SUFFIX) code: String, ): SourceFile { @@ -217,11 +196,6 @@ fun sample( sample: String ) = sample -infix fun TestCase.ScriptResult.xxx( - @Language("kotlin", prefix = KOTLIN_TEST_FILE_PREFIX, suffix = KOTLIN_TEST_FILE_SUFFIX) - sample: String -) = TestCase(sample.trimIndent(), this) - @Language("kotlin", prefix = KOTLIN_TEST_FILE_PREFIX, suffix = KOTLIN_TEST_FILE_SUFFIX) operator fun String.minus(result: TestCase.ScriptResult) = TestCase(this.trimIndent(), result) From a4ba36b2f09dd7e07b31b4d81a79332eaf8271ef Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Fri, 21 Jul 2023 01:07:57 +0600 Subject: [PATCH 35/43] added test of generic function --- .../ksp/processor/generic/GenericTest.kt | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/generic/GenericTest.kt diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/generic/GenericTest.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/generic/GenericTest.kt new file mode 100644 index 0000000..f81b5f2 --- /dev/null +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/generic/GenericTest.kt @@ -0,0 +1,30 @@ +@file:Suppress("MaxLineLength") + +package io.kabu.frontend.ksp.processor.generic + +import io.kabu.frontend.ksp.processor.BaseKspFrontendProcessorTest +import io.kabu.frontend.ksp.processor.TestCase.ScriptResult.Termination +import io.kabu.frontend.ksp.processor.minus +import io.kabu.frontend.ksp.processor.sample +import org.junit.Test + + +class GenericTest : BaseKspFrontendProcessorTest() { + + @Test + fun test() = compileAndCheckAndRun( + """ + @Pattern("a * b + c") + fun foo(a: T, b: Array, c: (T) -> R): T { + return if (false) { + c(a) + } else { + c(b.first()) + } + } + """, + sample(""" + "abc" * arrayOf("def") + { it + it } + """) - Termination("defdef"), + ) +} From a2ff0ce7b0e50a0b80a7e46a86179999746c3674 Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Wed, 26 Jul 2023 01:06:12 +0600 Subject: [PATCH 36/43] support for recursive type arguments bounds (+tests) --- .../kabu/backend/util/poet/TypeNameUtils.kt | 39 ++++++++++++------- .../generic/{ => test1}/GenericTest.kt | 4 +- .../test2/GenericRecursiveBoundsTest.kt | 30 ++++++++++++++ 3 files changed, 58 insertions(+), 15 deletions(-) rename frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/generic/{ => test1}/GenericTest.kt (87%) create mode 100644 frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/generic/test2/GenericRecursiveBoundsTest.kt diff --git a/backend/src/main/kotlin/io/kabu/backend/util/poet/TypeNameUtils.kt b/backend/src/main/kotlin/io/kabu/backend/util/poet/TypeNameUtils.kt index 3aade30..f7b49f0 100644 --- a/backend/src/main/kotlin/io/kabu/backend/util/poet/TypeNameUtils.kt +++ b/backend/src/main/kotlin/io/kabu/backend/util/poet/TypeNameUtils.kt @@ -35,24 +35,37 @@ object TypeNameUtils { private val packageNamesRegex = Regex("\\w+\\.") } -fun TypeName.gatherTypeVariableNames(): Collection { +fun TypeName.gatherTypeVariableNames(): MutableSet { + val set = mutableSetOf() + gatherTypeVariableNames(set) + return set +} + +fun TypeName.gatherTypeVariableNames(collector: MutableSet) { - fun Iterable.gatherTypeVariableNames(): Collection { - return flatMap { it.gatherTypeVariableNames() } + fun Iterable.gatherTypeVariableNames(bag: MutableSet) { + forEach { it.gatherTypeVariableNames(bag) } } - //todo RECURSIVE BOUNDS NOT HANDLED!!! - return when (this) { - is TypeVariableName -> bounds.gatherTypeVariableNames() + this - is ParameterizedTypeName -> typeArguments.gatherTypeVariableNames() - is WildcardTypeName -> inTypes.gatherTypeVariableNames() + outTypes.gatherTypeVariableNames() + when (this) { + is TypeVariableName -> { + if (collector.none { it.name == this.name }) collector += this + bounds.gatherTypeVariableNames(collector) + } + + is ParameterizedTypeName -> typeArguments.gatherTypeVariableNames(collector) + is WildcardTypeName -> { + inTypes.gatherTypeVariableNames(collector) + outTypes.gatherTypeVariableNames(collector) + } + is LambdaTypeName -> { - parameters.map { it.type }.gatherTypeVariableNames() + - returnType.gatherTypeVariableNames() + - receiver?.gatherTypeVariableNames().orEmpty() + parameters.map { it.type }.gatherTypeVariableNames(collector) + returnType.gatherTypeVariableNames(collector) + receiver?.gatherTypeVariableNames(collector) } - is ClassName -> emptyList() - Dynamic -> emptyList() + is ClassName -> Unit + Dynamic -> Unit } } diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/generic/GenericTest.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/generic/test1/GenericTest.kt similarity index 87% rename from frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/generic/GenericTest.kt rename to frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/generic/test1/GenericTest.kt index f81b5f2..b50b7d8 100644 --- a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/generic/GenericTest.kt +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/generic/test1/GenericTest.kt @@ -1,6 +1,6 @@ @file:Suppress("MaxLineLength") -package io.kabu.frontend.ksp.processor.generic +package io.kabu.frontend.ksp.processor.generic.test1 import io.kabu.frontend.ksp.processor.BaseKspFrontendProcessorTest import io.kabu.frontend.ksp.processor.TestCase.ScriptResult.Termination @@ -24,7 +24,7 @@ class GenericTest : BaseKspFrontendProcessorTest() { } """, sample(""" - "abc" * arrayOf("def") + { it + it } + print("abc" * arrayOf("def") + { it + it }) """) - Termination("defdef"), ) } diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/generic/test2/GenericRecursiveBoundsTest.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/generic/test2/GenericRecursiveBoundsTest.kt new file mode 100644 index 0000000..0c80f9e --- /dev/null +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/generic/test2/GenericRecursiveBoundsTest.kt @@ -0,0 +1,30 @@ +package io.kabu.frontend.ksp.processor.generic.test2 + +import io.kabu.frontend.ksp.processor.BaseKspFrontendProcessorTest +import io.kabu.frontend.ksp.processor.TestCase +import io.kabu.frontend.ksp.processor.minus +import io.kabu.frontend.ksp.processor.sample +import org.junit.Test + + +class GenericRecursiveBoundsTest : BaseKspFrontendProcessorTest() { + + @Test + fun test() = compileAndCheckAndRun( + """ + @Pattern("a * b + c") + fun , R : T> foo(a: T, b: Array, c: (T) -> R): T { + return if (false) { + c(a) + } else { + c(b.first()) + } + } + """, + sample( + """ + print("abc" * arrayOf("def") + { it + it }) + """ + ) - TestCase.ScriptResult.Termination("defdef"), + ) +} From b7a66f40fcd3adb94ad613466a0800b04d3d630d Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Wed, 26 Jul 2023 01:12:28 +0600 Subject: [PATCH 37/43] refactored tests --- .../processor/BaseKspFrontendProcessorTest.kt | 157 +++--------------- .../KotlinCompilationResultAssert.kt | 51 ++++++ .../frontend/ksp/processor/SourceFiles.kt | 12 ++ .../kabu/frontend/ksp/processor/TestCase.kt | 30 ++++ .../ksp/processor/TestCasePrefixSuffix.kt | 37 +++++ .../ksp/processor/{ => misc}/AliasesTest.kt | 3 +- .../{ => misc}/TypeParametersTest.kt | 3 +- .../{ => misc}/ValueParametersTest.kt | 3 +- 8 files changed, 161 insertions(+), 135 deletions(-) create mode 100644 frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/KotlinCompilationResultAssert.kt create mode 100644 frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/SourceFiles.kt create mode 100644 frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/TestCase.kt create mode 100644 frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/TestCasePrefixSuffix.kt rename frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/{ => misc}/AliasesTest.kt (79%) rename frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/{ => misc}/TypeParametersTest.kt (89%) rename frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/{ => misc}/ValueParametersTest.kt (93%) diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/BaseKspFrontendProcessorTest.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/BaseKspFrontendProcessorTest.kt index 1499198..af95d90 100644 --- a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/BaseKspFrontendProcessorTest.kt +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/BaseKspFrontendProcessorTest.kt @@ -16,15 +16,14 @@ import org.junit.rules.TemporaryFolder import java.io.File import java.nio.file.Path import kotlin.test.assertEquals -import kotlin.test.assertTrue -open class BaseKspFrontendProcessorTest { +open class BaseKspFrontendProcessorTest : KotlinCompilationResultAssert() { @Rule @JvmField var temporaryFolder: TemporaryFolder = TemporaryFolder() - lateinit var tempDirPath: Path + private lateinit var tempDirPath: Path @Before fun before() { @@ -57,64 +56,21 @@ open class BaseKspFrontendProcessorTest { compilationResult.block() } - protected fun KotlinCompilation.Result.assertCompilationError(lineNumber: Int, vararg expectedMessages: String) { - assertCompilationError() - assertExpectedLineNumber(lineNumber) - - expectedMessages.forEach { - assertExpectedMessage(it) - } - } - private fun compile( kspWithCompilation: Boolean, vararg source: SourceFile, - ): KotlinCompilation.Result = KotlinCompilation().apply { - verbose = false - sources = source.toList() - symbolProcessorProviders = listOf(KspFrontendProcessorProvider()) -// workingDir = temporaryFolder.root.also { println(it) } - workingDir = tempDirPath.toFile().also { logger.debug(it.absolutePath) } - inheritClassPath = true - kspIncremental = false - kspArgs = mutableMapOf("ksp.io.kabu.allowUnsafe" to "true") - kspIncrementalLog = false - this.kspWithCompilation = kspWithCompilation - }.compile() - - private fun createKotlinFile( - @Language("kotlin", prefix = KOTLIN_TEST_FILE_PREFIX, suffix = KOTLIN_TEST_FILE_SUFFIX) code: String, - ): SourceFile { - return SourceFile.kotlin("testfile.kt", KOTLIN_TEST_FILE_PREFIX + code + KOTLIN_TEST_FILE_SUFFIX) - } - - protected fun KotlinCompilation.Result.assertCompilationError() { - assertEquals(KotlinCompilation.ExitCode.COMPILATION_ERROR, exitCode) - } - - protected fun KotlinCompilation.Result.assertCompilationError(errorMessage: String) { - assertEquals(KotlinCompilation.ExitCode.COMPILATION_ERROR, exitCode) - assertTrue(errorMessage in messages) - } - - protected fun KotlinCompilation.Result.assertKspError(message: String) { - val messageExists = messages.splitToSequence(newline) - .any { it.startsWith("$KSP_ERROR_PREFIX$message") } - assertTrue(messageExists) - } - - protected fun KotlinCompilation.Result.assertOk() { - assertEquals(KotlinCompilation.ExitCode.OK, exitCode) - } - - protected fun KotlinCompilation.Result.assertExpectedMessage(expectedMessage: String) { - assertTrue("Expected message containing text '$expectedMessage' but got: '$messages'") { - messages.contains(expectedMessage) - } - } - - protected fun KotlinCompilation.Result.assertExpectedLineNumber(lineNumber: Int) { - assertExpectedMessage("testfile.kt:$lineNumber") + ): KotlinCompilation.Result { + return KotlinCompilation().apply { + verbose = false + sources = source.toList() + symbolProcessorProviders = listOf(KspFrontendProcessorProvider()) + workingDir = tempDirPath.toFile().also { logger.debug(it.absolutePath) } + inheritClassPath = true + kspIncremental = false + kspArgs = kabuKspOptions + kspIncrementalLog = false + this.kspWithCompilation = kspWithCompilation + }.compile() } protected fun compileAndCheckAndRun( @@ -130,8 +86,6 @@ open class BaseKspFrontendProcessorTest { } } - private fun emptyJavaSourceFile() = SourceFile.java("Empty.java", "public class Empty {}") - private fun validateCase(compilationResult: KotlinCompilation.Result, testCase: TestCase) { val actualOutput = getScriptOutput(testCase.sampleScript) when (val expected = testCase.expectedResult) { @@ -143,16 +97,10 @@ open class BaseKspFrontendProcessorTest { private fun getScriptOutput(sampleScript: String): String { logger.debug { "Running script for '$sampleScript'" } - val projectRoot = "../../../" - val mainKtsLib = "${projectRoot}frontend/ksp/testing/lib/kotlin-main-kts-1.9.0.jar" - val runtimeClassFiles = "${projectRoot}runtime/build/classes/kotlin/main" - val annotationClassFiles = "${projectRoot}annotation/build/classes/kotlin/main" - val classFiles = "${projectRoot}frontend/ksp/processor/build/ksptesting/classes" - val classpath = "$mainKtsLib:$annotationClassFiles:$runtimeClassFiles:$classFiles" val file = File.createTempFile("sample", ".main.kts").apply { writeText(KOTLIN_TEST_FILE_PREFIX + sampleScript + KOTLIN_TEST_FILE_SUFFIX) } - val process = ProcessBuilder("kotlin", "-cp", classpath, file.absolutePath).start() + val process = ProcessBuilder("kotlin", "-cp", createClassPath(), file.absolutePath).start() return if (process.waitFor() != 0) { val errOutput = process.errorStream.bufferedReader().readText() System.err.println(errOutput) @@ -164,73 +112,18 @@ open class BaseKspFrontendProcessorTest { } } - private companion object { - private const val KSP_ERROR_PREFIX = "e: [ksp] " - private val newline = Regex("\n") - private val logger = InterceptingLogging.logger {} + private fun createClassPath(): String { + val projectRoot = "../../../" + val mainKtsLib = "${projectRoot}frontend/ksp/testing/lib/kotlin-main-kts-1.9.0.jar" + val runtimeClassFiles = "${projectRoot}runtime/build/classes/kotlin/main" + val annotationClassFiles = "${projectRoot}annotation/build/classes/kotlin/main" + val classFiles = "${projectRoot}frontend/ksp/processor/build/ksptesting/classes" + return "$mainKtsLib:$annotationClassFiles:$runtimeClassFiles:$classFiles" } -} - -class TestCase( - @Language("kotlin", prefix = KOTLIN_TEST_SCRIPT_FILE_PREFIX, suffix = KOTLIN_TEST_SCRIPT_FILE_SUFFIX) - val sampleScript: String, - val expectedResult: ScriptResult, -) { - - sealed class ScriptResult { - class Termination(val string: String) : ScriptResult() - - sealed class Error : ScriptResult() { - abstract val message: String + private companion object { + val logger = InterceptingLogging.logger {} - class Exception(override val message: String) : Error() - class KspError(override val message: String) : Error() - } + val kabuKspOptions = mutableMapOf("ksp.io.kabu.allowUnsafe" to "true") } } - - -fun sample( - @Language("kotlin", prefix = KOTLIN_TEST_SCRIPT_FILE_PREFIX, suffix = KOTLIN_TEST_SCRIPT_FILE_SUFFIX) - sample: String -) = sample - -@Language("kotlin", prefix = KOTLIN_TEST_FILE_PREFIX, suffix = KOTLIN_TEST_FILE_SUFFIX) -operator fun String.minus(result: TestCase.ScriptResult) = TestCase(this.trimIndent(), result) - - private const val KOTLIN_TEST_FILE_PREFIX = - """ - package tests - - import io.kabu.annotation.Pattern - import io.kabu.annotation.LocalPattern - import io.kabu.annotation.ContextCreator - import io.kabu.annotation.Context - // lines below are for future imports or other declarations to fix line numbers used in tests - - - - - // end of common part - """ - - private const val KOTLIN_TEST_FILE_SUFFIX = "" - -private const val KOTLIN_TEST_SCRIPT_FILE_PREFIX = - """ - package tests - - import io.kabu.annotation.Pattern - import io.kabu.annotation.LocalPattern - import io.kabu.annotation.ContextCreator - // lines below are for future imports or other declarations to fix line numbers used in tests - - - - - // end of common part - run { - """ -private const val KOTLIN_TEST_SCRIPT_FILE_SUFFIX = "" + - "}" diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/KotlinCompilationResultAssert.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/KotlinCompilationResultAssert.kt new file mode 100644 index 0000000..bf73d8b --- /dev/null +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/KotlinCompilationResultAssert.kt @@ -0,0 +1,51 @@ +package io.kabu.frontend.ksp.processor + +import com.tschuchort.compiletesting.KotlinCompilation +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +open class KotlinCompilationResultAssert { + + protected fun KotlinCompilation.Result.assertCompilationError(lineNumber: Int, vararg expectedMessages: String) { + assertCompilationError() + assertExpectedLineNumber(lineNumber) + + expectedMessages.forEach { + assertExpectedMessage(it) + } + } + + protected fun KotlinCompilation.Result.assertCompilationError() { + assertEquals(KotlinCompilation.ExitCode.COMPILATION_ERROR, exitCode) + } + + protected fun KotlinCompilation.Result.assertCompilationError(errorMessage: String) { + assertEquals(KotlinCompilation.ExitCode.COMPILATION_ERROR, exitCode) + assertTrue(errorMessage in messages) + } + + protected fun KotlinCompilation.Result.assertKspError(message: String) { + val messageExists = messages.splitToSequence(newline) + .any { it.startsWith("${KSP_ERROR_PREFIX}$message") } + assertTrue(messageExists) + } + + protected fun KotlinCompilation.Result.assertOk() { + assertEquals(KotlinCompilation.ExitCode.OK, exitCode) + } + + protected fun KotlinCompilation.Result.assertExpectedMessage(expectedMessage: String) { + assertTrue("Expected message containing text '$expectedMessage' but got: '$messages'") { + messages.contains(expectedMessage) + } + } + + protected fun KotlinCompilation.Result.assertExpectedLineNumber(lineNumber: Int) { + assertExpectedMessage("testfile.kt:$lineNumber") + } + + private companion object { + private const val KSP_ERROR_PREFIX = "e: [ksp] " + private val newline = Regex("\n") + } +} diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/SourceFiles.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/SourceFiles.kt new file mode 100644 index 0000000..6f17e79 --- /dev/null +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/SourceFiles.kt @@ -0,0 +1,12 @@ +package io.kabu.frontend.ksp.processor + +import com.tschuchort.compiletesting.SourceFile +import org.intellij.lang.annotations.Language + +fun createKotlinFile( + @Language("kotlin", prefix = KOTLIN_TEST_FILE_PREFIX, suffix = KOTLIN_TEST_FILE_SUFFIX) code: String, +): SourceFile { + return SourceFile.kotlin("testfile.kt", KOTLIN_TEST_FILE_PREFIX + code + KOTLIN_TEST_FILE_SUFFIX) +} + +fun emptyJavaSourceFile() = SourceFile.java("Empty.java", "public class Empty {}") diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/TestCase.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/TestCase.kt new file mode 100644 index 0000000..fbdc34d --- /dev/null +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/TestCase.kt @@ -0,0 +1,30 @@ +package io.kabu.frontend.ksp.processor + +import org.intellij.lang.annotations.Language + +class TestCase( + @Language("kotlin", prefix = KOTLIN_TEST_SCRIPT_FILE_PREFIX, suffix = KOTLIN_TEST_SCRIPT_FILE_SUFFIX) + val sampleScript: String, + val expectedResult: ScriptResult, +) { + + sealed class ScriptResult { + + class Termination(val string: String) : ScriptResult() + + sealed class Error : ScriptResult() { + abstract val message: String + + class Exception(override val message: String) : Error() + class KspError(override val message: String) : Error() + } + } +} + +fun sample( + @Language("kotlin", prefix = KOTLIN_TEST_SCRIPT_FILE_PREFIX, suffix = KOTLIN_TEST_SCRIPT_FILE_SUFFIX) + sample: String, +) = sample + +@Language("kotlin", prefix = KOTLIN_TEST_FILE_PREFIX, suffix = KOTLIN_TEST_FILE_SUFFIX) +operator fun String.minus(result: TestCase.ScriptResult) = TestCase(this.trimIndent(), result) diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/TestCasePrefixSuffix.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/TestCasePrefixSuffix.kt new file mode 100644 index 0000000..14e2c5c --- /dev/null +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/TestCasePrefixSuffix.kt @@ -0,0 +1,37 @@ +package io.kabu.frontend.ksp.processor + +internal const val KOTLIN_TEST_FILE_PREFIX = + """ + package tests + + import io.kabu.annotation.Pattern + import io.kabu.annotation.LocalPattern + import io.kabu.annotation.ContextCreator + import io.kabu.annotation.Context + // lines below are for future imports or other declarations to fix line numbers used in tests + + + + + // end of common part + """ + +internal const val KOTLIN_TEST_FILE_SUFFIX = "" + +internal const val KOTLIN_TEST_SCRIPT_FILE_PREFIX = + """ + package tests + + import io.kabu.annotation.Pattern + import io.kabu.annotation.LocalPattern + import io.kabu.annotation.ContextCreator + // lines below are for future imports or other declarations to fix line numbers used in tests + + + + + // end of common part + run { + """ +internal const val KOTLIN_TEST_SCRIPT_FILE_SUFFIX = "" + + "}" diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/AliasesTest.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/misc/AliasesTest.kt similarity index 79% rename from frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/AliasesTest.kt rename to frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/misc/AliasesTest.kt index bd80b07..e2cdd14 100644 --- a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/AliasesTest.kt +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/misc/AliasesTest.kt @@ -1,5 +1,6 @@ -package io.kabu.frontend.ksp.processor +package io.kabu.frontend.ksp.processor.misc +import io.kabu.frontend.ksp.processor.BaseKspFrontendProcessorTest import org.junit.Test class AliasesTest : BaseKspFrontendProcessorTest(){ diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/TypeParametersTest.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/misc/TypeParametersTest.kt similarity index 89% rename from frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/TypeParametersTest.kt rename to frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/misc/TypeParametersTest.kt index b9d7bdb..f794560 100644 --- a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/TypeParametersTest.kt +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/misc/TypeParametersTest.kt @@ -1,5 +1,6 @@ -package io.kabu.frontend.ksp.processor +package io.kabu.frontend.ksp.processor.misc +import io.kabu.frontend.ksp.processor.BaseKspFrontendProcessorTest import org.junit.Test class TypeParametersTest : BaseKspFrontendProcessorTest() { diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/ValueParametersTest.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/misc/ValueParametersTest.kt similarity index 93% rename from frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/ValueParametersTest.kt rename to frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/misc/ValueParametersTest.kt index 08746f2..f188e2b 100644 --- a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/ValueParametersTest.kt +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/misc/ValueParametersTest.kt @@ -1,5 +1,6 @@ -package io.kabu.frontend.ksp.processor +package io.kabu.frontend.ksp.processor.misc +import io.kabu.frontend.ksp.processor.BaseKspFrontendProcessorTest import org.junit.Test class ValueParametersTest : BaseKspFrontendProcessorTest(){ From 94e97460658d26981e2e2257200d1e5cddb0b568 Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Thu, 27 Jul 2023 01:00:32 +0600 Subject: [PATCH 38/43] implemented code separation by packages in tests --- .../processor/BaseKspFrontendProcessorTest.kt | 18 +++++--- .../frontend/ksp/processor/SourceFiles.kt | 43 ++++++++++++++++++- .../ksp/processor/TestCasePrefixSuffix.kt | 6 +++ .../test2/GenericRecursiveBoundsTest.kt | 2 + 4 files changed, 61 insertions(+), 8 deletions(-) diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/BaseKspFrontendProcessorTest.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/BaseKspFrontendProcessorTest.kt index af95d90..9212404 100644 --- a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/BaseKspFrontendProcessorTest.kt +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/BaseKspFrontendProcessorTest.kt @@ -51,18 +51,18 @@ open class BaseKspFrontendProcessorTest : KotlinCompilationResultAssert() { @Language("kotlin", prefix = KOTLIN_TEST_FILE_PREFIX, suffix = KOTLIN_TEST_FILE_SUFFIX) code: String, block: KotlinCompilation.Result.() -> Unit, ) { - val kotlinSource = createKotlinFile(code) - val compilationResult = compile(kspWithCompilation = false, kotlinSource, emptyJavaSourceFile()) + val kotlinSources = createKotlinFiles(code) + val compilationResult = compile(kspWithCompilation = false, kotlinSources + emptyJavaSourceFile()) compilationResult.block() } private fun compile( kspWithCompilation: Boolean, - vararg source: SourceFile, + sourceFiles: List, ): KotlinCompilation.Result { return KotlinCompilation().apply { verbose = false - sources = source.toList() + sources = sourceFiles symbolProcessorProviders = listOf(KspFrontendProcessorProvider()) workingDir = tempDirPath.toFile().also { logger.debug(it.absolutePath) } inheritClassPath = true @@ -78,8 +78,8 @@ open class BaseKspFrontendProcessorTest : KotlinCompilationResultAssert() { vararg cases: TestCase, onCompilationResult: KotlinCompilation.Result.() -> Unit = { assertOk() }, ) { - val kotlinSource = createKotlinFile(code) - val compilationResult = compile(kspWithCompilation = true, kotlinSource, emptyJavaSourceFile()) + val kotlinSources = createKotlinFiles(code) + val compilationResult = compile(kspWithCompilation = true, kotlinSources + emptyJavaSourceFile()) compilationResult.onCompilationResult() cases.forEach { validateCase(compilationResult, it) @@ -97,8 +97,12 @@ open class BaseKspFrontendProcessorTest : KotlinCompilationResultAssert() { private fun getScriptOutput(sampleScript: String): String { logger.debug { "Running script for '$sampleScript'" } + + val (packageName, contents) = groupByPackageNames(sampleScript).entries.single() + val fileContents = getKotlinTestFilePrefix(packageName) + contents + KOTLIN_TEST_FILE_SUFFIX + val file = File.createTempFile("sample", ".main.kts").apply { - writeText(KOTLIN_TEST_FILE_PREFIX + sampleScript + KOTLIN_TEST_FILE_SUFFIX) + writeText(fileContents) } val process = ProcessBuilder("kotlin", "-cp", createClassPath(), file.absolutePath).start() return if (process.waitFor() != 0) { diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/SourceFiles.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/SourceFiles.kt index 6f17e79..9b944ca 100644 --- a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/SourceFiles.kt +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/SourceFiles.kt @@ -3,10 +3,51 @@ package io.kabu.frontend.ksp.processor import com.tschuchort.compiletesting.SourceFile import org.intellij.lang.annotations.Language +fun createKotlinFiles(code: String): List { + return groupByPackageNames(code).map { createKotlinFile(it.value, it.key) } +} + +fun groupByPackageNames(code: String): MutableMap { + val map = mutableMapOf() // packageName -> contents + + fun addPackageContents(packageName: String, contents: MutableList) { + if (contents.all { it.isBlank() }) { + contents.clear() + return + } else { + map[packageName] = contents.joinToString("\n") + contents.clear() + } + } + + var packageName = DEFAULT_TEST_PACKAGE + val packageContents = mutableListOf() + for (line in code.lines()) { + val matcher = PACKAGE_REGEX.matchEntire(line) + if (matcher != null) { + addPackageContents(packageName, packageContents) + packageName = matcher.groupValues[1] + continue + } + packageContents += line + } + addPackageContents(packageName, packageContents) + + return map +} + fun createKotlinFile( @Language("kotlin", prefix = KOTLIN_TEST_FILE_PREFIX, suffix = KOTLIN_TEST_FILE_SUFFIX) code: String, + packageName: String = DEFAULT_TEST_PACKAGE, //todo remove default? ): SourceFile { - return SourceFile.kotlin("testfile.kt", KOTLIN_TEST_FILE_PREFIX + code + KOTLIN_TEST_FILE_SUFFIX) + val packagePath = packageName.replace('.', '/') + return SourceFile.kotlin( + name = "$packagePath/testfile.kt", + contents = getKotlinTestFilePrefix(packageName) + code + KOTLIN_TEST_FILE_SUFFIX + ) } fun emptyJavaSourceFile() = SourceFile.java("Empty.java", "public class Empty {}") + +private val DEFAULT_TEST_PACKAGE = "tests" //todo remove? +private val PACKAGE_REGEX = Regex("^\\s*//\\s*PACKAGE\\s*(\\S+)\\s*") diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/TestCasePrefixSuffix.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/TestCasePrefixSuffix.kt index 14e2c5c..4da5e54 100644 --- a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/TestCasePrefixSuffix.kt +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/TestCasePrefixSuffix.kt @@ -1,5 +1,11 @@ package io.kabu.frontend.ksp.processor +internal fun getKotlinTestFilePrefix(packageName: String) = + KOTLIN_TEST_FILE_PREFIX.replace("package tests", "package $packageName") + +internal fun getKotlinTestScriptFilePrefix(packageName: String) = + KOTLIN_TEST_SCRIPT_FILE_PREFIX.replace("package tests", "package $packageName") + internal const val KOTLIN_TEST_FILE_PREFIX = """ package tests diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/generic/test2/GenericRecursiveBoundsTest.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/generic/test2/GenericRecursiveBoundsTest.kt index 0c80f9e..c6ef577 100644 --- a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/generic/test2/GenericRecursiveBoundsTest.kt +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/generic/test2/GenericRecursiveBoundsTest.kt @@ -12,6 +12,7 @@ class GenericRecursiveBoundsTest : BaseKspFrontendProcessorTest() { @Test fun test() = compileAndCheckAndRun( """ + // PACKAGE test2 @Pattern("a * b + c") fun , R : T> foo(a: T, b: Array, c: (T) -> R): T { return if (false) { @@ -23,6 +24,7 @@ class GenericRecursiveBoundsTest : BaseKspFrontendProcessorTest() { """, sample( """ + // PACKAGE test2 print("abc" * arrayOf("def") + { it + it }) """ ) - TestCase.ScriptResult.Termination("defdef"), From c05e9b1a3d5ee05953165648ff4d068bf5948977 Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Thu, 27 Jul 2023 01:03:52 +0600 Subject: [PATCH 39/43] refactored tests --- .../processor/BaseKspFrontendProcessorTest.kt | 26 ++++----- .../frontend/ksp/processor/SourceFiles.kt | 3 +- .../ksp/processor/TestCasePrefixSuffix.kt | 54 +++++++++---------- 3 files changed, 39 insertions(+), 44 deletions(-) diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/BaseKspFrontendProcessorTest.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/BaseKspFrontendProcessorTest.kt index 9212404..4764404 100644 --- a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/BaseKspFrontendProcessorTest.kt +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/BaseKspFrontendProcessorTest.kt @@ -56,6 +56,19 @@ open class BaseKspFrontendProcessorTest : KotlinCompilationResultAssert() { compilationResult.block() } + protected fun compileAndCheckAndRun( + @Language("kotlin", prefix = KOTLIN_TEST_FILE_PREFIX, suffix = KOTLIN_TEST_FILE_SUFFIX) code: String, + vararg cases: TestCase, + onCompilationResult: KotlinCompilation.Result.() -> Unit = { assertOk() }, + ) { + val kotlinSources = createKotlinFiles(code) + val compilationResult = compile(kspWithCompilation = true, kotlinSources + emptyJavaSourceFile()) + compilationResult.onCompilationResult() + cases.forEach { + validateCase(compilationResult, it) + } + } + private fun compile( kspWithCompilation: Boolean, sourceFiles: List, @@ -73,19 +86,6 @@ open class BaseKspFrontendProcessorTest : KotlinCompilationResultAssert() { }.compile() } - protected fun compileAndCheckAndRun( - @Language("kotlin", prefix = KOTLIN_TEST_FILE_PREFIX, suffix = KOTLIN_TEST_FILE_SUFFIX) code: String, - vararg cases: TestCase, - onCompilationResult: KotlinCompilation.Result.() -> Unit = { assertOk() }, - ) { - val kotlinSources = createKotlinFiles(code) - val compilationResult = compile(kspWithCompilation = true, kotlinSources + emptyJavaSourceFile()) - compilationResult.onCompilationResult() - cases.forEach { - validateCase(compilationResult, it) - } - } - private fun validateCase(compilationResult: KotlinCompilation.Result, testCase: TestCase) { val actualOutput = getScriptOutput(testCase.sampleScript) when (val expected = testCase.expectedResult) { diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/SourceFiles.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/SourceFiles.kt index 9b944ca..bffc3fb 100644 --- a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/SourceFiles.kt +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/SourceFiles.kt @@ -38,7 +38,7 @@ fun groupByPackageNames(code: String): MutableMap { fun createKotlinFile( @Language("kotlin", prefix = KOTLIN_TEST_FILE_PREFIX, suffix = KOTLIN_TEST_FILE_SUFFIX) code: String, - packageName: String = DEFAULT_TEST_PACKAGE, //todo remove default? + packageName: String, ): SourceFile { val packagePath = packageName.replace('.', '/') return SourceFile.kotlin( @@ -49,5 +49,4 @@ fun createKotlinFile( fun emptyJavaSourceFile() = SourceFile.java("Empty.java", "public class Empty {}") -private val DEFAULT_TEST_PACKAGE = "tests" //todo remove? private val PACKAGE_REGEX = Regex("^\\s*//\\s*PACKAGE\\s*(\\S+)\\s*") diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/TestCasePrefixSuffix.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/TestCasePrefixSuffix.kt index 4da5e54..0acec26 100644 --- a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/TestCasePrefixSuffix.kt +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/TestCasePrefixSuffix.kt @@ -1,43 +1,39 @@ package io.kabu.frontend.ksp.processor internal fun getKotlinTestFilePrefix(packageName: String) = - KOTLIN_TEST_FILE_PREFIX.replace("package tests", "package $packageName") + KOTLIN_TEST_FILE_PREFIX.replace("package $DEFAULT_TEST_PACKAGE", "package $packageName") internal fun getKotlinTestScriptFilePrefix(packageName: String) = - KOTLIN_TEST_SCRIPT_FILE_PREFIX.replace("package tests", "package $packageName") + KOTLIN_TEST_SCRIPT_FILE_PREFIX.replace("package $DEFAULT_TEST_PACKAGE", "package $packageName") + +internal const val DEFAULT_TEST_PACKAGE = "tests" internal const val KOTLIN_TEST_FILE_PREFIX = - """ - package tests - - import io.kabu.annotation.Pattern - import io.kabu.annotation.LocalPattern - import io.kabu.annotation.ContextCreator - import io.kabu.annotation.Context - // lines below are for future imports or other declarations to fix line numbers used in tests - - - - - // end of common part - """ + "\npackage " + + DEFAULT_TEST_PACKAGE + + "\n\n" + + "import io.kabu.annotation.Pattern\n" + + "import io.kabu.annotation.LocalPattern\n" + + "import io.kabu.annotation.ContextCreator\n" + + "import io.kabu.annotation.Context\n" + + "// lines below are for future imports or other declarations to fix line numbers used in tests\n" + + "\n\n\n\n" + + "// end of common part\n" internal const val KOTLIN_TEST_FILE_SUFFIX = "" internal const val KOTLIN_TEST_SCRIPT_FILE_PREFIX = - """ - package tests - - import io.kabu.annotation.Pattern - import io.kabu.annotation.LocalPattern - import io.kabu.annotation.ContextCreator - // lines below are for future imports or other declarations to fix line numbers used in tests - - - + "\npackage " + + DEFAULT_TEST_PACKAGE + + "\n\n" + + "import io.kabu.annotation.Pattern\n" + + "import io.kabu.annotation.LocalPattern\n" + + "import io.kabu.annotation.ContextCreator\n" + + "import io.kabu.annotation.Context\n" + + "// lines below are for future imports or other declarations to fix line numbers used in tests\n" + + "\n\n\n\n" + + "// end of common part\n" + + "run {\n" - // end of common part - run { - """ internal const val KOTLIN_TEST_SCRIPT_FILE_SUFFIX = "" + "}" From eca74b5b6ff5e038e3d79cf18b760f1f6179d80b Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Sat, 29 Jul 2023 01:27:24 +0600 Subject: [PATCH 40/43] implemented safeCast in WatcherContext --- .../io/kabu/backend/provider/provider/AssignProvider.kt | 2 +- .../io/kabu/backend/provider/provider/ComparisonProvider.kt | 3 +-- .../io/kabu/backend/provider/provider/InclusionProvider.kt | 2 +- runtime/src/main/kotlin/io/kabu/runtime/WatcherContext.kt | 5 +++++ 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/backend/src/main/kotlin/io/kabu/backend/provider/provider/AssignProvider.kt b/backend/src/main/kotlin/io/kabu/backend/provider/provider/AssignProvider.kt index a2a9521..ccd4266 100644 --- a/backend/src/main/kotlin/io/kabu/backend/provider/provider/AssignProvider.kt +++ b/backend/src/main/kotlin/io/kabu/backend/provider/provider/AssignProvider.kt @@ -21,7 +21,7 @@ class AssignProvider( // extracting values from stack for (i in providers.size - 1 downTo 0) { val provider = providers[i] - append("val v$i=$STACK_PROPERTY_NAME.pop() as ${provider.type};") + append("val v$i=safeCast<${provider.type}>($STACK_PROPERTY_NAME.pop());") } // constructor invocation diff --git a/backend/src/main/kotlin/io/kabu/backend/provider/provider/ComparisonProvider.kt b/backend/src/main/kotlin/io/kabu/backend/provider/provider/ComparisonProvider.kt index feefc84..89385e4 100644 --- a/backend/src/main/kotlin/io/kabu/backend/provider/provider/ComparisonProvider.kt +++ b/backend/src/main/kotlin/io/kabu/backend/provider/provider/ComparisonProvider.kt @@ -16,7 +16,6 @@ class ComparisonProvider( override fun provideCodeForConstructionFromAux(auxName: String): String { val holderClassCanonicalName = (typeNode as HolderTypeNode).rawClassName.canonicalName - //todo do safeCast method to bring right exceptions to the user //todo make holder creation through CodeBlock(%T, className) val code = buildString { @@ -25,7 +24,7 @@ class ComparisonProvider( val operatorInfoProviderIndex = providers.indexOf(operatorInfoProvider) for (i in providers.size - 1 downTo 0) { if (i == operatorInfoProviderIndex) continue - append("val v$i=$STACK_PROPERTY_NAME.pop() as ${providers[i].type};") + append("val v$i=safeCast<${providers[i].type}>($STACK_PROPERTY_NAME.pop());") } append("val v$operatorInfoProviderIndex=") diff --git a/backend/src/main/kotlin/io/kabu/backend/provider/provider/InclusionProvider.kt b/backend/src/main/kotlin/io/kabu/backend/provider/provider/InclusionProvider.kt index 05a72f1..16dda5c 100644 --- a/backend/src/main/kotlin/io/kabu/backend/provider/provider/InclusionProvider.kt +++ b/backend/src/main/kotlin/io/kabu/backend/provider/provider/InclusionProvider.kt @@ -20,7 +20,7 @@ class InclusionProvider( val providerInfoProviderIndex = providers.indexOfFirst { it is OperatorInfoProvider } for (i in providers.size - 1 downTo 0) { if (i == providerInfoProviderIndex) continue - append("val v$i=$STACK_PROPERTY_NAME.pop() as ${providers[i].type};") + append("val v$i=safeCast<${providers[i].type}>($STACK_PROPERTY_NAME.pop());") } append("val v$providerInfoProviderIndex=if(aux)InclusionInfo.IN else InclusionInfo.NOT_IN;") append("$holderClassCanonicalName(") diff --git a/runtime/src/main/kotlin/io/kabu/runtime/WatcherContext.kt b/runtime/src/main/kotlin/io/kabu/runtime/WatcherContext.kt index f4b63d8..9d9fd3d 100644 --- a/runtime/src/main/kotlin/io/kabu/runtime/WatcherContext.kt +++ b/runtime/src/main/kotlin/io/kabu/runtime/WatcherContext.kt @@ -1,8 +1,13 @@ package io.kabu.runtime +import io.kabu.runtime.exception.PatternEvaluationException import java.util.* open class WatcherContext { val stack: Stack = Stack() + + @Suppress("UNCHECKED_CAST") + fun safeCast(value: Any?): T = + value as? T ?: throw PatternEvaluationException("Unexpected type of $this in watcher stack.") } From 4cf6f050ecd098b0f21cc93adc2ef0da95da19db Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Sat, 29 Jul 2023 02:01:56 +0600 Subject: [PATCH 41/43] added comments and TODOs --- .../src/main/kotlin/io/kabu/backend/integration/TypeUtils.kt | 3 ++- .../backend/integration/detector/FunctionConflictDetector.kt | 1 + .../backend/integration/detector/PropertyConflictDetector.kt | 2 ++ .../kabu/backend/integration/detector/TypeConflictDetector.kt | 1 + .../backend/integration/detector/UserCodeConflictDetector.kt | 2 ++ .../io/kabu/backend/integration/resolver/ConflictResolver.kt | 1 + .../integration/resolver/TypeAndPropertyConflictResolver.kt | 1 + .../io/kabu/backend/node/namespace/ClassNamespaceNode.kt | 3 +++ .../kotlin/io/kabu/backend/node/namespace/NamespaceNode.kt | 3 +++ .../io/kabu/backend/node/namespace/PackageNamespaceNode.kt | 3 +++ 10 files changed, 19 insertions(+), 1 deletion(-) diff --git a/backend/src/main/kotlin/io/kabu/backend/integration/TypeUtils.kt b/backend/src/main/kotlin/io/kabu/backend/integration/TypeUtils.kt index 2ff79a7..ceae6e4 100644 --- a/backend/src/main/kotlin/io/kabu/backend/integration/TypeUtils.kt +++ b/backend/src/main/kotlin/io/kabu/backend/integration/TypeUtils.kt @@ -44,10 +44,11 @@ private fun areTypesPlatformClashing(first: TypeNode, second: TypeNode): Boolean val rawClassName1 = rawClassName(typeName1) val rawClassName2 = rawClassName(typeName2) + // raw classes is enough for "platform clashing" check rawClassName1 == rawClassName2 } typeName1 is LambdaTypeName && typeName2 is LambdaTypeName -> { - true + true //todo treating all functional types as conflicting for now } else -> false diff --git a/backend/src/main/kotlin/io/kabu/backend/integration/detector/FunctionConflictDetector.kt b/backend/src/main/kotlin/io/kabu/backend/integration/detector/FunctionConflictDetector.kt index a41de04..78ab629 100644 --- a/backend/src/main/kotlin/io/kabu/backend/integration/detector/FunctionConflictDetector.kt +++ b/backend/src/main/kotlin/io/kabu/backend/integration/detector/FunctionConflictDetector.kt @@ -15,6 +15,7 @@ class FunctionConflictDetector { private fun areFunctionNodesConflicting(node: FunctionNode, other: FunctionNode): Boolean { if (node.name != other.name) return false + // don't take into account returning type intentionally return areParametersPlatformClashing(node.parameters, other.parameters) } } diff --git a/backend/src/main/kotlin/io/kabu/backend/integration/detector/PropertyConflictDetector.kt b/backend/src/main/kotlin/io/kabu/backend/integration/detector/PropertyConflictDetector.kt index 5c8ec9b..6722bb5 100644 --- a/backend/src/main/kotlin/io/kabu/backend/integration/detector/PropertyConflictDetector.kt +++ b/backend/src/main/kotlin/io/kabu/backend/integration/detector/PropertyConflictDetector.kt @@ -17,6 +17,7 @@ class PropertyConflictDetector { private fun isConflictingWithPropertyNode(node: PropertyNode, other: PropertyNode): Boolean { if (node.name != other.name) return false + // don't take into account returning type intentionally return areParametersPlatformClashing( listOfNotNull(node.receiverTypeNode), listOfNotNull(other.receiverTypeNode), @@ -26,6 +27,7 @@ class PropertyConflictDetector { private fun isConflictingWithTypeNode(node: PropertyNode, other: TypeNode): Boolean { if (node.name != other.name) return false + // a property can conflict with type/object only if the property has not a receiver return node.receiverTypeNode == null } } diff --git a/backend/src/main/kotlin/io/kabu/backend/integration/detector/TypeConflictDetector.kt b/backend/src/main/kotlin/io/kabu/backend/integration/detector/TypeConflictDetector.kt index 7a867c3..3e60ab4 100644 --- a/backend/src/main/kotlin/io/kabu/backend/integration/detector/TypeConflictDetector.kt +++ b/backend/src/main/kotlin/io/kabu/backend/integration/detector/TypeConflictDetector.kt @@ -32,6 +32,7 @@ class TypeConflictDetector { private fun isConflictingWithPropertyNode(node: TypeNode, other: PropertyNode): Boolean { if (node.name != other.name) return false + // a property can conflict with type/object only if the property has not a receiver return other.receiverTypeNode == null } } diff --git a/backend/src/main/kotlin/io/kabu/backend/integration/detector/UserCodeConflictDetector.kt b/backend/src/main/kotlin/io/kabu/backend/integration/detector/UserCodeConflictDetector.kt index fbbb03f..0ca94e6 100644 --- a/backend/src/main/kotlin/io/kabu/backend/integration/detector/UserCodeConflictDetector.kt +++ b/backend/src/main/kotlin/io/kabu/backend/integration/detector/UserCodeConflictDetector.kt @@ -22,6 +22,8 @@ class UserCodeConflictDetector { return false } + //todo implement via KSP + //todo search for conflicting element (class, interface, object or property) in designated namespace fun isTypeNameOccupied(namespaceNode: NamespaceNode, typeName: String): Boolean { return false } diff --git a/backend/src/main/kotlin/io/kabu/backend/integration/resolver/ConflictResolver.kt b/backend/src/main/kotlin/io/kabu/backend/integration/resolver/ConflictResolver.kt index 9f50d48..7ebe4bf 100644 --- a/backend/src/main/kotlin/io/kabu/backend/integration/resolver/ConflictResolver.kt +++ b/backend/src/main/kotlin/io/kabu/backend/integration/resolver/ConflictResolver.kt @@ -4,5 +4,6 @@ import io.kabu.backend.node.Node interface ConflictResolver { + //todo any conflict resolver must take user types into account fun resolve(node1: Node, node2: Node) } diff --git a/backend/src/main/kotlin/io/kabu/backend/integration/resolver/TypeAndPropertyConflictResolver.kt b/backend/src/main/kotlin/io/kabu/backend/integration/resolver/TypeAndPropertyConflictResolver.kt index 66086c3..6781818 100644 --- a/backend/src/main/kotlin/io/kabu/backend/integration/resolver/TypeAndPropertyConflictResolver.kt +++ b/backend/src/main/kotlin/io/kabu/backend/integration/resolver/TypeAndPropertyConflictResolver.kt @@ -28,6 +28,7 @@ class TypeAndPropertyConflictResolver(private val integrator: Integrator) : Conf propertyNode: PropertyNode, ) { if (generatedTypeNode.desiredName != null) { + //todo there could be properties with changeable names (it could be possible to change property name) integrator.unresolvedConflictError(generatedTypeNode, propertyNode) } diff --git a/backend/src/main/kotlin/io/kabu/backend/node/namespace/ClassNamespaceNode.kt b/backend/src/main/kotlin/io/kabu/backend/node/namespace/ClassNamespaceNode.kt index 628b722..0abe94c 100644 --- a/backend/src/main/kotlin/io/kabu/backend/node/namespace/ClassNamespaceNode.kt +++ b/backend/src/main/kotlin/io/kabu/backend/node/namespace/ClassNamespaceNode.kt @@ -2,6 +2,9 @@ package io.kabu.backend.node.namespace import com.squareup.kotlinpoet.ClassName +/** + * Defines a namespace associated with some class. + */ interface ClassNamespaceNode : NamespaceNode { override val recursiveName: String diff --git a/backend/src/main/kotlin/io/kabu/backend/node/namespace/NamespaceNode.kt b/backend/src/main/kotlin/io/kabu/backend/node/namespace/NamespaceNode.kt index 93de918..1a90901 100644 --- a/backend/src/main/kotlin/io/kabu/backend/node/namespace/NamespaceNode.kt +++ b/backend/src/main/kotlin/io/kabu/backend/node/namespace/NamespaceNode.kt @@ -11,6 +11,9 @@ interface NamespaceNode : Node { val typeNameGenerator: SequentialTypeNameGenerator var accessorObjectNode : ObjectTypeNode? + /** + * Compose a ClassName for a [name]-named class inside this NamespaceNode + */ fun composeClassName(name: String): ClassName fun getRoot(): NamespaceNode { diff --git a/backend/src/main/kotlin/io/kabu/backend/node/namespace/PackageNamespaceNode.kt b/backend/src/main/kotlin/io/kabu/backend/node/namespace/PackageNamespaceNode.kt index d4442b6..962deda 100644 --- a/backend/src/main/kotlin/io/kabu/backend/node/namespace/PackageNamespaceNode.kt +++ b/backend/src/main/kotlin/io/kabu/backend/node/namespace/PackageNamespaceNode.kt @@ -2,6 +2,9 @@ package io.kabu.backend.node.namespace import com.squareup.kotlinpoet.ClassName +/** + * Defines a namespace associated with some package. + */ interface PackageNamespaceNode : NamespaceNode { override val recursiveName: String From dcc68dd03d43f80fe5e863747cf4cb28a1fdb84b Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Sat, 29 Jul 2023 22:46:30 +0600 Subject: [PATCH 42/43] implemented support for generic local patterns and generic extension contexts --- .../extension/ExtensionLambdaHandler.kt | 4 +-- .../ContextMediatorClassDeclaration.kt | 9 ++++-- .../functions/AbstractFunctionDeclaration.kt | 29 ++++++++++++++--- .../functions/FunctionDeclaration.kt | 4 ++- .../functions/TerminalFunctionDeclaration.kt | 4 ++- .../node/ContextMediatorTypeNodeImpl.kt | 5 ++- .../node/factory/node/RegularFunctionNode.kt | 1 + .../node/factory/node/TerminalFunctionNode.kt | 1 + .../main/kotlin/io/kabu/backend/node/node.kt | 16 ++++++++-- .../backend/processor/BackendProcessor.kt | 5 ++- .../provider/ExtensionLambdaProvider.kt | 9 +++--- .../kabu/backend/util/poet/TypeNameUtils.kt | 17 ++++++++++ .../ksp/processor/util/MethodCreationUtils.kt | 6 ++-- .../ksp/processor/util/TypeValidationUtils.kt | 9 +++--- .../util/builder/AbstractFunctionBuilder.kt | 25 +++++++++++++++ .../builder/ContextCreatorFunctionBuilder.kt | 12 +++---- .../builder/LocalPatternFunctionBuilder.kt | 13 +++----- ...assFoundByAnnotatedConstructorValidator.kt | 2 +- .../generic/test3/GenericContextTest.kt | 31 ++++++++++++++++++ .../test4/GenericContextCreationTest.kt | 32 +++++++++++++++++++ .../ksp/processor/misc/TypeParametersTest.kt | 14 +++----- ...oundByAnnotatedConstructorSupportedTest.kt | 20 ++++++++++++ .../ContextCreatorsFunctionsSupportedTest.kt | 11 +++++++ .../LocalPatternFunctionsSupportedTest.kt | 16 ++++++++++ ...dByAnnotatedConstructorNotSupportedTest.kt | 10 ------ ...ontextCreatorsFunctionsNotSupportedTest.kt | 11 ------- .../LocalPatternFunctionsNotSupportedTest.kt | 14 -------- 27 files changed, 242 insertions(+), 88 deletions(-) create mode 100644 frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/generic/test3/GenericContextTest.kt create mode 100644 frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/generic/test4/GenericContextCreationTest.kt create mode 100644 frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/supported/ContextClassFoundByAnnotatedConstructorSupportedTest.kt diff --git a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/extension/ExtensionLambdaHandler.kt b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/extension/ExtensionLambdaHandler.kt index ac69a84..fe869a0 100644 --- a/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/extension/ExtensionLambdaHandler.kt +++ b/backend/src/main/kotlin/io/kabu/backend/analyzer/handler/lambda/extension/ExtensionLambdaHandler.kt @@ -41,14 +41,14 @@ class ExtensionLambdaHandler( } val returningTypeNode = DerivativeTypeNode(namespaceNode, mutableListOf(contextMediatorTypeNode)) { deps -> - LambdaTypeName.get(returnType = UNIT, receiver = (deps.first() as ContextMediatorTypeNode).className) + LambdaTypeName.get(returnType = UNIT, receiver = (deps.first() as ContextMediatorTypeNode).typeName) } registerNode(returningTypeNode) return ExtensionLambdaProvider( typeNode = returningTypeNode, returningProvider = ArgumentProvider(extensionContextTypeNode, parameterName), - contextMediatorTypeNode = contextMediatorTypeNode, + contextMediatorTypeNode = contextMediatorTypeNode as ContextMediatorTypeNode, //todo fix in MethodsRegistry contextCreatorDefinition = extensionContextCreatorDefinition, destinationParameterTypeNode = destinationParameterType, analyzer = analyzer, diff --git a/backend/src/main/kotlin/io/kabu/backend/declaration/classes/ContextMediatorClassDeclaration.kt b/backend/src/main/kotlin/io/kabu/backend/declaration/classes/ContextMediatorClassDeclaration.kt index faa6d16..99bef62 100644 --- a/backend/src/main/kotlin/io/kabu/backend/declaration/classes/ContextMediatorClassDeclaration.kt +++ b/backend/src/main/kotlin/io/kabu/backend/declaration/classes/ContextMediatorClassDeclaration.kt @@ -8,14 +8,18 @@ import com.squareup.kotlinpoet.TypeSpec import io.kabu.backend.declaration.AbstractTypeDeclaration import io.kabu.backend.declaration.Declaration import io.kabu.backend.generator.addDeclarations +import io.kabu.backend.node.ContextMediatorTypeNode import io.kabu.backend.parameter.Parameter class ContextMediatorClassDeclaration( - override val className: ClassName, + val typeNode: ContextMediatorTypeNode, val contextProperty: Parameter, ) : AbstractTypeDeclaration() { + override val className: ClassName + get() = typeNode.rawClassName + // for adding declarations on generation code phase val innerDeclarations: MutableList = mutableListOf() @@ -26,7 +30,8 @@ class ContextMediatorClassDeclaration( } }.build() - return TypeSpec.classBuilder(className).apply { + return TypeSpec.classBuilder(typeNode.rawClassName).apply { + addTypeVariables(typeNode.gatherTypeVariableNames()) addModifiers(KModifier.PUBLIC) primaryConstructor(constructor).apply { contextProperty.let { diff --git a/backend/src/main/kotlin/io/kabu/backend/declaration/functions/AbstractFunctionDeclaration.kt b/backend/src/main/kotlin/io/kabu/backend/declaration/functions/AbstractFunctionDeclaration.kt index 755c27f..193ae63 100644 --- a/backend/src/main/kotlin/io/kabu/backend/declaration/functions/AbstractFunctionDeclaration.kt +++ b/backend/src/main/kotlin/io/kabu/backend/declaration/functions/AbstractFunctionDeclaration.kt @@ -4,12 +4,17 @@ import com.squareup.kotlinpoet.CodeBlock import com.squareup.kotlinpoet.FunSpec import com.squareup.kotlinpoet.KModifier import com.squareup.kotlinpoet.TypeName +import com.squareup.kotlinpoet.TypeVariableName import io.kabu.backend.declaration.AbstractCallableDeclaration +import io.kabu.backend.node.ContextMediatorTypeNode +import io.kabu.backend.node.namespace.NamespaceNode import io.kabu.backend.provider.group.OrderedNamedProviders import io.kabu.backend.util.poet.gatherTypeVariableNames -abstract class AbstractFunctionDeclaration : AbstractCallableDeclaration() { +abstract class AbstractFunctionDeclaration( + protected val namespaceNode: NamespaceNode?, +) : AbstractCallableDeclaration() { abstract fun generateFunSpec(): FunSpec @@ -24,10 +29,7 @@ abstract class AbstractFunctionDeclaration : AbstractCallableDeclaration() { isHelper: Boolean = false, ): FunSpec { return FunSpec.builder(name).apply { - val typeVariableNames = returnType.gatherTypeVariableNames() + - receiverType?.gatherTypeVariableNames().orEmpty() + - providers.providers.flatMap { it.type.gatherTypeVariableNames() } - addTypeVariables(typeVariableNames.toSet()) + addTypeVariables(gatherRequiredTypeVariableNames(providers, returnType, receiverType)) if (isHelper) addModifiers(KModifier.PRIVATE) when { @@ -46,4 +48,21 @@ abstract class AbstractFunctionDeclaration : AbstractCallableDeclaration() { }.build() } + + private fun gatherRequiredTypeVariableNames( + providers: OrderedNamedProviders, + returnType: TypeName, + receiverType: TypeName?, + ): Set { + val outerTypeVariableNames = if (namespaceNode is ContextMediatorTypeNode) { + namespaceNode.gatherTypeVariableNames() + } else emptyList() + + val typeVariableNames = returnType.gatherTypeVariableNames() + + receiverType?.gatherTypeVariableNames().orEmpty() + + providers.providers.flatMap { it.type.gatherTypeVariableNames() } + + @Suppress("ConvertArgumentToSet") + return typeVariableNames.toSet() - outerTypeVariableNames + } } diff --git a/backend/src/main/kotlin/io/kabu/backend/declaration/functions/FunctionDeclaration.kt b/backend/src/main/kotlin/io/kabu/backend/declaration/functions/FunctionDeclaration.kt index 9db3d23..f58fdcf 100644 --- a/backend/src/main/kotlin/io/kabu/backend/declaration/functions/FunctionDeclaration.kt +++ b/backend/src/main/kotlin/io/kabu/backend/declaration/functions/FunctionDeclaration.kt @@ -4,6 +4,7 @@ import com.squareup.kotlinpoet.CodeBlock import com.squareup.kotlinpoet.FunSpec import io.kabu.backend.node.TypeNode import io.kabu.backend.node.factory.node.util.RegularFunctionNodeKind +import io.kabu.backend.node.namespace.NamespaceNode import io.kabu.backend.parser.InfixFunction import io.kabu.backend.parser.Operator import io.kabu.backend.provider.group.FunDeclarationProviders @@ -16,7 +17,8 @@ class FunctionDeclaration( val funDeclarationProviders: FunDeclarationProviders, val returnTypeNode: TypeNode, val kind: RegularFunctionNodeKind, -) : AbstractFunctionDeclaration() { + namespaceNode: NamespaceNode?, +) : AbstractFunctionDeclaration(namespaceNode) { val functionName: String get() = when (kind) { diff --git a/backend/src/main/kotlin/io/kabu/backend/declaration/functions/TerminalFunctionDeclaration.kt b/backend/src/main/kotlin/io/kabu/backend/declaration/functions/TerminalFunctionDeclaration.kt index bb4f9b6..fde81e3 100644 --- a/backend/src/main/kotlin/io/kabu/backend/declaration/functions/TerminalFunctionDeclaration.kt +++ b/backend/src/main/kotlin/io/kabu/backend/declaration/functions/TerminalFunctionDeclaration.kt @@ -5,6 +5,7 @@ import com.squareup.kotlinpoet.TypeName import com.squareup.kotlinpoet.UNIT import io.kabu.backend.analyzer.Analyzer import io.kabu.backend.declaration.util.TerminalCallableBuilder +import io.kabu.backend.node.namespace.NamespaceNode import io.kabu.backend.parser.Assign import io.kabu.backend.parser.FunctionMustReturn import io.kabu.backend.parser.InfixFunction @@ -18,7 +19,8 @@ open class TerminalFunctionDeclaration( val operator: Operator, val funDeclarationProviders: FunDeclarationProviders, val analyzer: Analyzer, -) : AbstractFunctionDeclaration() { + namespaceNode: NamespaceNode?, +) : AbstractFunctionDeclaration(namespaceNode) { private val callableBuilder = TerminalCallableBuilder() diff --git a/backend/src/main/kotlin/io/kabu/backend/node/factory/node/ContextMediatorTypeNodeImpl.kt b/backend/src/main/kotlin/io/kabu/backend/node/factory/node/ContextMediatorTypeNodeImpl.kt index 5503113..f37af01 100644 --- a/backend/src/main/kotlin/io/kabu/backend/node/factory/node/ContextMediatorTypeNodeImpl.kt +++ b/backend/src/main/kotlin/io/kabu/backend/node/factory/node/ContextMediatorTypeNodeImpl.kt @@ -1,5 +1,6 @@ package io.kabu.backend.node.factory.node +import com.squareup.kotlinpoet.TypeVariableName import io.kabu.backend.declaration.classes.ContextMediatorClassDeclaration import io.kabu.backend.node.ContextMediatorTypeNode import io.kabu.backend.node.namespace.NamespaceNode @@ -7,16 +8,18 @@ import io.kabu.backend.parameter.Parameter class ContextMediatorTypeNodeImpl( name: String, + typeVariableNames: List, namespaceNode: NamespaceNode, private val contextProperty: Parameter, ) : ContextMediatorTypeNode( name = name, + typeVariableNames = typeVariableNames, desiredName = null, namespaceNode = namespaceNode, ) { private fun getContextMediatorClassDeclaration() = ContextMediatorClassDeclaration( - className = this.className, + typeNode = this, contextProperty = contextProperty, ) diff --git a/backend/src/main/kotlin/io/kabu/backend/node/factory/node/RegularFunctionNode.kt b/backend/src/main/kotlin/io/kabu/backend/node/factory/node/RegularFunctionNode.kt index c43631c..e6e09d6 100644 --- a/backend/src/main/kotlin/io/kabu/backend/node/factory/node/RegularFunctionNode.kt +++ b/backend/src/main/kotlin/io/kabu/backend/node/factory/node/RegularFunctionNode.kt @@ -29,6 +29,7 @@ class RegularFunctionNode( funDeclarationProviders = funDeclarationProviders, returnTypeNode = typeNode, kind = kind, + namespaceNode = namespaceNode, ) } diff --git a/backend/src/main/kotlin/io/kabu/backend/node/factory/node/TerminalFunctionNode.kt b/backend/src/main/kotlin/io/kabu/backend/node/factory/node/TerminalFunctionNode.kt index bdb312e..111d28b 100644 --- a/backend/src/main/kotlin/io/kabu/backend/node/factory/node/TerminalFunctionNode.kt +++ b/backend/src/main/kotlin/io/kabu/backend/node/factory/node/TerminalFunctionNode.kt @@ -28,6 +28,7 @@ class TerminalFunctionNode( operator = operator, funDeclarationProviders = funDeclarationProviders, analyzer = analyzer, + namespaceNode = namespaceNode, ) override fun createDeclarations() = listOf(getTerminalFunctionDeclaration()) diff --git a/backend/src/main/kotlin/io/kabu/backend/node/node.kt b/backend/src/main/kotlin/io/kabu/backend/node/node.kt index eab3003..edb5a38 100644 --- a/backend/src/main/kotlin/io/kabu/backend/node/node.kt +++ b/backend/src/main/kotlin/io/kabu/backend/node/node.kt @@ -246,6 +246,7 @@ open class WatcherContextTypeNode( open class ContextMediatorTypeNode( name: String, + val typeVariableNames: List, override val desiredName: String? = null, override var namespaceNode: NamespaceNode?, ) : GeneratedTypeNode(name), ClassNamespaceNode { @@ -265,12 +266,21 @@ open class ContextMediatorTypeNode( get() = mutableListOf() .apply { namespaceNode?.let { add(it) } } - val className: ClassName + val rawClassName: ClassName get() = namespaceNode!!.composeClassName(name) - //todo className vs typeName override val typeName: TypeName - get() = className + get() = composeTypeName() + + private fun composeTypeName(): TypeName { + return if (typeVariableNames.isEmpty()) rawClassName else { + rawClassName.parameterizedBy(typeVariableNames) + } + } + + fun gatherTypeVariableNames(): List { + return typeVariableNames + } init { updateLinks() diff --git a/backend/src/main/kotlin/io/kabu/backend/processor/BackendProcessor.kt b/backend/src/main/kotlin/io/kabu/backend/processor/BackendProcessor.kt index ba6f347..b296813 100644 --- a/backend/src/main/kotlin/io/kabu/backend/processor/BackendProcessor.kt +++ b/backend/src/main/kotlin/io/kabu/backend/processor/BackendProcessor.kt @@ -24,6 +24,7 @@ import io.kabu.backend.node.factory.node.ContextMediatorTypeNodeImpl import io.kabu.backend.node.namespace.NamespaceNode import io.kabu.backend.parameter.Parameter import io.kabu.backend.util.Constants +import io.kabu.backend.util.poet.gatherTypeVariableNames class BackendProcessor(private val options: Options = Options.DEFAULT) { @@ -89,8 +90,10 @@ class BackendProcessor(private val options: Options = Options.DEFAULT) { val contextMediatorClassSimpleName = packageNode.typeNameGenerator.generateNextTypeName() val contextMediatorTypeNode = ContextMediatorTypeNodeImpl( name = contextMediatorClassSimpleName, - namespaceNode = packageNode, + //todo consider (extensionContextTypeName as ParameterizedTypeName).typeArguments + typeVariableNames = extensionContextTypeName.gatherTypeVariableNames().toList(), //todo Origin() && Parameter ? + namespaceNode = packageNode, contextProperty = Parameter(Constants.EXTENSION_CONTEXT_PROPERTY_NAME, extensionContextTypeName, Origin()), ) diff --git a/backend/src/main/kotlin/io/kabu/backend/provider/provider/ExtensionLambdaProvider.kt b/backend/src/main/kotlin/io/kabu/backend/provider/provider/ExtensionLambdaProvider.kt index 54a841b..7a2ef17 100644 --- a/backend/src/main/kotlin/io/kabu/backend/provider/provider/ExtensionLambdaProvider.kt +++ b/backend/src/main/kotlin/io/kabu/backend/provider/provider/ExtensionLambdaProvider.kt @@ -1,19 +1,20 @@ package io.kabu.backend.provider.provider -import com.squareup.kotlinpoet.ClassName import io.kabu.backend.analyzer.Analyzer import io.kabu.backend.analyzer.handler.lambda.extension.ContextCreatorDefinition import io.kabu.backend.diagnostic.Origin import io.kabu.backend.diagnostic.builder.parameterIsNotEvaluatedYetError +import io.kabu.backend.node.ContextMediatorTypeNode import io.kabu.backend.node.TypeNode import io.kabu.backend.provider.evaluation.RetrievalWay import io.kabu.backend.util.poet.asCodeBlock +import io.kabu.backend.util.poet.fullNameWithTypeArguments class ExtensionLambdaProvider( typeNode: TypeNode, returningProvider: AbstractProvider, //todo don't need? //todo rename - val contextMediatorTypeNode: TypeNode, + val contextMediatorTypeNode: ContextMediatorTypeNode, val contextCreatorDefinition: ContextCreatorDefinition, val destinationParameterTypeNode: TypeNode, analyzer: Analyzer, @@ -63,9 +64,9 @@ class ExtensionLambdaProvider( // constructing evaluation code val contextCreatorInvocation = creatorMethod.getInvocationCode(creatorParameterProviders, providerContainer) - val contextMediatorClassName = (contextMediatorTypeNode.typeName as ClassName).canonicalName + val mediatorFullNameWithTypeArguments = contextMediatorTypeNode.typeName.fullNameWithTypeArguments() - val code = "($contextCreatorInvocation).also{with($contextMediatorClassName(it)){${selfName!!}()}}" + val code = "($contextCreatorInvocation).also{with($mediatorFullNameWithTypeArguments(it)){${selfName!!}()}}" return RetrievalWay(code.asCodeBlock(), isReentrant = false) } diff --git a/backend/src/main/kotlin/io/kabu/backend/util/poet/TypeNameUtils.kt b/backend/src/main/kotlin/io/kabu/backend/util/poet/TypeNameUtils.kt index f7b49f0..018b343 100644 --- a/backend/src/main/kotlin/io/kabu/backend/util/poet/TypeNameUtils.kt +++ b/backend/src/main/kotlin/io/kabu/backend/util/poet/TypeNameUtils.kt @@ -8,6 +8,7 @@ import com.squareup.kotlinpoet.TypeName import com.squareup.kotlinpoet.TypeVariableName import com.squareup.kotlinpoet.WildcardTypeName import io.kabu.backend.node.FixedTypeNode +import io.kabu.backend.util.poet.TypeNameUtils.requireClassName object TypeNameUtils { @@ -69,3 +70,19 @@ fun TypeName.gatherTypeVariableNames(collector: MutableSet) { Dynamic -> Unit } } + +fun TypeName.fullNameWithTypeArguments(): String { + val rawClassCanonicalName = requireClassName.canonicalName + + val typeArguments = when(this) { + is ParameterizedTypeName -> typeArguments.map { (it as TypeVariableName).name } + is ClassName -> emptyList() + else -> error("Unknown context mediator type: $this") + } + + val typeArgumentsPart = if (typeArguments.isNotEmpty()) { + typeArguments.joinToString(prefix = "<", postfix = ">", separator = ",") + } else "" + + return rawClassCanonicalName + typeArgumentsPart +} diff --git a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/MethodCreationUtils.kt b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/MethodCreationUtils.kt index a2e8f7f..b6ebf1b 100644 --- a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/MethodCreationUtils.kt +++ b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/MethodCreationUtils.kt @@ -2,6 +2,7 @@ package io.kabu.frontend.ksp.processor.util import com.google.devtools.ksp.symbol.KSFunctionDeclaration import com.google.devtools.ksp.symbol.KSTypeReference +import com.squareup.kotlinpoet.ksp.TypeParameterResolver import com.squareup.kotlinpoet.ksp.toTypeParameterResolver import io.kabu.backend.diagnostic.Origin import io.kabu.backend.exception.PatternProcessingException @@ -11,8 +12,9 @@ import io.kabu.backend.util.Constants.RECEIVER_PARAMETER_NAME import io.kabu.frontend.ksp.diagnostic.builder.parameterProcessingError -internal fun KSFunctionDeclaration.toMethod(): Method { - val typeParameterResolver = typeParameters.toTypeParameterResolver() +internal fun KSFunctionDeclaration.toMethod(parentTypeParametersResolver: TypeParameterResolver? = null): Method { + val typeParameterResolver = typeParameters + .toTypeParameterResolver(parentTypeParametersResolver, "'$this, ${this.location}'") val methodOrigin = originOf(this) val methodName = simpleName.asString() diff --git a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/TypeValidationUtils.kt b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/TypeValidationUtils.kt index b191f85..0202971 100644 --- a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/TypeValidationUtils.kt +++ b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/TypeValidationUtils.kt @@ -5,7 +5,6 @@ import com.google.devtools.ksp.symbol.KSType import com.google.devtools.ksp.symbol.KSTypeArgument import com.google.devtools.ksp.symbol.KSTypeReference import com.google.devtools.ksp.symbol.KSValueParameter -import com.google.devtools.ksp.symbol.Variance internal fun KSTypeReference.validate() { val type = resolve() @@ -34,11 +33,11 @@ internal fun KSType.validate() { } internal fun validateTypeArgument(typeArgument: KSTypeArgument) { -// areNotSupported(typeArgument.variance == Variance.CONTRAVARIANT, typeArgument) { // supported +// areNotSupported(typeArgument.variance == Variance.CONTRAVARIANT, typeArgument) { // tested // supported // "Contravariant type arguments" -// } // tested -// areNotSupported(typeArgument.variance == Variance.COVARIANT, typeArgument) { "Covariant type arguments" } // supported - areNotSupported(typeArgument.variance == Variance.STAR, typeArgument) { "Star projections" } // tested +// } +// areNotSupported(typeArgument.variance == Variance.COVARIANT, typeArgument) { "Covariant type arguments" } // tested // supported +// areNotSupported(typeArgument.variance == Variance.STAR, typeArgument) { "Star projections" } // tested // supported } /** diff --git a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/builder/AbstractFunctionBuilder.kt b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/builder/AbstractFunctionBuilder.kt index 22cb6be..1ff0878 100644 --- a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/builder/AbstractFunctionBuilder.kt +++ b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/builder/AbstractFunctionBuilder.kt @@ -9,17 +9,42 @@ import com.google.devtools.ksp.symbol.KSClassDeclaration import com.google.devtools.ksp.symbol.KSFunctionDeclaration import com.google.devtools.ksp.symbol.Modifier import com.google.devtools.ksp.symbol.Visibility +import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy +import com.squareup.kotlinpoet.TypeName +import com.squareup.kotlinpoet.ksp.TypeParameterResolver +import com.squareup.kotlinpoet.ksp.toTypeVariableName import io.kabu.backend.inout.input.method.Method +import io.kabu.backend.util.poet.TypeNameUtils.requireClassName import io.kabu.frontend.ksp.processor.util.areNotSupported +import io.kabu.frontend.ksp.processor.util.asTypeName import io.kabu.frontend.ksp.processor.util.builder.validator.notSupportedFunctionKinds import io.kabu.frontend.ksp.processor.util.builder.validator.notSupportedFunctionModifiers import io.kabu.frontend.ksp.processor.util.builder.validator.notSupportedFunctionVisibilities +import io.kabu.frontend.ksp.processor.util.validate abstract class AbstractFunctionBuilder { abstract fun build(function: KSFunctionDeclaration): T + protected fun getTypeNameOfEnclosingType( + classDeclaration: KSClassDeclaration, + typeParameterResolver: TypeParameterResolver, + ): TypeName { + val declaringType = classDeclaration + .asStarProjectedType() + .also { it.validate() } + .asTypeName() + + val typeVariableNames = classDeclaration.typeParameters.map { it.toTypeVariableName(typeParameterResolver) } + + return if (typeVariableNames.isNotEmpty()) { + declaringType.requireClassName.parameterizedBy(typeVariableNames) + } else { + declaringType + } + } + protected open fun validateFunction(function: KSFunctionDeclaration, role: String) { val isInObject = (function.parentDeclaration as? KSClassDeclaration)?.classKind == ClassKind.OBJECT areNotSupported(isInObject, function) { "Functions of objects as $role" } // tested diff --git a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/builder/ContextCreatorFunctionBuilder.kt b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/builder/ContextCreatorFunctionBuilder.kt index 3e71896..0ff6c30 100644 --- a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/builder/ContextCreatorFunctionBuilder.kt +++ b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/builder/ContextCreatorFunctionBuilder.kt @@ -4,6 +4,7 @@ import com.google.devtools.ksp.isConstructor import com.google.devtools.ksp.symbol.FunctionKind import com.google.devtools.ksp.symbol.KSClassDeclaration import com.google.devtools.ksp.symbol.KSFunctionDeclaration +import com.squareup.kotlinpoet.ksp.toTypeParameterResolver import io.kabu.annotation.Context import io.kabu.annotation.ContextCreator import io.kabu.backend.diagnostic.diagnosticError @@ -11,13 +12,11 @@ import io.kabu.backend.inout.input.method.ContextConstructorMethod.Companion.toC import io.kabu.backend.inout.input.method.ContextCreatorMethod import io.kabu.backend.inout.input.method.ContextCreatorMethod.Companion.toContextCreatorMethod import io.kabu.frontend.ksp.processor.util.areNotSupported -import io.kabu.frontend.ksp.processor.util.asTypeName import io.kabu.frontend.ksp.processor.util.builder.validator.ContextClassFoundByAnnotatedConstructorValidator import io.kabu.frontend.ksp.processor.util.getAnnotation import io.kabu.frontend.ksp.processor.util.getAnnotationOrNull import io.kabu.frontend.ksp.processor.util.originOf import io.kabu.frontend.ksp.processor.util.toMethod -import io.kabu.frontend.ksp.processor.util.validate class ContextCreatorFunctionBuilder : AbstractFunctionBuilder() { @@ -63,12 +62,11 @@ class ContextCreatorFunctionBuilder : AbstractFunctionBuilder() { @@ -24,7 +23,6 @@ class LocalPatternFunctionBuilder : AbstractFunctionBuilder( val role = LocalPattern::class.simpleName!! validateFunction(function, role) - val localPatternAnnotation = function.getAnnotation() val pattern = localPatternAnnotation.arguments .single { it.name?.asString() == LocalPattern::pattern.name } @@ -33,12 +31,11 @@ class LocalPatternFunctionBuilder : AbstractFunctionBuilder( val classDeclaration = function.parentDeclaration as? KSClassDeclaration ?: unexpectedLocalPatternError(originOf(function), function.parentDeclaration?.let { originOf(it) }) - val declaringType = classDeclaration - .asStarProjectedType() //todo highlight generic nuances intentionally - .also { it.validate() } - .asTypeName() //todo val typeParameterResolver = typeParameters.toTypeParameterResolver() + //todo set parent resolver from enclosing class? + val typeParameterResolver = classDeclaration.typeParameters.toTypeParameterResolver() + val declaringType = getTypeNameOfEnclosingType(classDeclaration, typeParameterResolver) - return function.toMethod().toLocalPatternMethod(declaringType, pattern) + return function.toMethod(typeParameterResolver).toLocalPatternMethod(declaringType, pattern) } override fun validateFunction(function: KSFunctionDeclaration, role: String) { diff --git a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/builder/validator/ContextClassFoundByAnnotatedConstructorValidator.kt b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/builder/validator/ContextClassFoundByAnnotatedConstructorValidator.kt index 2ecd92b..6d7c8a4 100644 --- a/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/builder/validator/ContextClassFoundByAnnotatedConstructorValidator.kt +++ b/frontend/ksp/processor/src/main/kotlin/io/kabu/frontend/ksp/processor/util/builder/validator/ContextClassFoundByAnnotatedConstructorValidator.kt @@ -47,7 +47,7 @@ class ContextClassFoundByAnnotatedConstructorValidator : ContextClassValidator() areNotSupported(clazz.isCompanionObject, clazz) { "Companion objects as $role" } // tested areNotSupported(clazz.isActual, clazz) { "Classes with keyword 'actual' as $role" } areNotSupported(clazz.isExpect, clazz) { "Classes with keyword 'expect' as $role" } - areNotSupported(clazz.typeParameters.isNotEmpty(), clazz) { "Parameterized classes as $role" } // tested +// areNotSupported(clazz.typeParameters.isNotEmpty(), clazz) { "Parameterized classes as $role" } // supported areNotSupported(clazz.isAbstract(), clazz) { "Abstract classes as $role" } // tested } } diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/generic/test3/GenericContextTest.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/generic/test3/GenericContextTest.kt new file mode 100644 index 0000000..b34f688 --- /dev/null +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/generic/test3/GenericContextTest.kt @@ -0,0 +1,31 @@ +package io.kabu.frontend.ksp.processor.generic.test3 + +import io.kabu.frontend.ksp.processor.BaseKspFrontendProcessorTest +import io.kabu.frontend.ksp.processor.TestCase +import io.kabu.frontend.ksp.processor.minus +import io.kabu.frontend.ksp.processor.sample +import org.junit.Test + + +class GenericContextTest : BaseKspFrontendProcessorTest() { + + @Test + fun test() = compileAndCheckAndRun( + """ + // PACKAGE test3 + + @Context("ctx") + class Ctx { + + @LocalPattern("a - b (c)") + fun foo(a: T, b: Array, c: (E) -> E) = Unit + } + """, + sample( + """ + // PACKAGE test3 + print(H1::class) + """ + ) - TestCase.ScriptResult.Termination("class test3.H1"), + ) +} diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/generic/test4/GenericContextCreationTest.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/generic/test4/GenericContextCreationTest.kt new file mode 100644 index 0000000..3cb659c --- /dev/null +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/generic/test4/GenericContextCreationTest.kt @@ -0,0 +1,32 @@ +package io.kabu.frontend.ksp.processor.generic.test4 + +import io.kabu.frontend.ksp.processor.BaseKspFrontendProcessorTest +import io.kabu.frontend.ksp.processor.TestCase +import io.kabu.frontend.ksp.processor.minus +import io.kabu.frontend.ksp.processor.sample +import org.junit.Test + + +class GenericContextCreationTest : BaseKspFrontendProcessorTest() { + + @Test + fun test() = compileAndCheckAndRun( + """ + // PACKAGE test4 + + @Context("ctx") + class Ctx(val t: T) + + @Pattern("b - @Extend(context = ctx(b), parameter = ctx) {}") + fun foo(ctx: Ctx, b: T): T { + return ctx.t + } + """, + sample( + """ + // PACKAGE test4 + print("abc" - {}) + """ + ) - TestCase.ScriptResult.Termination("abc"), + ) +} diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/misc/TypeParametersTest.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/misc/TypeParametersTest.kt index f794560..a786219 100644 --- a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/misc/TypeParametersTest.kt +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/misc/TypeParametersTest.kt @@ -6,20 +6,14 @@ import org.junit.Test class TypeParametersTest : BaseKspFrontendProcessorTest() { @Test - fun `unsupported star projections`() = compileAndCheck( + fun `supported star projections`() = compileAndCheck( """ - class A - - @Pattern("foo @Extend(context = bar(), parameter = par) {}") - fun f(par: A<*>){ + @Pattern("list {}") + fun f(list: List<*>){ } """ ) { - assertCompilationError() - assertExpectedMessage("Error while processing parameter 'par' of function 'f': " + - "Star projections aren't supported yet") - assertExpectedLineNumber(17) - assertExpectedMessage("\"par\"") + assertOk() } @Test diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/supported/ContextClassFoundByAnnotatedConstructorSupportedTest.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/supported/ContextClassFoundByAnnotatedConstructorSupportedTest.kt new file mode 100644 index 0000000..363642c --- /dev/null +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/supported/ContextClassFoundByAnnotatedConstructorSupportedTest.kt @@ -0,0 +1,20 @@ +package io.kabu.frontend.ksp.processor.supported + +import io.kabu.frontend.ksp.processor.BaseKspFrontendProcessorTest +import org.junit.Test + +/** + * Validation of context class constructor of which is marked as [ContextCreator] + */ +class ContextClassFoundByAnnotatedConstructorSupportedTest : BaseKspFrontendProcessorTest() { + + @Test + fun `parameterized class supported`() = compileAndCheck( + """ + class Foo @ContextCreator("ctx") constructor() { + } + """ + ) { + assertOk() + } +} diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/supported/ContextCreatorsFunctionsSupportedTest.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/supported/ContextCreatorsFunctionsSupportedTest.kt index a8b6579..b008ecc 100644 --- a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/supported/ContextCreatorsFunctionsSupportedTest.kt +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/supported/ContextCreatorsFunctionsSupportedTest.kt @@ -32,4 +32,15 @@ class ContextCreatorsFunctionsSupportedTest : BaseKspFrontendProcessorTest() { ) { assertOk() } + + @Test + fun `parameterized function supported`() = compileAndCheck( + """ + @ContextCreator("ctx") + fun func(bar: T) { + } + """ + ) { + assertOk() + } } diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/supported/LocalPatternFunctionsSupportedTest.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/supported/LocalPatternFunctionsSupportedTest.kt index be34b34..87a1327 100644 --- a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/supported/LocalPatternFunctionsSupportedTest.kt +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/supported/LocalPatternFunctionsSupportedTest.kt @@ -1,7 +1,23 @@ package io.kabu.frontend.ksp.processor.supported import io.kabu.frontend.ksp.processor.BaseKspFrontendProcessorTest +import org.junit.Test class LocalPatternFunctionsSupportedTest : BaseKspFrontendProcessorTest() { + // todo add tests for supported cases + + @Test + fun `parameterized function supported`() = compileAndCheck( + """ + class Foo { + + @LocalPattern("!bar") + fun func(bar: T) { + } + } + """ + ) { + assertOk() + } } diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/unsupported/ContextClassFoundByAnnotatedConstructorNotSupportedTest.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/unsupported/ContextClassFoundByAnnotatedConstructorNotSupportedTest.kt index 737e1c9..8ff5ca3 100644 --- a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/unsupported/ContextClassFoundByAnnotatedConstructorNotSupportedTest.kt +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/unsupported/ContextClassFoundByAnnotatedConstructorNotSupportedTest.kt @@ -159,14 +159,4 @@ class ContextClassFoundByAnnotatedConstructorNotSupportedTest : BaseKspFrontendP ) { assertCompilationError(16, "Object as $role isn't supported yet", "\"Foo\"") } - - @Test - fun `parameterized class not supported`() = compileAndCheck( - """ - class Foo @ContextCreator("ctx") constructor() { - } - """ - ) { - assertCompilationError(14, "Parameterized classes as $role aren't supported yet", "\"Foo\"") - } } diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/unsupported/ContextCreatorsFunctionsNotSupportedTest.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/unsupported/ContextCreatorsFunctionsNotSupportedTest.kt index f4acce1..f81198f 100644 --- a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/unsupported/ContextCreatorsFunctionsNotSupportedTest.kt +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/unsupported/ContextCreatorsFunctionsNotSupportedTest.kt @@ -221,15 +221,4 @@ class ContextCreatorsFunctionsNotSupportedTest : BaseKspFrontendProcessorTest() ) { assertCompilationError(17, "Tailrec functions as $role aren't supported yet", "\"findFixPoint\"") } - - @Test - fun `parameterized function not supported`() = compileAndCheck( - """ - @ContextCreator("ctx") - fun func(bar: T) { - } - """ - ) { - assertCompilationError(15, "Functions with type parameters as $role aren't supported yet", "\"func\"") - } } diff --git a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/unsupported/LocalPatternFunctionsNotSupportedTest.kt b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/unsupported/LocalPatternFunctionsNotSupportedTest.kt index 442c0a4..011e37f 100644 --- a/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/unsupported/LocalPatternFunctionsNotSupportedTest.kt +++ b/frontend/ksp/processor/src/test/kotlin/io/kabu/frontend/ksp/processor/unsupported/LocalPatternFunctionsNotSupportedTest.kt @@ -205,18 +205,4 @@ class LocalPatternFunctionsNotSupportedTest : BaseKspFrontendProcessorTest() { ) { assertCompilationError(18, "Tailrec functions as $role aren't supported yet", "\"findFixPoint\"") } - - @Test - fun `parameterized function not supported`() = compileAndCheck( - """ - class Foo { - - @LocalPattern("!bar") - fun func(bar: T) { - } - } - """ - ) { - assertCompilationError(17, "Functions with type parameters as $role aren't supported yet", "\"func\"") - } } From 90d9f122765a6c96585fa960a753e62e4699875c Mon Sep 17 00:00:00 2001 From: bipokot <10675204+bipokot@users.noreply.github.com> Date: Sat, 29 Jul 2023 23:38:02 +0600 Subject: [PATCH 43/43] updated documentation --- README.md | 1 + doc/patternExtension.md | 2 +- doc/targetFunctions.md | 3 +-- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 73a3861..208fb7f 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ Patterns can be almost as complex as you can do it with Kotlin. - **[Rich support for Kotlin operations](doc/patternSyntax.md)**: Kabu supports almost all operations usable for DSL creation (and some previously considered useless). - **Any pattern complexity**: if it's syntactically correct, Kabu will generate it. - **[Pattern extensibility](doc/patternExtension.md)**: use lambdas with receiver in a more convenient and safe way by [extending](doc/patternExtension.md) your pattern. +- **Support for generics**: target functions and extension context classes may be generic. - **Retrieving actual used operator**: know whether `<` or `>` was used in runtime expression (`in`/`!in` for inclusion). - **Propagation of user given names**: generated code takes into account user given names for elements. - **Conflict resolution**: possible conflicts between declarations for different patterns are resolved automatically. diff --git a/doc/patternExtension.md b/doc/patternExtension.md index dbef882..57a6399 100644 --- a/doc/patternExtension.md +++ b/doc/patternExtension.md @@ -40,7 +40,7 @@ An error occurs if there are no applicable context creators or there are more th `result=` - where `` defines a parameter of the [target function](targetFunctions.md), which will receive a returned value of the lambda invocation. ## Context class -Context class defines a scope for local [target functions](targetFunctions.md) (`@LocalPattern` functions). Context class must be a non-abstract top level class. A context class may be used for different extension points. +Context class defines a scope for local [target functions](targetFunctions.md) (`@LocalPattern` functions). Context class must be a non-abstract top level class. One context class may be used for different extension points. Member functions of a context class which are annotated with `@LocalPattern` annotation constitute a set of allowed operations inside a lambda. Statements corresponding to patterns of those local [target functions](targetFunctions.md) will be the only accessible way to interact with an instance of the context class. diff --git a/doc/targetFunctions.md b/doc/targetFunctions.md index ea6f8a4..4b041c8 100644 --- a/doc/targetFunctions.md +++ b/doc/targetFunctions.md @@ -5,7 +5,6 @@ Target functions are functions which have been annotated with `@Pattern`/`@Local ## Restrictions These types of functions can not be used as target functions: - anonymous or local functions -- generic functions - functions with following modifiers: - inline - operator @@ -91,7 +90,7 @@ You can use nullable types in your function signature. See `Example-011`. #### Generic types -Generic parameter types are not fully supported yet. You can use parameters with generic types with type parameters in `invariant` position only. +You can use generic parameter types. #### Functional types You can use functional types (with optional parameters/receivers) to receive an object of functional type in a target function and use it appropriately (e.g. call its `invoke` under some condition).