aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdwin Cheng <[email protected]>2019-04-17 05:34:43 +0100
committerEdwin Cheng <[email protected]>2019-04-17 05:34:43 +0100
commit57e4122b890d56c11f9d74c1bdfed40f186331a4 (patch)
tree5ce7ba4ec6fbf9ce8a25bfe2877abc78dd4e9f45
parent546d9be2a7bf7b3942c125f922a01321aea6ad26 (diff)
Add mbe stmt matcher
-rw-r--r--crates/ra_mbe/src/lib.rs15
-rw-r--r--crates/ra_mbe/src/mbe_expander.rs4
-rw-r--r--crates/ra_mbe/src/subtree_parser.rs4
-rw-r--r--crates/ra_mbe/src/tt_cursor.rs5
-rw-r--r--crates/ra_parser/src/grammar.rs4
-rw-r--r--crates/ra_parser/src/grammar/expressions.rs154
-rw-r--r--crates/ra_parser/src/lib.rs5
7 files changed, 119 insertions, 72 deletions
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs
index a530f3b03..a1f438906 100644
--- a/crates/ra_mbe/src/lib.rs
+++ b/crates/ra_mbe/src/lib.rs
@@ -582,4 +582,19 @@ SOURCE_FILE@[0; 40)
582 ); 582 );
583 assert_expansion(&rules, "foo! { (a, b) }", "fn foo () {let (a , b) ;}"); 583 assert_expansion(&rules, "foo! { (a, b) }", "fn foo () {let (a , b) ;}");
584 } 584 }
585
586 #[test]
587 fn test_stmt() {
588 let rules = create_rules(
589 r#"
590 macro_rules! foo {
591 ($ i:stmt) => (
592 fn bar() { $ i; }
593 )
594 }
595"#,
596 );
597 assert_expansion(&rules, "foo! { 2 }", "fn bar () {2 ;}");
598 assert_expansion(&rules, "foo! { let a = 0 }", "fn bar () {let a = 0 ;}");
599 }
585} 600}
diff --git a/crates/ra_mbe/src/mbe_expander.rs b/crates/ra_mbe/src/mbe_expander.rs
index 7a259f338..7587b575d 100644
--- a/crates/ra_mbe/src/mbe_expander.rs
+++ b/crates/ra_mbe/src/mbe_expander.rs
@@ -157,6 +157,10 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings,
157 let pat = input.eat_pat().ok_or(ExpandError::UnexpectedToken)?.clone(); 157 let pat = input.eat_pat().ok_or(ExpandError::UnexpectedToken)?.clone();
158 res.inner.insert(text.clone(), Binding::Simple(pat.into())); 158 res.inner.insert(text.clone(), Binding::Simple(pat.into()));
159 } 159 }
160 "stmt" => {
161 let pat = input.eat_stmt().ok_or(ExpandError::UnexpectedToken)?.clone();
162 res.inner.insert(text.clone(), Binding::Simple(pat.into()));
163 }
160 _ => return Err(ExpandError::UnexpectedToken), 164 _ => return Err(ExpandError::UnexpectedToken),
161 } 165 }
162 } 166 }
diff --git a/crates/ra_mbe/src/subtree_parser.rs b/crates/ra_mbe/src/subtree_parser.rs
index 13d5d2169..f075ce245 100644
--- a/crates/ra_mbe/src/subtree_parser.rs
+++ b/crates/ra_mbe/src/subtree_parser.rs
@@ -42,6 +42,10 @@ impl<'a> Parser<'a> {
42 self.parse(ra_parser::parse_pat) 42 self.parse(ra_parser::parse_pat)
43 } 43 }
44 44
45 pub fn parse_stmt(self) -> Option<tt::TokenTree> {
46 self.parse(|src, sink| ra_parser::parse_stmt(src, sink, false))
47 }
48
45 fn parse<F>(self, f: F) -> Option<tt::TokenTree> 49 fn parse<F>(self, f: F) -> Option<tt::TokenTree>
46 where 50 where
47 F: FnOnce(&dyn TokenSource, &mut dyn TreeSink), 51 F: FnOnce(&dyn TokenSource, &mut dyn TreeSink),
diff --git a/crates/ra_mbe/src/tt_cursor.rs b/crates/ra_mbe/src/tt_cursor.rs
index f6cefe087..adfe5520d 100644
--- a/crates/ra_mbe/src/tt_cursor.rs
+++ b/crates/ra_mbe/src/tt_cursor.rs
@@ -99,6 +99,11 @@ impl<'a> TtCursor<'a> {
99 parser.parse_pat() 99 parser.parse_pat()
100 } 100 }
101 101
102 pub(crate) fn eat_stmt(&mut self) -> Option<tt::TokenTree> {
103 let parser = Parser::new(&mut self.pos, self.subtree);
104 parser.parse_stmt()
105 }
106
102 pub(crate) fn expect_char(&mut self, char: char) -> Result<(), ParseError> { 107 pub(crate) fn expect_char(&mut self, char: char) -> Result<(), ParseError> {
103 if self.at_char(char) { 108 if self.at_char(char) {
104 self.bump(); 109 self.bump();
diff --git a/crates/ra_parser/src/grammar.rs b/crates/ra_parser/src/grammar.rs
index 5a7a55141..2c2f785d0 100644
--- a/crates/ra_parser/src/grammar.rs
+++ b/crates/ra_parser/src/grammar.rs
@@ -65,6 +65,10 @@ pub(crate) fn pattern(p: &mut Parser) {
65 patterns::pattern(p) 65 patterns::pattern(p)
66} 66}
67 67
68pub(crate) fn stmt(p: &mut Parser, with_semi: bool) {
69 expressions::stmt(p, with_semi)
70}
71
68pub(crate) fn reparser( 72pub(crate) fn reparser(
69 node: SyntaxKind, 73 node: SyntaxKind,
70 first_child: Option<SyntaxKind>, 74 first_child: Option<SyntaxKind>,
diff --git a/crates/ra_parser/src/grammar/expressions.rs b/crates/ra_parser/src/grammar/expressions.rs
index 295577325..06f2b45b1 100644
--- a/crates/ra_parser/src/grammar/expressions.rs
+++ b/crates/ra_parser/src/grammar/expressions.rs
@@ -48,88 +48,77 @@ fn is_expr_stmt_attr_allowed(kind: SyntaxKind) -> bool {
48 } 48 }
49} 49}
50 50
51pub(crate) fn expr_block_contents(p: &mut Parser) { 51pub(super) fn stmt(p: &mut Parser, with_semi: bool) {
52 // This is checked by a validator 52 // test block_items
53 attributes::inner_attributes(p); 53 // fn a() { fn b() {} }
54 54 let m = p.start();
55 while !p.at(EOF) && !p.at(R_CURLY) { 55 // test attr_on_expr_stmt
56 // test nocontentexpr 56 // fn foo() {
57 // fn foo(){ 57 // #[A] foo();
58 // ;;;some_expr();;;;{;;;};;;;Ok(()) 58 // #[B] bar!{}
59 // } 59 // #[C] #[D] {}
60 if p.current() == SEMI { 60 // #[D] return ();
61 p.bump(); 61 // }
62 continue; 62 let has_attrs = p.at(POUND);
63 } 63 attributes::outer_attributes(p);
64 64
65 // test block_items 65 if p.at(LET_KW) {
66 // fn a() { fn b() {} } 66 let_stmt(p, m, with_semi);
67 let m = p.start(); 67 return;
68 // test attr_on_expr_stmt 68 }
69 // fn foo() {
70 // #[A] foo();
71 // #[B] bar!{}
72 // #[C] #[D] {}
73 // #[D] return ();
74 // }
75 let has_attrs = p.at(POUND);
76 attributes::outer_attributes(p);
77 if p.at(LET_KW) {
78 let_stmt(p, m);
79 continue;
80 }
81 69
82 let m = match items::maybe_item(p, m, items::ItemFlavor::Mod) { 70 let m = match items::maybe_item(p, m, items::ItemFlavor::Mod) {
83 Ok(()) => continue, 71 Ok(()) => return,
84 Err(m) => m, 72 Err(m) => m,
85 }; 73 };
86 74
87 let (cm, blocklike) = expr_stmt(p); 75 let (cm, blocklike) = expr_stmt(p);
88 let kind = cm.as_ref().map(|cm| cm.kind()).unwrap_or(ERROR); 76 let kind = cm.as_ref().map(|cm| cm.kind()).unwrap_or(ERROR);
89 77
90 if has_attrs && !is_expr_stmt_attr_allowed(kind) { 78 if has_attrs && !is_expr_stmt_attr_allowed(kind) {
91 // test_err attr_on_expr_not_allowed 79 // test_err attr_on_expr_not_allowed
92 // fn foo() { 80 // fn foo() {
93 // #[A] 1 + 2; 81 // #[A] 1 + 2;
94 // #[B] if true {}; 82 // #[B] if true {};
95 // } 83 // }
96 p.error(format!("attributes are not allowed on {:?}", kind)); 84 p.error(format!("attributes are not allowed on {:?}", kind));
97 } 85 }
98 86
99 if p.at(R_CURLY) { 87 if p.at(R_CURLY) {
100 // test attr_on_last_expr_in_block 88 // test attr_on_last_expr_in_block
101 // fn foo() { 89 // fn foo() {
102 // { #[A] bar!()? } 90 // { #[A] bar!()? }
103 // #[B] &() 91 // #[B] &()
104 // } 92 // }
105 if let Some(cm) = cm { 93 if let Some(cm) = cm {
106 cm.undo_completion(p).abandon(p); 94 cm.undo_completion(p).abandon(p);
107 m.complete(p, kind); 95 m.complete(p, kind);
108 } else {
109 m.abandon(p);
110 }
111 } else { 96 } else {
112 // test no_semi_after_block 97 m.abandon(p);
113 // fn foo() { 98 }
114 // if true {} 99 } else {
115 // loop {} 100 // test no_semi_after_block
116 // match () {} 101 // fn foo() {
117 // while true {} 102 // if true {}
118 // for _ in () {} 103 // loop {}
119 // {} 104 // match () {}
120 // {} 105 // while true {}
121 // macro_rules! test { 106 // for _ in () {}
122 // () => {} 107 // {}
123 // } 108 // {}
124 // test!{} 109 // macro_rules! test {
125 // } 110 // () => {}
111 // }
112 // test!{}
113 // }
114 if with_semi {
126 if blocklike.is_block() { 115 if blocklike.is_block() {
127 p.eat(SEMI); 116 p.eat(SEMI);
128 } else { 117 } else {
129 p.expect(SEMI); 118 p.expect(SEMI);
130 } 119 }
131 m.complete(p, EXPR_STMT);
132 } 120 }
121 m.complete(p, EXPR_STMT);
133 } 122 }
134 123
135 // test let_stmt; 124 // test let_stmt;
@@ -139,7 +128,7 @@ pub(crate) fn expr_block_contents(p: &mut Parser) {
139 // let c = 92; 128 // let c = 92;
140 // let d: i32 = 92; 129 // let d: i32 = 92;
141 // } 130 // }
142 fn let_stmt(p: &mut Parser, m: Marker) { 131 fn let_stmt(p: &mut Parser, m: Marker, with_semi: bool) {
143 assert!(p.at(LET_KW)); 132 assert!(p.at(LET_KW));
144 p.bump(); 133 p.bump();
145 patterns::pattern(p); 134 patterns::pattern(p);
@@ -149,11 +138,32 @@ pub(crate) fn expr_block_contents(p: &mut Parser) {
149 if p.eat(EQ) { 138 if p.eat(EQ) {
150 expressions::expr(p); 139 expressions::expr(p);
151 } 140 }
152 p.expect(SEMI); 141
142 if with_semi {
143 p.expect(SEMI);
144 }
153 m.complete(p, LET_STMT); 145 m.complete(p, LET_STMT);
154 } 146 }
155} 147}
156 148
149pub(crate) fn expr_block_contents(p: &mut Parser) {
150 // This is checked by a validator
151 attributes::inner_attributes(p);
152
153 while !p.at(EOF) && !p.at(R_CURLY) {
154 // test nocontentexpr
155 // fn foo(){
156 // ;;;some_expr();;;;{;;;};;;;Ok(())
157 // }
158 if p.current() == SEMI {
159 p.bump();
160 continue;
161 }
162
163 stmt(p, true)
164 }
165}
166
157#[derive(Clone, Copy)] 167#[derive(Clone, Copy)]
158struct Restrictions { 168struct Restrictions {
159 forbid_structs: bool, 169 forbid_structs: bool,
diff --git a/crates/ra_parser/src/lib.rs b/crates/ra_parser/src/lib.rs
index 56755c394..9133c1b8a 100644
--- a/crates/ra_parser/src/lib.rs
+++ b/crates/ra_parser/src/lib.rs
@@ -88,6 +88,11 @@ pub fn parse_pat(token_source: &dyn TokenSource, tree_sink: &mut dyn TreeSink) {
88 parse_from_tokens(token_source, tree_sink, grammar::pattern); 88 parse_from_tokens(token_source, tree_sink, grammar::pattern);
89} 89}
90 90
91/// Parse given tokens into the given sink as a statement
92pub fn parse_stmt(token_source: &dyn TokenSource, tree_sink: &mut dyn TreeSink, with_semi: bool) {
93 parse_from_tokens(token_source, tree_sink, |p| grammar::stmt(p, with_semi));
94}
95
91/// A parsing function for a specific braced-block. 96/// A parsing function for a specific braced-block.
92pub struct Reparser(fn(&mut parser::Parser)); 97pub struct Reparser(fn(&mut parser::Parser));
93 98