Extract to separate files

This commit is contained in:
Him188 2020-05-13 11:51:12 +08:00
parent 7d589a0dec
commit 4eccb1a778
3 changed files with 187 additions and 185 deletions

View File

@ -2,11 +2,6 @@
package net.mamoe.mirai.console.command
import net.mamoe.mirai.Bot
import net.mamoe.mirai.console.command.AbstractCommandParserContext.Node
import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.contact.Member
import kotlin.internal.LowPriorityInOverloadResolution
import kotlin.reflect.KClass
/**
@ -34,70 +29,6 @@ class CommandDescriptor(
val permission: CommandPermission = CommandPermission.Default
)
/**
* 指令形式参数.
*/
data class CommandParam<T : Any>(
/**
* 参数名, `null` 时即为匿名参数.
* 参数名允许重复 (尽管并不建议这样做).
* 参数名仅提供给 [CommandArgParser] 以发送更好的错误信息.
*/
val name: String?,
/**
* 参数类型. 将从 [CommandDescriptor.context] 中寻找 [CommandArgParser] 解析.
*/
val type: KClass<T> // exact type
) {
constructor(name: String?, type: KClass<T>, parser: CommandArgParser<T>) : this(name, type) {
this.parser = parser
}
@JvmField
internal var parser: CommandArgParser<T>? = null
/**
* 覆盖的 [CommandArgParser].
*
* 如果非 `null`, 将不会从 [CommandParserContext] 寻找 [CommandArgParser]
*/
val overrideParser: CommandArgParser<T>? get() = parser
}
private fun preview() {
class MyArg(val string: String)
CommandDescriptor("test") {
permission(CommandPermission.GroupOwner or CommandPermission.Console)
permission {
println("正在检查 $this 的权限")
true
}
param<String>("test")
param<Boolean>("test")
param<String>("test")
param("p2", String::class)
param("p2", String::class)
params {
"p2" typed String::class
"testPram" typed CharSequence::class using StringArgParser
"p3" using StringArgParser
}
context {
MyArg::class with {
println("正在解析 $it")
MyArg(it)
}
}
}
}
/**
* 构建一个 [CommandDescriptor]
*/
@ -146,13 +77,27 @@ class CommandDescriptorBuilder(
this.params.addAll(params)
}
fun param(name: String?, type: KClass<*>): CommandDescriptorBuilder = apply {
this.params.add(CommandParam(name, type))
@JvmSynthetic
fun <T : Any> param(
name: String?,
type: KClass<T>,
overrideParser: CommandArgParser<T>? = null
): CommandDescriptorBuilder = apply {
this.params.add(CommandParam(name, type).apply { this.parser = overrideParser })
}
inline fun <reified T : Any> param(name: String? = null): CommandDescriptorBuilder = apply {
this.params.add(CommandParam(name, T::class))
}
fun <T : Any> param(
name: String?,
type: Class<T>,
overrideParser: CommandArgParser<T>? = null
): CommandDescriptorBuilder =
param(name, type, overrideParser)
inline fun <reified T : Any> param(
name: String? = null,
overrideParser: CommandArgParser<T>? = null
): CommandDescriptorBuilder =
param(name, T::class, overrideParser)
@JvmSynthetic
fun param(vararg pairs: Pair<String?, KClass<*>>): CommandDescriptorBuilder = apply {
@ -178,7 +123,8 @@ class CommandDescriptorBuilder(
fun build(): CommandDescriptor = CommandDescriptor(fullName, context, params, permission)
}
inline class ParamBlock(@PublishedApi internal val list: MutableList<CommandParam<*>>) {
@Suppress("NON_PUBLIC_PRIMARY_CONSTRUCTOR_OF_INLINE_CLASS")
inline class ParamBlock internal constructor(@PublishedApi internal val list: MutableList<CommandParam<*>>) {
/** 添加一个名称为 [this], 类型为 [klass] 的参数. 返回添加成功的对象 */
infix fun <T : Any> String.typed(klass: KClass<T>): CommandParam<T> =
CommandParam(this, klass).also { list.add(it) }
@ -190,114 +136,4 @@ inline class ParamBlock(@PublishedApi internal val list: MutableList<CommandPara
/** 覆盖 [CommandArgParser] */
inline infix fun <reified T : Any> String.using(parser: CommandArgParser<T>): CommandParam<T> =
this typed T::class using parser
}
/**
* [KClass] [CommandArgParser] 的匹配
*/
interface CommandParserContext {
operator fun <T : Any> get(klass: KClass<T>): CommandArgParser<T>?
/**
* 内建的默认 [CommandArgParser]
*/
object Builtins : CommandParserContext by (CommandParserContext {
Int::class with IntArgParser
Byte::class with ByteArgParser
Short::class with ShortArgParser
Boolean::class with BooleanArgParser
String::class with StringArgParser
Long::class with LongArgParser
Double::class with DoubleArgParser
Float::class with FloatArgParser
Member::class with ExistMemberArgParser
Group::class with ExistGroupArgParser
Bot::class with ExistBotArgParser
})
}
fun <T : Any> CommandParserContext.parserFor(param: CommandParam<T>): CommandArgParser<T>? = this[param.type]
/**
* 合并两个 [CommandParserContext], [replacer] 将会替换 [this] 中重复的 parser.
*/
operator fun CommandParserContext.plus(replacer: CommandParserContext): CommandParserContext {
return object : CommandParserContext {
override fun <T : Any> get(klass: KClass<T>): CommandArgParser<T>? = replacer[klass] ?: this@plus[klass]
}
}
@Suppress("UNCHECKED_CAST")
open class AbstractCommandParserContext(val list: List<Node<*>>) : CommandParserContext {
class Node<T : Any>(
val klass: KClass<T>,
val parser: CommandArgParser<T>
)
override fun <T : Any> get(klass: KClass<T>): CommandArgParser<T>? =
this.list.firstOrNull { it.klass == klass }?.parser as CommandArgParser<T>?
}
/**
* 构建一个 [CommandParserContext].
*
* ```
* CommandParserContext {
* Int::class with IntArgParser
* Member::class with ExistMemberArgParser
* Group::class with { s: String, sender: CommandSender ->
* Bot.getInstance(s.toLong()).getGroup(s.toLong())
* }
* Bot::class with { s: String ->
* Bot.getInstance(s.toLong())
* }
* }
* ```
*/
@Suppress("FunctionName")
@JvmSynthetic
inline fun CommandParserContext(block: CommandParserContextBuilder.() -> Unit): CommandParserContext {
return AbstractCommandParserContext(
CommandParserContextBuilder().apply(block).distinctByReversed { it.klass })
}
/**
* @see CommandParserContext
*/
class CommandParserContextBuilder : MutableList<Node<*>> by mutableListOf() {
@JvmName("add")
inline infix fun <T : Any> KClass<T>.with(parser: CommandArgParser<T>): Node<*> =
Node(this, parser)
/**
* 添加一个指令解析器
*/
@JvmSynthetic
@LowPriorityInOverloadResolution
inline infix fun <T : Any> KClass<T>.with(
crossinline parser: CommandArgParser<T>.(s: String, sender: CommandSender) -> T
): Node<*> = Node(this, CommandArgParser(parser))
/**
* 添加一个指令解析器
*/
@JvmSynthetic
inline infix fun <T : Any> KClass<T>.with(
crossinline parser: CommandArgParser<T>.(s: String) -> T
): Node<*> = Node(this, CommandArgParser { s: String, _: CommandSender -> parser(s) })
}
@PublishedApi
internal inline fun <T, K> Iterable<T>.distinctByReversed(selector: (T) -> K): List<T> {
val set = HashSet<K>()
val list = ArrayList<T>()
for (i in list.indices.reversed()) {
val element = list[i]
if (set.add(element.let(selector))) {
list.add(element)
}
}
return list
}

View File

@ -0,0 +1,36 @@
@file:Suppress("unused")
package net.mamoe.mirai.console.command
import kotlin.reflect.KClass
/**
* 指令形式参数.
*/
data class CommandParam<T : Any>(
/**
* 参数名, `null` 时即为匿名参数.
* 参数名允许重复 (尽管并不建议这样做).
* 参数名仅提供给 [CommandArgParser] 以发送更好的错误信息.
*/
val name: String?,
/**
* 参数类型. 将从 [CommandDescriptor.context] 中寻找 [CommandArgParser] 解析.
*/
val type: KClass<T> // exact type
) {
constructor(name: String?, type: KClass<T>, parser: CommandArgParser<T>) : this(name, type) {
this.parser = parser
}
@JvmField
internal var parser: CommandArgParser<T>? = null
/**
* 覆盖的 [CommandArgParser].
*
* 如果非 `null`, 将不会从 [CommandParserContext] 寻找 [CommandArgParser]
*/
val overrideParser: CommandArgParser<T>? get() = parser
}

View File

@ -0,0 +1,130 @@
/*
* 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("NOTHING_TO_INLINE", "INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "unused", "MemberVisibilityCanBePrivate")
package net.mamoe.mirai.console.command
import net.mamoe.mirai.Bot
import net.mamoe.mirai.console.command.AbstractCommandParserContext.Node
import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.contact.Member
import kotlin.internal.LowPriorityInOverloadResolution
import kotlin.reflect.KClass
/**
* [KClass] [CommandArgParser] 的匹配
*/
interface CommandParserContext {
operator fun <T : Any> get(klass: KClass<T>): CommandArgParser<T>?
/**
* 内建的默认 [CommandArgParser]
*/
object Builtins : CommandParserContext by (CommandParserContext {
Int::class with IntArgParser
Byte::class with ByteArgParser
Short::class with ShortArgParser
Boolean::class with BooleanArgParser
String::class with StringArgParser
Long::class with LongArgParser
Double::class with DoubleArgParser
Float::class with FloatArgParser
Member::class with ExistMemberArgParser
Group::class with ExistGroupArgParser
Bot::class with ExistBotArgParser
})
}
fun <T : Any> CommandParserContext.parserFor(param: CommandParam<T>): CommandArgParser<T>? = this[param.type]
/**
* 合并两个 [CommandParserContext], [replacer] 将会替换 [this] 中重复的 parser.
*/
operator fun CommandParserContext.plus(replacer: CommandParserContext): CommandParserContext {
return object : CommandParserContext {
override fun <T : Any> get(klass: KClass<T>): CommandArgParser<T>? = replacer[klass] ?: this@plus[klass]
}
}
@Suppress("UNCHECKED_CAST")
open class AbstractCommandParserContext(val list: List<Node<*>>) : CommandParserContext {
class Node<T : Any>(
val klass: KClass<T>,
val parser: CommandArgParser<T>
)
override fun <T : Any> get(klass: KClass<T>): CommandArgParser<T>? =
this.list.firstOrNull { it.klass == klass }?.parser as CommandArgParser<T>?
}
/**
* 构建一个 [CommandParserContext].
*
* ```
* CommandParserContext {
* Int::class with IntArgParser
* Member::class with ExistMemberArgParser
* Group::class with { s: String, sender: CommandSender ->
* Bot.getInstance(s.toLong()).getGroup(s.toLong())
* }
* Bot::class with { s: String ->
* Bot.getInstance(s.toLong())
* }
* }
* ```
*/
@Suppress("FunctionName")
@JvmSynthetic
inline fun CommandParserContext(block: CommandParserContextBuilder.() -> Unit): CommandParserContext {
return AbstractCommandParserContext(
CommandParserContextBuilder().apply(block).distinctByReversed { it.klass })
}
/**
* @see CommandParserContext
*/
class CommandParserContextBuilder : MutableList<Node<*>> by mutableListOf() {
@JvmName("add")
inline infix fun <T : Any> KClass<T>.with(parser: CommandArgParser<T>): Node<*> =
Node(this, parser)
/**
* 添加一个指令解析器
*/
@JvmSynthetic
@LowPriorityInOverloadResolution
inline infix fun <T : Any> KClass<T>.with(
crossinline parser: CommandArgParser<T>.(s: String, sender: CommandSender) -> T
): Node<*> = Node(this, CommandArgParser(parser))
/**
* 添加一个指令解析器
*/
@JvmSynthetic
inline infix fun <T : Any> KClass<T>.with(
crossinline parser: CommandArgParser<T>.(s: String) -> T
): Node<*> = Node(this, CommandArgParser { s: String, _: CommandSender -> parser(s) })
}
@PublishedApi
internal inline fun <T, K> Iterable<T>.distinctByReversed(selector: (T) -> K): List<T> {
val set = HashSet<K>()
val list = ArrayList<T>()
for (i in list.indices.reversed()) {
val element = list[i]
if (set.add(element.let(selector))) {
list.add(element)
}
}
return list
}