first version of parameters variations

This commit is contained in:
2025-02-12 12:20:22 +06:00
parent f807f2beeb
commit a5008c3d15
3 changed files with 199 additions and 44 deletions

View File

@@ -8,14 +8,13 @@ import com.google.devtools.ksp.processing.SymbolProcessor
import com.google.devtools.ksp.symbol.*
import com.squareup.kotlinpoet.*
import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
import com.squareup.kotlinpoet.ksp.toClassName
import com.squareup.kotlinpoet.ksp.toKModifier
import com.squareup.kotlinpoet.ksp.toTypeName
import dev.inmo.micro_ksp.generator.companion
import dev.inmo.micro_ksp.generator.findSubClasses
import dev.inmo.micro_ksp.generator.writeFile
import dev.inmo.micro_utils.ksp.variations.GenerateVariations
import dev.inmo.micro_utils.ksp.variations.GenerationVariant
import kotlin.math.pow
class Processor(
private val codeGenerator: CodeGenerator
@@ -50,73 +49,212 @@ class Processor(
) {
val annotation = ksFunctionDeclaration.getAnnotationsByType(GenerateVariations::class).first()
val variations: List<Pair<List<GenerationVariant>, KSValueParameter>> = ksFunctionDeclaration.parameters.mapNotNull {
val variationAnnotations = it.getAnnotationsByType(GenerationVariant::class).toList().ifEmpty { return@mapNotNull null }
val variationAnnotations = it.getAnnotationsByType(GenerationVariant::class).toList()
variationAnnotations to it
}
val accumulatedGenerations = mutableSetOf<FunSpec>()
val accumulatedGenerations = mutableSetOf<Pair<FunSpec, Map<String, String>>>()
val baseFunctionParameters = ksFunctionDeclaration.parameters.mapNotNull {
ParameterSpec
.builder(
it.name ?.asString() ?: return@mapNotNull null,
it.type.toTypeName(),
)
.apply {
if (it.isCrossInline) {
addModifiers(KModifier.CROSSINLINE)
}
if (it.isVal) {
addModifiers(KModifier.VALUE)
}
if (it.isNoInline) {
addModifiers(KModifier.NOINLINE)
}
if (it.isVararg) {
addModifiers(KModifier.VARARG)
}
}
.build() to it.hasDefault
}
val baseFunctionFunSpecs = mutableListOf<Pair<FunSpec, Map<String, String>>>()
let {
var defaultParametersIndicator = 0u
val maxIndicator = baseFunctionParameters.filter { it.second }.foldIndexed(0u) { index, acc, _ ->
2.0.pow(index).toUInt() + acc
}
while (defaultParametersIndicator <= maxIndicator) {
var currentDefaultParameterIndex = 0u
val baseFunctionDefaults = mutableMapOf<String, String>()
val funSpec = FunSpec.builder(ksFunctionDeclaration.simpleName.asString()).apply {
modifiers.addAll(ksFunctionDeclaration.modifiers.mapNotNull { it.toKModifier() })
ksFunctionDeclaration.extensionReceiver ?.let {
receiver(it.toTypeName())
}
}
baseFunctionParameters.forEach { (parameter, hasDefault) ->
if (hasDefault) {
val shouldBeIncluded = (2.0.pow(currentDefaultParameterIndex.toInt()).toUInt()).and(defaultParametersIndicator) > 0u
currentDefaultParameterIndex++
if (!shouldBeIncluded) {
return@forEach
}
}
funSpec.addParameter(parameter)
val name = parameter.name
val defaultValueString = if (parameter.modifiers.contains(KModifier.VARARG)) {
"*$name"
} else {
"$name"
}
baseFunctionDefaults[parameter.name] = defaultValueString
}
baseFunctionFunSpecs.add(
funSpec.build() to baseFunctionDefaults.toMap()
)
defaultParametersIndicator++
}
}
variations.forEach { (variations, parameter) ->
if (accumulatedGenerations.isEmpty()) {
(baseFunctionFunSpecs + accumulatedGenerations).forEach { (accumulatedGeneration, baseDefaults) ->
if ((parameter.name ?.asString() ?: "this") !in baseDefaults.keys) {
return@forEach
}
variations.forEach { variation ->
val defaults = mutableMapOf<String, String>()
accumulatedGenerations.add(
FunSpec.builder(ksFunctionDeclaration.simpleName.asString()).apply {
modifiers.addAll(ksFunctionDeclaration.modifiers.mapNotNull { it.toKModifier() })
ksFunctionDeclaration.parameters.forEach {
FunSpec.builder(accumulatedGeneration.name).apply {
modifiers.addAll(accumulatedGeneration.modifiers)
accumulatedGeneration.receiverType ?.let {
receiver(it)
}
accumulatedGeneration.parameters.forEach {
parameters.add(
(if (it == parameter) {
(if (it.name == (parameter.name ?.asString() ?: "this")) {
ParameterSpec
.builder(
variation.argName,
if (variation.varargTypes.isEmpty()) {
variation.type.asTypeName()
ClassName.bestGuess(variation.type)
} else {
variation.type.parameterizedBy(*variation.varargTypes)
ClassName.bestGuess(variation.type).parameterizedBy(
*variation.varargTypes.map { it.asTypeName() }.toTypedArray()
)
}
)
.apply {
val name = it.name ?.asString() ?: "this"
if (it.isVararg) {
defaultValue(
"""
*$name.map { it.${variation.conversion} }.toTypedArray()
""".trimIndent()
)
val defaultValueString = if (it.modifiers.contains(KModifier.VARARG)) {
"""
*${variation.argName}.map { it.${variation.conversion} }.toTypedArray()
""".trimIndent()
} else {
defaultValue("$name.${variation.conversion}")
"${variation.argName}.${variation.conversion}"
}
defaults[it.name] = defaultValueString
}
} else {
ParameterSpec
.builder(
it.name ?.asString() ?: return@forEach,
it.type.toTypeName(),
)
it.toBuilder()
})
.apply {
if (it.isCrossInline) {
addModifiers(KModifier.CROSSINLINE)
}
if (it.isVal) {
addModifiers(KModifier.VALUE)
}
if (it.isNoInline) {
addModifiers(KModifier.NOINLINE)
}
if (it.isVararg) {
addModifiers(KModifier.VARARG)
}
}
.build()
)
}
}.build()
val parameters = accumulatedGeneration.parameters.joinToString(", ") {
val itName = it.name
"""
$itName = ${defaults[itName] ?: baseDefaults[itName] ?: itName}
""".trimIndent()
}
addCode(
"""
return ${ksFunctionDeclaration.simpleName.asString()}(
$parameters
)
""".trimIndent()
)
}.build() to defaults.toMap()
)
}
} else {
}
// if (accumulatedGenerations.isEmpty()) {
// variations.forEach { variation ->
// val defaults = mutableMapOf<String, String>()
// accumulatedGenerations.add(
// FunSpec.builder(ksFunctionDeclaration.simpleName.asString()).apply {
// modifiers.addAll(ksFunctionDeclaration.modifiers.mapNotNull { it.toKModifier() })
// ksFunctionDeclaration.extensionReceiver ?.let {
// receiver(it.toTypeName())
// }
// ksFunctionDeclaration.parameters.forEach {
// parameters.add(
// (if (it == parameter) {
// ParameterSpec
// .builder(
// variation.argName,
// if (variation.varargTypes.isEmpty()) {
// ClassName.bestGuess(variation.type)
// } else {
// ClassName.bestGuess(variation.type).parameterizedBy(
// *variation.varargTypes.map { it.asTypeName() }.toTypedArray()
// )
// }
// )
// } else {
// ParameterSpec
// .builder(
// it.name ?.asString() ?: return@forEach,
// it.type.toTypeName(),
// )
// })
// .apply {
// if (it.isCrossInline) {
// addModifiers(KModifier.CROSSINLINE)
// }
// if (it.isVal) {
// addModifiers(KModifier.VALUE)
// }
// if (it.isNoInline) {
// addModifiers(KModifier.NOINLINE)
// }
// if (it.isVararg) {
// addModifiers(KModifier.VARARG)
// }
// }
// .build()
// .apply {
// val name = it.name ?.asString() ?: "this"
// val defaultValueString = if (it.isVararg) {
// """
// *$name.map { it.${variation.conversion} }.toTypedArray()
// """.trimIndent()
// } else {
// "$name.${variation.conversion}"
// }
// defaults[this.name] = defaultValueString
// }
// )
// }
// val parameters = ksFunctionDeclaration.parameters.joinToString(", ") {
// val itName = it.name ?.asString() ?: "this"
// """
// $itName = ${defaults[itName] ?: itName}
// """.trimIndent()
// }
// addCode(
// """
// return ${ksFunctionDeclaration.simpleName.asString()}(
// $parameters
// )
// """.trimIndent()
// )
// }.build() to defaults.toMap()
// )
// }
// } else {
// val reusingGenerations = accumulatedGenerations.toList()
// reusingGenerations
// }
}
accumulatedGenerations.forEach {
addFunction(it)
addFunction(it.first)
}
}

View File

@@ -9,8 +9,25 @@ data class Sample(
fun sample(
@GenerationVariant(
"example",
Sample::class,
"Sample",
"value"
)
example: String = "12"
) = println(example)
@GenerateVariations
suspend fun Sample.sample2(
@GenerationVariant(
"arg12",
"kotlin.Int",
"toString()"
)
arg1: String = "1",
@GenerationVariant(
"arg22",
"kotlin.String",
"toInt()"
)
arg2: Int = 2,
arg3: Boolean = false
) = println(arg1)

View File

@@ -7,7 +7,7 @@ import kotlin.reflect.KClass
@Target(AnnotationTarget.TYPE_PARAMETER, AnnotationTarget.VALUE_PARAMETER)
annotation class GenerationVariant(
val argName: String,
val type: KClass<*>,
val type: String,
val conversion: String,
vararg val varargTypes: KClass<*>
)