We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Macros, FFI and Type-Driven Design step 3 of 28
Classify syntax with macro fragment specifiers
Complete kind_of! so the supplied classify() function labels its macro
inputs correctly. Keep also! and classify() unchanged.
pub fn classify() -> Vec<String>
There are 24 calls: 12 to kind_of!, followed by 12 to also!. The starter's
catch-all makes the first 12 return "tt"; the supplied also! calls already
produce their required results.
Match the requested syntax
Add these rules to kind_of! in order, before the existing catch-all:
lifetime, literal, ident, stmt followed by ;, block, path, ty,
then expr. Each rule returns the string naming its fragment kind.
Input to kind_of! |
Required tag |
|---|---|
'static |
"lifetime" |
42, -7 |
"literal" |
foo, pub |
"ident" |
let z = 1; |
"stmt" |
{ let x = 1; x } |
"block" |
std::vec::Vec |
"path" |
[u8; 4], &str |
"ty" |
1 + 2 |
"expr" |
a b 1 2 |
"tt" |
A single tt matches one token or one delimited group. The existing
$($any:tt)* catch-all repeats that match, so it can accept several tokens.
The supplied tagged macro checks additional cases:
Input to also! |
Required tag |
|---|---|
pat Some(ref x), pat _ |
"pat" |
ty _ |
"ty" |
ident _ |
"no" |
vis pub fn, vis fn |
"vis" |
meta doc = "hi", meta derive(Debug) |
"meta" |
item fn nothing() {} |
"item" |
bare_stmt let z = 1; |
"no" |
expr21 1 + 2 |
"expr21" |
expr21 _ |
"no" |
The result vector preserves the order of all 24 calls in classify().
Captured syntax is classified, not evaluated: foo does not need a value
declaration, and the captured function item is not emitted into the program.
Fragment kinds overlap
The same input can match several kinds. foo can be an identifier, a path,
a type or an expression. The first successful rule determines the tag, so
put ident before the broader alternatives. [u8; 4] and &str are types,
but not paths. _ matches an inferred type or a wildcard pattern, but not
an ident. Keywords such as pub can match ident.
The literal matcher can capture -7, including its minus sign. This is
a macro matching rule; in ordinary expression syntax, negation is a unary
operation. The vis matcher can consume no tokens, which lets one rule
accept both public and private item declarations.
Match the let-statement semicolon explicitly
For let z = 1;, $s:stmt captures the statement without its final ;.
A matcher containing only $s:stmt therefore does not match the whole input.
The kind_of! rule needs $s:stmt ; to match the remaining separator.
This is not universal for every statement: item statements that require a semicolon include it in the captured fragment. Keep the distinction between matching input tokens and emitting an already-parsed statement.
The macro definition's edition matters
In edition 2024, expr also accepts a top-level _ or const { ... }.
expr_2021 excludes those top-level forms. Since edition 2021, pat accepts
top-level alternatives; pat_param excludes them. These choices depend on
the edition of the macro definition, not merely the caller.
Here is a complete example that isolates the expression-edition difference:
macro_rules! expression_kind {
(old $e:expr_2021) => { "old" };
(new $e:expr) => { "new" };
($($other:tt)*) => { "no" };
}
fn main() {
assert_eq!(expression_kind!(old 1 + 2), "old");
assert_eq!(expression_kind!(old _), "no");
assert_eq!(expression_kind!(new _), "new");
assert_eq!(expression_kind!(new const { 3 }), "new");
}
The untagged kind_of! cascade is designed for the supplied calls, not as a
universal Rust syntax classifier. Fragment parsing can produce a diagnostic
instead of falling through to a later rule on malformed input. Leading tags,
as used by also!, let a caller select the intended grammar explicitly.
They do not make malformed fragments valid.
Your solution must compile, preserve the supplied calls, return all tags in order and pass Clippy with warnings treated as errors.
Your code, saved here
Sign in to access your accepted solutions and saved draft history. You can keep reading the lesson without an account.
Sign in to your accountStuck?
Rust reference solution
Sign in to track your attempts toward unlocking the reference solution.