diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-03-17 09:41:30 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2020-03-17 09:41:30 +0000 |
commit | 6aa432d86b7e4fb691600032ebdf6f2301152447 (patch) | |
tree | aa012212c11e43a95547f553b5116922631f9896 /crates/ra_mbe | |
parent | cf4ae9aa591729dde25a7df3fa5c22ca0fd94145 (diff) | |
parent | 6c20d7e979b967eb20207414c0a0bf875bbcb98d (diff) |
Merge #3580
3580: More error-resilient MBE expansion r=matklad a=flodiebold
This is the beginning of an attempt to make macro-by-example expansion more resilient, so that we still get an expansion even if no rule exactly matches, with the goal to make completion work better in macro calls.
The general idea is to make everything return `(T, Option<ExpandError>)` instead of `Result<T, ExpandError>`; and then to try each macro arm in turn, and somehow choose the 'best' matching rule if none matches without errors. Finding that 'best' match isn't done yet; I'm currently counting how many tokens were consumed from the args before an error, but it also needs to take into account whether there were further patterns that had nothing to match.
I'll continue this later, but I'm interested whether you think this is the right path, @matklad & @edwin0cheng.
Co-authored-by: Florian Diebold <[email protected]>
Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ra_mbe')
-rw-r--r-- | crates/ra_mbe/src/lib.rs | 32 | ||||
-rw-r--r-- | crates/ra_mbe/src/mbe_expander.rs | 61 | ||||
-rw-r--r-- | crates/ra_mbe/src/mbe_expander/matcher.rs | 212 | ||||
-rw-r--r-- | crates/ra_mbe/src/mbe_expander/transcriber.rs | 69 | ||||
-rw-r--r-- | crates/ra_mbe/src/tests.rs | 4 |
5 files changed, 254 insertions, 124 deletions
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs index 43afe24cc..6a9037bfc 100644 --- a/crates/ra_mbe/src/lib.rs +++ b/crates/ra_mbe/src/lib.rs | |||
@@ -150,7 +150,7 @@ impl MacroRules { | |||
150 | Ok(MacroRules { rules, shift: Shift::new(tt) }) | 150 | Ok(MacroRules { rules, shift: Shift::new(tt) }) |
151 | } | 151 | } |
152 | 152 | ||
153 | pub fn expand(&self, tt: &tt::Subtree) -> Result<tt::Subtree, ExpandError> { | 153 | pub fn expand(&self, tt: &tt::Subtree) -> ExpandResult<tt::Subtree> { |
154 | // apply shift | 154 | // apply shift |
155 | let mut tt = tt.clone(); | 155 | let mut tt = tt.clone(); |
156 | self.shift.shift_all(&mut tt); | 156 | self.shift.shift_all(&mut tt); |
@@ -209,5 +209,35 @@ fn validate(pattern: &tt::Subtree) -> Result<(), ParseError> { | |||
209 | Ok(()) | 209 | Ok(()) |
210 | } | 210 | } |
211 | 211 | ||
212 | pub struct ExpandResult<T>(pub T, pub Option<ExpandError>); | ||
213 | |||
214 | impl<T> ExpandResult<T> { | ||
215 | pub fn ok(t: T) -> ExpandResult<T> { | ||
216 | ExpandResult(t, None) | ||
217 | } | ||
218 | |||
219 | pub fn only_err(err: ExpandError) -> ExpandResult<T> | ||
220 | where | ||
221 | T: Default, | ||
222 | { | ||
223 | ExpandResult(Default::default(), Some(err)) | ||
224 | } | ||
225 | |||
226 | pub fn map<U>(self, f: impl FnOnce(T) -> U) -> ExpandResult<U> { | ||
227 | ExpandResult(f(self.0), self.1) | ||
228 | } | ||
229 | |||
230 | pub fn result(self) -> Result<T, ExpandError> { | ||
231 | self.1.map(Err).unwrap_or(Ok(self.0)) | ||
232 | } | ||
233 | } | ||
234 | |||
235 | impl<T: Default> From<Result<T, ExpandError>> for ExpandResult<T> { | ||
236 | fn from(result: Result<T, ExpandError>) -> ExpandResult<T> { | ||
237 | result | ||
238 | .map_or_else(|e| ExpandResult(Default::default(), Some(e)), |it| ExpandResult(it, None)) | ||
239 | } | ||
240 | } | ||
241 | |||
212 | #[cfg(test)] | 242 | #[cfg(test)] |
213 | mod tests; | 243 | mod tests; |
diff --git a/crates/ra_mbe/src/mbe_expander.rs b/crates/ra_mbe/src/mbe_expander.rs index b455b7321..b1eacf124 100644 --- a/crates/ra_mbe/src/mbe_expander.rs +++ b/crates/ra_mbe/src/mbe_expander.rs | |||
@@ -8,19 +8,51 @@ mod transcriber; | |||
8 | use ra_syntax::SmolStr; | 8 | use ra_syntax::SmolStr; |
9 | use rustc_hash::FxHashMap; | 9 | use rustc_hash::FxHashMap; |
10 | 10 | ||
11 | use crate::ExpandError; | 11 | use crate::{ExpandError, ExpandResult}; |
12 | 12 | ||
13 | pub(crate) fn expand( | 13 | pub(crate) fn expand(rules: &crate::MacroRules, input: &tt::Subtree) -> ExpandResult<tt::Subtree> { |
14 | rules: &crate::MacroRules, | 14 | expand_rules(&rules.rules, input) |
15 | input: &tt::Subtree, | ||
16 | ) -> Result<tt::Subtree, ExpandError> { | ||
17 | rules.rules.iter().find_map(|it| expand_rule(it, input).ok()).ok_or(ExpandError::NoMatchingRule) | ||
18 | } | 15 | } |
19 | 16 | ||
20 | fn expand_rule(rule: &crate::Rule, input: &tt::Subtree) -> Result<tt::Subtree, ExpandError> { | 17 | fn expand_rules(rules: &[crate::Rule], input: &tt::Subtree) -> ExpandResult<tt::Subtree> { |
21 | let bindings = matcher::match_(&rule.lhs, input)?; | 18 | let mut match_: Option<(matcher::Match, &crate::Rule)> = None; |
22 | let res = transcriber::transcribe(&rule.rhs, &bindings)?; | 19 | for rule in rules { |
23 | Ok(res) | 20 | let new_match = match matcher::match_(&rule.lhs, input) { |
21 | Ok(m) => m, | ||
22 | Err(_e) => { | ||
23 | // error in pattern parsing | ||
24 | continue; | ||
25 | } | ||
26 | }; | ||
27 | if new_match.err.is_none() { | ||
28 | // If we find a rule that applies without errors, we're done. | ||
29 | // Unconditionally returning the transcription here makes the | ||
30 | // `test_repeat_bad_var` test fail. | ||
31 | let ExpandResult(res, transcribe_err) = | ||
32 | transcriber::transcribe(&rule.rhs, &new_match.bindings); | ||
33 | if transcribe_err.is_none() { | ||
34 | return ExpandResult::ok(res); | ||
35 | } | ||
36 | } | ||
37 | // Use the rule if we matched more tokens, or had fewer errors | ||
38 | if let Some((prev_match, _)) = &match_ { | ||
39 | if (new_match.unmatched_tts, new_match.err_count) | ||
40 | < (prev_match.unmatched_tts, prev_match.err_count) | ||
41 | { | ||
42 | match_ = Some((new_match, rule)); | ||
43 | } | ||
44 | } else { | ||
45 | match_ = Some((new_match, rule)); | ||
46 | } | ||
47 | } | ||
48 | if let Some((match_, rule)) = match_ { | ||
49 | // if we got here, there was no match without errors | ||
50 | let ExpandResult(result, transcribe_err) = | ||
51 | transcriber::transcribe(&rule.rhs, &match_.bindings); | ||
52 | ExpandResult(result, match_.err.or(transcribe_err)) | ||
53 | } else { | ||
54 | ExpandResult(tt::Subtree::default(), Some(ExpandError::NoMatchingRule)) | ||
55 | } | ||
24 | } | 56 | } |
25 | 57 | ||
26 | /// The actual algorithm for expansion is not too hard, but is pretty tricky. | 58 | /// The actual algorithm for expansion is not too hard, but is pretty tricky. |
@@ -111,7 +143,7 @@ mod tests { | |||
111 | } | 143 | } |
112 | 144 | ||
113 | fn assert_err(macro_body: &str, invocation: &str, err: ExpandError) { | 145 | fn assert_err(macro_body: &str, invocation: &str, err: ExpandError) { |
114 | assert_eq!(expand_first(&create_rules(&format_macro(macro_body)), invocation), Err(err)); | 146 | assert_eq!(expand_first(&create_rules(&format_macro(macro_body)), invocation).1, Some(err)); |
115 | } | 147 | } |
116 | 148 | ||
117 | fn format_macro(macro_body: &str) -> String { | 149 | fn format_macro(macro_body: &str) -> String { |
@@ -135,10 +167,7 @@ mod tests { | |||
135 | crate::MacroRules::parse(&definition_tt).unwrap() | 167 | crate::MacroRules::parse(&definition_tt).unwrap() |
136 | } | 168 | } |
137 | 169 | ||
138 | fn expand_first( | 170 | fn expand_first(rules: &crate::MacroRules, invocation: &str) -> ExpandResult<tt::Subtree> { |
139 | rules: &crate::MacroRules, | ||
140 | invocation: &str, | ||
141 | ) -> Result<tt::Subtree, ExpandError> { | ||
142 | let source_file = ast::SourceFile::parse(invocation).ok().unwrap(); | 171 | let source_file = ast::SourceFile::parse(invocation).ok().unwrap(); |
143 | let macro_invocation = | 172 | let macro_invocation = |
144 | source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); | 173 | source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); |
@@ -146,6 +175,6 @@ mod tests { | |||
146 | let (invocation_tt, _) = | 175 | let (invocation_tt, _) = |
147 | ast_to_token_tree(¯o_invocation.token_tree().unwrap()).unwrap(); | 176 | ast_to_token_tree(¯o_invocation.token_tree().unwrap()).unwrap(); |
148 | 177 | ||
149 | expand_rule(&rules.rules[0], &invocation_tt) | 178 | expand_rules(&rules.rules, &invocation_tt) |
150 | } | 179 | } |
151 | } | 180 | } |
diff --git a/crates/ra_mbe/src/mbe_expander/matcher.rs b/crates/ra_mbe/src/mbe_expander/matcher.rs index 49c53183a..2579382da 100644 --- a/crates/ra_mbe/src/mbe_expander/matcher.rs +++ b/crates/ra_mbe/src/mbe_expander/matcher.rs | |||
@@ -8,6 +8,7 @@ use crate::{ | |||
8 | ExpandError, | 8 | ExpandError, |
9 | }; | 9 | }; |
10 | 10 | ||
11 | use super::ExpandResult; | ||
11 | use ra_parser::{FragmentKind::*, TreeSink}; | 12 | use ra_parser::{FragmentKind::*, TreeSink}; |
12 | use ra_syntax::{SmolStr, SyntaxKind}; | 13 | use ra_syntax::{SmolStr, SyntaxKind}; |
13 | use tt::buffer::{Cursor, TokenBuffer}; | 14 | use tt::buffer::{Cursor, TokenBuffer}; |
@@ -58,36 +59,61 @@ macro_rules! err { | |||
58 | }; | 59 | }; |
59 | } | 60 | } |
60 | 61 | ||
61 | macro_rules! bail { | 62 | #[derive(Debug, Default)] |
62 | ($($tt:tt)*) => { | 63 | pub(super) struct Match { |
63 | return Err(err!($($tt)*)) | 64 | pub bindings: Bindings, |
64 | }; | 65 | /// We currently just keep the first error and count the rest to compare matches. |
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, | ||
65 | } | 70 | } |
66 | 71 | ||
67 | pub(super) fn match_(pattern: &tt::Subtree, src: &tt::Subtree) -> Result<Bindings, ExpandError> { | 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> { | ||
68 | assert!(pattern.delimiter == None); | 87 | assert!(pattern.delimiter == None); |
69 | 88 | ||
70 | let mut res = Bindings::default(); | 89 | let mut res = Match::default(); |
71 | let mut src = TtIter::new(src); | 90 | let mut src = TtIter::new(src); |
72 | 91 | ||
73 | match_subtree(&mut res, pattern, &mut src)?; | 92 | match_subtree(&mut res, pattern, &mut src)?; |
74 | 93 | ||
75 | if src.len() > 0 { | 94 | if src.len() > 0 { |
76 | bail!("leftover tokens"); | 95 | res.unmatched_tts += src.len(); |
96 | res.add_err(err!("leftover tokens")); | ||
77 | } | 97 | } |
78 | 98 | ||
79 | Ok(res) | 99 | Ok(res) |
80 | } | 100 | } |
81 | 101 | ||
82 | fn match_subtree( | 102 | fn match_subtree( |
83 | bindings: &mut Bindings, | 103 | res: &mut Match, |
84 | pattern: &tt::Subtree, | 104 | pattern: &tt::Subtree, |
85 | src: &mut TtIter, | 105 | src: &mut TtIter, |
86 | ) -> Result<(), ExpandError> { | 106 | ) -> Result<(), ExpandError> { |
87 | for op in parse_pattern(pattern) { | 107 | for op in parse_pattern(pattern) { |
88 | match op? { | 108 | match op? { |
89 | Op::TokenTree(tt::TokenTree::Leaf(lhs)) => { | 109 | Op::TokenTree(tt::TokenTree::Leaf(lhs)) => { |
90 | let rhs = src.expect_leaf().map_err(|()| err!("expected leaf: `{}`", lhs))?; | 110 | let rhs = match src.expect_leaf() { |
111 | Ok(l) => l, | ||
112 | Err(()) => { | ||
113 | res.add_err(err!("expected leaf: `{}`", lhs)); | ||
114 | continue; | ||
115 | } | ||
116 | }; | ||
91 | match (lhs, rhs) { | 117 | match (lhs, rhs) { |
92 | ( | 118 | ( |
93 | tt::Leaf::Punct(tt::Punct { char: lhs, .. }), | 119 | tt::Leaf::Punct(tt::Punct { char: lhs, .. }), |
@@ -101,31 +127,51 @@ fn match_subtree( | |||
101 | tt::Leaf::Literal(tt::Literal { text: lhs, .. }), | 127 | tt::Leaf::Literal(tt::Literal { text: lhs, .. }), |
102 | tt::Leaf::Literal(tt::Literal { text: rhs, .. }), | 128 | tt::Leaf::Literal(tt::Literal { text: rhs, .. }), |
103 | ) if lhs == rhs => (), | 129 | ) if lhs == rhs => (), |
104 | _ => return Err(ExpandError::UnexpectedToken), | 130 | _ => { |
131 | res.add_err(ExpandError::UnexpectedToken); | ||
132 | } | ||
105 | } | 133 | } |
106 | } | 134 | } |
107 | Op::TokenTree(tt::TokenTree::Subtree(lhs)) => { | 135 | Op::TokenTree(tt::TokenTree::Subtree(lhs)) => { |
108 | let rhs = src.expect_subtree().map_err(|()| err!("expected subtree"))?; | 136 | let rhs = match src.expect_subtree() { |
137 | Ok(s) => s, | ||
138 | Err(()) => { | ||
139 | res.add_err(err!("expected subtree")); | ||
140 | continue; | ||
141 | } | ||
142 | }; | ||
109 | if lhs.delimiter_kind() != rhs.delimiter_kind() { | 143 | if lhs.delimiter_kind() != rhs.delimiter_kind() { |
110 | bail!("mismatched delimiter") | 144 | res.add_err(err!("mismatched delimiter")); |
145 | continue; | ||
111 | } | 146 | } |
112 | let mut src = TtIter::new(rhs); | 147 | let mut src = TtIter::new(rhs); |
113 | match_subtree(bindings, lhs, &mut src)?; | 148 | match_subtree(res, lhs, &mut src)?; |
114 | if src.len() > 0 { | 149 | if src.len() > 0 { |
115 | bail!("leftover tokens"); | 150 | res.add_err(err!("leftover tokens")); |
116 | } | 151 | } |
117 | } | 152 | } |
118 | Op::Var { name, kind } => { | 153 | Op::Var { name, kind } => { |
119 | let kind = kind.as_ref().ok_or(ExpandError::UnexpectedToken)?; | 154 | let kind = match kind { |
120 | match match_meta_var(kind.as_str(), src)? { | 155 | Some(k) => k, |
156 | None => { | ||
157 | res.add_err(ExpandError::UnexpectedToken); | ||
158 | continue; | ||
159 | } | ||
160 | }; | ||
161 | let ExpandResult(matched, match_err) = match_meta_var(kind.as_str(), src); | ||
162 | match matched { | ||
121 | Some(fragment) => { | 163 | Some(fragment) => { |
122 | bindings.inner.insert(name.clone(), Binding::Fragment(fragment)); | 164 | res.bindings.inner.insert(name.clone(), Binding::Fragment(fragment)); |
123 | } | 165 | } |
124 | None => bindings.push_optional(name), | 166 | None if match_err.is_none() => res.bindings.push_optional(name), |
167 | _ => {} | ||
168 | } | ||
169 | if let Some(err) = match_err { | ||
170 | res.add_err(err); | ||
125 | } | 171 | } |
126 | } | 172 | } |
127 | Op::Repeat { subtree, kind, separator } => { | 173 | Op::Repeat { subtree, kind, separator } => { |
128 | match_repeat(bindings, subtree, kind, separator, src)? | 174 | match_repeat(res, subtree, kind, separator, src)?; |
129 | } | 175 | } |
130 | } | 176 | } |
131 | } | 177 | } |
@@ -221,7 +267,7 @@ impl<'a> TtIter<'a> { | |||
221 | pub(crate) fn expect_fragment( | 267 | pub(crate) fn expect_fragment( |
222 | &mut self, | 268 | &mut self, |
223 | fragment_kind: ra_parser::FragmentKind, | 269 | fragment_kind: ra_parser::FragmentKind, |
224 | ) -> Result<tt::TokenTree, ()> { | 270 | ) -> ExpandResult<Option<tt::TokenTree>> { |
225 | pub(crate) struct OffsetTokenSink<'a> { | 271 | pub(crate) struct OffsetTokenSink<'a> { |
226 | pub(crate) cursor: Cursor<'a>, | 272 | pub(crate) cursor: Cursor<'a>, |
227 | pub(crate) error: bool, | 273 | pub(crate) error: bool, |
@@ -246,45 +292,51 @@ impl<'a> TtIter<'a> { | |||
246 | 292 | ||
247 | ra_parser::parse_fragment(&mut src, &mut sink, fragment_kind); | 293 | ra_parser::parse_fragment(&mut src, &mut sink, fragment_kind); |
248 | 294 | ||
295 | let mut err = None; | ||
249 | if !sink.cursor.is_root() || sink.error { | 296 | if !sink.cursor.is_root() || sink.error { |
250 | // FIXME better recovery in this case would help completion inside macros immensely | 297 | err = Some(err!("expected {:?}", fragment_kind)); |
251 | return Err(()); | ||
252 | } | 298 | } |
253 | 299 | ||
254 | let mut curr = buffer.begin(); | 300 | let mut curr = buffer.begin(); |
255 | let mut res = vec![]; | 301 | let mut res = vec![]; |
256 | 302 | ||
257 | while curr != sink.cursor { | 303 | if sink.cursor.is_root() { |
258 | if let Some(token) = curr.token_tree() { | 304 | while curr != sink.cursor { |
259 | res.push(token); | 305 | if let Some(token) = curr.token_tree() { |
306 | res.push(token); | ||
307 | } | ||
308 | curr = curr.bump(); | ||
260 | } | 309 | } |
261 | curr = curr.bump(); | ||
262 | } | 310 | } |
263 | self.inner = self.inner.as_slice()[res.len()..].iter(); | 311 | self.inner = self.inner.as_slice()[res.len()..].iter(); |
264 | match res.len() { | 312 | if res.len() == 0 && err.is_none() { |
265 | 0 => Err(()), | 313 | err = Some(err!("no tokens consumed")); |
266 | 1 => Ok(res[0].clone()), | 314 | } |
267 | _ => Ok(tt::TokenTree::Subtree(tt::Subtree { | 315 | let res = match res.len() { |
316 | 1 => Some(res[0].clone()), | ||
317 | 0 => None, | ||
318 | _ => Some(tt::TokenTree::Subtree(tt::Subtree { | ||
268 | delimiter: None, | 319 | delimiter: None, |
269 | token_trees: res.into_iter().cloned().collect(), | 320 | token_trees: res.into_iter().cloned().collect(), |
270 | })), | 321 | })), |
271 | } | 322 | }; |
323 | ExpandResult(res, err) | ||
272 | } | 324 | } |
273 | 325 | ||
274 | pub(crate) fn eat_vis(&mut self) -> Option<tt::TokenTree> { | 326 | pub(crate) fn eat_vis(&mut self) -> Option<tt::TokenTree> { |
275 | let mut fork = self.clone(); | 327 | let mut fork = self.clone(); |
276 | match fork.expect_fragment(Visibility) { | 328 | match fork.expect_fragment(Visibility) { |
277 | Ok(tt) => { | 329 | ExpandResult(tt, None) => { |
278 | *self = fork; | 330 | *self = fork; |
279 | Some(tt) | 331 | tt |
280 | } | 332 | } |
281 | Err(()) => None, | 333 | ExpandResult(_, Some(_)) => None, |
282 | } | 334 | } |
283 | } | 335 | } |
284 | } | 336 | } |
285 | 337 | ||
286 | pub(super) fn match_repeat( | 338 | pub(super) fn match_repeat( |
287 | bindings: &mut Bindings, | 339 | res: &mut Match, |
288 | pattern: &tt::Subtree, | 340 | pattern: &tt::Subtree, |
289 | kind: RepeatKind, | 341 | kind: RepeatKind, |
290 | separator: Option<Separator>, | 342 | separator: Option<Separator>, |
@@ -304,36 +356,46 @@ pub(super) fn match_repeat( | |||
304 | } | 356 | } |
305 | } | 357 | } |
306 | 358 | ||
307 | let mut nested = Bindings::default(); | 359 | let mut nested = Match::default(); |
308 | match match_subtree(&mut nested, pattern, &mut fork) { | 360 | match_subtree(&mut nested, pattern, &mut fork)?; |
309 | Ok(()) => { | 361 | if nested.err.is_none() { |
310 | limit -= 1; | 362 | limit -= 1; |
311 | if limit == 0 { | 363 | if limit == 0 { |
312 | log::warn!("match_lhs excced in repeat pattern exceed limit => {:#?}\n{:#?}\n{:#?}\n{:#?}", pattern, src, kind, separator); | 364 | log::warn!( |
313 | break; | 365 | "match_lhs exceeded repeat pattern limit => {:#?}\n{:#?}\n{:#?}\n{:#?}", |
314 | } | 366 | pattern, |
315 | *src = fork; | 367 | src, |
368 | kind, | ||
369 | separator | ||
370 | ); | ||
371 | break; | ||
372 | } | ||
373 | *src = fork; | ||
316 | 374 | ||
317 | bindings.push_nested(counter, nested)?; | 375 | if let Err(err) = res.bindings.push_nested(counter, nested.bindings) { |
318 | counter += 1; | 376 | res.add_err(err); |
319 | if counter == 1 { | 377 | } |
320 | if let RepeatKind::ZeroOrOne = kind { | 378 | counter += 1; |
321 | break; | 379 | if counter == 1 { |
322 | } | 380 | if let RepeatKind::ZeroOrOne = kind { |
381 | break; | ||
323 | } | 382 | } |
324 | } | 383 | } |
325 | Err(_) => break, | 384 | } else { |
385 | break; | ||
326 | } | 386 | } |
327 | } | 387 | } |
328 | 388 | ||
329 | match (kind, counter) { | 389 | match (kind, counter) { |
330 | (RepeatKind::OneOrMore, 0) => return Err(ExpandError::UnexpectedToken), | 390 | (RepeatKind::OneOrMore, 0) => { |
391 | res.add_err(ExpandError::UnexpectedToken); | ||
392 | } | ||
331 | (_, 0) => { | 393 | (_, 0) => { |
332 | // Collect all empty variables in subtrees | 394 | // Collect all empty variables in subtrees |
333 | let mut vars = Vec::new(); | 395 | let mut vars = Vec::new(); |
334 | collect_vars(&mut vars, pattern)?; | 396 | collect_vars(&mut vars, pattern)?; |
335 | for var in vars { | 397 | for var in vars { |
336 | bindings.push_empty(&var) | 398 | res.bindings.push_empty(&var) |
337 | } | 399 | } |
338 | } | 400 | } |
339 | _ => (), | 401 | _ => (), |
@@ -341,7 +403,7 @@ pub(super) fn match_repeat( | |||
341 | Ok(()) | 403 | Ok(()) |
342 | } | 404 | } |
343 | 405 | ||
344 | fn match_meta_var(kind: &str, input: &mut TtIter) -> Result<Option<Fragment>, ExpandError> { | 406 | fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult<Option<Fragment>> { |
345 | let fragment = match kind { | 407 | let fragment = match kind { |
346 | "path" => Path, | 408 | "path" => Path, |
347 | "expr" => Expr, | 409 | "expr" => Expr, |
@@ -352,34 +414,32 @@ fn match_meta_var(kind: &str, input: &mut TtIter) -> Result<Option<Fragment>, Ex | |||
352 | "meta" => MetaItem, | 414 | "meta" => MetaItem, |
353 | "item" => Item, | 415 | "item" => Item, |
354 | _ => { | 416 | _ => { |
355 | let tt = match kind { | 417 | let tt_result = match kind { |
356 | "ident" => { | 418 | "ident" => input |
357 | let ident = input.expect_ident().map_err(|()| err!("expected ident"))?.clone(); | 419 | .expect_ident() |
358 | tt::Leaf::from(ident).into() | 420 | .map(|ident| Some(tt::Leaf::from(ident.clone()).into())) |
359 | } | 421 | .map_err(|()| err!("expected ident")), |
360 | "tt" => input.expect_tt().map_err(|()| err!())?.clone(), | 422 | "tt" => input.expect_tt().map(Some).map_err(|()| err!()), |
361 | "lifetime" => { | 423 | "lifetime" => input |
362 | let ident = input.expect_lifetime().map_err(|()| err!())?; | 424 | .expect_lifetime() |
363 | tt::Leaf::Ident(ident.clone()).into() | 425 | .map(|ident| Some(tt::Leaf::Ident(ident.clone()).into())) |
364 | } | 426 | .map_err(|()| err!("expected lifetime")), |
365 | "literal" => { | 427 | "literal" => input |
366 | let literal = input.expect_literal().map_err(|()| err!())?.clone(); | 428 | .expect_literal() |
367 | tt::Leaf::from(literal).into() | 429 | .map(|literal| Some(tt::Leaf::from(literal.clone()).into())) |
368 | } | 430 | .map_err(|()| err!()), |
369 | // `vis` is optional | 431 | // `vis` is optional |
370 | "vis" => match input.eat_vis() { | 432 | "vis" => match input.eat_vis() { |
371 | Some(vis) => vis, | 433 | Some(vis) => Ok(Some(vis)), |
372 | None => return Ok(None), | 434 | None => Ok(None), |
373 | }, | 435 | }, |
374 | _ => return Err(ExpandError::UnexpectedToken), | 436 | _ => Err(ExpandError::UnexpectedToken), |
375 | }; | 437 | }; |
376 | return Ok(Some(Fragment::Tokens(tt))); | 438 | return tt_result.map(|it| it.map(Fragment::Tokens)).into(); |
377 | } | 439 | } |
378 | }; | 440 | }; |
379 | let tt = | 441 | let result = input.expect_fragment(fragment); |
380 | input.expect_fragment(fragment).map_err(|()| err!("fragment did not parse as {}", kind))?; | 442 | result.map(|tt| if kind == "expr" { tt.map(Fragment::Ast) } else { tt.map(Fragment::Tokens) }) |
381 | let fragment = if kind == "expr" { Fragment::Ast(tt) } else { Fragment::Tokens(tt) }; | ||
382 | Ok(Some(fragment)) | ||
383 | } | 443 | } |
384 | 444 | ||
385 | fn collect_vars(buf: &mut Vec<SmolStr>, pattern: &tt::Subtree) -> Result<(), ExpandError> { | 445 | fn collect_vars(buf: &mut Vec<SmolStr>, pattern: &tt::Subtree) -> Result<(), ExpandError> { |
diff --git a/crates/ra_mbe/src/mbe_expander/transcriber.rs b/crates/ra_mbe/src/mbe_expander/transcriber.rs index 7662020f3..4b173edd3 100644 --- a/crates/ra_mbe/src/mbe_expander/transcriber.rs +++ b/crates/ra_mbe/src/mbe_expander/transcriber.rs | |||
@@ -3,6 +3,7 @@ | |||
3 | 3 | ||
4 | use ra_syntax::SmolStr; | 4 | use ra_syntax::SmolStr; |
5 | 5 | ||
6 | use super::ExpandResult; | ||
6 | use crate::{ | 7 | use crate::{ |
7 | mbe_expander::{Binding, Bindings, Fragment}, | 8 | mbe_expander::{Binding, Bindings, Fragment}, |
8 | parser::{parse_template, Op, RepeatKind, Separator}, | 9 | parser::{parse_template, Op, RepeatKind, Separator}, |
@@ -49,10 +50,7 @@ impl Bindings { | |||
49 | } | 50 | } |
50 | } | 51 | } |
51 | 52 | ||
52 | pub(super) fn transcribe( | 53 | pub(super) fn transcribe(template: &tt::Subtree, bindings: &Bindings) -> ExpandResult<tt::Subtree> { |
53 | template: &tt::Subtree, | ||
54 | bindings: &Bindings, | ||
55 | ) -> Result<tt::Subtree, ExpandError> { | ||
56 | assert!(template.delimiter == None); | 54 | assert!(template.delimiter == None); |
57 | let mut ctx = ExpandCtx { bindings: &bindings, nesting: Vec::new() }; | 55 | let mut ctx = ExpandCtx { bindings: &bindings, nesting: Vec::new() }; |
58 | expand_subtree(&mut ctx, template) | 56 | expand_subtree(&mut ctx, template) |
@@ -75,35 +73,46 @@ struct ExpandCtx<'a> { | |||
75 | nesting: Vec<NestingState>, | 73 | nesting: Vec<NestingState>, |
76 | } | 74 | } |
77 | 75 | ||
78 | fn expand_subtree(ctx: &mut ExpandCtx, template: &tt::Subtree) -> Result<tt::Subtree, ExpandError> { | 76 | fn expand_subtree(ctx: &mut ExpandCtx, template: &tt::Subtree) -> ExpandResult<tt::Subtree> { |
79 | let mut buf: Vec<tt::TokenTree> = Vec::new(); | 77 | let mut buf: Vec<tt::TokenTree> = Vec::new(); |
78 | let mut err = None; | ||
80 | for op in parse_template(template) { | 79 | for op in parse_template(template) { |
81 | match op? { | 80 | let op = match op { |
81 | Ok(op) => op, | ||
82 | Err(e) => { | ||
83 | err = Some(e); | ||
84 | break; | ||
85 | } | ||
86 | }; | ||
87 | match op { | ||
82 | Op::TokenTree(tt @ tt::TokenTree::Leaf(..)) => buf.push(tt.clone()), | 88 | Op::TokenTree(tt @ tt::TokenTree::Leaf(..)) => buf.push(tt.clone()), |
83 | Op::TokenTree(tt::TokenTree::Subtree(tt)) => { | 89 | Op::TokenTree(tt::TokenTree::Subtree(tt)) => { |
84 | let tt = expand_subtree(ctx, tt)?; | 90 | let ExpandResult(tt, e) = expand_subtree(ctx, tt); |
91 | err = err.or(e); | ||
85 | buf.push(tt.into()); | 92 | buf.push(tt.into()); |
86 | } | 93 | } |
87 | Op::Var { name, kind: _ } => { | 94 | Op::Var { name, kind: _ } => { |
88 | let fragment = expand_var(ctx, name)?; | 95 | let ExpandResult(fragment, e) = expand_var(ctx, name); |
96 | err = err.or(e); | ||
89 | push_fragment(&mut buf, fragment); | 97 | push_fragment(&mut buf, fragment); |
90 | } | 98 | } |
91 | Op::Repeat { subtree, kind, separator } => { | 99 | Op::Repeat { subtree, kind, separator } => { |
92 | let fragment = expand_repeat(ctx, subtree, kind, separator)?; | 100 | let ExpandResult(fragment, e) = expand_repeat(ctx, subtree, kind, separator); |
101 | err = err.or(e); | ||
93 | push_fragment(&mut buf, fragment) | 102 | push_fragment(&mut buf, fragment) |
94 | } | 103 | } |
95 | } | 104 | } |
96 | } | 105 | } |
97 | Ok(tt::Subtree { delimiter: template.delimiter, token_trees: buf }) | 106 | ExpandResult(tt::Subtree { delimiter: template.delimiter, token_trees: buf }, err) |
98 | } | 107 | } |
99 | 108 | ||
100 | fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr) -> Result<Fragment, ExpandError> { | 109 | fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr) -> ExpandResult<Fragment> { |
101 | let res = if v == "crate" { | 110 | if v == "crate" { |
102 | // We simply produce identifier `$crate` here. And it will be resolved when lowering ast to Path. | 111 | // We simply produce identifier `$crate` here. And it will be resolved when lowering ast to Path. |
103 | let tt = | 112 | let tt = |
104 | tt::Leaf::from(tt::Ident { text: "$crate".into(), id: tt::TokenId::unspecified() }) | 113 | tt::Leaf::from(tt::Ident { text: "$crate".into(), id: tt::TokenId::unspecified() }) |
105 | .into(); | 114 | .into(); |
106 | Fragment::Tokens(tt) | 115 | ExpandResult::ok(Fragment::Tokens(tt)) |
107 | } else if !ctx.bindings.contains(v) { | 116 | } else if !ctx.bindings.contains(v) { |
108 | // Note that it is possible to have a `$var` inside a macro which is not bound. | 117 | // Note that it is possible to have a `$var` inside a macro which is not bound. |
109 | // For example: | 118 | // For example: |
@@ -132,11 +141,13 @@ fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr) -> Result<Fragment, ExpandError> | |||
132 | ], | 141 | ], |
133 | } | 142 | } |
134 | .into(); | 143 | .into(); |
135 | Fragment::Tokens(tt) | 144 | ExpandResult::ok(Fragment::Tokens(tt)) |
136 | } else { | 145 | } else { |
137 | ctx.bindings.get(&v, &mut ctx.nesting)?.clone() | 146 | ctx.bindings.get(&v, &mut ctx.nesting).map_or_else( |
138 | }; | 147 | |e| ExpandResult(Fragment::Tokens(tt::TokenTree::empty()), Some(e)), |
139 | Ok(res) | 148 | |b| ExpandResult::ok(b.clone()), |
149 | ) | ||
150 | } | ||
140 | } | 151 | } |
141 | 152 | ||
142 | fn expand_repeat( | 153 | fn expand_repeat( |
@@ -144,17 +155,17 @@ fn expand_repeat( | |||
144 | template: &tt::Subtree, | 155 | template: &tt::Subtree, |
145 | kind: RepeatKind, | 156 | kind: RepeatKind, |
146 | separator: Option<Separator>, | 157 | separator: Option<Separator>, |
147 | ) -> Result<Fragment, ExpandError> { | 158 | ) -> ExpandResult<Fragment> { |
148 | let mut buf: Vec<tt::TokenTree> = Vec::new(); | 159 | let mut buf: Vec<tt::TokenTree> = Vec::new(); |
149 | ctx.nesting.push(NestingState { idx: 0, at_end: false, hit: false }); | 160 | ctx.nesting.push(NestingState { idx: 0, at_end: false, hit: false }); |
150 | // Dirty hack to make macro-expansion terminate. | 161 | // Dirty hack to make macro-expansion terminate. |
151 | // This should be replaced by a propper macro-by-example implementation | 162 | // This should be replaced by a proper macro-by-example implementation |
152 | let limit = 65536; | 163 | let limit = 65536; |
153 | let mut has_seps = 0; | 164 | let mut has_seps = 0; |
154 | let mut counter = 0; | 165 | let mut counter = 0; |
155 | 166 | ||
156 | loop { | 167 | loop { |
157 | let res = expand_subtree(ctx, template); | 168 | let ExpandResult(mut t, e) = expand_subtree(ctx, template); |
158 | let nesting_state = ctx.nesting.last_mut().unwrap(); | 169 | let nesting_state = ctx.nesting.last_mut().unwrap(); |
159 | if nesting_state.at_end || !nesting_state.hit { | 170 | if nesting_state.at_end || !nesting_state.hit { |
160 | break; | 171 | break; |
@@ -172,10 +183,10 @@ fn expand_repeat( | |||
172 | break; | 183 | break; |
173 | } | 184 | } |
174 | 185 | ||
175 | let mut t = match res { | 186 | if e.is_some() { |
176 | Ok(t) => t, | 187 | continue; |
177 | Err(_) => continue, | 188 | } |
178 | }; | 189 | |
179 | t.delimiter = None; | 190 | t.delimiter = None; |
180 | push_subtree(&mut buf, t); | 191 | push_subtree(&mut buf, t); |
181 | 192 | ||
@@ -209,14 +220,14 @@ fn expand_repeat( | |||
209 | buf.pop(); | 220 | buf.pop(); |
210 | } | 221 | } |
211 | 222 | ||
212 | if RepeatKind::OneOrMore == kind && counter == 0 { | ||
213 | return Err(ExpandError::UnexpectedToken); | ||
214 | } | ||
215 | |||
216 | // Check if it is a single token subtree without any delimiter | 223 | // Check if it is a single token subtree without any delimiter |
217 | // e.g {Delimiter:None> ['>'] /Delimiter:None>} | 224 | // e.g {Delimiter:None> ['>'] /Delimiter:None>} |
218 | let tt = tt::Subtree { delimiter: None, token_trees: buf }.into(); | 225 | let tt = tt::Subtree { delimiter: None, token_trees: buf }.into(); |
219 | Ok(Fragment::Tokens(tt)) | 226 | |
227 | if RepeatKind::OneOrMore == kind && counter == 0 { | ||
228 | return ExpandResult(Fragment::Tokens(tt), Some(ExpandError::UnexpectedToken)); | ||
229 | } | ||
230 | ExpandResult::ok(Fragment::Tokens(tt)) | ||
220 | } | 231 | } |
221 | 232 | ||
222 | fn push_fragment(buf: &mut Vec<tt::TokenTree>, fragment: Fragment) { | 233 | fn push_fragment(buf: &mut Vec<tt::TokenTree>, fragment: Fragment) { |
diff --git a/crates/ra_mbe/src/tests.rs b/crates/ra_mbe/src/tests.rs index 6d5d1e9e6..44f381938 100644 --- a/crates/ra_mbe/src/tests.rs +++ b/crates/ra_mbe/src/tests.rs | |||
@@ -1430,7 +1430,7 @@ impl MacroFixture { | |||
1430 | let (invocation_tt, _) = | 1430 | let (invocation_tt, _) = |
1431 | ast_to_token_tree(¯o_invocation.token_tree().unwrap()).unwrap(); | 1431 | ast_to_token_tree(¯o_invocation.token_tree().unwrap()).unwrap(); |
1432 | 1432 | ||
1433 | self.rules.expand(&invocation_tt) | 1433 | self.rules.expand(&invocation_tt).result() |
1434 | } | 1434 | } |
1435 | 1435 | ||
1436 | fn assert_expand_err(&self, invocation: &str, err: &ExpandError) { | 1436 | fn assert_expand_err(&self, invocation: &str, err: &ExpandError) { |
@@ -1662,5 +1662,5 @@ fn test_expand_bad_literal() { | |||
1662 | macro_rules! foo { ($i:literal) => {}; } | 1662 | macro_rules! foo { ($i:literal) => {}; } |
1663 | "#, | 1663 | "#, |
1664 | ) | 1664 | ) |
1665 | .assert_expand_err(r#"foo!(&k");"#, &ExpandError::NoMatchingRule); | 1665 | .assert_expand_err(r#"foo!(&k");"#, &ExpandError::BindingError("".to_string())); |
1666 | } | 1666 | } |