diff options
Diffstat (limited to 'crates/ra_mbe/src/lib.rs')
-rw-r--r-- | crates/ra_mbe/src/lib.rs | 50 |
1 files changed, 39 insertions, 11 deletions
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs index 535b7daa0..1a020398e 100644 --- a/crates/ra_mbe/src/lib.rs +++ b/crates/ra_mbe/src/lib.rs | |||
@@ -19,6 +19,7 @@ use crate::{ | |||
19 | #[derive(Debug, PartialEq, Eq)] | 19 | #[derive(Debug, PartialEq, Eq)] |
20 | pub enum ParseError { | 20 | pub enum ParseError { |
21 | Expected(String), | 21 | Expected(String), |
22 | RepetitionEmtpyTokenTree, | ||
22 | } | 23 | } |
23 | 24 | ||
24 | #[derive(Debug, PartialEq, Eq)] | 25 | #[derive(Debug, PartialEq, Eq)] |
@@ -194,20 +195,46 @@ impl Rule { | |||
194 | } | 195 | } |
195 | } | 196 | } |
196 | 197 | ||
198 | fn to_parse_error(e: ExpandError) -> ParseError { | ||
199 | let msg = match e { | ||
200 | ExpandError::InvalidRepeat => "invalid repeat".to_string(), | ||
201 | _ => "invalid macro definition".to_string(), | ||
202 | }; | ||
203 | ParseError::Expected(msg) | ||
204 | } | ||
205 | |||
197 | fn validate(pattern: &tt::Subtree) -> Result<(), ParseError> { | 206 | fn validate(pattern: &tt::Subtree) -> Result<(), ParseError> { |
198 | for op in parse_pattern(pattern) { | 207 | for op in parse_pattern(pattern) { |
199 | let op = match op { | 208 | let op = op.map_err(to_parse_error)?; |
200 | Ok(it) => it, | 209 | |
201 | Err(e) => { | ||
202 | let msg = match e { | ||
203 | ExpandError::InvalidRepeat => "invalid repeat".to_string(), | ||
204 | _ => "invalid macro definition".to_string(), | ||
205 | }; | ||
206 | return Err(ParseError::Expected(msg)); | ||
207 | } | ||
208 | }; | ||
209 | match op { | 210 | match op { |
210 | Op::TokenTree(tt::TokenTree::Subtree(subtree)) | Op::Repeat { subtree, .. } => { | 211 | Op::TokenTree(tt::TokenTree::Subtree(subtree)) => validate(subtree)?, |
212 | Op::Repeat { subtree, separator, .. } => { | ||
213 | // Checks that no repetition which could match an empty token | ||
214 | // https://github.com/rust-lang/rust/blob/a58b1ed44f5e06976de2bdc4d7dc81c36a96934f/src/librustc_expand/mbe/macro_rules.rs#L558 | ||
215 | |||
216 | if separator.is_none() { | ||
217 | if parse_pattern(subtree).all(|child_op| { | ||
218 | match child_op.map_err(to_parse_error) { | ||
219 | Ok(Op::Var { kind, .. }) => { | ||
220 | // vis is optional | ||
221 | if kind.map_or(false, |it| it == "vis") { | ||
222 | return true; | ||
223 | } | ||
224 | } | ||
225 | Ok(Op::Repeat { kind, .. }) => { | ||
226 | return matches!( | ||
227 | kind, | ||
228 | parser::RepeatKind::ZeroOrMore | parser::RepeatKind::ZeroOrOne | ||
229 | ) | ||
230 | } | ||
231 | _ => {} | ||
232 | } | ||
233 | false | ||
234 | }) { | ||
235 | return Err(ParseError::RepetitionEmtpyTokenTree); | ||
236 | } | ||
237 | } | ||
211 | validate(subtree)? | 238 | validate(subtree)? |
212 | } | 239 | } |
213 | _ => (), | 240 | _ => (), |
@@ -216,6 +243,7 @@ fn validate(pattern: &tt::Subtree) -> Result<(), ParseError> { | |||
216 | Ok(()) | 243 | Ok(()) |
217 | } | 244 | } |
218 | 245 | ||
246 | #[derive(Debug)] | ||
219 | pub struct ExpandResult<T>(pub T, pub Option<ExpandError>); | 247 | pub struct ExpandResult<T>(pub T, pub Option<ExpandError>); |
220 | 248 | ||
221 | impl<T> ExpandResult<T> { | 249 | impl<T> ExpandResult<T> { |