mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-15 01:17:27 +00:00
Merge #1228
1228: Add inner macro checker in mbe r=matklad a=edwin0cheng This PR do the following things: * Add an inner macro checker for allowing defining mbe in mbe. (It is a adhoc solution, we could eliminate it after we have a better mbe parser) * Move all tests to an tests modules * Filter empty tree while expanding mbe. This is the final PR extracting from #1219 Co-authored-by: Edwin Cheng <edwin0cheng@gmail.com>
This commit is contained in:
commit
26b4998114
3 changed files with 1409 additions and 1142 deletions
File diff suppressed because it is too large
Load diff
|
@ -84,6 +84,10 @@ enum Binding {
|
|||
}
|
||||
|
||||
impl Bindings {
|
||||
fn contains(&self, name: &SmolStr) -> bool {
|
||||
self.inner.contains_key(name)
|
||||
}
|
||||
|
||||
fn get(&self, name: &SmolStr, nesting: &[usize]) -> Result<&tt::TokenTree, ExpandError> {
|
||||
let mut b = self
|
||||
.inner
|
||||
|
@ -329,6 +333,14 @@ fn expand_subtree(
|
|||
.token_trees
|
||||
.iter()
|
||||
.map(|it| expand_tt(it, ctx))
|
||||
.filter(|it| {
|
||||
// Filter empty subtree
|
||||
if let Ok(tt::TokenTree::Subtree(subtree)) = it {
|
||||
subtree.delimiter != tt::Delimiter::None || !subtree.token_trees.is_empty()
|
||||
} else {
|
||||
true
|
||||
}
|
||||
})
|
||||
.collect::<Result<Vec<_>, ExpandError>>()?;
|
||||
|
||||
Ok(tt::Subtree { token_trees, delimiter: template.delimiter })
|
||||
|
@ -450,6 +462,33 @@ fn expand_tt(
|
|||
// FIXME: Properly handle $crate token
|
||||
tt::Leaf::from(tt::Ident { text: "$crate".into(), id: TokenId::unspecified() })
|
||||
.into()
|
||||
} else if !ctx.bindings.contains(&v.text) {
|
||||
// Note that it is possible to have a `$var` inside a macro which is not bound.
|
||||
// For example:
|
||||
// ```
|
||||
// macro_rules! foo {
|
||||
// ($a:ident, $b:ident, $c:tt) => {
|
||||
// macro_rules! bar {
|
||||
// ($bi:ident) => {
|
||||
// fn $bi() -> u8 {$c}
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// ```
|
||||
// We just treat it a normal tokens
|
||||
tt::Subtree {
|
||||
delimiter: tt::Delimiter::None,
|
||||
token_trees: vec![
|
||||
tt::Leaf::from(tt::Punct { char: '$', spacing: tt::Spacing::Alone })
|
||||
.into(),
|
||||
tt::Leaf::from(tt::Ident {
|
||||
text: v.text.clone(),
|
||||
id: TokenId::unspecified(),
|
||||
})
|
||||
.into(),
|
||||
],
|
||||
}
|
||||
.into()
|
||||
} else {
|
||||
let tkn = ctx.bindings.get(&v.text, &ctx.nesting)?.clone();
|
||||
ctx.var_expanded = true;
|
||||
|
@ -476,11 +515,12 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_expand_rule() {
|
||||
assert_err(
|
||||
"($i:ident) => ($j)",
|
||||
"foo!{a}",
|
||||
ExpandError::BindingError(String::from("could not find binding `j`")),
|
||||
);
|
||||
// FIXME: The missing $var check should be in parsing phase
|
||||
// assert_err(
|
||||
// "($i:ident) => ($j)",
|
||||
// "foo!{a}",
|
||||
// ExpandError::BindingError(String::from("could not find binding `j`")),
|
||||
// );
|
||||
|
||||
assert_err(
|
||||
"($($i:ident);*) => ($i)",
|
||||
|
|
1363
crates/ra_mbe/src/tests.rs
Normal file
1363
crates/ra_mbe/src/tests.rs
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue