Is is possible to write documentation for individual match cases of an exported macro.
/// This macro does stuff // this works
#[macro_export]
macro_rules! macro{
/// Today it's time for cats // error: no rules expected the token `[`
(cat) => { ... };
/// Today it's time for dogs // error: no rules expected the token `[`
(dog) => { ... };
/// Why not both // error: no rules expected the token `[`
(cats and dogs) => { ... };
}
Is something like this possible or do I have to do it like this:
/// This macro does stuff
/// `(cat)` - Today it's time for cats
/// `(dog)` - Today it's time for dogs
/// `(cats and dogs)` - Why not both
#[macro_export]
macro_rules! macro{
(cat) => { ... };
(dog) => { ... };
(cats and dogs) => { ... };
}
You can't. The only place you can attach documentation to a macro is to the macro as a whole.
Related
We can easily put Doc comments for Dart Class variables e.g.
class SomeClass {
/// Class variable Doc Comment.
var someVariable;
}
How can I do the same for Dart Function parameters e.g. I tried this
void someFunction(
{/// Function parameter documentation
String funParameter="Some Default Value"}
) {
}
But it's not showing anything. If it's not possible please suggest me any alternative.
It is against the Effective Dart conventions to document parameters of functions using a direct syntax like that. Instead, use prose to describe the parameter and how it relates to the function's purpose.
// Instead of this
/// someFunction
/// #funParameter Does something fun
void someFunction({ String funParameter="Some Default Value" }) ...
// Or this
/// someFunction
void someFunction({
/// Does something fun
String funParameter="Some Default Value"
}) ...
// Do this
/// Does something fun with the [funParameter].
void someFunction({ String funParameter="Some Default Value" }) ...
Here's perhaps a more practical example:
/// Takes the values [a] and [b] and returns their sum. Optionally a
/// third parameter [c] can be provided and it will be added to the
/// sum as well.
int add(int a, int b, [int c = 0]) ...
You should use the doc comment like this:
/// the function uses [funParameter] to do stuff
void someFunction({String funParameter = "Some Default Value"}) {
// ..
}
Can I repeat match in a Rust macro? I want to be able to do something like:
my_dsl! {
foo <other tokens>;
bar <other tokens>;
foo <other tokens>;
...
}
Basically, an arbitrary number of semicolon-delimited statement, and each statement is handled by different rules.
I know I can have several foo!(), bar!() macros - each per statement, but ideally I'd like to avoid that.
I was thinking if I can capture something like $($t:tt)*, but excluding semicolon, and then delegate to other macros?
You should read The Little Book of Rust Macros and specifically for your question section 4.2: Incremental TT munchers.
For example:
macro_rules! my_dsl {
() => {};
(foo $name:ident; $($tail:tt)*) => {
{
println!(concat!("foo ", stringify!($name));
my_dsl!($($tail)*);
}
};
(bar $name:ident; $($tail:tt)*) => {
{
println!(concat!("bar ", stringify!($name));
my_dsl!($($tail)*);
}
};
}
I'm working on a procedural macro, and I found that compiler does not give information about proc-macro crates when the procedural macro panics. I tried to override panic! to print a location:
macro_rules! std_panic {
($($args:tt)+) => {{
panic!($($args)*);
}};
}
/// panic! with location reporting.
macro_rules! panic {
($($args:tt)+) => {{
std_panic!("{}\n --> {}:{}:{}", format_args!($($args)*), file!(), line!(), column!());
}};
}
But the compiler fails with
error: recursion limit reached while expanding the macro `std_panic`
--> src/lib.rs:30:9
|
30 | std_panic!("{}\n --> {}:{}:{}", format_args!($($args)*), file!(), line!(), column!());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
54 | _ => unimplemented!("handling tuple struct"),
in this macro invocation
|
= help: consider adding a `#![recursion_limit="131072"]` attribute to your crate
I set the limit to 65536 to prove that this is related to recursive expansion.
According to the macros chapter of The Rust Programming Language, first edition, my own panic! is not visible to std_panic!, so it should use panic! from the standard library.
I also tried
#![feature(no_std)]
#![no_std]
#[macro_use(panic)]
extern crate std;
but it doesn't work.
Yes, you can override a macro from the standard library:
macro_rules! panic {
($($arg:tt),*) => {};
}
fn main() {
panic!("Exit");
println!("Or not...");
}
No, you cannot then call the macro you just shadowed.
Macros are expanded at the site of use. In your example, when you try to use panic!, it expands to std_panic! which in turn expands to panic!. At that point, your own panic! is the one in scope.
This simpler example shows that a macro calls whatever do_foo happens to be in scope where the macro is expanded. Note that there isn't even a do_foo defined where the macro is:
macro_rules! foo {
() => {
do_foo()
};
}
fn main() {
{
fn do_foo() {
println!("1")
}
foo!();
}
{
fn do_foo() {
println!("2")
}
foo!();
}
}
Instead, you will need to refer to the original macro via its complete path (available since Rust 1.30):
macro_rules! panic {
($($args:tt)+) => {{
std::panic!("{}\n --> {}:{}:{}", format_args!($($args)*), file!(), line!(), column!());
}};
}
See also:
How to write a panic! like macro in Rust?
Is it possible to change the whole panic message?
I would like to pass mutability to a macro so that I can do
mymacro![mut foo];
mymacro![bar];
and the macro will see them as different matches. which specifier to use?
There isn't one. You'll need two rules: one which matches a literal mut, and one that doesn't.
macro_rules! do_something {
(mut $name:ident) => { ... };
($name:ident) => { ... };
}
And yes, they do have to be in that order, because macro arms are matched top-to-bottom.
Is it possible to build an enum inside a Rust macro using fields that are defined as macro parameters? I've tried this:
macro_rules! build {
($($case:ty),*) => { enum Test { $($case),* } };
}
fn main() {
build!{ Foo(i32), Bar(i32, i32) };
}
But it fails with error: expected ident, found 'Foo(i32)'
Note that if the fields are defined inside the enum, there is no problem:
macro_rules! build {
($($case:ty),*) => { enum Test { Foo(i32), Bar(i32, i32) } };
}
fn main() {
build!{ Foo(i32), Bar(i32, i32) };
}
It also works if my macro only accepts simple fields:
macro_rules! build {
($($case:ident),*) => { enum Test { $($case),* } };
}
fn main() {
build!{ Foo, Bar };
}
But I've been unable to get it to work in the general case.
It's absolutely possible, but you're conflating totally unrelated concepts.
Something like $case:ty does not mean $case is something which looks like a type, it means $case is literally a type. Enums are not made up of a sequence of types; they're made up of a sequence of variants which are an identifier followed (optionally) by a tuple structure body, a record structure body, or a tag value.
The parser doesn't care if the type you give it happens to coincidentally look like a valid variant, it's simply not expecting a type, and will refuse to parse one in that position.
What you need is to use something like $case:variant. Unfortunately for you, no such matcher exists. The only way to do something like this is to manually parse it using a recursive incremental parser and that is so out of scope of an SO question it's not funny. If you want to learn more, try the chapter on incremental TT munchers in the Little Book of Rust Macros as a starting point.
However, you don't appear to actually do anything with the cases. You're just blindly substituting them. In that case, you can just cheat and not bother with trying to match anything coherent:
macro_rules! build {
($($body:tt)*) => {
as_item! {
enum Test { $($body)* }
}
};
}
macro_rules! as_item {
($i:item) => { $i };
}
fn main() {
build!{ Foo, Bar };
}
(Incidentally, that as_item! thing is explained in the section on AST coercion (a.k.a. "the reparse trick").)
This just grabs everything provided as input to build!, and shoves it into the body of an enum without caring what it looks like.
If you were trying to do something meaningful with the variants, well, you're going to have to be more specific about what you're actually trying to accomplish, as the best advice of how to proceed varies wildly depending on the answer.