diff options
Diffstat (limited to 'crates/ra_mbe')
-rw-r--r-- | crates/ra_mbe/src/lib.rs | 97 | ||||
-rw-r--r-- | crates/ra_mbe/src/mbe_expander.rs | 13 | ||||
-rw-r--r-- | crates/ra_mbe/src/subtree_parser.rs | 12 | ||||
-rw-r--r-- | crates/ra_mbe/src/subtree_source.rs | 14 | ||||
-rw-r--r-- | crates/ra_mbe/src/tt_cursor.rs | 15 |
5 files changed, 148 insertions, 3 deletions
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs index 4126854d1..a530f3b03 100644 --- a/crates/ra_mbe/src/lib.rs +++ b/crates/ra_mbe/src/lib.rs | |||
@@ -189,6 +189,14 @@ impl_froms!(TokenTree: Leaf, Subtree); | |||
189 | rules.expand(&invocation_tt).unwrap() | 189 | rules.expand(&invocation_tt).unwrap() |
190 | } | 190 | } |
191 | 191 | ||
192 | pub(crate) fn expand_to_syntax( | ||
193 | rules: &MacroRules, | ||
194 | invocation: &str, | ||
195 | ) -> ra_syntax::TreeArc<ast::SourceFile> { | ||
196 | let expanded = expand(rules, invocation); | ||
197 | token_tree_to_ast_item_list(&expanded) | ||
198 | } | ||
199 | |||
192 | pub(crate) fn assert_expansion(rules: &MacroRules, invocation: &str, expansion: &str) { | 200 | pub(crate) fn assert_expansion(rules: &MacroRules, invocation: &str, expansion: &str) { |
193 | let expanded = expand(rules, invocation); | 201 | let expanded = expand(rules, invocation); |
194 | assert_eq!(expanded.to_string(), expansion); | 202 | assert_eq!(expanded.to_string(), expansion); |
@@ -485,4 +493,93 @@ SOURCE_FILE@[0; 40) | |||
485 | ); | 493 | ); |
486 | assert_expansion(&rules, "foo! { foo }", "fn foo () {let a = foo :: bar ;}"); | 494 | assert_expansion(&rules, "foo! { foo }", "fn foo () {let a = foo :: bar ;}"); |
487 | } | 495 | } |
496 | |||
497 | #[test] | ||
498 | fn test_expr() { | ||
499 | let rules = create_rules( | ||
500 | r#" | ||
501 | macro_rules! foo { | ||
502 | ($ i:expr) => { | ||
503 | fn bar() { $ i; } | ||
504 | } | ||
505 | } | ||
506 | "#, | ||
507 | ); | ||
508 | |||
509 | assert_expansion( | ||
510 | &rules, | ||
511 | "foo! { 2 + 2 * baz(3).quux() }", | ||
512 | "fn bar () {2 + 2 * baz (3) . quux () ;}", | ||
513 | ); | ||
514 | } | ||
515 | |||
516 | #[test] | ||
517 | fn test_expr_order() { | ||
518 | let rules = create_rules( | ||
519 | r#" | ||
520 | macro_rules! foo { | ||
521 | ($ i:expr) => { | ||
522 | fn bar() { $ i * 2; } | ||
523 | } | ||
524 | } | ||
525 | "#, | ||
526 | ); | ||
527 | |||
528 | assert_eq!( | ||
529 | expand_to_syntax(&rules, "foo! { 1 + 1 }").syntax().debug_dump().trim(), | ||
530 | r#"SOURCE_FILE@[0; 15) | ||
531 | FN_DEF@[0; 15) | ||
532 | FN_KW@[0; 2) "fn" | ||
533 | NAME@[2; 5) | ||
534 | IDENT@[2; 5) "bar" | ||
535 | PARAM_LIST@[5; 7) | ||
536 | L_PAREN@[5; 6) "(" | ||
537 | R_PAREN@[6; 7) ")" | ||
538 | BLOCK@[7; 15) | ||
539 | L_CURLY@[7; 8) "{" | ||
540 | EXPR_STMT@[8; 14) | ||
541 | BIN_EXPR@[8; 13) | ||
542 | BIN_EXPR@[8; 11) | ||
543 | LITERAL@[8; 9) | ||
544 | INT_NUMBER@[8; 9) "1" | ||
545 | PLUS@[9; 10) "+" | ||
546 | LITERAL@[10; 11) | ||
547 | INT_NUMBER@[10; 11) "1" | ||
548 | STAR@[11; 12) "*" | ||
549 | LITERAL@[12; 13) | ||
550 | INT_NUMBER@[12; 13) "2" | ||
551 | SEMI@[13; 14) ";" | ||
552 | R_CURLY@[14; 15) "}""#, | ||
553 | ); | ||
554 | } | ||
555 | |||
556 | #[test] | ||
557 | fn test_ty() { | ||
558 | let rules = create_rules( | ||
559 | r#" | ||
560 | macro_rules! foo { | ||
561 | ($ i:ty) => ( | ||
562 | fn bar() -> $ i { unimplemented!() } | ||
563 | ) | ||
564 | } | ||
565 | "#, | ||
566 | ); | ||
567 | assert_expansion( | ||
568 | &rules, | ||
569 | "foo! { Baz<u8> }", | ||
570 | "fn bar () -> Baz < u8 > {unimplemented ! ()}", | ||
571 | ); | ||
572 | } | ||
573 | |||
574 | #[test] | ||
575 | fn test_pat_() { | ||
576 | let rules = create_rules( | ||
577 | r#" | ||
578 | macro_rules! foo { | ||
579 | ($ i:pat) => { fn foo() { let $ i; } } | ||
580 | } | ||
581 | "#, | ||
582 | ); | ||
583 | assert_expansion(&rules, "foo! { (a, b) }", "fn foo () {let (a , b) ;}"); | ||
584 | } | ||
488 | } | 585 | } |
diff --git a/crates/ra_mbe/src/mbe_expander.rs b/crates/ra_mbe/src/mbe_expander.rs index ce41d7225..7a259f338 100644 --- a/crates/ra_mbe/src/mbe_expander.rs +++ b/crates/ra_mbe/src/mbe_expander.rs | |||
@@ -144,6 +144,19 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings, | |||
144 | input.eat_path().ok_or(ExpandError::UnexpectedToken)?.clone(); | 144 | input.eat_path().ok_or(ExpandError::UnexpectedToken)?.clone(); |
145 | res.inner.insert(text.clone(), Binding::Simple(path.into())); | 145 | res.inner.insert(text.clone(), Binding::Simple(path.into())); |
146 | } | 146 | } |
147 | "expr" => { | ||
148 | let expr = | ||
149 | input.eat_expr().ok_or(ExpandError::UnexpectedToken)?.clone(); | ||
150 | res.inner.insert(text.clone(), Binding::Simple(expr.into())); | ||
151 | } | ||
152 | "ty" => { | ||
153 | let ty = input.eat_ty().ok_or(ExpandError::UnexpectedToken)?.clone(); | ||
154 | res.inner.insert(text.clone(), Binding::Simple(ty.into())); | ||
155 | } | ||
156 | "pat" => { | ||
157 | let pat = input.eat_pat().ok_or(ExpandError::UnexpectedToken)?.clone(); | ||
158 | res.inner.insert(text.clone(), Binding::Simple(pat.into())); | ||
159 | } | ||
147 | _ => return Err(ExpandError::UnexpectedToken), | 160 | _ => return Err(ExpandError::UnexpectedToken), |
148 | } | 161 | } |
149 | } | 162 | } |
diff --git a/crates/ra_mbe/src/subtree_parser.rs b/crates/ra_mbe/src/subtree_parser.rs index 164240d92..13d5d2169 100644 --- a/crates/ra_mbe/src/subtree_parser.rs +++ b/crates/ra_mbe/src/subtree_parser.rs | |||
@@ -30,6 +30,18 @@ impl<'a> Parser<'a> { | |||
30 | self.parse(ra_parser::parse_path) | 30 | self.parse(ra_parser::parse_path) |
31 | } | 31 | } |
32 | 32 | ||
33 | pub fn parse_expr(self) -> Option<tt::TokenTree> { | ||
34 | self.parse(ra_parser::parse_expr) | ||
35 | } | ||
36 | |||
37 | pub fn parse_ty(self) -> Option<tt::TokenTree> { | ||
38 | self.parse(ra_parser::parse_ty) | ||
39 | } | ||
40 | |||
41 | pub fn parse_pat(self) -> Option<tt::TokenTree> { | ||
42 | self.parse(ra_parser::parse_pat) | ||
43 | } | ||
44 | |||
33 | fn parse<F>(self, f: F) -> Option<tt::TokenTree> | 45 | fn parse<F>(self, f: F) -> Option<tt::TokenTree> |
34 | where | 46 | where |
35 | F: FnOnce(&dyn TokenSource, &mut dyn TreeSink), | 47 | F: FnOnce(&dyn TokenSource, &mut dyn TreeSink), |
diff --git a/crates/ra_mbe/src/subtree_source.rs b/crates/ra_mbe/src/subtree_source.rs index 6aa20057e..0a070b46a 100644 --- a/crates/ra_mbe/src/subtree_source.rs +++ b/crates/ra_mbe/src/subtree_source.rs | |||
@@ -109,6 +109,8 @@ impl<'a> SubTreeWalker<'a> { | |||
109 | self.cursor = match self.ts.get(0) { | 109 | self.cursor = match self.ts.get(0) { |
110 | DelimToken::Token(token) => match token { | 110 | DelimToken::Token(token) => match token { |
111 | tt::TokenTree::Subtree(subtree) => { | 111 | tt::TokenTree::Subtree(subtree) => { |
112 | let ts = TokenSeq::from(subtree); | ||
113 | self.stack.push((ts, 0)); | ||
112 | WalkCursor::Token(0, convert_delim(subtree.delimiter, false)) | 114 | WalkCursor::Token(0, convert_delim(subtree.delimiter, false)) |
113 | } | 115 | } |
114 | tt::TokenTree::Leaf(leaf) => { | 116 | tt::TokenTree::Leaf(leaf) => { |
@@ -254,7 +256,7 @@ impl<'a> WalkerOwner<'a> { | |||
254 | } | 256 | } |
255 | } | 257 | } |
256 | } else if walker.stack.len() == 1 { | 258 | } else if walker.stack.len() == 1 { |
257 | if let DelimToken::Delim(_, is_end) = walker.ts.get(*u) { | 259 | if let DelimToken::Delim(_, is_end) = walker.top().get(*u) { |
258 | if !is_end { | 260 | if !is_end { |
259 | let (_, last_idx) = &walker.stack[0]; | 261 | let (_, last_idx) = &walker.stack[0]; |
260 | if let DelimToken::Token(token) = walker.ts.get(*last_idx) { | 262 | if let DelimToken::Token(token) = walker.ts.get(*last_idx) { |
@@ -310,10 +312,16 @@ impl<'a> TokenSource for SubtreeTokenSource<'a> { | |||
310 | } | 312 | } |
311 | } | 313 | } |
312 | fn is_token_joint_to_next(&self, pos: usize) -> bool { | 314 | fn is_token_joint_to_next(&self, pos: usize) -> bool { |
313 | self.walker.get(pos).unwrap().is_joint_to_next | 315 | match self.walker.get(pos) { |
316 | Some(t) => t.is_joint_to_next, | ||
317 | _ => false, | ||
318 | } | ||
314 | } | 319 | } |
315 | fn is_keyword(&self, pos: usize, kw: &str) -> bool { | 320 | fn is_keyword(&self, pos: usize, kw: &str) -> bool { |
316 | self.walker.get(pos).unwrap().text == *kw | 321 | match self.walker.get(pos) { |
322 | Some(t) => t.text == *kw, | ||
323 | _ => false, | ||
324 | } | ||
317 | } | 325 | } |
318 | } | 326 | } |
319 | 327 | ||
diff --git a/crates/ra_mbe/src/tt_cursor.rs b/crates/ra_mbe/src/tt_cursor.rs index d29faa77c..f6cefe087 100644 --- a/crates/ra_mbe/src/tt_cursor.rs +++ b/crates/ra_mbe/src/tt_cursor.rs | |||
@@ -84,6 +84,21 @@ impl<'a> TtCursor<'a> { | |||
84 | parser.parse_path() | 84 | parser.parse_path() |
85 | } | 85 | } |
86 | 86 | ||
87 | pub(crate) fn eat_expr(&mut self) -> Option<tt::TokenTree> { | ||
88 | let parser = Parser::new(&mut self.pos, self.subtree); | ||
89 | parser.parse_expr() | ||
90 | } | ||
91 | |||
92 | pub(crate) fn eat_ty(&mut self) -> Option<tt::TokenTree> { | ||
93 | let parser = Parser::new(&mut self.pos, self.subtree); | ||
94 | parser.parse_ty() | ||
95 | } | ||
96 | |||
97 | pub(crate) fn eat_pat(&mut self) -> Option<tt::TokenTree> { | ||
98 | let parser = Parser::new(&mut self.pos, self.subtree); | ||
99 | parser.parse_pat() | ||
100 | } | ||
101 | |||
87 | pub(crate) fn expect_char(&mut self, char: char) -> Result<(), ParseError> { | 102 | pub(crate) fn expect_char(&mut self, char: char) -> Result<(), ParseError> { |
88 | if self.at_char(char) { | 103 | if self.at_char(char) { |
89 | self.bump(); | 104 | self.bump(); |