framework
framework copied to clipboard
Argument parsing for required and optional arguments should have a flexible order
The current argument parsing system for commands enforces a strict order of the types of arguments, which proceeds as:
- Required arguments
- Optional arguments
- Variadic argument or
#[rest]argument
Each type of argument may be absent, but violating this order will result in a macro error. What this issue proposes, however, is to break the strict order for required and optional arguments. This would allow for backtracking when parsing arguments for a command.
For example, for the following command:
#[command]
async fn boogie(ctx: FrameworkContext, msg: &Message, user2: Option<UserId>, user: UserId) -> CommandResult {
// ....
}
no error would originate from the macro. Instead, if just one argument is given, user2 will be None, while user will be populated with the argument. And in the case of two arguments, user2 will be the first argument, and user the second argument.
Order between required/optional arguments and a variadic/#[rest] argument will stay the same and will have to be uphold.
Most of the finicky backtracking business can be implemented in declarative macros, which is very nice for code conciseness. In an experimental alternative framework I made such a macro that can so-far parse:
T#[rest] T#[rest] &strOption<T>(greedy)#[lazy] Option<T>(lazy)Vec<T>(greedy)
Where T: serenity::utils::Parse. All of these can be arranged arbitrarily.
It's used like this, which can relatively painlessly be generated by a procedural macro I think
let arg_string = "hello 1 2 3 foo bar";
let (hello, empty, numbers, foo_bar_member) = parse_args!(ctx, msg, arg_string =>
(&str),
#[lazy] (Option<&str>),
(Vec<u32>),
#[rest] (serenity::model::prelude::Member),
).await?