Skip to content

Commit

Permalink
Merge dev into master
Browse files Browse the repository at this point in the history
  • Loading branch information
bipokot committed Jul 30, 2023
2 parents 715a16e + 90d9f12 commit 3e4feb5
Show file tree
Hide file tree
Showing 159 changed files with 1,662 additions and 1,199 deletions.
13 changes: 9 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -218,7 +219,8 @@ data class FootballTeam(
val trophies: List<Trophy>
)

class PlayersBuilder @ContextCreator("playersBuilder") constructor() {
@Context("playersBuilder")
class PlayersBuilder {
val players = mutableListOf<Player>()

@LocalPattern("name - number")
Expand All @@ -227,7 +229,8 @@ class PlayersBuilder @ContextCreator("playersBuilder") constructor() {
}
}

class FootballTeamBuilder @ContextCreator("footballTeamBuilder") constructor() {
@Context("footballTeamBuilder")
class FootballTeamBuilder {

val trophies = mutableListOf<Trophy>()
var isChampion = false
Expand Down Expand Up @@ -282,7 +285,8 @@ fun main() {
```kotlin
// Example-009

class Actions @ContextCreator("actions") constructor() {
@Context("actions")
class Actions {
val trueActions = mutableListOf<() -> Unit>()
val falseActions = mutableListOf<() -> Unit>()

Expand Down Expand Up @@ -474,7 +478,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>()

Expand Down
10 changes: 10 additions & 0 deletions annotation/src/main/kotlin/io/kabu/annotation/Context.kt
Original file line number Diff line number Diff line change
@@ -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
)
3 changes: 2 additions & 1 deletion backend/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ interface Analyzer {

val methodsRegistry: MethodsRegistry

val contextPropertyName: String?
val isLocalPattern: Boolean

val namespaceNode: NamespaceNode

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,13 @@ 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(
override val method: PatternMethod,
override val methodsRegistry: MethodsRegistry,
override val contextPropertyName: String?,
val options: Options,
private val contextMediatorNamespaceNode: NamespaceNode? = null,
) : Analyzer {
Expand All @@ -58,6 +55,8 @@ class AnalyzerImpl(
} catch (e: PatternParsingException) {
patternParsingError(e)
}
override val isLocalPattern: Boolean
get() = contextMediatorNamespaceNode != null

val parametersRegistry = ParametersRegistry(method, expression)

Expand Down Expand Up @@ -136,7 +135,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<Provider> = expressions.drop(1)
.map { providerOf(it) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -15,41 +15,35 @@ class ParametersRegistry(
val expression: KotlinExpression
) {

val entryParameters: List<EntryParameter> = composeEntryParameters()
.also { validateEntryParameters(it) }
val parametersTypes: Map<String, FixedTypeNode> = entryParameters
val parameters: List<Parameter> = composeParameters()
.also { validateParameters(it) }
val parametersTypes: Map<String, FixedTypeNode> = parameters
.groupBy({ it.name }, { it.type.toFixedTypeNode() })
.mapValues { it.value.single() }

var receiverCatchIsNecessary = false
private var operatorInfoParametersUsed = false
val strictMethodParametersOrdering get() = operatorInfoParametersUsed

private fun composeEntryParameters(): List<EntryParameter> {
val receiverParameter = method.receiverType?.let {
EntryParameter(RECEIVER_PARAMETER_NAME, it, method.origin) //todo origin for receiver
}
val parameterList = method.parameters.map {
EntryParameter(it.name, it.type, it.origin)
}
return listOfNotNull(receiverParameter) + parameterList
private fun composeParameters(): List<Parameter> {
return listOfNotNull(method.receiver) + method.parameters
}

private fun validateEntryParameters(entryParameters: List<EntryParameter>) {
checkStrictParametersOrdering(entryParameters)
private fun validateParameters(parameters: List<Parameter>) {
checkStrictParametersOrdering(parameters)
checkReceiverParameterPresence()
checkForSameNamedParameters(entryParameters)
checkForSameNamedParameters(parameters)
}

private fun checkForSameNamedParameters(methodParameters: List<EntryParameter>) {
private fun checkForSameNamedParameters(methodParameters: List<Parameter>) {
val sameNamedParameters = methodParameters
.groupBy { it.name }
.filter { it.value.size > 1 }
sameNamedParameters.entries.firstOrNull()
?.let { (name, parameters) -> sameNamedParametersError(name, parameters) }
}

private fun checkStrictParametersOrdering(methodParameters: List<EntryParameter>) {
private fun checkStrictParametersOrdering(methodParameters: List<Parameter>) {
operatorInfoParametersUsed = methodParameters.any { it.type.isOperatorInfoType }
}

Expand Down
41 changes: 27 additions & 14 deletions backend/src/main/kotlin/io/kabu/backend/analyzer/handler/Handler.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,42 @@ 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
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
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
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
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(
Expand All @@ -46,7 +49,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

Expand All @@ -56,16 +59,26 @@ 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?
): BaseProvider {
leftHandSideOfAssign: LeftHandSideOfAssign?
): AbstractProvider {
val funDeclarationProviders = FunDeclarationProvidersFactory
.from(rawProviders, operator.invertedArgumentOrdering)
.from(rawProviders, operator.overriding.invertedArgumentOrdering)

val functionBlockContext = FunctionBlockContext(funDeclarationProviders)
//todo not adding operator info provider here!
Expand Down Expand Up @@ -108,23 +121,23 @@ 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,
returnTypeNode = translationReturnedTypeNode,
assignableSuffixExpression = assignableSuffixExpression,
leftHandSideOfAssign = leftHandSideOfAssign,
rawProviders = rawProviders,
)
val watcherLambda = analyzer.currentWatcherLambda ?: watcherLambdaMissingError(operator)
watcherLambda.register(captureType)

// 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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -102,14 +101,12 @@ class IdentifierHandler(analyzer: AnalyzerImpl) : Handler(analyzer) {
}

private fun createReceiverHolderParameter(name: String): HolderProvider {
val method = analyzer.method
val receiverType = method.receiverType //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 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()
Expand All @@ -119,6 +116,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)
}
}
Loading

0 comments on commit 3e4feb5

Please sign in to comment.