-
Notifications
You must be signed in to change notification settings - Fork 451
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
Add documentation for meta variable expressions #1485
base: master
Are you sure you want to change the base?
Conversation
src/macros-by-example.md
Outdated
@@ -195,6 +195,220 @@ compiler knows how to expand them properly: | |||
not have the same number. This requirement applies to every layer of nested | |||
repetitions. | |||
|
|||
## Meta variable expressions |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Meta variable" should be "metavariable" for consistency with everything else. Ditto for all other appearances of the phrase.
src/macros-by-example.md
Outdated
@@ -195,6 +195,220 @@ compiler knows how to expand them properly: | |||
not have the same number. This requirement applies to every layer of nested | |||
repetitions. | |||
|
|||
## Meta variable expressions | |||
|
|||
Give access to additional metadata about meta variables that otherwise would be difficult or even impossible to get through elements such as `count` or `index`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
elements such as
count
orindex
.
The wording implies that count
and index
are "elements" through which it would be difficult or impossible to get metadata, but presumably that's not the intention.
src/macros-by-example.md
Outdated
} | ||
``` | ||
|
||
### length(depth) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bikeshedding, but should consider changing the name to "len". Length is abbreviated to "len" everywhere in std; there is only a single, unstable, API that uses "length".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jdahlstrom you may want to bring that up on the implementation PR, currently under FCP proposal rust-lang/rust#122808
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tgross35 Indeed, done!
@c410-f3r Can you update this from the changes in rust-lang/rust#124987? |
a85c9f7
to
327c2f8
Compare
Updated |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added some suggestions for wording that I think is a bit easier to understand. I think this section could really get its own page since "Macros By Example" is already huge, and metavariable expressions will likely have more entries in the future.
Also, most of this md doc is wrapped to 80 chars, probably good to keep that consistent rather than switching wrapping styles
|
||
### count($ident, depth) | ||
|
||
Expands to an unsuffixed integer literal representing the number of times a ***metavariable*** repeats in total. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Expands to an unsuffixed integer literal representing the number of times a ***metavariable*** repeats in total. | |
Expands to an unsuffixed integer literal representing the number of times a | |
***metavariable*** repeats in total. That is, this will be the number of times | |
that a metavariable gets replaced in expanded code. |
I think it is good to clarify what "repeats" means here
@@ -196,6 +196,220 @@ compiler knows how to expand them properly: | |||
not have the same number. This requirement applies to every layer of nested | |||
repetitions. | |||
|
|||
## Metavariable expressions | |||
|
|||
Gives access to additional information about metavariables that otherwise would be difficult or even impossible to obtain manually. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gives access to additional information about metavariables that otherwise would be difficult or even impossible to obtain manually. | |
Metavariable expressions are function-like operators that are used to access "meta" | |
information about how macros get matched and expanded, such as how many items | |
get matched in a repetition group. This information is typically difficult or even | |
impossible to otherwise obtain. | |
Metavariable expressions live within a special braced syntax `${...}`. There are a few | |
different operators available: |
|
||
Gives access to additional information about metavariables that otherwise would be difficult or even impossible to obtain manually. | ||
|
||
### count($ident, depth) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
### count($ident, depth) | |
### `count($ident, depth=0)` |
Indicating the default is probably good
|
||
Expands to an unsuffixed integer literal representing the number of times a ***metavariable*** repeats in total. | ||
|
||
The output of `count` depends on where it is placed as well the provided index. If no index is provided, then it will always start at the innermost level. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The output of `count` depends on where it is placed as well the provided index. If no index is provided, then it will always start at the innermost level. |
I would give a simple example first and mention depth after
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this shouldn't be removed, rather it should be expanded to fully describe the exact algorithm used to determine the result. I assume it's something like this but I don't know the right terms for all the concepts involved (and I only experimented with depth=0
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general, it seems to be something like
- let's say
$ident
occurs under N repetition groups in the matcher - and now we use
${count($ident, D)}
under M repetition groups in the transcriber - then we must have M+D < N
- and we are counting how often the repetition group D up from
$ident
in the matcher occurs inside the current iteration of the M outer repetitions in the transcriber. IOW, for the case where D=0 (IMO the only one we should stabilize for now), we are counting how many times$ident
would expand if we surrounded$ident
in enough repetition groups to make it legal to occur at this point.
macro_rules! no_repetition0 { | ||
( $( $a:ident: $( $b:literal ),* );+ ) => { | ||
[${count($b)}] | ||
}; | ||
} | ||
|
||
macro_rules! no_repetition1 { | ||
( $( $a:ident: $( $b:literal ),* );+ ) => { | ||
[${count($b, 1)}] | ||
}; | ||
} | ||
|
||
macro_rules! outermost { | ||
( $( $a:ident: $( $b:literal ),* );+ ) => { | ||
[$( ${ignore($a)} ${count($b)}, )+] | ||
}; | ||
} | ||
|
||
fn main() { | ||
// 1 2 3 4 5 = 5 elements | ||
assert_eq!(no_repetition0!(a: 1, 2, 3; b: 4, 5), [5]); | ||
|
||
// a b = 2 elements | ||
assert_eq!(no_repetition1!(a: 1, 2, 3; b: 4, 5), [2]); | ||
|
||
// 1 2 3 = 3 elements | ||
// 4 5 = 2 elements | ||
assert_eq!(outermost!(a: 1, 2, 3; b: 4, 5), [3, 2]); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
macro_rules! no_repetition0 { | |
( $( $a:ident: $( $b:literal ),* );+ ) => { | |
[${count($b)}] | |
}; | |
} | |
macro_rules! no_repetition1 { | |
( $( $a:ident: $( $b:literal ),* );+ ) => { | |
[${count($b, 1)}] | |
}; | |
} | |
macro_rules! outermost { | |
( $( $a:ident: $( $b:literal ),* );+ ) => { | |
[$( ${ignore($a)} ${count($b)}, )+] | |
}; | |
} | |
fn main() { | |
// 1 2 3 4 5 = 5 elements | |
assert_eq!(no_repetition0!(a: 1, 2, 3; b: 4, 5), [5]); | |
// a b = 2 elements | |
assert_eq!(no_repetition1!(a: 1, 2, 3; b: 4, 5), [2]); | |
// 1 2 3 = 3 elements | |
// 4 5 = 2 elements | |
assert_eq!(outermost!(a: 1, 2, 3; b: 4, 5), [3, 2]); | |
} | |
macro_rules! count_value { | |
( $( $name:ident: $( $value:literal ),* );+ ) => { | |
// Count the total number of times that the (innermost) group | |
// containing `$value` gets matched. | |
${count($value)} | |
// This is the same as `${count($value, 0)}` | |
}; | |
} | |
macro_rules! count_name1 { | |
( $( $name:ident: $( $value:literal ),* );+ ) => { | |
// This is one way to get the number of times that the group | |
// containing `$name` gets matched. Alternatively... | |
${count($name)} | |
}; | |
} | |
macro_rules! count_name2 { | |
( $( $name:ident: $( $value:literal ),* );+ ) => { | |
// ...`$value` can be used again with a depth specifier of 1, | |
// indicating that repetitions of the 1st parent group of | |
// `$value` should be counted, rather than `$value`'s innermost group. | |
// | |
// `1` is the maximum value here since `$value`'s group has a single | |
// parent. | |
${count($value, 1)} | |
}; | |
} | |
macro_rules! count_value_nested { | |
( $( $name:ident: $( $value:literal ),* );+ ) => { | |
[ $( | |
// using `count` within a repetition group will return the number | |
// of times `$value` is matched _within that group_. | |
${count($value)}, | |
)+ ] | |
}; | |
} | |
fn main() { | |
// all instances of `$value` counted: count(1, 2, 3, 4, 5) = 5 | |
assert_eq!(count_value!(a: 1, 2, 3; b: 4, 5), 5); | |
// count(1, 2, 3, ... 11) = 11 | |
assert_eq!( | |
count_value!(a: 1, 2, 3; b: 4, 5; c: 6, 7; d: 8, 9, 10, 11), | |
11 | |
); | |
// `$value` is never matched; count() = 0 | |
assert_eq!(count_value!(a:), 0); | |
// count(a, b) = 2 matches | |
assert_eq!(count_name1!(a: 1, 2, 3; b: 4, 5), 2); | |
// count(a, b, c, d) = 4 matches | |
assert_eq!( | |
count_name1!(a: 1, 2, 3; b: 4, 5; c: 6, 7; d: 8, 9, 10, 11), | |
4 | |
); | |
// count(a) = 1 match | |
assert_eq!(count_name1!(a:), 1); | |
// These have the same results as the above | |
assert_eq!(count_name2!(a: 1, 2, 3; b: 4, 5), 2); | |
assert_eq!( | |
count_name2!(a: 1, 2, 3; b: 4, 5; c: 6, 7; d: 8, 9, 10, 11), | |
4 | |
); | |
assert_eq!(count_name2!(a:), 1); | |
// first match: count(1, 2, 3) = 3. second match: count(4, 5) = 2. | |
assert_eq!(count_value_nested!(a: 1, 2, 3; b: 4, 5), [3, 2]); | |
// first match: count(1, 2, 3) = 3. second match: count(4, 5) = 2. | |
// third match: count(6, 7) = 4. fourth match: count(8, 9, 10, 11) = 4. | |
assert_eq!( | |
count_value_nested!(a: 1, 2, 3; b: 4, 5; c: 6, 7; d: 8, 9, 10, 11), | |
[3, 2, 2, 4] | |
); | |
// `$value` is never matched; count() = 0 | |
assert_eq!(count_value_nested!(a:), [0]); | |
} |
- Added guiding comments
- Change
$a
and$b
matcher names, which I found confusing since they don't align with thea
andb
identifiers within macro usage blocks. ignore
isn't needed here- Add some more examples
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
using
count
within a repetition group will return the number>
of times$value
is matched within that group.
This is a key part of the spec. It should be in the reference text above, not just in the examples.
} | ||
``` | ||
|
||
Contrary to `count`, `len` must be placed inside a repetition. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Contrary to `count`, `len` must be placed inside a repetition. | |
Unlike `count`, `len` must be placed inside a repetition. |
} | ||
``` | ||
|
||
If repetitions are nested, then the optional depth parameter can be used to limit the number of nested repetitions that are counted. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If repetitions are nested, then the optional depth parameter can be used to limit the number of nested repetitions that are counted. | |
If repetitions are nested, then the optional depth parameter can be used to | |
count the repetitions of a parent repetition group. |
} | ||
``` | ||
|
||
If repetitions are nested, then the optional depth parameter can be used to limit the number of nested repetitions that are counted. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If repetitions are nested, then the optional depth parameter can be used to limit the number of nested repetitions that are counted. | |
If repetitions are nested, then the optional depth parameter can be used to | |
count the repetitions of a parent repetition group. |
|
||
The `ignore` metavariable acts as if the ident was used for the purposes of repetition, but expands to nothing. | ||
|
||
### index(depth) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
### index(depth) | |
### `index(depth=0)` |
} | ||
``` | ||
|
||
### len(depth) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
### len(depth) | |
### `len(depth=0)` |
} | ||
``` | ||
|
||
`count` can not be placed inside the innermost repetition. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be good to have an example of that; I don't know what is meant here.
Is this even about the innermost repetition? In ( $( $name:ident: $( $value:literal ),* );+ )
, can I do $( ${count($name) }
? That is not the innermost repetition, as value
is even-more-inner -- but I am trying to count name
inside a repetition for name
which will always return 1.
Requested in rust-lang/rust#122808