diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-04-17 06:10:29 +0100 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-04-17 06:10:29 +0100 |
commit | 0e35603069b4f3cee97641204b09d91fd723d01d (patch) | |
tree | 5ce7ba4ec6fbf9ce8a25bfe2877abc78dd4e9f45 /crates/ra_parser/src/grammar/expressions.rs | |
parent | 546d9be2a7bf7b3942c125f922a01321aea6ad26 (diff) | |
parent | 57e4122b890d56c11f9d74c1bdfed40f186331a4 (diff) |
Merge #1157
1157: Add mbe stmt matcher r=matklad a=edwin0cheng
Add `stmt` matcher in `ra_mbe` , and added corresponding `stmt()` parser in `ra_syntax`.
This PR also help PR #1148 for `MarcoKind::Items` parsing.
Note:
* According [the book](https://doc.rust-lang.org/reference/macros-by-example.html), mbe `stmt` matcher will only match statement without the trailing semicolon
* `item` is a valid statement.
Co-authored-by: Edwin Cheng <[email protected]>
Diffstat (limited to 'crates/ra_parser/src/grammar/expressions.rs')
-rw-r--r-- | crates/ra_parser/src/grammar/expressions.rs | 154 |
1 files changed, 82 insertions, 72 deletions
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, |