diff options
author | Edwin Cheng <[email protected]> | 2019-04-17 05:34:43 +0100 |
---|---|---|
committer | Edwin Cheng <[email protected]> | 2019-04-17 05:34:43 +0100 |
commit | 57e4122b890d56c11f9d74c1bdfed40f186331a4 (patch) | |
tree | 5ce7ba4ec6fbf9ce8a25bfe2877abc78dd4e9f45 | |
parent | 546d9be2a7bf7b3942c125f922a01321aea6ad26 (diff) |
Add mbe stmt matcher
-rw-r--r-- | crates/ra_mbe/src/lib.rs | 15 | ||||
-rw-r--r-- | crates/ra_mbe/src/mbe_expander.rs | 4 | ||||
-rw-r--r-- | crates/ra_mbe/src/subtree_parser.rs | 4 | ||||
-rw-r--r-- | crates/ra_mbe/src/tt_cursor.rs | 5 | ||||
-rw-r--r-- | crates/ra_parser/src/grammar.rs | 4 | ||||
-rw-r--r-- | crates/ra_parser/src/grammar/expressions.rs | 154 | ||||
-rw-r--r-- | crates/ra_parser/src/lib.rs | 5 |
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 | ||
68 | pub(crate) fn stmt(p: &mut Parser, with_semi: bool) { | ||
69 | expressions::stmt(p, with_semi) | ||
70 | } | ||
71 | |||
68 | pub(crate) fn reparser( | 72 | pub(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 | ||
51 | pub(crate) fn expr_block_contents(p: &mut Parser) { | 51 | pub(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 | ||
149 | pub(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)] |
158 | struct Restrictions { | 168 | struct 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 | ||
92 | pub 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. |
92 | pub struct Reparser(fn(&mut parser::Parser)); | 97 | pub struct Reparser(fn(&mut parser::Parser)); |
93 | 98 | ||