diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/Codegen.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/Codegen.kt new file mode 100644 index 000000000..f79214b89 --- /dev/null +++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/Codegen.kt @@ -0,0 +1,98 @@ +/* + * Copyright 2020 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/master/LICENSE + */ + +@file:Suppress("FunctionName", "INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") + +package net.mamoe.mirai.console.codegen + +import org.intellij.lang.annotations.Language + +abstract class Replacer(private val name: String) : (String) -> String { + override fun toString(): String { + return name + } +} + +fun Codegen.Replacer(block: (String) -> String): Replacer { + return object : Replacer(this@Replacer::class.simpleName ?: "") { + override fun invoke(p1: String): String = block(p1) + } +} + +class CodegenScope : MutableList by mutableListOf() { + fun applyTo(fileContent: String): String { + return this.fold(fileContent) { acc, replacer -> replacer(acc) } + } + + @CodegenDsl + operator fun Codegen.invoke(vararg ktTypes: KtType) { + if (ktTypes.isEmpty() && this is DefaultInvoke) { + invoke(defaultInvokeArgs) + } + invoke(ktTypes.toList()) + } + + @CodegenDsl + operator fun Codegen.invoke(ktTypes: Collection) { + add(Replacer { + it + buildString { + ktTypes.forEach { applyTo(this, it) } + } + }) + } + + @RegionCodegenDsl + operator fun RegionCodegen.invoke(vararg ktTypes: KtType) = invoke(ktTypes.toList()) + + @RegionCodegenDsl + operator fun RegionCodegen.invoke(ktTypes: Collection) { + add(Replacer { + it.replace(Regex("""//// region $regionName CODEGEN START ////([\s\S]*?)//// endregion $regionName CODEGEN END ////""")) { + val code = CodegenScope().apply { (this@invoke as Codegen).invoke(*ktTypes.toTypedArray()) }.applyTo("") + """ + |//// region $regionName CODEGEN START //// + | + |$code + | + |//// endregion $regionName CODEGEN END //// + """.trimMargin() + } + }) + } + + @DslMarker + annotation class CodegenDsl +} + +@DslMarker +annotation class RegionCodegenDsl + +interface DefaultInvoke { + val defaultInvokeArgs: List +} + +abstract class Codegen { + fun applyTo(stringBuilder: StringBuilder, ktType: KtType) = this.run { stringBuilder.apply(ktType) } + + protected abstract fun StringBuilder.apply(ktType: KtType) +} + +abstract class RegionCodegen(regionName: String? = null) : Codegen() { + val regionName: String by lazy { + regionName ?: this::class.simpleName!!.substringBefore("Codegen") + } +} + +abstract class PrimitiveCodegen : Codegen() { + protected abstract fun StringBuilder.apply(ktType: KtPrimitive) + + fun StringBuilder.apply(ktType: List) = ktType.forEach { apply(it) } +} + +fun StringBuilder.appendKCode(@Language("kt") ktCode: String): StringBuilder = append(kCode(ktCode)).appendLine() diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/JSettingCodegen.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/JSettingCodegen.kt index fff3f18ae..885a7e898 100644 --- a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/JSettingCodegen.kt +++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/JSettingCodegen.kt @@ -46,35 +46,37 @@ fun JClazz.getTemplate():String = """ fun main(){ println(buildString { - appendln(COPYRIGHT) - appendln() - appendln(FILE_SUPPRESS) - appendln() - appendln("/**\n" + - " * !!! This file is auto-generated by backend/codegen/src/kotlin/net.mamoe.mirai.console.codegen.JSettingCodegen.kt\n" + - " * !!! DO NOT MODIFY THIS FILE MANUALLY\n" + - " */\n" + - "\"\"\"") - appendln() - appendln() + appendLine(COPYRIGHT) + appendLine() + appendLine(FILE_SUPPRESS) + appendLine() + appendLine( + "/**\n" + + " * !!! This file is auto-generated by backend/codegen/src/kotlin/net.mamoe.mirai.console.codegen.JSettingCodegen.kt\n" + + " * !!! DO NOT MODIFY THIS FILE MANUALLY\n" + + " */\n" + + "\"\"\"" + ) + appendLine() + appendLine() //do simplest (J_EXTRA + J_NUMBERS).forEach { - appendln(it.getTemplate()) + appendLine(it.getTemplate()) } (J_EXTRA + J_NUMBERS).forEach { - appendln(JListClazz(it).getTemplate()) + appendLine(JListClazz(it).getTemplate()) } (J_EXTRA + J_NUMBERS).forEach { - appendln(JArrayClazz(it).getTemplate()) + appendLine(JArrayClazz(it).getTemplate()) } (J_EXTRA + J_NUMBERS).forEach {key -> (J_EXTRA + J_NUMBERS).forEach { value -> - appendln(JMapClazz(key, value).getTemplate()) + appendLine(JMapClazz(key, value).getTemplate()) } } }) diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/SettingCodegen.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/SettingCodegen.kt new file mode 100644 index 000000000..d6ac306e1 --- /dev/null +++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/SettingCodegen.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2020 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/master/LICENSE + */ + +package net.mamoe.mirai.console.codegen + +object SettingCodegen { + object PrimitiveValuesCodegen : RegionCodegen(), DefaultInvoke { + override val defaultInvokeArgs: List + get() = KtType.Primitives + KtString + + override fun StringBuilder.apply(ktType: KtType) { + @Suppress("ClassName") + appendKCode( + """ + /** + * Represents a non-null [$ktType] value. + */ + interface ${ktType}Value : PrimitiveValue<$ktType> + """ + ) + } + } + +} + +object ValueKtCodegen { + @JvmStatic + fun main(args: Array) { + codegen("Value.kt") { + SettingCodegen.PrimitiveValuesCodegen() + } + } +} + diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/SettingValueUseSiteCodegen.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/SettingValueUseSiteCodegen.kt index 36af092a4..561bb40c9 100644 --- a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/SettingValueUseSiteCodegen.kt +++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/SettingValueUseSiteCodegen.kt @@ -19,19 +19,19 @@ fun main() { File("backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/_Setting.kt").apply { createNewFile() }.writeText(buildString { - appendln(COPYRIGHT) - appendln() - appendln(FILE_SUPPRESS) - appendln() - appendln(PACKAGE) - appendln() - appendln(IMPORTS) - appendln() - appendln() - appendln(DO_NOT_MODIFY) - appendln() - appendln() - appendln(genAllValueUseSite()) + appendLine(COPYRIGHT) + appendLine() + appendLine(FILE_SUPPRESS) + appendLine() + appendLine(PACKAGE) + appendLine() + appendLine(IMPORTS) + appendLine() + appendLine() + appendLine(DO_NOT_MODIFY) + appendLine() + appendLine() + appendLine(genAllValueUseSite()) }) } @@ -56,7 +56,7 @@ import kotlin.internal.LowPriorityInOverloadResolution fun genAllValueUseSite(): String = buildString { fun appendln(@Language("kt") code: String) { - this.appendln(code.trimIndent()) + this.appendLine(code.trimIndent()) } // PRIMITIVE for (number in NUMBERS + OTHER_PRIMITIVES) { @@ -83,7 +83,7 @@ fun genAllValueUseSite(): String = buildString { // MUTABLE LIST / MUTABLE SET for (collectionName in listOf("List", "Set")) { for (number in NUMBERS + OTHER_PRIMITIVES) { - appendln() + appendLine() appendln( """ @JvmName("valueMutable") @@ -94,7 +94,7 @@ fun genAllValueUseSite(): String = buildString { } // SPECIAL - appendln() + appendLine() appendln( """ fun Setting.value(default: T): Value { diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValueImplCodegen.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValueImplCodegen.kt index b4c0014a3..f9e94702f 100644 --- a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValueImplCodegen.kt +++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValueImplCodegen.kt @@ -19,17 +19,17 @@ fun main() { File("backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/_ValueImpl.kt").apply { createNewFile() }.writeText(buildString { - appendln(COPYRIGHT) - appendln() - appendln(PACKAGE) - appendln() - appendln(IMPORTS) - appendln() - appendln() - appendln(DO_NOT_MODIFY) - appendln() - appendln() - appendln(genAllValueImpl()) + appendLine(COPYRIGHT) + appendLine() + appendLine(PACKAGE) + appendLine() + appendLine(IMPORTS) + appendLine() + appendLine() + appendLine(DO_NOT_MODIFY) + appendLine() + appendLine() + appendLine(genAllValueImpl()) }) } @@ -52,19 +52,19 @@ import net.mamoe.mirai.console.setting.* fun genAllValueImpl(): String = buildString { fun appendln(@Language("kt") code: String) { - this.appendln(code.trimIndent()) + this.appendLine(code.trimIndent()) } // PRIMITIVE for (number in NUMBERS + OTHER_PRIMITIVES) { appendln(genPrimitiveValueImpl(number, number, "$number.serializer()", false)) - appendln() + appendLine() } // PRIMITIVE ARRAYS for (number in NUMBERS + OTHER_PRIMITIVES.filterNot { it == "String" }) { appendln(genPrimitiveValueImpl("${number}Array", "${number}Array", "${number}ArraySerializer()", true)) - appendln() + appendLine() } // TYPED ARRAYS @@ -77,7 +77,7 @@ fun genAllValueImpl(): String = buildString { true ) ) - appendln() + appendLine() } // PRIMITIVE LISTS / SETS @@ -92,11 +92,11 @@ fun genAllValueImpl(): String = buildString { false ) ) - appendln() + appendLine() } } - appendln() + appendLine() // MUTABLE LIST / MUTABLE SET @@ -141,11 +141,11 @@ fun genAllValueImpl(): String = buildString { } """ ) - appendln() + appendLine() } } - appendln() + appendLine() appendln( diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValuesCodegen.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValuesCodegen.kt index 018f7242e..4920d6754 100644 --- a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValuesCodegen.kt +++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValuesCodegen.kt @@ -56,11 +56,11 @@ internal val OTHER_PRIMITIVES = listOf( fun genPublicApi() = buildString { fun appendln(@Language("kt") code: String) { - this.appendln(code.trimIndent()) + this.appendLine(code.trimIndent()) } appendln(COPYRIGHT.trim()) - appendln() + appendLine() appendln( """ package net.mamoe.mirai.console.setting @@ -70,7 +70,7 @@ fun genPublicApi() = buildString { import kotlin.reflect.KProperty """ ) - appendln() + appendLine() appendln( """ /** @@ -80,7 +80,7 @@ fun genPublicApi() = buildString { */ """ ) - appendln() + appendLine() appendln( """ @@ -107,7 +107,7 @@ sealed class Value : ReadWriteProperty { } """ ) - appendln() + appendLine() // PRIMITIVES @@ -127,7 +127,7 @@ sealed class Value : ReadWriteProperty { appendln(template) } - appendln() + appendLine() for (number in OTHER_PRIMITIVES) { val template = """ @@ -137,7 +137,7 @@ sealed class Value : ReadWriteProperty { appendln(template) } - appendln() + appendLine() // ARRAYS @@ -154,7 +154,7 @@ sealed class Value : ReadWriteProperty { sealed class PrimitiveArrayValue : ArrayValue() """ ) - appendln() + appendLine() for (number in (NUMBERS + OTHER_PRIMITIVES).filterNot { it == "String" }) { appendln( @@ -164,10 +164,10 @@ sealed class Value : ReadWriteProperty { } """ ) - appendln() + appendLine() } - appendln() + appendLine() // TYPED ARRAYS @@ -178,7 +178,7 @@ sealed class Value : ReadWriteProperty { } """ ) - appendln() + appendLine() for (number in (NUMBERS + OTHER_PRIMITIVES)) { appendln( @@ -188,7 +188,7 @@ sealed class Value : ReadWriteProperty { ) } - appendln() + appendLine() // TYPED LISTS / SETS for (collectionName in listOf("List", "Set")) { @@ -207,14 +207,14 @@ sealed class Value : ReadWriteProperty { appendln(template) } - appendln() + appendLine() // SETTING appendln( """ abstract class Setting${collectionName}Value internal constructor() : Value<${collectionName}>(), ${collectionName} """ ) - appendln() + appendLine() } // SETTING VALUE @@ -225,7 +225,7 @@ sealed class Value : ReadWriteProperty { """ ) - appendln() + appendLine() // MUTABLE LIST / MUTABLE SET for (collectionName in listOf("List", "Set")) { @@ -235,7 +235,7 @@ sealed class Value : ReadWriteProperty { """ ) - appendln() + appendLine() for (number in (NUMBERS + OTHER_PRIMITIVES)) { appendln( @@ -245,17 +245,17 @@ sealed class Value : ReadWriteProperty { ) } - appendln() + appendLine() // SETTING appendln( """ abstract class MutableSetting${collectionName}Value internal constructor() : Value>(), Mutable${collectionName} """ ) - appendln() + appendLine() } - appendln() + appendLine() // DYNAMIC appendln( diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/setting/SettingCodegen.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/setting/SettingCodegen.kt deleted file mode 100644 index 9c97af271..000000000 --- a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/setting/SettingCodegen.kt +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright 2020 Mamoe Technologies and contributors. - * - * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. - * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. - * - * https://github.com/mamoe/mirai/blob/master/LICENSE - */ - -package net.mamoe.mirai.console.codegen.setting - diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/util.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/util.kt index 172819f94..247a8ced0 100644 --- a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/util.kt +++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/util.kt @@ -7,11 +7,91 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ +@file:Suppress("NOTHING_TO_INLINE", "MemberVisibilityCanBePrivate", "unused") + package net.mamoe.mirai.console.codegen +import org.intellij.lang.annotations.Language import java.io.File -fun codegen(targetFile: String, regionName: String, block: StringBuilder.() -> Unit) { + +typealias KtByte = KtType.KtPrimitive.KtByte +typealias KtShort = KtType.KtPrimitive.KtShort +typealias KtInt = KtType.KtPrimitive.KtInt +typealias KtLong = KtType.KtPrimitive.KtLong +typealias KtFloat = KtType.KtPrimitive.KtFloat +typealias KtDouble = KtType.KtPrimitive.KtDouble +typealias KtChar = KtType.KtPrimitive.KtChar +typealias KtBoolean = KtType.KtPrimitive.KtBoolean + +typealias KtString = KtType.KtString + +typealias KtCollection = KtType.KtCollection +typealias KtMap = KtType.KtMap + +typealias KtPrimitive = KtType.KtPrimitive + + +sealed class KtType { + /** + * Its classname in standard library + */ + abstract val standardName: String + override fun toString(): String = standardName + + /** + * Not Including [String] + */ + sealed class KtPrimitive( + override val standardName: String, + val jPrimitiveName: String = standardName.toLowerCase(), + val jObjectName: String = standardName + ) : KtType() { + object KtByte : KtPrimitive("Byte") + object KtShort : KtPrimitive("Short") + object KtInt : KtPrimitive("Int", jObjectName = "Integer") + object KtLong : KtPrimitive("Long") + + object KtFloat : KtPrimitive("Float") + object KtDouble : KtPrimitive("Double") + + object KtChar : KtPrimitive("Char", jObjectName = "Character") + object KtBoolean : KtPrimitive("Boolean") + } + + object KtString : KtType() { + override val standardName: String get() = "String" + } + + /** + * [List], [Set] + */ + data class KtCollection(override val standardName: String) : KtType() + + object KtMap : KtType() { + override val standardName: String get() = "Map" + } + + companion object { + val PrimitiveIntegers = listOf(KtByte, KtShort, KtInt, KtLong) + val PrimitiveFloatings = listOf(KtFloat, KtDouble) + + val PrimitiveNumbers = PrimitiveIntegers + PrimitiveFloatings + val PrimitiveNonNumbers = listOf(KtChar, KtBoolean) + + val Primitives = PrimitiveNumbers + PrimitiveNonNumbers + } +} + +operator fun KtType.plus(type: KtType): List { + return listOf(this, type) +} + +val KtType.lowerCaseName: String get() = this.standardName.toLowerCase() + +inline fun kCode(@Language("kt") source: String) = source.trimIndent() + +fun codegen(targetFile: String, block: CodegenScope.() -> Unit) { //// region PrimitiveValue CODEGEN START //// //// region PrimitiveValue CODEGEN END //// @@ -19,17 +99,11 @@ fun codegen(targetFile: String, regionName: String, block: StringBuilder.() -> U println("Codegen target: ${it.absolutePath}") }.apply { writeText( - readText() - .replace(Regex("""//// region $regionName CODEGEN START ////([\s\S]*?)//// endregion $regionName CODEGEN END ////""")) { - val code = StringBuilder().apply(block).toString() - """ - |//// region $regionName CODEGEN START //// - | - |$code - | - |//// endregion $regionName CODEGEN END //// - """.trimMargin() + CodegenScope().apply(block).also { list -> + list.forEach { + println("Applying replacement: $it") } + }.applyTo(readText()) ) } } @@ -48,7 +122,7 @@ fun String.findFileSmart(): File = kotlin.run { } fun main() { - codegen("Value.kt", "PrimitiveValue") { - + codegen("Value.kt") { + SettingCodegen.PrimitiveValuesCodegen() } } \ No newline at end of file