mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-25 15:40:28 +08:00
Call parse with errors
This commit is contained in:
parent
8da8615721
commit
64790d0114
@ -12,7 +12,10 @@
|
|||||||
package net.mamoe.mirai.console.command
|
package net.mamoe.mirai.console.command
|
||||||
|
|
||||||
import net.mamoe.mirai.console.command.CommandExecuteResult.CommandExecuteStatus
|
import net.mamoe.mirai.console.command.CommandExecuteResult.CommandExecuteStatus
|
||||||
import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors
|
import net.mamoe.mirai.console.command.descriptor.*
|
||||||
|
import net.mamoe.mirai.console.command.parse.CommandCall
|
||||||
|
import net.mamoe.mirai.console.command.parse.CommandValueArgument
|
||||||
|
import net.mamoe.mirai.console.command.resolve.ResolvedCommandCall
|
||||||
import net.mamoe.mirai.console.util.ConsoleExperimentalApi
|
import net.mamoe.mirai.console.util.ConsoleExperimentalApi
|
||||||
import net.mamoe.mirai.message.data.Message
|
import net.mamoe.mirai.message.data.Message
|
||||||
import net.mamoe.mirai.message.data.MessageChain
|
import net.mamoe.mirai.message.data.MessageChain
|
||||||
@ -37,6 +40,12 @@ public sealed class CommandExecuteResult {
|
|||||||
/** 尝试执行的指令 (如果匹配到) */
|
/** 尝试执行的指令 (如果匹配到) */
|
||||||
public abstract val command: Command?
|
public abstract val command: Command?
|
||||||
|
|
||||||
|
/** 解析的 [CommandCall] (如果匹配到) */
|
||||||
|
public abstract val call: CommandCall?
|
||||||
|
|
||||||
|
/** 解析的 [ResolvedCommandCall] (如果匹配到) */
|
||||||
|
public abstract val resolvedCall: ResolvedCommandCall?
|
||||||
|
|
||||||
/** 尝试执行的指令名 (如果匹配到) */
|
/** 尝试执行的指令名 (如果匹配到) */
|
||||||
public abstract val commandName: String?
|
public abstract val commandName: String?
|
||||||
|
|
||||||
@ -49,10 +58,14 @@ public sealed class CommandExecuteResult {
|
|||||||
public class Success(
|
public class Success(
|
||||||
/** 尝试执行的指令 */
|
/** 尝试执行的指令 */
|
||||||
public override val command: Command,
|
public override val command: Command,
|
||||||
|
/** 解析的 [CommandCall] (如果匹配到) */
|
||||||
|
public override val call: CommandCall,
|
||||||
|
/** 解析的 [ResolvedCommandCall] (如果匹配到) */
|
||||||
|
public override val resolvedCall: ResolvedCommandCall,
|
||||||
/** 尝试执行的指令名 */
|
/** 尝试执行的指令名 */
|
||||||
public override val commandName: String,
|
public override val commandName: String,
|
||||||
/** 基础分割后的实际参数列表, 元素类型可能为 [Message] 或 [String] */
|
/** 基础分割后的实际参数列表, 元素类型可能为 [Message] 或 [String] */
|
||||||
public override val args: MessageChain
|
public override val args: MessageChain,
|
||||||
) : CommandExecuteResult() {
|
) : CommandExecuteResult() {
|
||||||
/** 指令执行时发生的错误, 总是 `null` */
|
/** 指令执行时发生的错误, 总是 `null` */
|
||||||
public override val exception: Nothing? get() = null
|
public override val exception: Nothing? get() = null
|
||||||
@ -61,61 +74,82 @@ public sealed class CommandExecuteResult {
|
|||||||
public override val status: CommandExecuteStatus get() = CommandExecuteStatus.SUCCESSFUL
|
public override val status: CommandExecuteStatus get() = CommandExecuteStatus.SUCCESSFUL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 指令执行失败 */
|
||||||
|
public abstract class Failure : CommandExecuteResult()
|
||||||
|
|
||||||
/** 执行执行时发生了一个非法参数错误 */
|
/** 执行执行时发生了一个非法参数错误 */
|
||||||
public class IllegalArgument(
|
public class IllegalArgument(
|
||||||
/** 指令执行时发生的错误 */
|
/** 指令执行时发生的错误 */
|
||||||
public override val exception: IllegalCommandArgumentException,
|
public override val exception: IllegalCommandArgumentException,
|
||||||
/** 尝试执行的指令 */
|
/** 尝试执行的指令 */
|
||||||
public override val command: Command,
|
public override val command: Command,
|
||||||
|
/** 解析的 [CommandCall] (如果匹配到) */
|
||||||
|
public override val call: CommandCall,
|
||||||
|
/** 解析的 [ResolvedCommandCall] (如果匹配到) */
|
||||||
|
public override val resolvedCall: ResolvedCommandCall,
|
||||||
/** 尝试执行的指令名 */
|
/** 尝试执行的指令名 */
|
||||||
public override val commandName: String,
|
public override val commandName: String,
|
||||||
/** 基础分割后的实际参数列表, 元素类型可能为 [Message] 或 [String] */
|
/** 基础分割后的实际参数列表, 元素类型可能为 [Message] 或 [String] */
|
||||||
public override val args: MessageChain
|
public override val args: MessageChain,
|
||||||
) : CommandExecuteResult() {
|
) : Failure() {
|
||||||
/** 指令最终执行状态, 总是 [CommandExecuteStatus.EXECUTION_EXCEPTION] */
|
/** 指令最终执行状态, 总是 [CommandExecuteStatus.EXECUTION_EXCEPTION] */
|
||||||
public override val status: CommandExecuteStatus get() = CommandExecuteStatus.ILLEGAL_ARGUMENT
|
public override val status: CommandExecuteStatus get() = CommandExecuteStatus.ILLEGAL_ARGUMENT
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 指令执行过程出现了错误 */
|
/** 指令方法调用过程出现了错误 */
|
||||||
public class ExecutionFailed(
|
public class ExecutionFailed(
|
||||||
/** 指令执行时发生的错误 */
|
/** 指令执行时发生的错误 */
|
||||||
public override val exception: Throwable,
|
public override val exception: Throwable,
|
||||||
/** 尝试执行的指令 */
|
/** 尝试执行的指令 */
|
||||||
public override val command: Command,
|
public override val command: Command,
|
||||||
|
/** 解析的 [CommandCall] (如果匹配到) */
|
||||||
|
public override val call: CommandCall,
|
||||||
|
/** 解析的 [ResolvedCommandCall] (如果匹配到) */
|
||||||
|
public override val resolvedCall: ResolvedCommandCall,
|
||||||
/** 尝试执行的指令名 */
|
/** 尝试执行的指令名 */
|
||||||
public override val commandName: String,
|
public override val commandName: String,
|
||||||
/** 基础分割后的实际参数列表, 元素类型可能为 [Message] 或 [String] */
|
/** 基础分割后的实际参数列表, 元素类型可能为 [Message] 或 [String] */
|
||||||
public override val args: MessageChain
|
public override val args: MessageChain,
|
||||||
) : CommandExecuteResult() {
|
) : Failure() {
|
||||||
/** 指令最终执行状态, 总是 [CommandExecuteStatus.EXECUTION_EXCEPTION] */
|
/** 指令最终执行状态, 总是 [CommandExecuteStatus.EXECUTION_EXCEPTION] */
|
||||||
public override val status: CommandExecuteStatus get() = CommandExecuteStatus.EXECUTION_EXCEPTION
|
public override val status: CommandExecuteStatus get() = CommandExecuteStatus.EXECUTION_EXCEPTION
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 没有匹配的指令 */
|
/** 没有匹配的指令 */
|
||||||
public class UnresolvedCall(
|
public class UnresolvedCommand(
|
||||||
/** 尝试执行的指令名 */
|
/** 尝试执行的指令名 */
|
||||||
public override val commandName: String,
|
public override val commandName: String,
|
||||||
) : CommandExecuteResult() {
|
) : Failure() {
|
||||||
/** 指令执行时发生的错误, 总是 `null` */
|
/** 指令执行时发生的错误, 总是 `null` */
|
||||||
public override val exception: Nothing? get() = null
|
public override val exception: Nothing? get() = null
|
||||||
|
|
||||||
/** 尝试执行的指令, 总是 `null` */
|
/** 尝试执行的指令, 总是 `null` */
|
||||||
public override val command: Nothing? get() = null
|
public override val command: Nothing? get() = null
|
||||||
|
|
||||||
|
/** 解析的 [CommandCall] (如果匹配到) */
|
||||||
|
public override val call: CommandCall? get() = null
|
||||||
|
|
||||||
|
/** 解析的 [ResolvedCommandCall] (如果匹配到) */
|
||||||
|
public override val resolvedCall: ResolvedCommandCall? get() = null
|
||||||
|
|
||||||
/** 基础分割后的实际参数列表, 元素类型可能为 [Message] 或 [String] */
|
/** 基础分割后的实际参数列表, 元素类型可能为 [Message] 或 [String] */
|
||||||
public override val args: Nothing? get() = null
|
public override val args: Nothing? get() = null
|
||||||
|
|
||||||
/** 指令最终执行状态, 总是 [CommandExecuteStatus.COMMAND_NOT_FOUND] */
|
/** 指令最终执行状态, 总是 [CommandExecuteStatus.UNRESOLVED_COMMAND] */
|
||||||
public override val status: CommandExecuteStatus get() = CommandExecuteStatus.COMMAND_NOT_FOUND
|
public override val status: CommandExecuteStatus get() = CommandExecuteStatus.UNRESOLVED_COMMAND
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 权限不足 */
|
/** 权限不足 */
|
||||||
public class PermissionDenied(
|
public class PermissionDenied(
|
||||||
/** 尝试执行的指令 */
|
/** 尝试执行的指令 */
|
||||||
public override val command: Command,
|
public override val command: Command,
|
||||||
|
/** 解析的 [CommandCall] (如果匹配到) */
|
||||||
|
public override val call: CommandCall,
|
||||||
|
/** 解析的 [ResolvedCommandCall] (如果匹配到) */
|
||||||
|
public override val resolvedCall: ResolvedCommandCall,
|
||||||
/** 尝试执行的指令名 */
|
/** 尝试执行的指令名 */
|
||||||
public override val commandName: String
|
public override val commandName: String,
|
||||||
) : CommandExecuteResult() {
|
) : Failure() {
|
||||||
/** 基础分割后的实际参数列表, 元素类型可能为 [Message] 或 [String] */
|
/** 基础分割后的实际参数列表, 元素类型可能为 [Message] 或 [String] */
|
||||||
public override val args: Nothing? get() = null
|
public override val args: Nothing? get() = null
|
||||||
|
|
||||||
@ -126,6 +160,33 @@ public sealed class CommandExecuteResult {
|
|||||||
public override val status: CommandExecuteStatus get() = CommandExecuteStatus.PERMISSION_DENIED
|
public override val status: CommandExecuteStatus get() = CommandExecuteStatus.PERMISSION_DENIED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 没有匹配的指令 */
|
||||||
|
public class UnmatchedSignature(
|
||||||
|
/** 尝试执行的指令名 */
|
||||||
|
public override val commandName: String,
|
||||||
|
/** 尝试执行的指令 */
|
||||||
|
public override val command: Command,
|
||||||
|
/** 尝试执行的指令 */
|
||||||
|
@ExperimentalCommandDescriptors
|
||||||
|
@ConsoleExperimentalApi
|
||||||
|
public val failureReasons: List<UnmatchedCommandSignature>,
|
||||||
|
) : Failure() {
|
||||||
|
/** 指令执行时发生的错误, 总是 `null` */
|
||||||
|
public override val exception: Nothing? get() = null
|
||||||
|
|
||||||
|
/** 解析的 [CommandCall] (如果匹配到) */
|
||||||
|
public override val call: CommandCall? get() = null
|
||||||
|
|
||||||
|
/** 解析的 [ResolvedCommandCall] (如果匹配到) */
|
||||||
|
public override val resolvedCall: ResolvedCommandCall? get() = null
|
||||||
|
|
||||||
|
/** 基础分割后的实际参数列表, 元素类型可能为 [Message] 或 [String] */
|
||||||
|
public override val args: Nothing? get() = null
|
||||||
|
|
||||||
|
/** 指令最终执行状态, 总是 [CommandExecuteStatus.UNMATCHED_SIGNATURE] */
|
||||||
|
public override val status: CommandExecuteStatus get() = CommandExecuteStatus.UNMATCHED_SIGNATURE
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 指令的执行状态
|
* 指令的执行状态
|
||||||
*/
|
*/
|
||||||
@ -137,15 +198,56 @@ public sealed class CommandExecuteResult {
|
|||||||
EXECUTION_EXCEPTION,
|
EXECUTION_EXCEPTION,
|
||||||
|
|
||||||
/** 没有匹配的指令 */
|
/** 没有匹配的指令 */
|
||||||
COMMAND_NOT_FOUND,
|
UNMATCHED_SIGNATURE,
|
||||||
|
|
||||||
|
/** 没有匹配的指令 */
|
||||||
|
UNRESOLVED_COMMAND,
|
||||||
|
|
||||||
/** 权限不足 */
|
/** 权限不足 */
|
||||||
PERMISSION_DENIED,
|
PERMISSION_DENIED,
|
||||||
|
|
||||||
/** 非法参数 */
|
/** 非法参数 */
|
||||||
ILLEGAL_ARGUMENT,
|
ILLEGAL_ARGUMENT,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ExperimentalCommandDescriptors
|
||||||
|
@ConsoleExperimentalApi
|
||||||
|
public class UnmatchedCommandSignature(
|
||||||
|
public val signature: CommandSignature,
|
||||||
|
public val failureReason: FailureReason,
|
||||||
|
)
|
||||||
|
|
||||||
|
@ExperimentalCommandDescriptors
|
||||||
|
@ConsoleExperimentalApi
|
||||||
|
public sealed class FailureReason {
|
||||||
|
public class InapplicableReceiverArgument(
|
||||||
|
public override val parameter: CommandReceiverParameter<*>,
|
||||||
|
public val argument: CommandSender,
|
||||||
|
) : InapplicableArgument()
|
||||||
|
|
||||||
|
public class InapplicableValueArgument(
|
||||||
|
public override val parameter: CommandValueParameter<*>,
|
||||||
|
public val argument: CommandValueArgument,
|
||||||
|
) : InapplicableArgument()
|
||||||
|
|
||||||
|
public abstract class InapplicableArgument : FailureReason() {
|
||||||
|
public abstract val parameter: CommandParameter<*>
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class ArgumentLengthMismatch : FailureReason()
|
||||||
|
|
||||||
|
public data class ResolutionAmbiguity(
|
||||||
|
/**
|
||||||
|
* Including [self][UnmatchedCommandSignature.signature].
|
||||||
|
*/
|
||||||
|
public val allCandidates: List<CommandSignature>,
|
||||||
|
) : FailureReason()
|
||||||
|
|
||||||
|
public object TooManyArguments : ArgumentLengthMismatch()
|
||||||
|
public object NotEnoughArguments : ArgumentLengthMismatch()
|
||||||
|
}
|
||||||
|
|
||||||
@ExperimentalCommandDescriptors
|
@ExperimentalCommandDescriptors
|
||||||
@Suppress("RemoveRedundantQualifierName")
|
@Suppress("RemoveRedundantQualifierName")
|
||||||
public typealias CommandExecuteStatus = CommandExecuteResult.CommandExecuteStatus
|
public typealias CommandExecuteStatus = CommandExecuteResult.CommandExecuteStatus
|
||||||
@ -164,59 +266,7 @@ public fun CommandExecuteResult.isSuccess(): Boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 当 [this] 为 [CommandExecuteResult.IllegalArgument] 时返回 `true`
|
* 当 [this] 为 [CommandExecuteResult.ExecutionFailed], [CommandExecuteResult.IllegalArgument] , [CommandExecuteResult.UnmatchedSignature] 或 [CommandExecuteResult.UnresolvedCommand] 时返回 `true`
|
||||||
*/
|
|
||||||
@ExperimentalCommandDescriptors
|
|
||||||
@JvmSynthetic
|
|
||||||
public fun CommandExecuteResult.isIllegalArgument(): Boolean {
|
|
||||||
contract {
|
|
||||||
returns(true) implies (this@isIllegalArgument is CommandExecuteResult.IllegalArgument)
|
|
||||||
returns(false) implies (this@isIllegalArgument !is CommandExecuteResult.IllegalArgument)
|
|
||||||
}
|
|
||||||
return this is CommandExecuteResult.IllegalArgument
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当 [this] 为 [CommandExecuteResult.ExecutionFailed] 时返回 `true`
|
|
||||||
*/
|
|
||||||
@ExperimentalCommandDescriptors
|
|
||||||
@JvmSynthetic
|
|
||||||
public fun CommandExecuteResult.isExecutionException(): Boolean {
|
|
||||||
contract {
|
|
||||||
returns(true) implies (this@isExecutionException is CommandExecuteResult.ExecutionFailed)
|
|
||||||
returns(false) implies (this@isExecutionException !is CommandExecuteResult.ExecutionFailed)
|
|
||||||
}
|
|
||||||
return this is CommandExecuteResult.ExecutionFailed
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当 [this] 为 [CommandExecuteResult.PermissionDenied] 时返回 `true`
|
|
||||||
*/
|
|
||||||
@ExperimentalCommandDescriptors
|
|
||||||
@JvmSynthetic
|
|
||||||
public fun CommandExecuteResult.isPermissionDenied(): Boolean {
|
|
||||||
contract {
|
|
||||||
returns(true) implies (this@isPermissionDenied is CommandExecuteResult.PermissionDenied)
|
|
||||||
returns(false) implies (this@isPermissionDenied !is CommandExecuteResult.PermissionDenied)
|
|
||||||
}
|
|
||||||
return this is CommandExecuteResult.PermissionDenied
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当 [this] 为 [CommandExecuteResult.UnresolvedCall] 时返回 `true`
|
|
||||||
*/
|
|
||||||
@ExperimentalCommandDescriptors
|
|
||||||
@JvmSynthetic
|
|
||||||
public fun CommandExecuteResult.isCommandNotFound(): Boolean {
|
|
||||||
contract {
|
|
||||||
returns(true) implies (this@isCommandNotFound is CommandExecuteResult.UnresolvedCall)
|
|
||||||
returns(false) implies (this@isCommandNotFound !is CommandExecuteResult.UnresolvedCall)
|
|
||||||
}
|
|
||||||
return this is CommandExecuteResult.UnresolvedCall
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当 [this] 为 [CommandExecuteResult.ExecutionFailed], [CommandExecuteResult.IllegalArgument] 或 [CommandExecuteResult.UnresolvedCall] 时返回 `true`
|
|
||||||
*/
|
*/
|
||||||
@ExperimentalCommandDescriptors
|
@ExperimentalCommandDescriptors
|
||||||
@JvmSynthetic
|
@JvmSynthetic
|
||||||
|
@ -75,15 +75,15 @@ public sealed class ArgumentAcceptance(
|
|||||||
) {
|
) {
|
||||||
public object Direct : ArgumentAcceptance(Int.MAX_VALUE)
|
public object Direct : ArgumentAcceptance(Int.MAX_VALUE)
|
||||||
|
|
||||||
public class WithTypeConversion(
|
public data class WithTypeConversion(
|
||||||
public val typeVariant: TypeVariant<*>,
|
public val typeVariant: TypeVariant<*>,
|
||||||
) : ArgumentAcceptance(20)
|
) : ArgumentAcceptance(20)
|
||||||
|
|
||||||
public class WithContextualConversion(
|
public data class WithContextualConversion(
|
||||||
public val parser: CommandValueArgumentParser<*>,
|
public val parser: CommandValueArgumentParser<*>,
|
||||||
) : ArgumentAcceptance(10)
|
) : ArgumentAcceptance(10)
|
||||||
|
|
||||||
public class ResolutionAmbiguity(
|
public data class ResolutionAmbiguity(
|
||||||
public val candidates: List<TypeVariant<*>>,
|
public val candidates: List<TypeVariant<*>>,
|
||||||
) : ArgumentAcceptance(0)
|
) : ArgumentAcceptance(0)
|
||||||
|
|
||||||
@ -101,7 +101,7 @@ public sealed class ArgumentAcceptance(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ExperimentalCommandDescriptors
|
@ExperimentalCommandDescriptors
|
||||||
public class CommandReceiverParameter<T : CommandSender>(
|
public data class CommandReceiverParameter<T : CommandSender>(
|
||||||
override val isOptional: Boolean,
|
override val isOptional: Boolean,
|
||||||
override val type: KType,
|
override val type: KType,
|
||||||
) : CommandParameter<T>, AbstractCommandParameter<T>() {
|
) : CommandParameter<T>, AbstractCommandParameter<T>() {
|
||||||
|
@ -9,9 +9,7 @@
|
|||||||
|
|
||||||
package net.mamoe.mirai.console.command.resolve
|
package net.mamoe.mirai.console.command.resolve
|
||||||
|
|
||||||
import net.mamoe.mirai.console.command.Command
|
import net.mamoe.mirai.console.command.*
|
||||||
import net.mamoe.mirai.console.command.CommandManager
|
|
||||||
import net.mamoe.mirai.console.command.CommandSender
|
|
||||||
import net.mamoe.mirai.console.command.descriptor.*
|
import net.mamoe.mirai.console.command.descriptor.*
|
||||||
import net.mamoe.mirai.console.command.descriptor.ArgumentAcceptance.Companion.isNotAcceptable
|
import net.mamoe.mirai.console.command.descriptor.ArgumentAcceptance.Companion.isNotAcceptable
|
||||||
import net.mamoe.mirai.console.command.parse.CommandCall
|
import net.mamoe.mirai.console.command.parse.CommandCall
|
||||||
@ -35,13 +33,19 @@ public object BuiltInCommandCallResolver : CommandCallResolver {
|
|||||||
val valueArguments = call.valueArguments
|
val valueArguments = call.valueArguments
|
||||||
val context = callee.safeCast<CommandArgumentContextAware>()?.context
|
val context = callee.safeCast<CommandArgumentContextAware>()?.context
|
||||||
|
|
||||||
val signature = resolveImpl(call.caller, callee, valueArguments, context) ?: return CommandResolveResult(null)
|
val errorSink = ErrorSink()
|
||||||
|
val signature = resolveImpl(call.caller, callee, valueArguments, context, errorSink) ?: kotlin.run {
|
||||||
|
return CommandResolveResult(errorSink.createFailure(call, callee))
|
||||||
|
}
|
||||||
|
|
||||||
return CommandResolveResult(ResolvedCommandCallImpl(call.caller,
|
return CommandResolveResult(
|
||||||
|
ResolvedCommandCallImpl(
|
||||||
|
call.caller,
|
||||||
callee,
|
callee,
|
||||||
signature.signature,
|
signature.signature,
|
||||||
signature.zippedArguments.map { it.second },
|
signature.zippedArguments.map { it.second },
|
||||||
context ?: EmptyCommandArgumentContext)
|
context ?: EmptyCommandArgumentContext
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,17 +63,41 @@ public object BuiltInCommandCallResolver : CommandCallResolver {
|
|||||||
val acceptance: ArgumentAcceptance,
|
val acceptance: ArgumentAcceptance,
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun resolveImpl(
|
private class ErrorSink {
|
||||||
|
private val unmatchedCommandSignatures = mutableListOf<UnmatchedCommandSignature>()
|
||||||
|
private val resolutionAmbiguities = mutableListOf<CommandSignature>()
|
||||||
|
|
||||||
|
fun reportUnmatched(failure: UnmatchedCommandSignature) {
|
||||||
|
unmatchedCommandSignatures.add(failure)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun reportAmbiguity(resolutionAmbiguity: CommandSignature) {
|
||||||
|
resolutionAmbiguities.add(resolutionAmbiguity)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createFailure(call: CommandCall, command: Command): CommandExecuteResult.Failure {
|
||||||
|
val failureReasons = unmatchedCommandSignatures.toMutableList()
|
||||||
|
val rA = FailureReason.ResolutionAmbiguity(resolutionAmbiguities)
|
||||||
|
failureReasons.addAll(resolutionAmbiguities.map { UnmatchedCommandSignature(it, rA) })
|
||||||
|
return CommandExecuteResult.UnmatchedSignature(call.calleeName, command, unmatchedCommandSignatures)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private
|
||||||
|
fun CommandSignature.toResolveData(
|
||||||
caller: CommandSender,
|
caller: CommandSender,
|
||||||
callee: Command,
|
|
||||||
valueArguments: List<CommandValueArgument>,
|
valueArguments: List<CommandValueArgument>,
|
||||||
context: CommandArgumentContext?,
|
context: CommandArgumentContext?,
|
||||||
|
errorSink: ErrorSink,
|
||||||
): ResolveData? {
|
): ResolveData? {
|
||||||
|
val signature = this
|
||||||
callee.overloads
|
val receiverParameter = signature.receiverParameter
|
||||||
.mapNotNull l@{ signature ->
|
if (receiverParameter?.type?.classifierAsKClass()?.isInstance(caller) == false) {
|
||||||
if (signature.receiverParameter?.type?.classifierAsKClass()?.isInstance(caller) == false) {
|
errorSink.reportUnmatched(
|
||||||
return@l null // not compatible receiver
|
UnmatchedCommandSignature(signature, FailureReason.InapplicableReceiverArgument(receiverParameter, caller))
|
||||||
|
)// not compatible receiver
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
val valueParameters = signature.valueParameters
|
val valueParameters = signature.valueParameters
|
||||||
@ -78,9 +106,12 @@ public object BuiltInCommandCallResolver : CommandCallResolver {
|
|||||||
|
|
||||||
val remainingParameters = valueParameters.drop(zipped.size).toMutableList()
|
val remainingParameters = valueParameters.drop(zipped.size).toMutableList()
|
||||||
|
|
||||||
if (remainingParameters.any { !it.isOptional && !it.isVararg }) return@l null // not enough args. // vararg can be empty.
|
if (remainingParameters.any { !it.isOptional && !it.isVararg }) {
|
||||||
|
errorSink.reportUnmatched(UnmatchedCommandSignature(signature, FailureReason.NotEnoughArguments))// not enough args. // vararg can be empty.
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
if (zipped.isEmpty()) {
|
return if (zipped.isEmpty()) {
|
||||||
ResolveData(
|
ResolveData(
|
||||||
signature = signature,
|
signature = signature,
|
||||||
zippedArguments = emptyList(),
|
zippedArguments = emptyList(),
|
||||||
@ -109,7 +140,9 @@ public object BuiltInCommandCallResolver : CommandCallResolver {
|
|||||||
argumentAcceptances = zipped.mapIndexed { index, (parameter, argument) ->
|
argumentAcceptances = zipped.mapIndexed { index, (parameter, argument) ->
|
||||||
val accepting = parameter.accepting(argument, context)
|
val accepting = parameter.accepting(argument, context)
|
||||||
if (accepting.isNotAcceptable) {
|
if (accepting.isNotAcceptable) {
|
||||||
return@l null // argument type not assignable
|
errorSink.reportUnmatched(UnmatchedCommandSignature(signature,
|
||||||
|
FailureReason.InapplicableValueArgument(parameter, argument)))// argument type not assignable
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
ArgumentAcceptanceWithIndex(index, accepting)
|
ArgumentAcceptanceWithIndex(index, accepting)
|
||||||
},
|
},
|
||||||
@ -117,18 +150,34 @@ public object BuiltInCommandCallResolver : CommandCallResolver {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.also { result -> result.singleOrNull()?.let { return it } }
|
|
||||||
|
private fun resolveImpl(
|
||||||
|
caller: CommandSender,
|
||||||
|
callee: Command,
|
||||||
|
valueArguments: List<CommandValueArgument>,
|
||||||
|
context: CommandArgumentContext?,
|
||||||
|
errorSink: ErrorSink,
|
||||||
|
): ResolveData? {
|
||||||
|
|
||||||
|
callee.overloads
|
||||||
|
.mapNotNull l@{ signature ->
|
||||||
|
signature.toResolveData(caller, valueArguments, context, errorSink)
|
||||||
|
}
|
||||||
|
.also { result -> result.takeSingleResolveData()?.let { return it } }
|
||||||
.takeLongestMatches()
|
.takeLongestMatches()
|
||||||
.ifEmpty { return null }
|
.ifEmpty { return null }
|
||||||
.also { result -> result.singleOrNull()?.let { return it } }
|
.also { result -> result.takeSingleResolveData()?.let { return it } }
|
||||||
// take single ArgumentAcceptance.Direct
|
// take single ArgumentAcceptance.Direct
|
||||||
.also { list ->
|
.also { list ->
|
||||||
|
|
||||||
val candidates = list
|
val candidates = list
|
||||||
|
.asSequence().filterIsInstance<ResolveData>()
|
||||||
.flatMap { phase ->
|
.flatMap { phase ->
|
||||||
phase.argumentAcceptances.filter { it.acceptance is ArgumentAcceptance.Direct }.map { phase to it }
|
phase.argumentAcceptances.filter { it.acceptance is ArgumentAcceptance.Direct }.map { phase to it }
|
||||||
}
|
}.toList()
|
||||||
|
|
||||||
candidates.singleOrNull()?.let { return it.first } // single Direct
|
candidates.singleOrNull()?.let { return it.first } // single Direct
|
||||||
|
|
||||||
if (candidates.distinctBy { it.second.index }.size != candidates.size) {
|
if (candidates.distinctBy { it.second.index }.size != candidates.size) {
|
||||||
// Resolution ambiguity
|
// Resolution ambiguity
|
||||||
/*
|
/*
|
||||||
@ -142,13 +191,17 @@ public object BuiltInCommandCallResolver : CommandCallResolver {
|
|||||||
fun foo(a: AA, c: C) = 1
|
fun foo(a: AA, c: C) = 1
|
||||||
*/
|
*/
|
||||||
// The call is foo(AA(), C()) or foo(A(), CC())
|
// The call is foo(AA(), C()) or foo(A(), CC())
|
||||||
return null
|
|
||||||
|
candidates.forEach { candidate -> errorSink.reportAmbiguity(candidate.first.signature) }
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun Collection<Any>.takeSingleResolveData() = asSequence().filterIsInstance<ResolveData>().singleOrNull()
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,9 +40,9 @@ public class CommandResolveResult private constructor(
|
|||||||
callsInPlace(onSuccess, InvocationKind.AT_MOST_ONCE)
|
callsInPlace(onSuccess, InvocationKind.AT_MOST_ONCE)
|
||||||
callsInPlace(onFailure, InvocationKind.AT_MOST_ONCE)
|
callsInPlace(onFailure, InvocationKind.AT_MOST_ONCE)
|
||||||
}
|
}
|
||||||
call?.let(onSuccess)
|
call?.let(onSuccess)?.let { return it }
|
||||||
failure?.let(onFailure)
|
failure?.let(onFailure)?.let { return it }
|
||||||
null!!
|
throw kotlin.AssertionError()
|
||||||
}
|
}
|
||||||
|
|
||||||
public constructor(call: ResolvedCommandCall?) : this(call as Any?)
|
public constructor(call: ResolvedCommandCall?) : this(call as Any?)
|
||||||
|
@ -17,6 +17,7 @@ import net.mamoe.mirai.console.command.*
|
|||||||
import net.mamoe.mirai.console.command.Command.Companion.allNames
|
import net.mamoe.mirai.console.command.Command.Companion.allNames
|
||||||
import net.mamoe.mirai.console.command.CommandManager.INSTANCE.findDuplicate
|
import net.mamoe.mirai.console.command.CommandManager.INSTANCE.findDuplicate
|
||||||
import net.mamoe.mirai.console.command.CommandSender.Companion.toCommandSender
|
import net.mamoe.mirai.console.command.CommandSender.Companion.toCommandSender
|
||||||
|
import net.mamoe.mirai.console.command.descriptor.CommandArgumentParserException
|
||||||
import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors
|
import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors
|
||||||
import net.mamoe.mirai.console.command.parse.CommandCallParser.Companion.parseCommandCall
|
import net.mamoe.mirai.console.command.parse.CommandCallParser.Companion.parseCommandCall
|
||||||
import net.mamoe.mirai.console.command.resolve.CommandCallResolver.Companion.resolve
|
import net.mamoe.mirai.console.command.resolve.CommandCallResolver.Companion.resolve
|
||||||
@ -94,7 +95,9 @@ internal object CommandManagerImpl : CommandManager, CoroutineScope by MiraiCons
|
|||||||
sender.catchExecutionException(result.exception)
|
sender.catchExecutionException(result.exception)
|
||||||
intercept()
|
intercept()
|
||||||
}
|
}
|
||||||
is CommandExecuteResult.UnresolvedCall -> {
|
is CommandExecuteResult.UnmatchedSignature,
|
||||||
|
is CommandExecuteResult.UnresolvedCommand,
|
||||||
|
-> {
|
||||||
// noop
|
// noop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -175,20 +178,25 @@ internal suspend fun executeCommandImpl(
|
|||||||
caller: CommandSender,
|
caller: CommandSender,
|
||||||
checkPermission: Boolean,
|
checkPermission: Boolean,
|
||||||
): CommandExecuteResult {
|
): CommandExecuteResult {
|
||||||
val call = message.asMessageChain().parseCommandCall(caller) ?: return CommandExecuteResult.UnresolvedCall("")
|
val call = message.asMessageChain().parseCommandCall(caller) ?: return CommandExecuteResult.UnresolvedCommand("")
|
||||||
val resolved = call.resolve() ?: return CommandExecuteResult.UnresolvedCall(call.calleeName)
|
val resolved = call.resolve().fold(
|
||||||
|
onSuccess = { it },
|
||||||
|
onFailure = { return it }
|
||||||
|
)
|
||||||
|
|
||||||
val command = resolved.callee
|
val command = resolved.callee
|
||||||
|
|
||||||
if (checkPermission && !command.permission.testPermission(caller)) {
|
if (checkPermission && !command.permission.testPermission(caller)) {
|
||||||
return CommandExecuteResult.PermissionDenied(command, call.calleeName)
|
return CommandExecuteResult.PermissionDenied(command, call, resolved, call.calleeName)
|
||||||
}
|
}
|
||||||
|
|
||||||
return try {
|
return try {
|
||||||
resolved.calleeSignature.call(resolved)
|
resolved.calleeSignature.call(resolved)
|
||||||
CommandExecuteResult.Success(resolved.callee, call.calleeName, EmptyMessageChain)
|
CommandExecuteResult.Success(resolved.callee, call, resolved, call.calleeName, EmptyMessageChain)
|
||||||
|
} catch (e: CommandArgumentParserException) {
|
||||||
|
CommandExecuteResult.IllegalArgument(e, resolved.callee, call, resolved, call.calleeName, EmptyMessageChain)
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
CommandExecuteResult.ExecutionFailed(e, resolved.callee, call.calleeName, EmptyMessageChain)
|
CommandExecuteResult.ExecutionFailed(e, resolved.callee, call, resolved, call.calleeName, EmptyMessageChain)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,11 +12,14 @@ package net.mamoe.mirai.console.terminal
|
|||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import net.mamoe.mirai.console.MiraiConsole
|
import net.mamoe.mirai.console.MiraiConsole
|
||||||
import net.mamoe.mirai.console.command.*
|
import net.mamoe.mirai.console.command.*
|
||||||
|
import net.mamoe.mirai.console.command.CommandExecuteResult.*
|
||||||
|
import net.mamoe.mirai.console.command.CommandExecuteResult.CommandExecuteStatus.*
|
||||||
import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors
|
import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors
|
||||||
import net.mamoe.mirai.console.terminal.noconsole.NoConsole
|
import net.mamoe.mirai.console.terminal.noconsole.NoConsole
|
||||||
import net.mamoe.mirai.console.util.ConsoleInternalApi
|
import net.mamoe.mirai.console.util.ConsoleInternalApi
|
||||||
import net.mamoe.mirai.console.util.requestInput
|
import net.mamoe.mirai.console.util.requestInput
|
||||||
import net.mamoe.mirai.utils.DefaultLogger
|
import net.mamoe.mirai.utils.DefaultLogger
|
||||||
|
import net.mamoe.mirai.utils.warning
|
||||||
import org.jline.reader.EndOfFileException
|
import org.jline.reader.EndOfFileException
|
||||||
import org.jline.reader.UserInterruptException
|
import org.jline.reader.UserInterruptException
|
||||||
|
|
||||||
@ -55,21 +58,28 @@ internal fun startupConsoleThread() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// consoleLogger.debug("INPUT> $next")
|
// consoleLogger.debug("INPUT> $next")
|
||||||
val result = ConsoleCommandSender.executeCommand(next)
|
when (val result = ConsoleCommandSender.executeCommand(next)) {
|
||||||
when (result.status) {
|
is Success -> {
|
||||||
CommandExecuteStatus.SUCCESSFUL -> {
|
|
||||||
}
|
}
|
||||||
CommandExecuteStatus.ILLEGAL_ARGUMENT -> {
|
is IllegalArgument -> {
|
||||||
result.exception?.message?.let { consoleLogger.warning(it) }
|
result.exception.message?.let { consoleLogger.warning(it) } ?: kotlin.run {
|
||||||
|
consoleLogger.warning(result.exception)
|
||||||
}
|
}
|
||||||
CommandExecuteStatus.EXECUTION_EXCEPTION -> {
|
|
||||||
result.exception?.let(consoleLogger::error)
|
|
||||||
}
|
}
|
||||||
CommandExecuteStatus.COMMAND_NOT_FOUND -> {
|
is ExecutionFailed -> {
|
||||||
consoleLogger.warning("未知指令: ${result.commandName}, 输入 ? 获取帮助")
|
consoleLogger.error(result.exception)
|
||||||
}
|
}
|
||||||
CommandExecuteStatus.PERMISSION_DENIED -> {
|
is UnresolvedCommand -> {
|
||||||
consoleLogger.warning("Permission denied.")
|
consoleLogger.warning { "未知指令: ${result.commandName}, 输入 ? 获取帮助" }
|
||||||
|
}
|
||||||
|
is PermissionDenied -> {
|
||||||
|
consoleLogger.warning { "权限不足." }
|
||||||
|
}
|
||||||
|
is UnmatchedSignature -> {
|
||||||
|
consoleLogger.warning { "参数不匹配: " + result.failureReasons.joinToString("\n") { it.render() } }
|
||||||
|
}
|
||||||
|
is Failure -> {
|
||||||
|
consoleLogger.warning { result.toString() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: InterruptedException) {
|
} catch (e: InterruptedException) {
|
||||||
@ -88,3 +98,22 @@ internal fun startupConsoleThread() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalCommandDescriptors::class)
|
||||||
|
internal fun UnmatchedCommandSignature.render(): String {
|
||||||
|
return this.signature.toString() + " ${failureReason.render()}"
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalCommandDescriptors::class)
|
||||||
|
internal fun FailureReason.render(): String {
|
||||||
|
return when (this) {
|
||||||
|
is FailureReason.InapplicableArgument -> "参数类型错误"
|
||||||
|
is FailureReason.TooManyArguments -> "参数过多"
|
||||||
|
is FailureReason.NotEnoughArguments -> "参数不足"
|
||||||
|
is FailureReason.ResolutionAmbiguity -> "调用歧义"
|
||||||
|
is FailureReason.ArgumentLengthMismatch -> {
|
||||||
|
// should not happen, render it anyway.
|
||||||
|
"参数长度不匹配"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user