aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_mbe
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-03-17 09:41:30 +0000
committerGitHub <[email protected]>2020-03-17 09:41:30 +0000
commit6aa432d86b7e4fb691600032ebdf6f2301152447 (patch)
treeaa012212c11e43a95547f553b5116922631f9896 /crates/ra_mbe
parentcf4ae9aa591729dde25a7df3fa5c22ca0fd94145 (diff)
parent6c20d7e979b967eb20207414c0a0bf875bbcb98d (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.rs32
-rw-r--r--crates/ra_mbe/src/mbe_expander.rs61
-rw-r--r--crates/ra_mbe/src/mbe_expander/matcher.rs212
-rw-r--r--crates/ra_mbe/src/mbe_expander/transcriber.rs69
-rw-r--r--crates/ra_mbe/src/tests.rs4
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
212pub struct ExpandResult<T>(pub T, pub Option<ExpandError>);
213
214impl<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
235impl<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)]
213mod tests; 243mod 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;
8use ra_syntax::SmolStr; 8use ra_syntax::SmolStr;
9use rustc_hash::FxHashMap; 9use rustc_hash::FxHashMap;
10 10
11use crate::ExpandError; 11use crate::{ExpandError, ExpandResult};
12 12
13pub(crate) fn expand( 13pub(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
20fn expand_rule(rule: &crate::Rule, input: &tt::Subtree) -> Result<tt::Subtree, ExpandError> { 17fn 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(&macro_invocation.token_tree().unwrap()).unwrap(); 176 ast_to_token_tree(&macro_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
11use super::ExpandResult;
11use ra_parser::{FragmentKind::*, TreeSink}; 12use ra_parser::{FragmentKind::*, TreeSink};
12use ra_syntax::{SmolStr, SyntaxKind}; 13use ra_syntax::{SmolStr, SyntaxKind};
13use tt::buffer::{Cursor, TokenBuffer}; 14use tt::buffer::{Cursor, TokenBuffer};
@@ -58,36 +59,61 @@ macro_rules! err {
58 }; 59 };
59} 60}
60 61
61macro_rules! bail { 62#[derive(Debug, Default)]
62 ($($tt:tt)*) => { 63pub(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
67pub(super) fn match_(pattern: &tt::Subtree, src: &tt::Subtree) -> Result<Bindings, ExpandError> { 72impl 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
86pub(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
82fn match_subtree( 102fn 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
286pub(super) fn match_repeat( 338pub(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
344fn match_meta_var(kind: &str, input: &mut TtIter) -> Result<Option<Fragment>, ExpandError> { 406fn 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
385fn collect_vars(buf: &mut Vec<SmolStr>, pattern: &tt::Subtree) -> Result<(), ExpandError> { 445fn 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
4use ra_syntax::SmolStr; 4use ra_syntax::SmolStr;
5 5
6use super::ExpandResult;
6use crate::{ 7use 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
52pub(super) fn transcribe( 53pub(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
78fn expand_subtree(ctx: &mut ExpandCtx, template: &tt::Subtree) -> Result<tt::Subtree, ExpandError> { 76fn 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
100fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr) -> Result<Fragment, ExpandError> { 109fn 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
142fn expand_repeat( 153fn 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
222fn push_fragment(buf: &mut Vec<tt::TokenTree>, fragment: Fragment) { 233fn 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(&macro_invocation.token_tree().unwrap()).unwrap(); 1431 ast_to_token_tree(&macro_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}