From 0a0a8b408a393586e5f5152825b821c448a8ba89 Mon Sep 17 00:00:00 2001 From: Atliac Date: Sun, 15 Mar 2026 23:53:03 +0800 Subject: [PATCH 1/6] docs(introduction): improve phrasing and readability - Change "In this tutorial, you will learn:" to "Here's what you'll learn" - Simplify bullet point from "used in the Rust ecosystem" to "in the Rust ecosystem" --- src/introduction.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/introduction.md b/src/introduction.md index 980af3e..8cc33ad 100644 --- a/src/introduction.md +++ b/src/introduction.md @@ -35,10 +35,10 @@ Rust has two main kinds of macros: ## What You'll Learn -In this tutorial, you will learn: +Here's what you'll learn in this tutorial: - How to write your own macros - Best practices for macro safety and maintainability -- Common macro patterns used in the Rust ecosystem +- Common macro patterns in the Rust ecosystem ## How to Use This Book From c984b804d0251cf54be567d4bd323915032a3593 Mon Sep 17 00:00:00 2001 From: Atliac Date: Mon, 16 Mar 2026 01:00:22 +0800 Subject: [PATCH 2/6] docs(macros_1.0): add repetitions guide Introduce the repetitions guide in the Macros 1.0 section. Cover optional (?), zero or more (*), and one or more (+) repetitions, along with delimiters and custom delimiter tokens. Update SUMMARY.md to include the new page. --- src/SUMMARY.md | 1 + src/macros_1.0/repetitions.md | 71 +++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 src/macros_1.0/repetitions.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index aaa0edf..8a0d80c 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -4,5 +4,6 @@ - [Macros 1.0: macro_rules!](./macros_1.0.md) - [Metavariables](./macros_1.0/metavariables.md) + - [Repetitions](./macros_1.0/repetitions.md) - [Macros 2.0]() - [Procedural macros](./procedural_macros.md) diff --git a/src/macros_1.0/repetitions.md b/src/macros_1.0/repetitions.md new file mode 100644 index 0000000..dd8d6a6 --- /dev/null +++ b/src/macros_1.0/repetitions.md @@ -0,0 +1,71 @@ +# Repetitions + +We use `$()[delimiter]<*|?|+>` to specify metavariable repetition in both the pattern (matcher) and the expansion (transcriber). + +- `*`: Zero or more times +- `?`: Zero or one time +- `+`: One or more times + +## Optional Repetitions (?) + +```rust,editable +macro_rules! greet{ + ($($msg:literal)?) => { + let msg = concat!("Hello, world! ", $($msg)?); + println!("{}", msg); + } +} + +fn main(){ + greet!(); + greet!("Hello, Rustacean! 👋"); +} +``` + +## Zero or More Repetitions (*) + +```rust,editable +macro_rules! sum{ + ($($n:expr)*) => { + let mut sum=0; + $(sum += $n;)* + println!("The sum is {}", sum); + } +} +fn main(){ + sum!(1 2 3); +} +``` + +## Repetitions with Delimiters + +```rust,editable +macro_rules! sum{ + ($($n:expr),*) => { + let mut sum=0; + $(sum += $n;)* + println!("The sum is {}", sum); + } +} +fn main(){ + sum!(1, 2, 3); +} +``` + +## Custom Delimiter Tokens + +```rust,editable +macro_rules! sum{ + ($($n:literal)add*) => { + let mut sum=0; + $(sum += $n;)* + println!("The sum is {}", sum); + } +} +fn main(){ + sum!(1 add 2 add 3); +} +``` + +> [!TIP] +> The delimiter token can be any token other than a delimiter or one of the repetition operators, but `;` and `,` are the most common. From 32107ca2be96003f2b01dd9dc0ad96fba070a0e5 Mon Sep 17 00:00:00 2001 From: Atliac Date: Mon, 16 Mar 2026 01:29:08 +0800 Subject: [PATCH 3/6] docs(macros_1.0): add documentation for macro scoping Introduce a new section on macro scoping in Macros 1.0, covering textual scope, path-based scope, and the usage of #[macro_export]. --- src/SUMMARY.md | 1 + src/macros_1.0/scoping.md | 81 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 src/macros_1.0/scoping.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 8a0d80c..3560cdb 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -5,5 +5,6 @@ - [Macros 1.0: macro_rules!](./macros_1.0.md) - [Metavariables](./macros_1.0/metavariables.md) - [Repetitions](./macros_1.0/repetitions.md) + - [Scoping](./macros_1.0/scoping.md) - [Macros 2.0]() - [Procedural macros](./procedural_macros.md) diff --git a/src/macros_1.0/scoping.md b/src/macros_1.0/scoping.md new file mode 100644 index 0000000..23e7c33 --- /dev/null +++ b/src/macros_1.0/scoping.md @@ -0,0 +1,81 @@ +# Scoping + +## Textual scope + +```rust,editable +fn main(){ + // m!{}; // Error: macro `m` is not defined in this scope + + // new scope + { + macro_rules! m{ + () => { + println!("Hello, world!"); + } + } + m!{}; // OK + + // shadowing + macro_rules! m{ + () => { + println!("Hello, Rustacean!"); + } + } + m!{}; // OK + } + + // m!{}; // Error: macro `m` is not defined in this scope +} +``` + +> [!TIP] +> Textual scope works similarly to the scope of local variables declared with `let`. + +## Path-based Scope + +```rust,editable +mod mod1{ + macro_rules! m{ + () => { + println!("Hello, world!"); + } + } +} + +mod mod2{ + macro_rules! m{ + () => { + println!("Hello, Rustacean!"); + } + } + pub(crate) use m; // re-export to gain path-based scope +} + +fn main(){ + // mod1::m!{}; // Error: By default, a macro has no path-based scope. + mod2::m!{}; // OK: `m` is re-exported from `mod2`. +} +``` + +## Exporting Macros + +```rust,editable +mod mod_level_1{ + mod mod_level_2{ + // By default, a macro is implicitly `pub(crate)` + // `#[macro_export]` makes it `pub` and export it to the root of the crate. + #[macro_export] + macro_rules! m{ + () => { + println!("Hello, world!"); + } + } + } +} + +fn main(){ + // mod_level_1::m!{}; // Error: `m` is not in scope. + // mod_level_1::mod_level_2::m!{}; // Error: `m` is not in scope. + crate::m!{}; // OK +} +``` From a93c8e7e97a563d700fbce361644a649ac567080 Mon Sep 17 00:00:00 2001 From: Atliac Date: Mon, 16 Mar 2026 01:41:34 +0800 Subject: [PATCH 4/6] docs(macros_2.0): add initial draft of Macros 2.0 chapter Add a new file for Macros 2.0 providing a brief overview and update SUMMARY.md to include the link. --- src/SUMMARY.md | 2 +- src/macros_2.0.md | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 src/macros_2.0.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 3560cdb..1490758 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -6,5 +6,5 @@ - [Metavariables](./macros_1.0/metavariables.md) - [Repetitions](./macros_1.0/repetitions.md) - [Scoping](./macros_1.0/scoping.md) -- [Macros 2.0]() +- [Macros 2.0](./macros_2.0.md) - [Procedural macros](./procedural_macros.md) diff --git a/src/macros_2.0.md b/src/macros_2.0.md new file mode 100644 index 0000000..734656f --- /dev/null +++ b/src/macros_2.0.md @@ -0,0 +1,22 @@ +# Macros 2.0 + +[#39412](https://github.com/rust-lang/rust/issues/39412) + +> [!NOTE] +> Macros 2.0 is a proposal to improve the macros 1.0 (declarative macros `macro_rules!`). It is not yet implemented. + +## Why Macros 2.0? + +Macros 1.0 has several limitations: + +- Lack of hygiene: Macros 1.0 can capture variables from the surrounding scope, which can lead to unexpected behavior. +- Lack of modularity: Macros 1.0 cannot be easily composed or reused. +- Lack of type safety: Macros 1.0 cannot be easily checked for type safety. + +Macros 2.0 aims to address these limitations by providing a more powerful and flexible macro system. + +> [!NOTE] +> We will get it back when it is implemented. + +> [!TIP] +> We actually don't need neither macros 1.0 nor macros 2.0, if we can use procedural macros. From 96f03bdd156dbbd3d62174c820b0cfad34e2b17a Mon Sep 17 00:00:00 2001 From: Atliac Date: Mon, 16 Mar 2026 01:44:18 +0800 Subject: [PATCH 5/6] docs(macros2.0): fix grammatical error in tip Refined the sentence structure in the Macros 2.0 section to use correct negation. --- src/macros_2.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/macros_2.0.md b/src/macros_2.0.md index 734656f..4076b46 100644 --- a/src/macros_2.0.md +++ b/src/macros_2.0.md @@ -19,4 +19,4 @@ Macros 2.0 aims to address these limitations by providing a more powerful and fl > We will get it back when it is implemented. > [!TIP] -> We actually don't need neither macros 1.0 nor macros 2.0, if we can use procedural macros. +> We actually don't need macros 1.0 or macros 2.0, if we can use procedural macros. From b47d04e13b506a85ba2371042d3eb0ce229fa5d0 Mon Sep 17 00:00:00 2001 From: Atliac Date: Mon, 16 Mar 2026 02:15:08 +0800 Subject: [PATCH 6/6] docs(hygiene): add macro hygiene section to macros 1.0 Added a new page detailing macro hygiene concepts, including a code example that demonstrates variable and function resolution scoping. Updated SUMMARY.md to include the new section. --- src/SUMMARY.md | 1 + src/macros_1.0/hygiene.md | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 src/macros_1.0/hygiene.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 1490758..bd3840a 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -6,5 +6,6 @@ - [Metavariables](./macros_1.0/metavariables.md) - [Repetitions](./macros_1.0/repetitions.md) - [Scoping](./macros_1.0/scoping.md) + - [Hygiene](./macros_1.0/hygiene.md) - [Macros 2.0](./macros_2.0.md) - [Procedural macros](./procedural_macros.md) diff --git a/src/macros_1.0/hygiene.md b/src/macros_1.0/hygiene.md new file mode 100644 index 0000000..cf5d956 --- /dev/null +++ b/src/macros_1.0/hygiene.md @@ -0,0 +1,26 @@ +# Hygiene + +```rust,editable + +fn func() { + println!("Hello, world! (from definition site)"); +} + +fn main(){ + let x = 1; + macro_rules! m { + () => { + println!("x = {}", x); // Uses `x` from the definition site. + func(); // Uses `func` from the invocation site. + $crate::func(); // meta-variable `$crate` refers to the crate where the macro is defined. + }; + } + { + let x = 2; + fn func() { + println!("Hello, Rustacean! (from invocation site)"); + } + m!(); + } +} +```