diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_mbe/src/mbe_expander.rs | 22 | ||||
-rw-r--r-- | crates/ra_mbe/src/mbe_expander/matcher.rs | 112 |
2 files changed, 76 insertions, 58 deletions
diff --git a/crates/ra_mbe/src/mbe_expander.rs b/crates/ra_mbe/src/mbe_expander.rs index 3c00e3b64..7adb70d45 100644 --- a/crates/ra_mbe/src/mbe_expander.rs +++ b/crates/ra_mbe/src/mbe_expander.rs | |||
@@ -16,10 +16,15 @@ pub(crate) fn expand(rules: &crate::MacroRules, input: &tt::Subtree) -> ExpandRe | |||
16 | 16 | ||
17 | fn expand_rules(rules: &[crate::Rule], input: &tt::Subtree) -> ExpandResult<tt::Subtree> { | 17 | fn expand_rules(rules: &[crate::Rule], input: &tt::Subtree) -> ExpandResult<tt::Subtree> { |
18 | let mut match_: Option<(matcher::Match, &crate::Rule)> = None; | 18 | let mut match_: Option<(matcher::Match, &crate::Rule)> = None; |
19 | let mut err = Some(ExpandError::NoMatchingRule); | ||
20 | for rule in rules { | 19 | for rule in rules { |
21 | let ExpandResult(new_match, bindings_err) = matcher::match_(&rule.lhs, input); | 20 | let new_match = match matcher::match_(&rule.lhs, input) { |
22 | if bindings_err.is_none() { | 21 | Ok(m) => m, |
22 | Err(_e) => { | ||
23 | // error in pattern parsing | ||
24 | continue; | ||
25 | } | ||
26 | }; | ||
27 | if new_match.err.is_none() { | ||
23 | // If we find a rule that applies without errors, we're done. | 28 | // If we find a rule that applies without errors, we're done. |
24 | // Unconditionally returning the transcription here makes the | 29 | // Unconditionally returning the transcription here makes the |
25 | // `test_repeat_bad_var` test fail. | 30 | // `test_repeat_bad_var` test fail. |
@@ -32,25 +37,22 @@ fn expand_rules(rules: &[crate::Rule], input: &tt::Subtree) -> ExpandResult<tt:: | |||
32 | // Use the rule if we matched more tokens, or had fewer patterns left, | 37 | // Use the rule if we matched more tokens, or had fewer patterns left, |
33 | // or had no error | 38 | // or had no error |
34 | if let Some((prev_match, _)) = &match_ { | 39 | if let Some((prev_match, _)) = &match_ { |
35 | if (new_match.unmatched_tokens, new_match.unmatched_patterns) | 40 | if (new_match.unmatched_tts, new_match.err_count) |
36 | < (prev_match.unmatched_tokens, prev_match.unmatched_patterns) | 41 | < (prev_match.unmatched_tts, prev_match.err_count) |
37 | || err.is_some() && bindings_err.is_none() | ||
38 | { | 42 | { |
39 | match_ = Some((new_match, rule)); | 43 | match_ = Some((new_match, rule)); |
40 | err = bindings_err; | ||
41 | } | 44 | } |
42 | } else { | 45 | } else { |
43 | match_ = Some((new_match, rule)); | 46 | match_ = Some((new_match, rule)); |
44 | err = bindings_err; | ||
45 | } | 47 | } |
46 | } | 48 | } |
47 | if let Some((match_, rule)) = match_ { | 49 | if let Some((match_, rule)) = match_ { |
48 | // if we got here, there was no match without errors | 50 | // if we got here, there was no match without errors |
49 | let ExpandResult(result, transcribe_err) = | 51 | let ExpandResult(result, transcribe_err) = |
50 | transcriber::transcribe(&rule.rhs, &match_.bindings); | 52 | transcriber::transcribe(&rule.rhs, &match_.bindings); |
51 | ExpandResult(result, err.or(transcribe_err)) | 53 | ExpandResult(result, match_.err.or(transcribe_err)) |
52 | } else { | 54 | } else { |
53 | ExpandResult(tt::Subtree::default(), err) | 55 | ExpandResult(tt::Subtree::default(), Some(ExpandError::NoMatchingRule)) |
54 | } | 56 | } |
55 | } | 57 | } |
56 | 58 | ||
diff --git a/crates/ra_mbe/src/mbe_expander/matcher.rs b/crates/ra_mbe/src/mbe_expander/matcher.rs index 22fb5d74c..2579382da 100644 --- a/crates/ra_mbe/src/mbe_expander/matcher.rs +++ b/crates/ra_mbe/src/mbe_expander/matcher.rs | |||
@@ -62,24 +62,41 @@ macro_rules! err { | |||
62 | #[derive(Debug, Default)] | 62 | #[derive(Debug, Default)] |
63 | pub(super) struct Match { | 63 | pub(super) struct Match { |
64 | pub bindings: Bindings, | 64 | pub bindings: Bindings, |
65 | pub unmatched_tokens: usize, | 65 | /// We currently just keep the first error and count the rest to compare matches. |
66 | pub unmatched_patterns: usize, | 66 | pub err: Option<ExpandError>, |
67 | pub err_count: usize, | ||
68 | /// How many top-level token trees were left to match. | ||
69 | pub unmatched_tts: usize, | ||
67 | } | 70 | } |
68 | 71 | ||
69 | pub(super) fn match_(pattern: &tt::Subtree, src: &tt::Subtree) -> ExpandResult<Match> { | 72 | impl Match { |
73 | pub fn add_err(&mut self, err: ExpandError) { | ||
74 | let prev_err = self.err.take(); | ||
75 | self.err = prev_err.or(Some(err)); | ||
76 | self.err_count += 1; | ||
77 | } | ||
78 | } | ||
79 | |||
80 | // General note: These functions have two channels to return errors, a `Result` | ||
81 | // return value and the `&mut Match`. The returned Result is for pattern parsing | ||
82 | // errors; if a branch of the macro definition doesn't parse, it doesn't make | ||
83 | // sense to try using it. Matching errors are added to the `Match`. It might | ||
84 | // make sense to make pattern parsing a separate step? | ||
85 | |||
86 | pub(super) fn match_(pattern: &tt::Subtree, src: &tt::Subtree) -> Result<Match, ExpandError> { | ||
70 | assert!(pattern.delimiter == None); | 87 | assert!(pattern.delimiter == None); |
71 | 88 | ||
72 | let mut res = Match::default(); | 89 | let mut res = Match::default(); |
73 | let mut src = TtIter::new(src); | 90 | let mut src = TtIter::new(src); |
74 | 91 | ||
75 | let mut err = match_subtree(&mut res, pattern, &mut src).err(); | 92 | match_subtree(&mut res, pattern, &mut src)?; |
76 | 93 | ||
77 | res.unmatched_tokens += src.len(); | 94 | if src.len() > 0 { |
78 | if src.len() > 0 && err.is_none() { | 95 | res.unmatched_tts += src.len(); |
79 | err = Some(err!("leftover tokens")); | 96 | res.add_err(err!("leftover tokens")); |
80 | } | 97 | } |
81 | 98 | ||
82 | ExpandResult(res, err) | 99 | Ok(res) |
83 | } | 100 | } |
84 | 101 | ||
85 | fn match_subtree( | 102 | fn match_subtree( |
@@ -87,19 +104,13 @@ fn match_subtree( | |||
87 | pattern: &tt::Subtree, | 104 | pattern: &tt::Subtree, |
88 | src: &mut TtIter, | 105 | src: &mut TtIter, |
89 | ) -> Result<(), ExpandError> { | 106 | ) -> Result<(), ExpandError> { |
90 | let mut result = Ok(()); | ||
91 | for op in parse_pattern(pattern) { | 107 | for op in parse_pattern(pattern) { |
92 | if result.is_err() { | ||
93 | // We're just going through the patterns to count how many we missed | ||
94 | res.unmatched_patterns += 1; | ||
95 | continue; | ||
96 | } | ||
97 | match op? { | 108 | match op? { |
98 | Op::TokenTree(tt::TokenTree::Leaf(lhs)) => { | 109 | Op::TokenTree(tt::TokenTree::Leaf(lhs)) => { |
99 | let rhs = match src.expect_leaf() { | 110 | let rhs = match src.expect_leaf() { |
100 | Ok(l) => l, | 111 | Ok(l) => l, |
101 | Err(()) => { | 112 | Err(()) => { |
102 | result = Err(err!("expected leaf: `{}`", lhs)); | 113 | res.add_err(err!("expected leaf: `{}`", lhs)); |
103 | continue; | 114 | continue; |
104 | } | 115 | } |
105 | }; | 116 | }; |
@@ -117,7 +128,7 @@ fn match_subtree( | |||
117 | tt::Leaf::Literal(tt::Literal { text: rhs, .. }), | 128 | tt::Leaf::Literal(tt::Literal { text: rhs, .. }), |
118 | ) if lhs == rhs => (), | 129 | ) if lhs == rhs => (), |
119 | _ => { | 130 | _ => { |
120 | result = Err(ExpandError::UnexpectedToken); | 131 | res.add_err(ExpandError::UnexpectedToken); |
121 | } | 132 | } |
122 | } | 133 | } |
123 | } | 134 | } |
@@ -125,26 +136,25 @@ fn match_subtree( | |||
125 | let rhs = match src.expect_subtree() { | 136 | let rhs = match src.expect_subtree() { |
126 | Ok(s) => s, | 137 | Ok(s) => s, |
127 | Err(()) => { | 138 | Err(()) => { |
128 | result = Err(err!("expected subtree")); | 139 | res.add_err(err!("expected subtree")); |
129 | continue; | 140 | continue; |
130 | } | 141 | } |
131 | }; | 142 | }; |
132 | if lhs.delimiter_kind() != rhs.delimiter_kind() { | 143 | if lhs.delimiter_kind() != rhs.delimiter_kind() { |
133 | result = Err(err!("mismatched delimiter")); | 144 | res.add_err(err!("mismatched delimiter")); |
134 | continue; | 145 | continue; |
135 | } | 146 | } |
136 | let mut src = TtIter::new(rhs); | 147 | let mut src = TtIter::new(rhs); |
137 | result = match_subtree(res, lhs, &mut src); | 148 | match_subtree(res, lhs, &mut src)?; |
138 | res.unmatched_tokens += src.len(); | 149 | if src.len() > 0 { |
139 | if src.len() > 0 && result.is_ok() { | 150 | res.add_err(err!("leftover tokens")); |
140 | result = Err(err!("leftover tokens")); | ||
141 | } | 151 | } |
142 | } | 152 | } |
143 | Op::Var { name, kind } => { | 153 | Op::Var { name, kind } => { |
144 | let kind = match kind { | 154 | let kind = match kind { |
145 | Some(k) => k, | 155 | Some(k) => k, |
146 | None => { | 156 | None => { |
147 | result = Err(ExpandError::UnexpectedToken); | 157 | res.add_err(ExpandError::UnexpectedToken); |
148 | continue; | 158 | continue; |
149 | } | 159 | } |
150 | }; | 160 | }; |
@@ -156,14 +166,16 @@ fn match_subtree( | |||
156 | None if match_err.is_none() => res.bindings.push_optional(name), | 166 | None if match_err.is_none() => res.bindings.push_optional(name), |
157 | _ => {} | 167 | _ => {} |
158 | } | 168 | } |
159 | result = match_err.map_or(Ok(()), Err); | 169 | if let Some(err) = match_err { |
170 | res.add_err(err); | ||
171 | } | ||
160 | } | 172 | } |
161 | Op::Repeat { subtree, kind, separator } => { | 173 | Op::Repeat { subtree, kind, separator } => { |
162 | result = match_repeat(res, subtree, kind, separator, src); | 174 | match_repeat(res, subtree, kind, separator, src)?; |
163 | } | 175 | } |
164 | } | 176 | } |
165 | } | 177 | } |
166 | result | 178 | Ok(()) |
167 | } | 179 | } |
168 | 180 | ||
169 | impl<'a> TtIter<'a> { | 181 | impl<'a> TtIter<'a> { |
@@ -345,35 +357,39 @@ pub(super) fn match_repeat( | |||
345 | } | 357 | } |
346 | 358 | ||
347 | let mut nested = Match::default(); | 359 | let mut nested = Match::default(); |
348 | match match_subtree(&mut nested, pattern, &mut fork) { | 360 | match_subtree(&mut nested, pattern, &mut fork)?; |
349 | Ok(()) => { | 361 | if nested.err.is_none() { |
350 | limit -= 1; | 362 | limit -= 1; |
351 | if limit == 0 { | 363 | if limit == 0 { |
352 | log::warn!( | 364 | log::warn!( |
353 | "match_lhs exceeded repeat pattern limit => {:#?}\n{:#?}\n{:#?}\n{:#?}", | 365 | "match_lhs exceeded repeat pattern limit => {:#?}\n{:#?}\n{:#?}\n{:#?}", |
354 | pattern, | 366 | pattern, |
355 | src, | 367 | src, |
356 | kind, | 368 | kind, |
357 | separator | 369 | separator |
358 | ); | 370 | ); |
359 | break; | 371 | break; |
360 | } | 372 | } |
361 | *src = fork; | 373 | *src = fork; |
362 | 374 | ||
363 | res.bindings.push_nested(counter, nested.bindings)?; | 375 | if let Err(err) = res.bindings.push_nested(counter, nested.bindings) { |
364 | counter += 1; | 376 | res.add_err(err); |
365 | if counter == 1 { | 377 | } |
366 | if let RepeatKind::ZeroOrOne = kind { | 378 | counter += 1; |
367 | break; | 379 | if counter == 1 { |
368 | } | 380 | if let RepeatKind::ZeroOrOne = kind { |
381 | break; | ||
369 | } | 382 | } |
370 | } | 383 | } |
371 | Err(_) => break, | 384 | } else { |
385 | break; | ||
372 | } | 386 | } |
373 | } | 387 | } |
374 | 388 | ||
375 | match (kind, counter) { | 389 | match (kind, counter) { |
376 | (RepeatKind::OneOrMore, 0) => return Err(ExpandError::UnexpectedToken), | 390 | (RepeatKind::OneOrMore, 0) => { |
391 | res.add_err(ExpandError::UnexpectedToken); | ||
392 | } | ||
377 | (_, 0) => { | 393 | (_, 0) => { |
378 | // Collect all empty variables in subtrees | 394 | // Collect all empty variables in subtrees |
379 | let mut vars = Vec::new(); | 395 | let mut vars = Vec::new(); |