Skip to content
Snippets Groups Projects
Verified Commit 7b55d0b5 authored by Janne Mareike Koschinski's avatar Janne Mareike Koschinski
Browse files

Cleanup annotation/symbol processing

parent 369f3358
No related branches found
No related tags found
No related merge requests found
/*
* libquassel
* Copyright (c) 2021 Janne Mareike Koschinski
* Copyright (c) 2021 The Quassel Project
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
package de.justjanne.libquassel.generator.visitors
import com.google.devtools.ksp.processing.CodeGenerator
import com.google.devtools.ksp.processing.Dependencies
import de.justjanne.libquassel.generator.kotlinmodel.KotlinModel
import de.justjanne.libquassel.generator.kotlinmodel.KotlinModelVisitor
class KotlinSaver : KotlinModelVisitor<CodeGenerator, Unit> {
override fun visitFileModel(model: KotlinModel.FileModel, data: CodeGenerator) {
data.createNewFile(
Dependencies(false, model.source.containingFile!!),
model.data.packageName,
model.data.name
).bufferedWriter(Charsets.UTF_8).use {
model.data.writeTo(it)
}
}
override fun visitFunctionModel(
model: KotlinModel.FunctionModel,
data: CodeGenerator
) = Unit
}
/*
* libquassel
* Copyright (c) 2021 Janne Mareike Koschinski
* Copyright (c) 2021 The Quassel Project
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
package de.justjanne.libquassel.generator.visitors
import com.squareup.kotlinpoet.ANY
import com.squareup.kotlinpoet.ClassName
import com.squareup.kotlinpoet.FileSpec
import com.squareup.kotlinpoet.FunSpec
import com.squareup.kotlinpoet.KModifier
import com.squareup.kotlinpoet.ParameterSpec
import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
import com.squareup.kotlinpoet.PropertySpec
import com.squareup.kotlinpoet.TypeSpec
import com.squareup.kotlinpoet.asTypeName
import com.squareup.kotlinpoet.buildCodeBlock
import de.justjanne.libquassel.annotations.ProtocolSide
import de.justjanne.libquassel.generator.kotlinmodel.KotlinModel
import de.justjanne.libquassel.generator.rpcmodel.RpcModel
import de.justjanne.libquassel.generator.rpcmodel.RpcModelVisitor
import de.justjanne.libquassel.generator.util.kotlinpoet.ArgString
import de.justjanne.libquassel.generator.util.kotlinpoet.buildWhen
import de.justjanne.libquassel.generator.util.kotlinpoet.withIndent
class RpcModelProcessor : RpcModelVisitor<ProtocolSide, KotlinModel?> {
override fun visitObjectModel(model: RpcModel.ObjectModel, data: ProtocolSide): KotlinModel {
val name = ClassName(
TYPENAME_INVOKER.packageName,
"${model.rpcName}${data.name.toLowerCase().capitalize()}Invoker"
)
return KotlinModel.FileModel(
model.source,
FileSpec.builder(name.packageName, name.simpleName)
.addImport(
TYPENAME_QVARIANT_INTOORTHROW.packageName,
TYPENAME_QVARIANT_INTOORTHROW.simpleName
)
.addType(
TypeSpec.objectBuilder(name.simpleName)
.addSuperinterface(TYPENAME_INVOKER.parameterizedBy(model.name))
.addProperty(
PropertySpec.builder(
"className",
String::class.asTypeName(),
KModifier.OVERRIDE
).initializer("\"${model.rpcName}\"").build()
)
.addFunction(
FunSpec.builder("invoke")
.addModifiers(KModifier.OVERRIDE, KModifier.OPERATOR)
.addParameter(
ParameterSpec.builder(
"on",
TYPENAME_ANY
).build()
).addParameter(
ParameterSpec.builder(
"method",
String::class.asTypeName()
).build()
).addParameter(
ParameterSpec.builder(
"params",
TYPENAME_QVARIANTLIST
).build()
)
.addCode(
buildCodeBlock {
beginControlFlow("if (on is %T)", model.name)
buildWhen("method") {
for (method in model.methods) {
val block = method.accept(this@RpcModelProcessor, data)
as? KotlinModel.FunctionModel
?: continue
addCase(ArgString("%S", method.rpcName ?: method.name), block.data)
}
buildElse {
addStatement("throw %T(className, method)", TYPENAME_UNKNOWN_METHOD_EXCEPTION)
}
}
nextControlFlow("else")
addStatement("throw %T(on, className)", TYPENAME_WRONG_OBJECT_TYPE_EXCEPTION)
endControlFlow()
}
)
.build()
)
.build()
).build()
)
}
override fun visitFunctionModel(model: RpcModel.FunctionModel, data: ProtocolSide) = KotlinModel.FunctionModel(
model.source,
buildCodeBlock {
if (model.parameters.isEmpty()) {
addStatement("on.${model.name}()")
} else {
addStatement("on.${model.name}(")
withIndent {
val lastIndex = model.parameters.size - 1
for ((i, parameter) in model.parameters.withIndex()) {
val suffix = if (i != lastIndex) "," else ""
addStatement(
"${parameter.name} = params[$i].intoOrThrow<%T>()$suffix",
parameter.type
)
}
}
addStatement(")")
}
}
)
override fun visitParameterModel(model: RpcModel.ParameterModel, data: ProtocolSide): KotlinModel? = null
companion object {
private val TYPENAME_INVOKER = ClassName(
"de.justjanne.libquassel.state.invoker",
"Invoker"
)
private val TYPENAME_UNKNOWN_METHOD_EXCEPTION = ClassName(
"de.justjanne.libquassel.state.exceptions",
"UnknownMethodException"
)
private val TYPENAME_WRONG_OBJECT_TYPE_EXCEPTION = ClassName(
"de.justjanne.libquassel.state.exceptions",
"WrongObjectTypeException"
)
private val TYPENAME_QVARIANTLIST = ClassName(
"de.justjanne.libquassel.protocol.variant",
"QVariantList"
)
private val TYPENAME_QVARIANT_INTOORTHROW = ClassName(
"de.justjanne.libquassel.protocol.variant",
"intoOrThrow"
)
private val TYPENAME_ANY = ANY.copy(nullable = true)
init {
System.setProperty("idea.io.use.nio2", "true")
}
}
}
......@@ -107,6 +107,8 @@ sealed class QVariant<T> {
internal inline fun <reified U> withType(): QVariant<U>? =
withType(U::class.java)
fun type(): Class<*>? = data?.let { it::class.java }
internal fun serialize(buffer: ChainedByteBuffer, featureSet: FeatureSet) =
serializer.serialize(buffer, data, featureSet)
}
......@@ -130,6 +132,17 @@ inline fun <reified T> qVariant(data: T, type: QuasselType): QVariant<T> =
inline fun <reified T> QVariant_?.into(): T? =
this?.withType<T>()?.data
/**
* Extract the content of a QVariant in a type-safe manner
* @return value of the QVariant
* @throws if the value could not be coerced into the given type
*/
inline fun <reified T> QVariant_?.intoOrThrow(): T =
this?.withType<T>()?.data ?: throw WrongVariantTypeException(
T::class.java.canonicalName,
this?.type()?.canonicalName ?: "null"
)
/**
* Extract the content of a QVariant in a type-safe manner
* @param defValue default value if the type does not match or no value is found
......
......@@ -8,11 +8,9 @@
* obtain one at https://mozilla.org/MPL/2.0/.
*/
package de.justjanne.libquassel.generator.model
package de.justjanne.libquassel.protocol.variant
import com.google.devtools.ksp.symbol.KSType
data class SyncedParameterModel(
val name: String?,
val type: KSType
)
data class WrongVariantTypeException(
val expected: String,
val actual: String?
) : Exception("Could not coerce QVariant of type $actual into $expected")
......@@ -8,10 +8,9 @@
* obtain one at https://mozilla.org/MPL/2.0/.
*/
package de.justjanne.libquassel.generator.model
package de.justjanne.libquassel.state.exceptions
data class SyncedObjectModel(
val name: String,
val rpcName: String?,
val methods: List<SyncedCallModel>
)
data class UnknownMethodException(
val className: String,
val methodName: String
) : Exception()
......@@ -8,8 +8,9 @@
* obtain one at https://mozilla.org/MPL/2.0/.
*/
package de.justjanne.libquassel.generator.annotation
package de.justjanne.libquassel.state.exceptions
data class SyncedObjectAnnotationModel(
val name: String?
)
data class WrongObjectTypeException(
val obj: Any?,
val type: String
) : Exception()
/*
* libquassel
* Copyright (c) 2021 Janne Mareike Koschinski
* Copyright (c) 2021 The Quassel Project
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
package de.justjanne.libquassel.state.invoker
import de.justjanne.libquassel.protocol.variant.QVariantList
import de.justjanne.libquassel.state.exceptions.UnknownMethodException
import de.justjanne.libquassel.state.exceptions.WrongObjectTypeException
interface Invoker<out T> {
val className: String
@Throws(WrongObjectTypeException::class, UnknownMethodException::class)
fun invoke(on: Any?, method: String, params: QVariantList)
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment