Skip to content

Commit

Permalink
Handle top-level functions.
Browse files Browse the repository at this point in the history
  • Loading branch information
Gregory Lureau committed Feb 24, 2022
1 parent 1ae666a commit a08b944
Show file tree
Hide file tree
Showing 10 changed files with 267 additions and 102 deletions.
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ plugins {

allprojects {
group = "deezer.kustomexport"
version = "0.3.1"
version = "0.4.0"

repositories {
mavenLocal()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import com.google.devtools.ksp.symbol.KSAnnotated
import com.google.devtools.ksp.symbol.KSAnnotation
import com.google.devtools.ksp.symbol.KSClassDeclaration
import com.google.devtools.ksp.symbol.KSFile
import com.google.devtools.ksp.symbol.KSFunctionDeclaration
import com.google.devtools.ksp.symbol.KSType
import com.google.devtools.ksp.symbol.KSTypeAlias
import com.google.devtools.ksp.symbol.KSTypeReference
Expand All @@ -41,11 +42,14 @@ import deezer.kustomexport.compiler.js.ClassDescriptor
import deezer.kustomexport.compiler.js.EnumDescriptor
import deezer.kustomexport.compiler.js.InterfaceDescriptor
import deezer.kustomexport.compiler.js.SealedClassDescriptor
import deezer.kustomexport.compiler.js.TopLevelFunctionDescriptor
import deezer.kustomexport.compiler.js.ValueClassDescriptor
import deezer.kustomexport.compiler.js.pattern.`class`.transform
import deezer.kustomexport.compiler.js.pattern.`interface`.transform
import deezer.kustomexport.compiler.js.pattern.enum.transform
import deezer.kustomexport.compiler.js.pattern.function.transform
import deezer.kustomexport.compiler.js.pattern.parseClass
import deezer.kustomexport.compiler.js.pattern.parseFunction
import deezer.kustomexport.compiler.js.pattern.value.transform

// Trick to share the Logger everywhere without injecting the dependency everywhere
Expand Down Expand Up @@ -170,6 +174,14 @@ class ExportCompiler(private val environment: SymbolProcessorEnvironment) : Symb
parseAndWrite(targetClassDeclaration, targetTypeNames)
}

override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit) {
super.visitFunctionDeclaration(function, data)
val descriptor: TopLevelFunctionDescriptor = parseFunction(function)
Logger.warn("FUNCTION: ${function.simpleName.asString()}")
descriptor.transform()
.writeCode(environment, function.containingFile!!)
}

private fun parseAndWrite(
classDeclaration: KSClassDeclaration,
targetTypeNames: List<Pair<String, ClassName>>,
Expand All @@ -188,9 +200,6 @@ class ExportCompiler(private val environment: SymbolProcessorEnvironment) : Symb
.writeCode(environment, *allSources)
is InterfaceDescriptor -> descriptor.transform()
.writeCode(environment, *allSources)
null -> {
// Cannot parse this class, parsing error already reported on the parser
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ data class ParameterDescriptor(
inline fun portMethod(import: Boolean) = if (import) importedMethod else exportedMethod
}

data class TopLevelFunctionDescriptor(
val packageName: String,
val function: FunctionDescriptor,
)

data class FunctionDescriptor(
val name: String,
val isOverride: Boolean,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,16 @@

package deezer.kustomexport.compiler.js.pattern

import com.google.devtools.ksp.getAllSuperTypes
import com.google.devtools.ksp.getConstructors
import com.google.devtools.ksp.getDeclaredFunctions
import com.google.devtools.ksp.getDeclaredProperties
import com.google.devtools.ksp.isPrivate
import com.google.devtools.ksp.isPublic
import com.google.devtools.ksp.symbol.ClassKind
import com.google.devtools.ksp.symbol.KSClassDeclaration
import com.google.devtools.ksp.symbol.KSFunctionDeclaration
import com.google.devtools.ksp.symbol.KSName
import com.google.devtools.ksp.symbol.KSTypeParameter
import com.google.devtools.ksp.symbol.Modifier
import com.squareup.kotlinpoet.TypeName
import com.squareup.kotlinpoet.ksp.KotlinPoetKspPreview
Expand All @@ -45,49 +47,37 @@ import deezer.kustomexport.compiler.js.PropertyDescriptor
import deezer.kustomexport.compiler.js.SealedClassDescriptor
import deezer.kustomexport.compiler.js.SealedSubClassDescriptor
import deezer.kustomexport.compiler.js.SuperDescriptor
import deezer.kustomexport.compiler.js.TopLevelFunctionDescriptor
import deezer.kustomexport.compiler.js.TypeParameterDescriptor
import deezer.kustomexport.compiler.js.ValueClassDescriptor
import deezer.kustomexport.compiler.js.mapping.OriginTypeName

fun parseFunction(
function: KSFunctionDeclaration,
forcedConcreteTypeParameters: List<Pair<String, TypeName>>? = null,
): TopLevelFunctionDescriptor = TopLevelFunctionDescriptor(
packageName = function.packageName.asString(),
function = function.toDescriptor(
sequenceOf(),
function.typeParameters.toTypeParameterResolver(),
buildConcreteTypeParameters(forcedConcreteTypeParameters) { function.typeParameters[0] }
)
)

@KotlinPoetKspPreview
fun parseClass(
classDeclaration: KSClassDeclaration,
forcedConcreteTypeParameters: List<Pair<String, TypeName>>? = null,
exportedClassSimpleName: String
): Descriptor? {
): Descriptor {
val typeParamResolver = classDeclaration.typeParameters.toTypeParameterResolver()

val concreteTypeParameters: MutableList<TypeParameterDescriptor> = mutableListOf()
(forcedConcreteTypeParameters ?: emptyList())/* ?: typeParamResolver.parametersMap.values*/
.forEach { (name, type) ->
val className = try {
type.asClassName()
} catch (t: Throwable) {
Logger.error(
"Cannot use @KustomException on a not concrete generics class.",
classDeclaration.typeParameters[0]
)
return null
}
concreteTypeParameters.add(
TypeParameterDescriptor(
name = name,
origin = className.cached(concreteTypeParameters),
)
)
}
val concreteTypeParameters: MutableList<TypeParameterDescriptor> =
buildConcreteTypeParameters(forcedConcreteTypeParameters) { classDeclaration.typeParameters[0] }

val packageName = classDeclaration.packageName.asString()
val classSimpleName = classDeclaration.simpleName.asString()

//val superTypes = classDeclaration.getAllSuperTypes()

Logger.warn(
"PARSING - ${classSimpleName} ${classDeclaration.superTypes.count()} ${
classDeclaration.getAllSuperTypes().count()
}"
)

val superTypes = classDeclaration.superTypes
.map { superType ->
val superTypeName = superType.toTypeNamePatch(typeParamResolver).cached(concreteTypeParameters)
Expand Down Expand Up @@ -187,6 +177,32 @@ fun parseClass(
}
}

private fun buildConcreteTypeParameters(
forcedConcreteTypeParameters: List<Pair<String, TypeName>>?,
firstTypeParameterProvider: () -> KSTypeParameter
): MutableList<TypeParameterDescriptor> {
val concreteTypeParameters: MutableList<TypeParameterDescriptor> = mutableListOf()
(forcedConcreteTypeParameters ?: emptyList())/* ?: typeParamResolver.parametersMap.values*/
.forEach { (name, type) ->
val className = try {
type.asClassName()
} catch (t: Throwable) {
Logger.error(
"Cannot use @KustomException on a not concrete generics class.",
firstTypeParameterProvider()
)
error(t)
}
concreteTypeParameters.add(
TypeParameterDescriptor(
name = name,
origin = className.cached(concreteTypeParameters),
)
)
}
return concreteTypeParameters
}

private val nonExportableFunctions = listOf(
"<init>",
"equals",
Expand Down Expand Up @@ -216,21 +232,28 @@ fun KSClassDeclaration.parseFunctions(
.filter { it.simpleName.asString() !in nonExportableFunctions }
.filter { it.isPublic() }
.map { func ->
FunctionDescriptor(
name = func.simpleName.asString(),
isOverride = func.findOverridee() != null || !declaredNames.contains(func.simpleName),
isSuspend = func.modifiers.contains(Modifier.SUSPEND),
returnType = func.returnType!!.toTypeNamePatch(typeParamResolver).cached(concreteTypeParameters),
parameters = func.parameters.map { p ->
ParameterDescriptor(
name = p.name?.asString() ?: TODO("not sure what we want here"),
type = p.type.toTypeNamePatch(typeParamResolver).cached(concreteTypeParameters),
)
}
)
func.toDescriptor(declaredNames, typeParamResolver, concreteTypeParameters)
}.toList()
}

private fun KSFunctionDeclaration.toDescriptor(
declaredNames: Sequence<KSName>,
typeParamResolver: TypeParameterResolver,
concreteTypeParameters: MutableList<TypeParameterDescriptor>
) =
FunctionDescriptor(
name = simpleName.asString(),
isOverride = findOverridee() != null || !declaredNames.contains(simpleName),
isSuspend = modifiers.contains(Modifier.SUSPEND),
returnType = returnType!!.toTypeNamePatch(typeParamResolver).cached(concreteTypeParameters),
parameters = parameters.map { p ->
ParameterDescriptor(
name = p.name?.asString() ?: TODO("not sure what we want here"),
type = p.type.toTypeNamePatch(typeParamResolver).cached(concreteTypeParameters),
)
}
)

@OptIn(KotlinPoetKspPreview::class)
fun KSClassDeclaration.parseProperties(
typeParamResolver: TypeParameterResolver,
Expand Down

0 comments on commit a08b944

Please sign in to comment.