Skip to content
This repository has been archived by the owner on May 21, 2024. It is now read-only.

Argument parsing for required and optional arguments should have a flexible order #31

Open
arqunis opened this issue Mar 21, 2021 · 1 comment
Labels
feature request Proposition for a new feature or improvement

Comments

@arqunis
Copy link
Member

arqunis commented Mar 21, 2021

The current argument parsing system for commands enforces a strict order of the types of arguments, which proceeds as:

  1. Required arguments
  2. Optional arguments
  3. 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.

@arqunis arqunis added the feature request Proposition for a new feature or improvement label Mar 21, 2021
@arqunis arqunis mentioned this issue Mar 21, 2021
5 tasks
@kangalio
Copy link
Contributor

kangalio commented Mar 28, 2021

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] &str
  • Option<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?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
feature request Proposition for a new feature or improvement
Projects
None yet
Development

No branches or pull requests

2 participants