Skip to content

Commit

Permalink
(#19) Add support for immutable collections
Browse files Browse the repository at this point in the history
  • Loading branch information
jayasuryat committed Mar 6, 2024
1 parent 3be23d4 commit ffe4dfe
Show file tree
Hide file tree
Showing 5 changed files with 165 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import com.jayasuryat.dowel.annotation.Dowel
import com.jayasuryat.dowel.annotation.DowelList
import com.jayasuryat.dowel.processor.generator.DowelGenerator
import com.jayasuryat.dowel.processor.generator.DowelListGenerator
import com.jayasuryat.dowel.processor.model.PreDefinedDeclarations
import com.jayasuryat.dowel.processor.model.UserPredefinedParamProviderMapper
import com.jayasuryat.dowel.processor.model.UserPredefinedParamProviderMapper.ProcessedConsiderForDowelSymbols
import com.jayasuryat.dowel.processor.model.UserPredefinedParamProviders
Expand Down Expand Up @@ -69,6 +70,11 @@ internal class DowelSymbolProcessor(
codeGenerator = codeGenerator,
)
}
private val declarations: PreDefinedDeclarations by unsafeLazy {
PreDefinedDeclarations(
resolver = resolver,
)
}

/**
* Entry point into processing of symbols, called by Kotlin Symbol Processing to run the processing task.
Expand All @@ -81,7 +87,8 @@ internal class DowelSymbolProcessor(
resolver.processConsiderForDowelSymbols()

val invalidDowelSymbols: List<KSAnnotated> = resolver.processDowelSymbols(
predefinedProviders = considerForDowelSymbols.providers
predefinedProviders = considerForDowelSymbols.providers,
declarations = declarations,
)

val invalidDowelListSymbols: List<KSAnnotated> = resolver.processDowelListSymbols()
Expand All @@ -95,6 +102,7 @@ internal class DowelSymbolProcessor(
*/
private fun Resolver.processDowelSymbols(
predefinedProviders: UserPredefinedParamProviders,
declarations: PreDefinedDeclarations,
): List<KSAnnotated> {

val resolver = this
Expand All @@ -108,6 +116,7 @@ internal class DowelSymbolProcessor(

val dowelGenerator: DowelGenerator = DowelGenerator.createInstance(
predefinedProviders = predefinedProviders,
declarations = declarations,
)

// Triggering code generation for valid symbols
Expand Down Expand Up @@ -169,12 +178,14 @@ internal class DowelSymbolProcessor(
*/
private fun DowelGenerator.Companion.createInstance(
predefinedProviders: UserPredefinedParamProviders,
declarations: PreDefinedDeclarations,
): DowelGenerator {
return DowelGenerator(
resolver = resolver,
codeGenerator = codeGenerator,
logger = logger,
predefinedProviders = predefinedProviders
predefinedProviders = predefinedProviders,
declarations = declarations,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,21 @@ internal object Names {
"MutableMap"
)

val persistentList: ClassName = ClassName(
packageName = "kotlinx.collections.immutable",
"PersistentList",
)

val persistentSet: ClassName = ClassName(
packageName = "kotlinx.collections.immutable",
"PersistentSet",
)

val persistentMap: ClassName = ClassName(
packageName = "kotlinx.collections.immutable",
"PersistentMap",
)

val sequenceName: ClassName = Sequence::class.asTypeName()

val previewParamProvider: ClassName = ClassName(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import com.jayasuryat.dowel.processor.model.ClassRepresentation
import com.jayasuryat.dowel.processor.model.ClassRepresentation.ParameterSpec.DowelSpec
import com.jayasuryat.dowel.processor.model.ClassRepresentation.ParameterSpec.PreDefinedProviderSpec
import com.jayasuryat.dowel.processor.model.ClassRepresentationMapper
import com.jayasuryat.dowel.processor.model.PreDefinedDeclarations
import com.jayasuryat.dowel.processor.model.UserPredefinedParamProviders
import com.jayasuryat.dowel.processor.util.getEffectiveModuleVisibility
import com.jayasuryat.dowel.processor.util.unsafeLazy
Expand All @@ -54,13 +55,15 @@ internal class DowelGenerator(
private val codeGenerator: CodeGenerator,
private val logger: KSPLogger,
private val predefinedProviders: UserPredefinedParamProviders,
private val declarations: PreDefinedDeclarations,
) {

private val mapper: ClassRepresentationMapper by unsafeLazy {
ClassRepresentationMapper(
resolver = resolver,
logger = logger,
predefinedProviders = predefinedProviders,
declarations = declarations,
)
}
private val objectConstructor: ObjectConstructor by unsafeLazy { ObjectConstructor() }
Expand Down Expand Up @@ -265,6 +268,16 @@ internal class DowelGenerator(
spec.keySpec.getAllSupportingProvidersRecursively() +
spec.valueSpec.getAllSupportingProvidersRecursively()

is ClassRepresentation.ParameterSpec.PersistentListSpec ->
spec.elementSpec.getAllSupportingProvidersRecursively()

is ClassRepresentation.ParameterSpec.PersistentSetSpec ->
spec.elementSpec.getAllSupportingProvidersRecursively()

is ClassRepresentation.ParameterSpec.PersistentMapSpec ->
spec.keySpec.getAllSupportingProvidersRecursively() +
spec.valueSpec.getAllSupportingProvidersRecursively()

is ClassRepresentation.ParameterSpec.FlowSpec ->
spec.elementSpec.getAllSupportingProvidersRecursively()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,10 @@ internal class ObjectConstructor {
}

/**
* Returns [CodeBlock] representing assignment logic for the passed [ClassRepresentation.ParameterSpec]
* Returns [CodeBlock] representing assignment logic for the passed [ClassRepresentation.ParameterSpec].
*
* Note: For [SealedSpec], and all the other types which have generic type parameters,
* this method would get called recursively
*/
private fun ClassRepresentation.ParameterSpec.getAssigner(): CodeBlock {

Expand All @@ -84,14 +87,19 @@ internal class ObjectConstructor {
is BooleanSpec -> spec.getBoolAssigner()
is StringSpec -> spec.getStringAssigner()

is ListSpec -> spec.getListAssigner() // This would be a recursive call
is SetSpec -> spec.getSetAssigner() // This would be a recursive call
is MapSpec -> spec.getMapAssigner() // This would be a recursive call
is FlowSpec -> spec.getFlowAssigner() // This would be a recursive call
is PairSpec -> spec.getPairAssigner() // This would be a recursive call
is ListSpec -> spec.getListAssigner()
is SetSpec -> spec.getSetAssigner()
is MapSpec -> spec.getMapAssigner()

is PersistentListSpec -> spec.getPersistentListSpecAssigner()
is PersistentSetSpec -> spec.getPersistentSetAssigner()
is PersistentMapSpec -> spec.getPersistentMapAssigner()

is FlowSpec -> spec.getFlowAssigner()
is PairSpec -> spec.getPairAssigner()

is FunctionSpec -> spec.getFunctionAssigner()
is SealedSpec -> spec.getSealedAssigner() // This would be a recursive call
is SealedSpec -> spec.getSealedAssigner()
is EnumSpec -> spec.getEnumAssigner()
is ObjectSpec -> spec.getObjectAssigner()
is DowelSpec -> spec.getDowelAssigner()
Expand All @@ -101,7 +109,7 @@ internal class ObjectConstructor {
is NoArgsConstructorSpec -> spec.getNoArgsConstructorAssigner()

// Compose types
is StateSpec -> spec.getStateAssigner() // This would be a recursive call
is StateSpec -> spec.getStateAssigner()
is ColorSpec -> spec.getColorAssigner()

is UnsupportedNullableSpec -> spec.getUnsupportedNullableAssigner()
Expand Down Expand Up @@ -147,13 +155,13 @@ internal class ObjectConstructor {
return buildCodeBlock { add("%L", value) }
}

@Suppress("unused")
@Suppress("UnusedReceiverParameter")
private fun CharSpec.getCharAssigner(): CodeBlock {
val range = 'a'..'z'
return buildCodeBlock { add("\'%L\'", range.random()) }
}

@Suppress("unused")
@Suppress("UnusedReceiverParameter")
private fun BooleanSpec.getBoolAssigner(): CodeBlock {
return buildCodeBlock { add("%L", Random.nextBoolean()) }
}
Expand Down Expand Up @@ -267,6 +275,94 @@ internal class ObjectConstructor {
}
}

private fun PersistentListSpec.getPersistentListSpecAssigner(): CodeBlock {

val spec = this

val listSize = spec.size.value.toSafeRangeInt()
val persistentListOf = MemberName("kotlinx.collections.immutable", "persistentListOf")

if (listSize == 0) {
return buildCodeBlock { add("%M()", persistentListOf) }
}

val modListSize: Int = if (listSize != -1) listSize
else Random.nextLong(
from = spec.size.min,
until = spec.size.max,
).toSafeRangeInt()

return buildCodeBlock {
add("%M(\n", persistentListOf)
withIndent {
repeat(modListSize) {
add("%L,\n", spec.elementSpec.getAssigner())
}
}
add(")")
}
}

private fun PersistentSetSpec.getPersistentSetAssigner(): CodeBlock {

val spec = this

val setSize = spec.size.value.toSafeRangeInt()
val persistentSetOf = MemberName("kotlinx.collections.immutable", "persistentSetOf")

if (setSize == 0) {
return buildCodeBlock { add("%M()", persistentSetOf) }
}

val modSetSize: Int = if (setSize != -1) setSize
else Random.nextLong(
from = spec.size.min,
until = spec.size.max,
).toSafeRangeInt()

return buildCodeBlock {
add("%M(\n", persistentSetOf)
withIndent {
repeat(modSetSize) {
add("%L,\n", spec.elementSpec.getAssigner())
}
}
add(")")
}
}

private fun PersistentMapSpec.getPersistentMapAssigner(): CodeBlock {

val spec = this

val listSize = spec.size.value.toSafeRangeInt()
val persistentMapOf = MemberName("kotlinx.collections.immutable", "persistentMapOf")

if (listSize == 0) {
return buildCodeBlock { add("%M()", persistentMapOf) }
}

val modSize: Int = if (listSize != -1) listSize
else Random.nextLong(
from = spec.size.min,
until = spec.size.max,
).toSafeRangeInt()

return buildCodeBlock {
add("%M(\n", persistentMapOf)
withIndent {
repeat(modSize) {
add(
"%L to %L,\n",
spec.keySpec.getAssigner(),
spec.valueSpec.getAssigner(),
)
}
}
add(")")
}
}

private fun FlowSpec.getFlowAssigner(): CodeBlock {

val spec = this
Expand Down Expand Up @@ -369,7 +465,7 @@ internal class ObjectConstructor {
}
}

@Suppress("unused")
@Suppress("UnusedReceiverParameter")
private fun ColorSpec.getColorAssigner(): CodeBlock {

return buildCodeBlock {
Expand All @@ -380,7 +476,7 @@ internal class ObjectConstructor {
}
}

@Suppress("unused")
@Suppress("UnusedReceiverParameter")
private fun UnsupportedNullableSpec.getUnsupportedNullableAssigner(): CodeBlock {
return buildCodeBlock { add("null") }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,22 @@ internal data class ClassRepresentation(
val valueSpec: ParameterSpec,
) : ParameterSpec

data class PersistentListSpec(
val size: Size,
val elementSpec: ParameterSpec,
) : ParameterSpec

data class PersistentSetSpec(
val size: Size,
val elementSpec: ParameterSpec,
) : ParameterSpec

data class PersistentMapSpec(
val size: Size,
val keySpec: ParameterSpec,
val valueSpec: ParameterSpec,
) : ParameterSpec

data class FlowSpec(
val elementSpec: ParameterSpec,
) : ParameterSpec
Expand Down

0 comments on commit ffe4dfe

Please sign in to comment.