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