Skip to content

Commit

Permalink
Improve generation of Lens and Optional of nullable and Option
Browse files Browse the repository at this point in the history
…types.
  • Loading branch information
nomisRev committed Apr 7, 2018
1 parent a969a63 commit 85f3c9a
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 103 deletions.

This file was deleted.

35 changes: 0 additions & 35 deletions arrow-optics/src/test/kotlin/arrow/optics/BoundedTest.kt

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,28 @@ class LensesFileGenerator(
private val filePrefix = "lenses"
private val lens = "arrow.optics.Lens"

fun generate() = annotatedList.map(this::processElement)
.map { (element, funs) ->
"$filePrefix.${element.classData.`package`}.${element.type.simpleName.toString().toLowerCase()}.kt" to
funs.joinToString(prefix = "package ${element.classData.`package`.escapedClassName}\n\n", separator = "\n")
}.forEach { (name, fileString) -> File(generatedDir, name).writeText(fileString) }
fun generate() = annotatedList.map(this::processElement)
.map { (element, funs) ->
"$filePrefix.${element.classData.`package`}.${element.type.simpleName.toString().toLowerCase()}.kt" to
funs.joinToString(prefix = "package ${element.classData.`package`.escapedClassName}\n\n", separator = "\n")
}.forEach { (name, fileString) -> File(generatedDir, name).writeText(fileString) }

private fun String.toUpperCamelCase(): String = split(" ").joinToString("", transform = String::capitalize)

private fun processElement(annotatedOptic: AnnotatedOptic): Pair<AnnotatedOptic, List<String>> =
annotatedOptic to annotatedOptic.targets.map { variable ->
val sourceClassName = annotatedOptic.classData.fullName.escapedClassName
val sourceName = annotatedOptic.type.simpleName.toString().decapitalize()
val targetClassName = variable.fullName
val targetName = variable.paramName

"""
|fun $sourceName${targetName.toUpperCamelCase()}(): $lens<$sourceClassName, $targetClassName> = $lens(
private fun processElement(annotatedOptic: AnnotatedOptic): Pair<AnnotatedOptic, List<String>> =
annotatedOptic to annotatedOptic.targets.map { variable ->
val sourceClassName = annotatedOptic.classData.fullName.escapedClassName
val sourceName = annotatedOptic.type.simpleName.toString().decapitalize()
val targetClassName = variable.fullName
val targetName = variable.paramName
val lensType = when (variable) {
is Target.NullableTarget -> "Nullable${targetName.toUpperCamelCase()}"
is Target.OptionTarget -> "Option${targetName.toUpperCamelCase()}"
is Target.NonNullTarget -> targetName.toUpperCamelCase()
}

"""
|fun $sourceName$lensType(): $lens<$sourceClassName, $targetClassName> = $lens(
| get = { $sourceName: $sourceClassName -> $sourceName.${targetName.plusIfNotBlank(prefix = "`", postfix = "`")} },
| set = { value: $targetClassName ->
| { $sourceName: $sourceClassName ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ class OptikalProcessor : AbstractProcessor() {

private val annotatedOptional = mutableListOf<AnnotatedOptic>()

private val annotatedBounded = mutableListOf<AnnotatedOptic>()

override fun getSupportedSourceVersion(): SourceVersion = SourceVersion.latestSupported()

override fun getSupportedAnnotationTypes() = setOf(opticsAnnotationClass.canonicalName)

override fun onProcess(annotations: Set<TypeElement>, roundEnv: RoundEnvironment) {
Expand All @@ -49,12 +52,21 @@ class OptikalProcessor : AbstractProcessor() {
.filter { it.getAnnotation(opticsAnnotationClass).targets.contains(OpticsTarget.OPTIONAL) }
.mapNotNull(this::evalAnnotatedElement)

annotatedBounded += roundEnv
.getElementsAnnotatedWith(opticsAnnotationClass)
.filter { it.getAnnotation(opticsAnnotationClass).targets.contains(OpticsTarget.DSL) }
.mapNotNull(this::evalAnnotatedElement)

if (roundEnv.processingOver()) {
val generatedDir = File(this.generatedDir!!, "").also { it.mkdirs() }
LensesFileGenerator(annotatedLenses, generatedDir).generate()
PrismsFileGenerator(annotatedPrisms, generatedDir).generate()
IsosFileGenerator(annotatedIsos, generatedDir).generate()
OptionalFileGenerator(annotatedOptional, generatedDir).generate()

LensesFileGenerator(annotatedBounded, generatedDir).generate()
OptionalFileGenerator(annotatedBounded, generatedDir).generate()
BoundSetterGenerator(annotatedBounded, generatedDir).generate()
}
}

Expand All @@ -63,7 +75,7 @@ class OptikalProcessor : AbstractProcessor() {
AnnotatedOptic(
element as TypeElement,
element.getClassData(),
element.getConstructorTypesNames().zip(element.getConstructorParamNames(), ::Target)
element.getConstructorTypesNames().zip(element.getConstructorParamNames(), Target.Companion::invoke)
)

else -> null
Expand All @@ -88,16 +100,15 @@ class OptikalProcessor : AbstractProcessor() {

private fun evalAnnotatedIsoElement(element: Element): AnnotatedOptic? = when {
(element.kotlinMetadata as? KotlinClassMetadata)?.data?.classProto?.isDataClass == true -> {
val properties = element.getConstructorTypesNames().zip(element.getConstructorParamNames(), ::Target)
val properties = element.getConstructorTypesNames().zip(element.getConstructorParamNames(), Target.Companion::invoke)

if (properties.size > 10) {
logW("""
|Cannot generate arrow.optics.Iso for ${element.enclosingElement}.${element.simpleName}.
|Iso generation is supported up to 10 constructor parameters is supported
""")
null
} else
AnnotatedOptic(element as TypeElement, element.getClassData(), properties)
} else AnnotatedOptic(element as TypeElement, element.getClassData(), properties)
}

else -> null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,29 +22,29 @@ class OptionalFileGenerator(

private fun String.toUpperCamelCase(): String = split(" ").joinToString("", transform = String::capitalize)

private fun processElement(annotatedOptic: AnnotatedOptic): Pair<AnnotatedOptic, List<String>> =
annotatedOptic to annotatedOptic.targets.map { variable ->
val sourceClassName = annotatedOptic.classData.fullName.escapedClassName
val sourceName = annotatedOptic.type.simpleName.toString().decapitalize()
val targetClassName = variable.fullName
val targetName = variable.paramName
private fun processElement(annotatedOptic: AnnotatedOptic): Pair<AnnotatedOptic, List<String>> =
annotatedOptic to annotatedOptic.targets.map { variable ->
val sourceClassName = annotatedOptic.classData.fullName.escapedClassName
val sourceName = annotatedOptic.type.simpleName.toString().decapitalize()
val targetClassName = variable.fullName
val targetName = variable.paramName

when (variable) {
is Target.NullableTarget -> processNullableOptional(targetClassName.dropLast(1), sourceName, targetName, sourceClassName)
is Target.OptionTarget -> processOptionOptional(sourceName, targetName, sourceClassName, variable.nestedFullName)
is Target.NonNullTarget -> "" //Don't generate optional for non-null targets.
}
}
when (variable) {
is Target.NullableTarget -> processNullableOptional(targetClassName.dropLast(1), sourceName, targetName, sourceClassName)
is Target.OptionTarget -> processOptionOptional(sourceName, targetName, sourceClassName, variable.nestedFullName)
is Target.NonNullTarget -> "" //Don't generate optional for non-null targets.
}
}

private fun fileHeader(packageName: String): String =
"""package $packageName
private fun fileHeader(packageName: String): String =
"""package $packageName
|
|import arrow.core.left
|import arrow.core.right
|import arrow.core.toOption
|""".trimMargin()

private fun processNullableOptional(nonNullTargetClassName: String, sourceName: String, targetName: String, sourceClassName: String) = """
private fun processNullableOptional(nonNullTargetClassName: String, sourceName: String, targetName: String, sourceClassName: String) = """
|fun $sourceName${targetName.toUpperCamelCase()}(): $optional<$sourceClassName, $nonNullTargetClassName> = $optional(
| getOrModify = { $sourceName: $sourceClassName -> $sourceName.${targetName.plusIfNotBlank(prefix = "`", postfix = "`")}?.right() ?: $sourceName.left() },
| set = { value: $nonNullTargetClassName ->
Expand All @@ -55,7 +55,7 @@ class OptionalFileGenerator(
|)
""".trimMargin()

private fun processOptionOptional(sourceName: String, targetName: String, sourceClassName: String, clz: String) = """
private fun processOptionOptional(sourceName: String, targetName: String, sourceClassName: String, clz: String) = """
|fun $sourceName${targetName.toUpperCamelCase()}(): $optional<$sourceClassName, $clz> = $optional(
| getOrModify = { $sourceName: $sourceClassName -> $sourceName.${targetName.plusIfNotBlank(prefix = "`", postfix = "`")}.orNull()?.right() ?: $sourceName.left() },
| set = { value: $clz ->
Expand Down

0 comments on commit 85f3c9a

Please sign in to comment.