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:
bors[bot] 2019-05-03 15:36:19 +00:00
commit 26b4998114
3 changed files with 1409 additions and 1142 deletions

File diff suppressed because it is too large Load diff

View file

@ -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

File diff suppressed because it is too large Load diff