Skip to content

Macros #200

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
bin/*
stage/*
*~
129 changes: 126 additions & 3 deletions examples/staging/macros/repetition/input.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,136 @@ On the pattern side:
* `($($y:ident),*)`: matches a list of `ident`s separated by commas, but also
handles the zero arity case. Examples: `()` and `(foo, bar)`

* Neither of these two patterns will match a list that has a trailing comma. To
allow trailing commas, you can use this pattern: `($($z:expr),+,)`
* `($($z:expr) separator +)`: in general, the `$(...)` is separated from the
`*` or `+` by whitespace and a separator. The whitespace is ignored. The
separator can be any text and many symbols.

* A trailing comma is handled separately from a repetition pattern. This
works: `($($k:expr),+,)`

```rust
#![feature(macro_rules)]

macro_rules! echo {
// Match a series of expressions separated by `,`; return the same
// and convert the result into a string. `stringify!` causes
// evaluation to be skipped.
($($x:expr),+) => { stringify!($($x),+) };
}

macro_rules! echo_space {
// Same. Whitespace is ignored.
($($x:expr) , +) => { stringify!($($x) , +) };
}

macro_rules! echo_vert {
// Split on `|`. `stringify` is important here.
($($x:expr)|+) => { stringify!($($x)|+) };
}

macro_rules! echo_dollar {
// `$` isn't valid. It's a special macro key.
($($x:expr)$+) => { stringify!($($x)$+) };
}

macro_rules! echo_trail {
// Split on `,` with trailing comma.
($($x:expr),+,) => { stringify!($($x),+,) };
}

macro_rules! echo_word {
// Split on `word`. `stringify` is important here.
($($x:expr) word +) => { stringify!($($x) word +) };
}

macro_rules! echo_and {
// Split on `and`. `stringify` is important here.
($($x:expr) and +) => { stringify!($($x) and +) };
}

/*// Block comment these 2 macros
macro_rules! echo_double_comma {
// Error: only allows one symbol between `$(...)` and `+`
($($x:expr),,+) => { stringify!($($x),,+) };
}

macro_rules! echo_double_word {
// Error: only allows one word between `$(...)` and `+`
($($x:expr) two words +) => { stringify!($($x) two words +) };
}
*/

fn main() {
println!("{}", echo!(1u, 2u, 3u, 4u));
// Error: Only a single symbol allowed
//println!("{}", echo_double_comma!(1u,, 2u,, 3u,, 4u));
println!("{}", echo_space!(1u, 2u, 3u, 4u));
println!("{}", echo_vert!(1u | 2u | 3u));
// Error: not valid. Don't split on `$`.
//println!("{}", echo_dollar!(1u $ 2u $ 3u));
println!("{}", echo_trail!(1u, 2u, 3u,));
println!("{}", echo_word!(1u word 2u word 3u));
println!("{}", echo_and!(1u and 2u and 3u));
//Error: Only a single word allowed
//println!("{}", echo_double_word!(1u two words 2u two words 3u));
}
```

On the expansion side:

* `[$($x),+]`: will expand the input arguments (the `$x`s) into an array.
* `[$($x),+]`: will expand the input arguments (the `$x`s) into the given
container. In this case, an array.
Following the previous example: `['a', 'b']` and `[1 + 2, 3 * 4, 5 - 6]`
* `($($x),+)`: expand to a tuple: `('a', 'b')` and `(1 + 2, 3 * 4, 5 - 6)`
* `$($x),+`: expand to a sequence separated by `,` without a container.
* `$($x) and +`: expand to a sequence separated by `and` without a container.

```rust
#![feature(macro_rules)]

macro_rules! echo_and {
// Replace `,` with `and`
($($x:expr),+) => { stringify!($($x) and +) };
}

macro_rules! echo_semicolon {
// Replace `,` with `;`
($($x:expr),+) => { stringify!($($x);+) };
}

macro_rules! echo_vert {
// Replace `,` with `|`
($($x:expr),+) => { stringify!($($x)|+) };
}

// However, remove `stringify!` and they will be evaluated
macro_rules! repeat {
// Each `$x` will evaluate which will strip the `u`.
($($x:expr),+) => { ($($x),+) };
}

macro_rules! repeat_vert {
// `,` split this into a sequence but `|` is bit-or
($($x:expr),+) => { ($($x) | +) };
}

macro_rules! repeat_and {
// `and` makes this `(1 and 2 and 3 and 4)` which doesn't
// evaluate so this errors (`and` isn't an operator).
($($x:expr),+) => { ($($x) and +) };
}

fn main() {
// Evaluates to a number separated by `,`. Each number
// is a single expression which is evaluated. Evaluation
// strips the `u`.
println!("{}", repeat!(1u, 2u, 3u, 4u));
// bit-or evaluates `(1 | 2 | 3 | 4)` to `7`
println!("{}", repeat_vert!(1u, 2u, 3u, 4u));
// Error: `and` is not an operator
//println!("{}", repeat_and!(1u, 2u, 3u, 4u));
}
```

For our example, we'll make a `min!` macro that can take any number of
arguments and will return the smallest one. Under the hood it will use the
Expand Down