-
Notifications
You must be signed in to change notification settings - Fork 439
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Annotation * Processor
- Loading branch information
Showing
5 changed files
with
154 additions
and
0 deletions.
There are no files selected for viewing
12 changes: 12 additions & 0 deletions
12
kategory-annotations-processor/src/main/java/kategory/fold/AnnotatedAutoFold.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package kategory.fold | ||
|
||
import kategory.common.utils.ClassOrPackageDataWrapper | ||
import javax.lang.model.element.TypeElement | ||
|
||
data class AnnotatedFold( | ||
val type: TypeElement, | ||
val typeParams: List<String>, | ||
val classData: ClassOrPackageDataWrapper.Class, | ||
val targets: List<Variant> | ||
) | ||
data class Variant(val fullName: String, val typeParams: List<String>, val simpleName: String) |
7 changes: 7 additions & 0 deletions
7
kategory-annotations-processor/src/main/java/kategory/fold/AnnotationInfo.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package kategory.fold | ||
|
||
import kategory.autofold | ||
|
||
val foldAnnotationKClass = autofold::class | ||
val foldAnnotationClass = foldAnnotationKClass.java | ||
val foldAnnotationName = "@" + foldAnnotationClass.simpleName |
64 changes: 64 additions & 0 deletions
64
kategory-annotations-processor/src/main/java/kategory/fold/AutoFoldFileGenerator.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package kategory.fold | ||
|
||
import kategory.common.utils.fullName | ||
import me.eugeniomarletti.kotlin.metadata.escapedClassName | ||
import java.io.File | ||
|
||
class AutoFoldFileGenerator( | ||
private val annotatedList: Collection<AnnotatedFold>, | ||
private val generatedDir: File | ||
) { | ||
|
||
fun generate() = annotatedList.map(this::processElement) | ||
.map { (element, fold) -> | ||
"${foldAnnotationClass.simpleName}.${element.type.simpleName.toString().toLowerCase()}.kt" to | ||
fileHeader(element.classData.`package`.escapedClassName) + fold | ||
}.map { (name, fileString) -> File(generatedDir, name).writeText(fileString) } | ||
|
||
private fun processElement(annotatedFold: AnnotatedFold): Pair<AnnotatedFold, String> = | ||
annotatedFold to annotatedFold.targets.let { targets -> | ||
val sourceClassName = annotatedFold.classData.fullName.escapedClassName | ||
val sumTypeParams = typeParams(annotatedFold.typeParams) | ||
val returnType = getFoldType(annotatedFold.typeParams) | ||
val functionTypeParams = functionTypeParams(annotatedFold.typeParams, returnType) | ||
|
||
"""inline fun $functionTypeParams $sourceClassName$sumTypeParams.fold( | ||
|${params(targets, returnType)} | ||
|): $returnType = when (this) { | ||
|${patternMatching(targets)} | ||
|} | ||
""".trimMargin() | ||
} | ||
|
||
fun typeParams(params: List<String>): String = | ||
if (params.isNotEmpty()) params.joinToString(prefix = "<", postfix = ">") | ||
else "" | ||
|
||
fun params(variants: List<Variant>, returnType: String): String = variants.joinToString(transform = { variant -> | ||
" crossinline ${variant.simpleName.decapitalize()}: (${variant.fullName.escapedClassName}${typeParams(variant.typeParams)}) -> $returnType" | ||
}, separator = ",\n") | ||
|
||
fun patternMatching(variants: List<Variant>): String = variants.joinToString(transform = { variant -> | ||
" is ${variant.fullName.escapedClassName} -> ${variant.simpleName.decapitalize().escapedClassName}(this)" | ||
}, separator = "\n") | ||
|
||
fun functionTypeParams(params: List<String>, returnType: String): String = | ||
if (params.isEmpty()) "" | ||
else params.joinToString(prefix = "<", postfix = ", $returnType>") | ||
|
||
fun getFoldType(params: List<String>): String { | ||
fun check(param: String, next: List<String>): String = (param[0] + 1).let { | ||
if (next.contains(it.toString())) check(next.firstOrNull() ?: "", next.drop(1)) | ||
else it.toString() | ||
} | ||
|
||
return check(params.firstOrNull() ?: "", params.drop(1)) | ||
} | ||
|
||
fun fileHeader(packageName: String): String = | ||
"""package $packageName | ||
| | ||
|""".trimMargin() | ||
|
||
} | ||
|
65 changes: 65 additions & 0 deletions
65
kategory-annotations-processor/src/main/java/kategory/fold/AutoFoldProcessor.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package kategory.fold | ||
|
||
import com.google.auto.service.AutoService | ||
import kategory.common.utils.AbstractProcessor | ||
import kategory.common.utils.asClassOrPackageDataWrapper | ||
import kategory.common.utils.isSealed | ||
import kategory.common.utils.knownError | ||
import me.eugeniomarletti.kotlin.metadata.KotlinClassMetadata | ||
import me.eugeniomarletti.kotlin.metadata.kotlinMetadata | ||
import java.io.File | ||
import javax.annotation.processing.Processor | ||
import javax.annotation.processing.RoundEnvironment | ||
import javax.lang.model.SourceVersion | ||
import javax.lang.model.element.TypeElement | ||
import javax.lang.model.element.TypeParameterElement | ||
|
||
@AutoService(Processor::class) | ||
class AutoFoldProcessor : AbstractProcessor() { | ||
|
||
private val annotatedList = mutableListOf<AnnotatedFold>() | ||
|
||
override fun getSupportedSourceVersion(): SourceVersion = SourceVersion.latestSupported() | ||
|
||
override fun getSupportedAnnotationTypes(): Set<String> = setOf(foldAnnotationClass.canonicalName) | ||
|
||
/** | ||
* Processor entry point | ||
*/ | ||
override fun onProcess(annotations: Set<TypeElement>, roundEnv: RoundEnvironment) { | ||
annotatedList += roundEnv | ||
.getElementsAnnotatedWith(foldAnnotationClass) | ||
.map { element -> | ||
when { | ||
element.let { it.kotlinMetadata as? KotlinClassMetadata }?.data?.classProto?.isSealed == true -> { | ||
val (nameResolver, classProto) = element.kotlinMetadata.let { it as KotlinClassMetadata }.data | ||
|
||
AnnotatedFold( | ||
element as TypeElement, | ||
element.typeParameters.map(TypeParameterElement::toString), | ||
element.kotlinMetadata | ||
.let { it as KotlinClassMetadata } | ||
.data | ||
.asClassOrPackageDataWrapper(elementUtils.getPackageOf(element).toString()), | ||
classProto.sealedSubclassFqNameList | ||
.map(nameResolver::getString) | ||
.map { it.replace('/', '.') } | ||
.map { | ||
Variant(it, | ||
elementUtils.getTypeElement(it).typeParameters.map(TypeParameterElement::toString), | ||
it.substringAfterLast(".")) | ||
} | ||
) | ||
} | ||
|
||
else -> knownError("Generation of fold is only supported for sealed classes.") | ||
} | ||
} | ||
|
||
if (roundEnv.processingOver()) { | ||
val generatedDir = File(this.generatedDir!!, foldAnnotationClass.simpleName).also { it.mkdirs() } | ||
AutoFoldFileGenerator(annotatedList, generatedDir).generate() | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package kategory | ||
|
||
@Retention(AnnotationRetention.RUNTIME) | ||
@Target(AnnotationTarget.CLASS) | ||
@MustBeDocumented | ||
annotation class autofold |