aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_mbe
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_mbe')
-rw-r--r--crates/ra_mbe/src/mbe_expander.rs73
1 files changed, 69 insertions, 4 deletions
diff --git a/crates/ra_mbe/src/mbe_expander.rs b/crates/ra_mbe/src/mbe_expander.rs
index d4ce3bfe3..2dd97b665 100644
--- a/crates/ra_mbe/src/mbe_expander.rs
+++ b/crates/ra_mbe/src/mbe_expander.rs
@@ -85,12 +85,12 @@ impl Bindings {
85 let mut b = self 85 let mut b = self
86 .inner 86 .inner
87 .get(name) 87 .get(name)
88 .ok_or(ExpandError::BindingError(format!("could not find binding {}", name)))?; 88 .ok_or(ExpandError::BindingError(format!("could not find binding `{}`", name)))?;
89 for &idx in nesting.iter() { 89 for &idx in nesting.iter() {
90 b = match b { 90 b = match b {
91 Binding::Simple(_) => break, 91 Binding::Simple(_) => break,
92 Binding::Nested(bs) => bs.get(idx).ok_or(ExpandError::BindingError(format!( 92 Binding::Nested(bs) => bs.get(idx).ok_or(ExpandError::BindingError(format!(
93 "could not find nested binding {}", 93 "could not find nested binding `{}`",
94 name 94 name
95 )))?, 95 )))?,
96 }; 96 };
@@ -98,7 +98,7 @@ impl Bindings {
98 match b { 98 match b {
99 Binding::Simple(it) => Ok(it), 99 Binding::Simple(it) => Ok(it),
100 Binding::Nested(_) => Err(ExpandError::BindingError(format!( 100 Binding::Nested(_) => Err(ExpandError::BindingError(format!(
101 "expected simple binding, found nested binding {}", 101 "expected simple binding, found nested binding `{}`",
102 name 102 name
103 ))), 103 ))),
104 } 104 }
@@ -113,7 +113,7 @@ impl Bindings {
113 Some(Binding::Nested(it)) => it.push(value), 113 Some(Binding::Nested(it)) => it.push(value),
114 _ => { 114 _ => {
115 return Err(ExpandError::BindingError(format!( 115 return Err(ExpandError::BindingError(format!(
116 "nested binding for {} not found", 116 "could not find binding `{}`",
117 key 117 key
118 ))); 118 )));
119 } 119 }
@@ -216,3 +216,68 @@ fn expand_tt(
216 }; 216 };
217 Ok(res) 217 Ok(res)
218} 218}
219
220#[cfg(test)]
221mod tests {
222 use ra_syntax::{ast, AstNode};
223
224 use super::*;
225 use crate::ast_to_token_tree;
226
227 #[test]
228 fn test_expand_rule() {
229 assert_err(
230 "($i:ident) => ($j)",
231 "foo!{a}",
232 ExpandError::BindingError(String::from("could not find binding `j`")),
233 );
234
235 assert_err(
236 "($($i:ident);*) => ($i)",
237 "foo!{a}",
238 ExpandError::BindingError(String::from(
239 "expected simple binding, found nested binding `i`",
240 )),
241 );
242
243 assert_err("($i) => ($i)", "foo!{a}", ExpandError::UnexpectedToken);
244 assert_err("($i:) => ($i)", "foo!{a}", ExpandError::UnexpectedToken);
245 }
246
247 fn assert_err(macro_body: &str, invocation: &str, err: ExpandError) {
248 assert_eq!(expand_first(&create_rules(&format_macro(macro_body)), invocation), Err(err));
249 }
250
251 fn format_macro(macro_body: &str) -> String {
252 format!(
253 "
254 macro_rules! foo {{
255 {}
256 }}
257",
258 macro_body
259 )
260 }
261
262 fn create_rules(macro_definition: &str) -> crate::MacroRules {
263 let source_file = ast::SourceFile::parse(macro_definition);
264 let macro_definition =
265 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
266
267 let (definition_tt, _) = ast_to_token_tree(macro_definition.token_tree().unwrap()).unwrap();
268 crate::MacroRules::parse(&definition_tt).unwrap()
269 }
270
271 fn expand_first(
272 rules: &crate::MacroRules,
273 invocation: &str,
274 ) -> Result<tt::Subtree, ExpandError> {
275 let source_file = ast::SourceFile::parse(invocation);
276 let macro_invocation =
277 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
278
279 let (invocation_tt, _) = ast_to_token_tree(macro_invocation.token_tree().unwrap()).unwrap();
280
281 expand_rule(&rules.rules[0], &invocation_tt)
282 }
283}