mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-10 18:40:15 +08:00
Resolution with optional defaults
This commit is contained in:
parent
b3880093bf
commit
a486ceb602
@ -8,9 +8,7 @@ import net.mamoe.mirai.console.command.parse.CommandCall
|
||||
import net.mamoe.mirai.console.command.parse.CommandValueArgument
|
||||
import net.mamoe.mirai.console.extensions.CommandCallResolverProvider
|
||||
import net.mamoe.mirai.console.util.ConsoleExperimentalApi
|
||||
import net.mamoe.mirai.console.util.cast
|
||||
import net.mamoe.mirai.console.util.safeCast
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Builtin implementation of [CommandCallResolver]
|
||||
@ -34,7 +32,10 @@ public object BuiltInCommandCallResolver : CommandCallResolver {
|
||||
private data class ResolveData(
|
||||
val variant: CommandSignatureVariant,
|
||||
val argumentAcceptances: List<ArgumentAcceptanceWithIndex>,
|
||||
)
|
||||
val remainingParameters: List<AbstractCommandValueParameter<*>>,
|
||||
) {
|
||||
val remainingOptionalCount: Int = remainingParameters.count { it.isOptional }
|
||||
}
|
||||
|
||||
private data class ArgumentAcceptanceWithIndex(
|
||||
val index: Int,
|
||||
@ -51,15 +52,21 @@ public object BuiltInCommandCallResolver : CommandCallResolver {
|
||||
.mapNotNull l@{ signature ->
|
||||
val zipped = signature.valueParameters.zip(valueArguments)
|
||||
|
||||
if (signature.valueParameters.drop(zipped.size).any { !it.isOptional }) return@l null // not enough args
|
||||
val remaining = signature.valueParameters.drop(zipped.size)
|
||||
|
||||
ResolveData(signature, zipped.mapIndexed { index, (parameter, argument) ->
|
||||
if (remaining.any { !it.isOptional }) return@l null // not enough args
|
||||
|
||||
ResolveData(
|
||||
variant = signature,
|
||||
argumentAcceptances = zipped.mapIndexed { index, (parameter, argument) ->
|
||||
val accepting = parameter.accepting(argument, context)
|
||||
if (accepting.isNotAcceptable) {
|
||||
return@l null // argument type not assignable
|
||||
}
|
||||
ArgumentAcceptanceWithIndex(index, accepting)
|
||||
})
|
||||
},
|
||||
remainingParameters = remaining
|
||||
)
|
||||
}
|
||||
.also { result -> result.singleOrNull()?.let { return it.variant } }
|
||||
.takeLongestMatches()
|
||||
@ -117,11 +124,13 @@ fun main() {
|
||||
}
|
||||
*/
|
||||
|
||||
private fun List<ResolveData>.takeLongestMatches(): List<ResolveData> {
|
||||
private fun List<ResolveData>.takeLongestMatches(): Collection<ResolveData> {
|
||||
if (isEmpty()) return emptyList()
|
||||
return associateByTo(TreeMap(Comparator.reverseOrder())) { it.variant.valueParameters.size }.let { m ->
|
||||
val firstKey = m.keys.first().cast<Int>()
|
||||
m.filter { it.key == firstKey }.map { it.value.cast() }
|
||||
return associateWith {
|
||||
it.variant.valueParameters.size - it.remainingOptionalCount * 1.001 // slightly lower priority with optional defaults.
|
||||
}.let { m ->
|
||||
val maxMatch = m.values.maxByOrNull { it }
|
||||
m.filter { it.value == maxMatch }.keys
|
||||
}
|
||||
}
|
||||
}
|
@ -164,8 +164,8 @@ internal class TestCommand {
|
||||
@Test
|
||||
fun `composite command descriptors`() {
|
||||
val overloads = TestCompositeCommand.overloads
|
||||
assertEquals("CommandSignatureVariant(seconds: Int = ...)", overloads[0].toString())
|
||||
assertEquals("CommandSignatureVariant(target: Long, seconds: Int)", overloads[1].toString())
|
||||
assertEquals("CommandSignatureVariant(<mute>, seconds: Int = ...)", overloads[0].toString())
|
||||
assertEquals("CommandSignatureVariant(<mute>, target: Long, seconds: Int)", overloads[1].toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -225,6 +225,7 @@ internal class TestCommand {
|
||||
}
|
||||
|
||||
override fun parse(raw: MessageContent, sender: CommandSender): MyClass {
|
||||
if (raw is PlainText) return parse(raw.content, sender)
|
||||
assertSame(image, raw)
|
||||
return MyClass(2)
|
||||
}
|
||||
@ -238,7 +239,7 @@ internal class TestCommand {
|
||||
}
|
||||
|
||||
composite.withRegistration {
|
||||
assertEquals(333, withTesting<MyClass> { execute(sender, "mute 333") }.value)
|
||||
assertEquals(333, withTesting<MyClass> { assertSuccess(execute(sender, "mute 333")) }.value)
|
||||
assertEquals(2, withTesting<MyClass> {
|
||||
assertSuccess(
|
||||
execute(sender, buildMessageChain {
|
||||
|
Loading…
Reference in New Issue
Block a user