Skip to content

Commit 222666e

Browse files
authored
docs: add metavariables chapter and refine introduction (#5)
# docs: add metavariables chapter and refine introduction ## Description This PR introduces a new chapter focused on **Metavariables** (fragment specifiers) to the Rust Macros 1.0 section. It also refines the introductory content and simplifies the book's summary structure for a better learning experience. ## Key Changes ### 📖 New Content: Metavariables * **Concept Introduction**: Explained how metavariables allow macros to match complex patterns instead of just literal tokens. * **Deep Dive**: Provided detailed explanations and editable examples for `tt`, `expr`, and `ident`. * **Reference Table**: Added a comprehensive table covering all metavariable types (e.g., `block`, `pat`, `ty`, `vis`) with descriptions and examples. * **Special Metavariables**: Detailed the use of `$crate` for making macros hygiene-friendly. ### ✨ Improvements to Introduction * **Readability**: Refined wording in the "Prerequisites" and "Reading Order" sections. * **Visual Structure**: Used modern markdown callouts (`[!NOTE]`, `[!TIP]`) to highlight key information. * **Updated Learning Path**: Updated the "What You'll Learn" list to align with current tutorial progress. ### 🛠️ Structure & Navigation * **SUMMARY.md**: Registered the new chapter and removed redundant headers to keep the navigation sidebar clean. * **Reference Links**: Updated cross-references to ensure consistent linking between chapters. ## Motivation Metavariables are the fundamental building blocks of Rust declarative macros. This PR fills a critical gap in the tutorial by providing a structured reference and practical examples for how to capture different types of Rust code.
1 parent 5ed00f4 commit 222666e

4 files changed

Lines changed: 119 additions & 21 deletions

File tree

src/SUMMARY.md

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,7 @@
22

33
[Introduction](./introduction.md)
44

5-
# Tutorial
6-
75
- [Macros 1.0: macro_rules!](./macros_1.0.md)
6+
- [Metavariables](./macros_1.0/metavariables.md)
87
- [Macros 2.0]()
98
- [Procedural macros](./procedural_macros.md)
10-
11-
# Reference
12-
13-
- [Macros 1.0 `macro_rules!`]()
14-
- [Macros 2.0]()
15-
- [Procedural macros]()

src/introduction.md

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ Welcome Rustacean! Let's learn about Rust macros.
44

55
## Prerequisites
66

7-
To follow this tutorial, you should have:
7+
To get the most out of this tutorial, we recommend having:
88

9-
- Basic knowledge of Rust (variables, functions, structs, etc.)
10-
- A working Rust project setup (using `cargo`)
11-
- Understanding of Rust's type system and ownership
9+
- **Familiarity with basic Rust syntax** (variables, functions, and structs).
10+
- **A functional Rust development environment** (with `cargo` installed).
11+
- **A solid understanding** of Rust's core concepts, such as the type system and ownership.
1212

1313
If you're new to Rust, consider completing the official [Rust Book](https://doc.rust-lang.org/book/) first.
1414

@@ -36,21 +36,28 @@ Rust has two main kinds of macros:
3636
## What You'll Learn
3737

3838
In this tutorial, you will learn:
39-
- How macros work under the hood
4039
- How to write your own macros
4140
- Best practices for macro safety and maintainability
4241
- Common macro patterns used in the Rust ecosystem
4342

4443
## How to Use This Book
4544

46-
It is recommended to read the "Tutorial" part in order.
45+
This tutorial is designed to be interactive and hands-on. Here's how to get the most out of it:
4746

48-
This book has many runnable and editable code blocks. It is encouraged to run them by clicking the play button <i class="fas fa-play"></i> at the top-right of each code block.
47+
### Reading Order
4948

50-
For example:
49+
For the best learning experience, we recommend reading this tutorial in order. While you are free to explore different sections, macros build on concepts progressively; following the intended sequence will help you understand the material more effectively.
5150

52-
```rust,editable
53-
fn main() {
54-
println!("Hello, world!");
55-
}
56-
```
51+
### Interactive Code Blocks
52+
53+
This book contains many **runnable and editable** Rust code blocks:
54+
55+
- **Runnable**: Click the play button <i class="fas fa-play"></i> at the top-right of any code block to execute it and see the output directly.
56+
- **Editable**: Edit the code directly in the editor, then click the play button to re-run the updated code with your changes.
57+
58+
59+
### Tips for Learning
60+
61+
- Try modifying the examples to understand how macros work
62+
- Use the <i class="fas fa-play"></i> button to verify your changes compile and behave as expected
63+
- Don't hesitate to break things - the tutorial is designed for experimentation

src/macros_1.0/metavariables.md

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# Metavariables
2+
3+
Without metavariables, a rule can only match literal values exactly.
4+
5+
## A First Look at Metavariables
6+
7+
```rust,editable
8+
macro_rules! print{
9+
($x:tt) => { println!("{}", $x); };
10+
}
11+
fn main() {
12+
print!(1);
13+
let v="Hello, world!";
14+
print!(v);
15+
}
16+
```
17+
18+
`$x:tt` is a metavariable named `x` with the type `tt` (token tree).
19+
20+
> [!NOTE]
21+
> You may find that other resources use the term "fragment specifier" to describe metavariable types.
22+
23+
`tt` (Token Tree): Matches a single token or multiple tokens within matching delimiters `()`, `[]`, or `{}`.
24+
25+
While there are many other metavariable types, the `tt` type is the most flexible. You can think of it as a "catch-all" metavariable type.
26+
27+
## Building a DSL Example
28+
29+
```rust,editable
30+
macro_rules! SQL{
31+
// `expr` matches an expression.
32+
(SELECT $e:expr;)=>{
33+
println!("Value: {}", $e);
34+
};
35+
36+
// `ident` matches a single identifier.
37+
(SELECT * FROM $t:ident)=>{
38+
println!("Table: {}", $t);
39+
};
40+
41+
// Catch-all case. This uses repetition, which will be introduced in the next chapter.
42+
($($t:tt)*) => {
43+
print!("Unknown: ");
44+
$(
45+
print!("{} ", stringify!($t));
46+
)*
47+
println!();
48+
};
49+
}
50+
fn main(){
51+
SQL!(SELECT (3+2*4););
52+
let user_table="USER_TABLE";
53+
SQL!(SELECT * FROM user_table);
54+
SQL!(SELECT 1+1 AS total FROM "USER_TABLE" WHERE id > 10);
55+
}
56+
```
57+
58+
> [!TIP]
59+
> Always use the most specific metavariable type possible. For example, if you only need to match a single identifier, use `ident` instead of `tt`.
60+
61+
## The Built-in `$crate` Metavariable
62+
63+
`$crate` is a built-in metavariable that always expands to the name of the crate being compiled.
64+
65+
```rust,editable
66+
mod utils{
67+
pub const message: &'static str="Hello, world!";
68+
}
69+
macro_rules! greet{
70+
() => {
71+
println!("{}!", $crate::utils::message);
72+
};
73+
}
74+
fn main(){
75+
greet!();
76+
}
77+
```
78+
79+
## Metavariable Types
80+
81+
| Type | Description | Example |
82+
| :--- | :--- | :--- |
83+
| `block` | A block expression (code enclosed in braces `{}`). | `{ let x = 5; x }` |
84+
| `expr` | A valid Rust expression. (In Rust 2024, this includes `_` and `const {}`). | `2 + 2`, `f(x)`, `const { 1 + 1 }` |
85+
| `expr_2021` | An expression, but excludes `_` (UnderscoreExpression) and `const {}` (ConstBlockExpression). | `a * b`, `Some(42)` |
86+
| `ident` | An identifier or a keyword. (Excludes `_`, raw identifiers like `r#foo`, and `$crate`). | `count`, `String`, `match` |
87+
| `item` | A Rust item (such as a function, struct, trait, or module). | `fn run() {}`, `struct User { id: u32 }` |
88+
| `lifetime` | A lifetime token. | `'a`, `'static` |
89+
| `literal` | A literal value (optionally prefixed with a minus sign `-`). | `42`, `-10.5`, `"hello"`, `b'a'` |
90+
| `meta` | The contents (the "meta item") found inside an attribute like `#[...]`. | `derive(Debug, Clone)`, `name = "value"` |
91+
| `pat` | A pattern. Since Rust 2021, it allows top-level "or-patterns" (using `\|`). | `Some(x)`, `1..=5`, `_`, `0 \| 1` |
92+
| `pat_param` | A pattern that does **not** allow top-level "or-patterns". | `Some(x)`, `42` |
93+
| `path` | A path (TypePath style). | `std::io`, `self::utils::process` |
94+
| `stmt` | A statement. Usually captures without the trailing semicolon. | `let x = 1`, `drop(y)` |
95+
| `tt` | A **Token Tree**. It can be a single token or tokens inside matching `()`, `[]`, or `{}`. | `!`, `my_var`, `{ 1, 2, 3 }` |
96+
| `ty` | A Rust type. | `i32`, `Vec<String>`, `&'a str` |
97+
| `vis` | A visibility qualifier (this can be empty). | `pub`, `pub(crate)` |

src/macros_1.0_reference.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Macros 1.0 macro_rules!

0 commit comments

Comments
 (0)