aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2020-03-14 19:24:18 +0000
committerFlorian Diebold <[email protected]>2020-03-16 17:38:19 +0000
commit0f3a54dd4d439a6598526144c4ecccee9c5f1362 (patch)
treec974dab20b25d0403f23222f4438bb3f9f7d8b0d /crates
parent6305d094ac61ed6e437537b93f4e587b415678c9 (diff)
wip
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir_expand/src/db.rs16
-rw-r--r--crates/ra_ide/src/completion/complete_dot.rs4
-rw-r--r--crates/ra_ide/src/completion/complete_pattern.rs13
-rw-r--r--crates/ra_mbe/src/mbe_expander.rs49
-rw-r--r--crates/ra_mbe/src/mbe_expander/matcher.rs172
5 files changed, 160 insertions, 94 deletions
diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs
index e7b81a1e6..ad4a0732e 100644
--- a/crates/ra_hir_expand/src/db.rs
+++ b/crates/ra_hir_expand/src/db.rs
@@ -31,8 +31,12 @@ impl TokenExpander {
31 match self { 31 match self {
32 TokenExpander::MacroRules(it) => it.expand(tt), 32 TokenExpander::MacroRules(it) => it.expand(tt),
33 // FIXME switch these to ExpandResult as well 33 // FIXME switch these to ExpandResult as well
34 TokenExpander::Builtin(it) => it.expand(db, id, tt).map_or_else(|e| (tt::Subtree::default(), Some(e)), |r| (r, None)), 34 TokenExpander::Builtin(it) => it
35 TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt).map_or_else(|e| (tt::Subtree::default(), Some(e)), |r| (r, None)), 35 .expand(db, id, tt)
36 .map_or_else(|e| (tt::Subtree::default(), Some(e)), |r| (r, None)),
37 TokenExpander::BuiltinDerive(it) => it
38 .expand(db, id, tt)
39 .map_or_else(|e| (tt::Subtree::default(), Some(e)), |r| (r, None)),
36 } 40 }
37 } 41 }
38 42
@@ -182,7 +186,7 @@ fn macro_expand_with_arg(
182 if arg.is_some() { 186 if arg.is_some() {
183 return ( 187 return (
184 None, 188 None,
185 Some("hypothetical macro expansion not implemented for eager macro".to_owned()) 189 Some("hypothetical macro expansion not implemented for eager macro".to_owned()),
186 ); 190 );
187 } else { 191 } else {
188 return (Some(db.lookup_intern_eager_expansion(id).subtree), None); 192 return (Some(db.lookup_intern_eager_expansion(id).subtree), None);
@@ -252,9 +256,9 @@ pub fn parse_macro_with_arg(
252 let parents = std::iter::successors(loc.kind.file_id().call_node(db), |it| { 256 let parents = std::iter::successors(loc.kind.file_id().call_node(db), |it| {
253 it.file_id.call_node(db) 257 it.file_id.call_node(db)
254 }) 258 })
255 .map(|n| format!("{:#}", n.value)) 259 .map(|n| format!("{:#}", n.value))
256 .collect::<Vec<_>>() 260 .collect::<Vec<_>>()
257 .join("\n"); 261 .join("\n");
258 262
259 log::warn!( 263 log::warn!(
260 "fail on macro_parse: (reason: {} macro_call: {:#}) parents: {}", 264 "fail on macro_parse: (reason: {} macro_call: {:#}) parents: {}",
diff --git a/crates/ra_ide/src/completion/complete_dot.rs b/crates/ra_ide/src/completion/complete_dot.rs
index a30d1c2de..22f5077f5 100644
--- a/crates/ra_ide/src/completion/complete_dot.rs
+++ b/crates/ra_ide/src/completion/complete_dot.rs
@@ -777,8 +777,8 @@ mod tests {
777 [ 777 [
778 CompletionItem { 778 CompletionItem {
779 label: "the_field", 779 label: "the_field",
780 source_range: [552; 553), 780 source_range: [552; 552),
781 delete: [552; 553), 781 delete: [552; 552),
782 insert: "the_field", 782 insert: "the_field",
783 kind: Field, 783 kind: Field,
784 detail: "u32", 784 detail: "u32",
diff --git a/crates/ra_ide/src/completion/complete_pattern.rs b/crates/ra_ide/src/completion/complete_pattern.rs
index 6a1a66ef1..cb84bb934 100644
--- a/crates/ra_ide/src/completion/complete_pattern.rs
+++ b/crates/ra_ide/src/completion/complete_pattern.rs
@@ -89,7 +89,6 @@ mod tests {
89 89
90 #[test] 90 #[test]
91 fn completes_in_simple_macro_call() { 91 fn completes_in_simple_macro_call() {
92 // FIXME: doesn't work yet because of missing error recovery in macro expansion
93 let completions = complete( 92 let completions = complete(
94 r" 93 r"
95 macro_rules! m { ($e:expr) => { $e } } 94 macro_rules! m { ($e:expr) => { $e } }
@@ -102,6 +101,16 @@ mod tests {
102 } 101 }
103 ", 102 ",
104 ); 103 );
105 assert_debug_snapshot!(completions, @r###"[]"###); 104 assert_debug_snapshot!(completions, @r###"
105 [
106 CompletionItem {
107 label: "E",
108 source_range: [151; 151),
109 delete: [151; 151),
110 insert: "E",
111 kind: Enum,
112 },
113 ]
114 "###);
106 } 115 }
107} 116}
diff --git a/crates/ra_mbe/src/mbe_expander.rs b/crates/ra_mbe/src/mbe_expander.rs
index 5083d5410..b2faa86d2 100644
--- a/crates/ra_mbe/src/mbe_expander.rs
+++ b/crates/ra_mbe/src/mbe_expander.rs
@@ -8,33 +8,44 @@ mod transcriber;
8use ra_syntax::SmolStr; 8use ra_syntax::SmolStr;
9use rustc_hash::FxHashMap; 9use rustc_hash::FxHashMap;
10 10
11use crate::{ExpandResult, 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 let (mut result, mut unmatched_tokens, mut unmatched_patterns, mut err) = (
15 input: &tt::Subtree, 15 tt::Subtree::default(),
16) -> ExpandResult<tt::Subtree> { 16 usize::max_value(),
17 let (mut result, mut left_over, mut err) = (tt::Subtree::default(), usize::max_value(), Some(ExpandError::NoMatchingRule)); 17 usize::max_value(),
18 Some(ExpandError::NoMatchingRule),
19 );
18 for rule in &rules.rules { 20 for rule in &rules.rules {
19 let ((res, left), e) = expand_rule(rule, input); 21 let ((res, tokens, patterns), e) = expand_rule(rule, input);
20 if e.is_none() { 22 if e.is_none() {
21 // if we find a rule that applies without errors, we're done 23 // if we find a rule that applies without errors, we're done
22 return (res, None); 24 return (res, None);
23 } 25 }
24 // use the rule if we matched more tokens 26 // use the rule if we matched more tokens, or had fewer patterns left
25 if left < left_over { 27 if tokens < unmatched_tokens || tokens == unmatched_tokens && patterns < unmatched_patterns
28 {
26 result = res; 29 result = res;
27 err = e; 30 err = e;
28 left_over = left; 31 unmatched_tokens = tokens;
32 unmatched_patterns = patterns;
29 } 33 }
30 } 34 }
31 (result, err) 35 (result, err)
32} 36}
33 37
34fn expand_rule(rule: &crate::Rule, input: &tt::Subtree) -> ExpandResult<(tt::Subtree, usize)> { 38fn expand_rule(
35 let ((bindings, left_over), bindings_err) = dbg!(matcher::match_(&rule.lhs, input)); 39 rule: &crate::Rule,
36 let (res, transcribe_err) = dbg!(transcriber::transcribe(&rule.rhs, &bindings)); 40 input: &tt::Subtree,
37 ((res, left_over), bindings_err.or(transcribe_err)) 41) -> ExpandResult<(tt::Subtree, usize, usize)> {
42 dbg!(&rule.lhs);
43 let (match_result, bindings_err) = dbg!(matcher::match_(&rule.lhs, input));
44 let (res, transcribe_err) = dbg!(transcriber::transcribe(&rule.rhs, &match_result.bindings));
45 (
46 (res, match_result.unmatched_tokens, match_result.unmatched_patterns),
47 bindings_err.or(transcribe_err),
48 )
38} 49}
39 50
40/// The actual algorithm for expansion is not too hard, but is pretty tricky. 51/// The actual algorithm for expansion is not too hard, but is pretty tricky.
@@ -149,10 +160,7 @@ mod tests {
149 crate::MacroRules::parse(&definition_tt).unwrap() 160 crate::MacroRules::parse(&definition_tt).unwrap()
150 } 161 }
151 162
152 fn expand_first( 163 fn expand_first(rules: &crate::MacroRules, invocation: &str) -> ExpandResult<tt::Subtree> {
153 rules: &crate::MacroRules,
154 invocation: &str,
155 ) -> ExpandResult<tt::Subtree> {
156 let source_file = ast::SourceFile::parse(invocation).ok().unwrap(); 164 let source_file = ast::SourceFile::parse(invocation).ok().unwrap();
157 let macro_invocation = 165 let macro_invocation =
158 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); 166 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
@@ -160,6 +168,7 @@ mod tests {
160 let (invocation_tt, _) = 168 let (invocation_tt, _) =
161 ast_to_token_tree(&macro_invocation.token_tree().unwrap()).unwrap(); 169 ast_to_token_tree(&macro_invocation.token_tree().unwrap()).unwrap();
162 170
163 expand_rule(&rules.rules[0], &invocation_tt) 171 let expanded = expand_rule(&rules.rules[0], &invocation_tt);
172 ((expanded.0).0, expanded.1)
164 } 173 }
165} 174}
diff --git a/crates/ra_mbe/src/mbe_expander/matcher.rs b/crates/ra_mbe/src/mbe_expander/matcher.rs
index 52f1ac252..ae65fb69a 100644
--- a/crates/ra_mbe/src/mbe_expander/matcher.rs
+++ b/crates/ra_mbe/src/mbe_expander/matcher.rs
@@ -8,10 +8,10 @@ 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};
14use super::ExpandResult;
15 15
16impl Bindings { 16impl Bindings {
17 fn push_optional(&mut self, name: &SmolStr) { 17 fn push_optional(&mut self, name: &SmolStr) {
@@ -59,36 +59,50 @@ macro_rules! err {
59 }; 59 };
60} 60}
61 61
62macro_rules! bail { 62#[derive(Debug, Default)]
63 ($($tt:tt)*) => { 63pub(super) struct Match {
64 return Err(err!($($tt)*)) 64 pub bindings: Bindings,
65 }; 65 pub unmatched_tokens: usize,
66 pub unmatched_patterns: usize,
66} 67}
67 68
68pub(super) fn match_(pattern: &tt::Subtree, src: &tt::Subtree) -> ExpandResult<(Bindings, usize)> { 69pub(super) fn match_(pattern: &tt::Subtree, src: &tt::Subtree) -> ExpandResult<Match> {
69 assert!(pattern.delimiter == None); 70 assert!(pattern.delimiter == None);
70 71
71 let mut res = Bindings::default(); 72 let mut res = Match::default();
72 let mut src = TtIter::new(src); 73 let mut src = TtIter::new(src);
73 74
74 let mut err = match_subtree(&mut res, pattern, &mut src).err(); 75 let mut err = match_subtree(&mut res, pattern, &mut src).err();
75 76
77 res.unmatched_tokens += src.len();
76 if src.len() > 0 && err.is_none() { 78 if src.len() > 0 && err.is_none() {
77 err = Some(err!("leftover tokens")); 79 err = Some(err!("leftover tokens"));
78 } 80 }
79 81
80 ((res, src.len()), err) 82 (res, err)
81} 83}
82 84
83fn match_subtree( 85fn match_subtree(
84 bindings: &mut Bindings, 86 res: &mut Match,
85 pattern: &tt::Subtree, 87 pattern: &tt::Subtree,
86 src: &mut TtIter, 88 src: &mut TtIter,
87) -> Result<(), ExpandError> { 89) -> Result<(), ExpandError> {
90 let mut result = Ok(());
88 for op in parse_pattern(pattern) { 91 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 }
89 match op? { 97 match op? {
90 Op::TokenTree(tt::TokenTree::Leaf(lhs)) => { 98 Op::TokenTree(tt::TokenTree::Leaf(lhs)) => {
91 let rhs = src.expect_leaf().map_err(|()| err!("expected leaf: `{}`", lhs))?; 99 let rhs = match src.expect_leaf() {
100 Ok(l) => l,
101 Err(()) => {
102 result = Err(err!("expected leaf: `{}`", lhs));
103 continue;
104 }
105 };
92 match (lhs, rhs) { 106 match (lhs, rhs) {
93 ( 107 (
94 tt::Leaf::Punct(tt::Punct { char: lhs, .. }), 108 tt::Leaf::Punct(tt::Punct { char: lhs, .. }),
@@ -102,35 +116,54 @@ fn match_subtree(
102 tt::Leaf::Literal(tt::Literal { text: lhs, .. }), 116 tt::Leaf::Literal(tt::Literal { text: lhs, .. }),
103 tt::Leaf::Literal(tt::Literal { text: rhs, .. }), 117 tt::Leaf::Literal(tt::Literal { text: rhs, .. }),
104 ) if lhs == rhs => (), 118 ) if lhs == rhs => (),
105 _ => return Err(ExpandError::UnexpectedToken), 119 _ => {
120 result = Err(ExpandError::UnexpectedToken);
121 }
106 } 122 }
107 } 123 }
108 Op::TokenTree(tt::TokenTree::Subtree(lhs)) => { 124 Op::TokenTree(tt::TokenTree::Subtree(lhs)) => {
109 let rhs = src.expect_subtree().map_err(|()| err!("expected subtree"))?; 125 let rhs = match src.expect_subtree() {
126 Ok(s) => s,
127 Err(()) => {
128 result = Err(err!("expected subtree"));
129 continue;
130 }
131 };
110 if lhs.delimiter_kind() != rhs.delimiter_kind() { 132 if lhs.delimiter_kind() != rhs.delimiter_kind() {
111 bail!("mismatched delimiter") 133 result = Err(err!("mismatched delimiter"));
134 continue;
112 } 135 }
113 let mut src = TtIter::new(rhs); 136 let mut src = TtIter::new(rhs);
114 match_subtree(bindings, lhs, &mut src)?; 137 result = match_subtree(res, lhs, &mut src);
115 if src.len() > 0 { 138 res.unmatched_tokens += src.len();
116 bail!("leftover tokens"); 139 if src.len() > 0 && result.is_ok() {
140 result = Err(err!("leftover tokens"));
117 } 141 }
118 } 142 }
119 Op::Var { name, kind } => { 143 Op::Var { name, kind } => {
120 let kind = kind.as_ref().ok_or(ExpandError::UnexpectedToken)?; 144 let kind = match kind {
121 match match_meta_var(kind.as_str(), src)? { 145 Some(k) => k,
146 None => {
147 result = Err(ExpandError::UnexpectedToken);
148 continue;
149 }
150 };
151 let (matched, match_err) = match_meta_var(kind.as_str(), src);
152 match matched {
122 Some(fragment) => { 153 Some(fragment) => {
123 bindings.inner.insert(name.clone(), Binding::Fragment(fragment)); 154 res.bindings.inner.insert(name.clone(), Binding::Fragment(fragment));
124 } 155 }
125 None => bindings.push_optional(name), 156 None if match_err.is_none() => res.bindings.push_optional(name),
157 _ => {}
126 } 158 }
159 result = match_err.map_or(Ok(()), Err);
127 } 160 }
128 Op::Repeat { subtree, kind, separator } => { 161 Op::Repeat { subtree, kind, separator } => {
129 match_repeat(bindings, subtree, kind, separator, src)? 162 result = match_repeat(res, subtree, kind, separator, src);
130 } 163 }
131 } 164 }
132 } 165 }
133 Ok(()) 166 result
134} 167}
135 168
136impl<'a> TtIter<'a> { 169impl<'a> TtIter<'a> {
@@ -222,7 +255,7 @@ impl<'a> TtIter<'a> {
222 pub(crate) fn expect_fragment( 255 pub(crate) fn expect_fragment(
223 &mut self, 256 &mut self,
224 fragment_kind: ra_parser::FragmentKind, 257 fragment_kind: ra_parser::FragmentKind,
225 ) -> Result<tt::TokenTree, ()> { 258 ) -> ExpandResult<tt::TokenTree> {
226 pub(crate) struct OffsetTokenSink<'a> { 259 pub(crate) struct OffsetTokenSink<'a> {
227 pub(crate) cursor: Cursor<'a>, 260 pub(crate) cursor: Cursor<'a>,
228 pub(crate) error: bool, 261 pub(crate) error: bool,
@@ -247,45 +280,47 @@ impl<'a> TtIter<'a> {
247 280
248 ra_parser::parse_fragment(&mut src, &mut sink, fragment_kind); 281 ra_parser::parse_fragment(&mut src, &mut sink, fragment_kind);
249 282
283 let mut err = None;
250 if !sink.cursor.is_root() || sink.error { 284 if !sink.cursor.is_root() || sink.error {
251 // FIXME better recovery in this case would help completion inside macros immensely 285 err = Some(err!("expected {:?}", fragment_kind));
252 return Err(());
253 } 286 }
254 287
255 let mut curr = buffer.begin(); 288 let mut curr = buffer.begin();
256 let mut res = vec![]; 289 let mut res = vec![];
257 290
258 while curr != sink.cursor { 291 if sink.cursor.is_root() {
259 if let Some(token) = curr.token_tree() { 292 while curr != sink.cursor {
260 res.push(token); 293 if let Some(token) = curr.token_tree() {
294 res.push(token);
295 }
296 curr = curr.bump();
261 } 297 }
262 curr = curr.bump();
263 } 298 }
264 self.inner = self.inner.as_slice()[res.len()..].iter(); 299 self.inner = self.inner.as_slice()[res.len()..].iter();
265 match res.len() { 300 let res = match res.len() {
266 0 => Err(()), 301 1 => res[0].clone(),
267 1 => Ok(res[0].clone()), 302 _ => tt::TokenTree::Subtree(tt::Subtree {
268 _ => Ok(tt::TokenTree::Subtree(tt::Subtree {
269 delimiter: None, 303 delimiter: None,
270 token_trees: res.into_iter().cloned().collect(), 304 token_trees: res.into_iter().cloned().collect(),
271 })), 305 }),
272 } 306 };
307 (res, err)
273 } 308 }
274 309
275 pub(crate) fn eat_vis(&mut self) -> Option<tt::TokenTree> { 310 pub(crate) fn eat_vis(&mut self) -> Option<tt::TokenTree> {
276 let mut fork = self.clone(); 311 let mut fork = self.clone();
277 match fork.expect_fragment(Visibility) { 312 match fork.expect_fragment(Visibility) {
278 Ok(tt) => { 313 (tt, None) => {
279 *self = fork; 314 *self = fork;
280 Some(tt) 315 Some(tt)
281 } 316 }
282 Err(()) => None, 317 (_, Some(_)) => None,
283 } 318 }
284 } 319 }
285} 320}
286 321
287pub(super) fn match_repeat( 322pub(super) fn match_repeat(
288 bindings: &mut Bindings, 323 res: &mut Match,
289 pattern: &tt::Subtree, 324 pattern: &tt::Subtree,
290 kind: RepeatKind, 325 kind: RepeatKind,
291 separator: Option<Separator>, 326 separator: Option<Separator>,
@@ -305,17 +340,23 @@ pub(super) fn match_repeat(
305 } 340 }
306 } 341 }
307 342
308 let mut nested = Bindings::default(); 343 let mut nested = Match::default();
309 match match_subtree(&mut nested, pattern, &mut fork) { 344 match match_subtree(&mut nested, pattern, &mut fork) {
310 Ok(()) => { 345 Ok(()) => {
311 limit -= 1; 346 limit -= 1;
312 if limit == 0 { 347 if limit == 0 {
313 log::warn!("match_lhs excced in repeat pattern exceed limit => {:#?}\n{:#?}\n{:#?}\n{:#?}", pattern, src, kind, separator); 348 log::warn!(
349 "match_lhs exceeded repeat pattern limit => {:#?}\n{:#?}\n{:#?}\n{:#?}",
350 pattern,
351 src,
352 kind,
353 separator
354 );
314 break; 355 break;
315 } 356 }
316 *src = fork; 357 *src = fork;
317 358
318 bindings.push_nested(counter, nested)?; 359 res.bindings.push_nested(counter, nested.bindings)?;
319 counter += 1; 360 counter += 1;
320 if counter == 1 { 361 if counter == 1 {
321 if let RepeatKind::ZeroOrOne = kind { 362 if let RepeatKind::ZeroOrOne = kind {
@@ -334,7 +375,7 @@ pub(super) fn match_repeat(
334 let mut vars = Vec::new(); 375 let mut vars = Vec::new();
335 collect_vars(&mut vars, pattern)?; 376 collect_vars(&mut vars, pattern)?;
336 for var in vars { 377 for var in vars {
337 bindings.push_empty(&var) 378 res.bindings.push_empty(&var)
338 } 379 }
339 } 380 }
340 _ => (), 381 _ => (),
@@ -342,7 +383,7 @@ pub(super) fn match_repeat(
342 Ok(()) 383 Ok(())
343} 384}
344 385
345fn match_meta_var(kind: &str, input: &mut TtIter) -> Result<Option<Fragment>, ExpandError> { 386fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult<Option<Fragment>> {
346 let fragment = match kind { 387 let fragment = match kind {
347 "path" => Path, 388 "path" => Path,
348 "expr" => Expr, 389 "expr" => Expr,
@@ -353,34 +394,33 @@ fn match_meta_var(kind: &str, input: &mut TtIter) -> Result<Option<Fragment>, Ex
353 "meta" => MetaItem, 394 "meta" => MetaItem,
354 "item" => Item, 395 "item" => Item,
355 _ => { 396 _ => {
356 let tt = match kind { 397 let tt_result = match kind {
357 "ident" => { 398 "ident" => input
358 let ident = input.expect_ident().map_err(|()| err!("expected ident"))?.clone(); 399 .expect_ident()
359 tt::Leaf::from(ident).into() 400 .map(|ident| Some(tt::Leaf::from(ident.clone()).into()))
360 } 401 .map_err(|()| err!("expected ident")),
361 "tt" => input.expect_tt().map_err(|()| err!())?.clone(), 402 "tt" => input.expect_tt().map(Some).map_err(|()| err!()),
362 "lifetime" => { 403 "lifetime" => input
363 let ident = input.expect_lifetime().map_err(|()| err!())?; 404 .expect_lifetime()
364 tt::Leaf::Ident(ident.clone()).into() 405 .map(|ident| Some(tt::Leaf::Ident(ident.clone()).into()))
365 } 406 .map_err(|()| err!("expected lifetime")),
366 "literal" => { 407 "literal" => input
367 let literal = input.expect_literal().map_err(|()| err!())?.clone(); 408 .expect_literal()
368 tt::Leaf::from(literal).into() 409 .map(|literal| Some(tt::Leaf::from(literal.clone()).into()))
369 } 410 .map_err(|()| err!()),
370 // `vis` is optional 411 // `vis` is optional
371 "vis" => match input.eat_vis() { 412 "vis" => match input.eat_vis() {
372 Some(vis) => vis, 413 Some(vis) => Ok(Some(vis)),
373 None => return Ok(None), 414 None => Ok(None),
374 }, 415 },
375 _ => return Err(ExpandError::UnexpectedToken), 416 _ => Err(ExpandError::UnexpectedToken),
376 }; 417 };
377 return Ok(Some(Fragment::Tokens(tt))); 418 return to_expand_result(tt_result.map(|it| it.map(Fragment::Tokens)));
378 } 419 }
379 }; 420 };
380 let tt = 421 let (tt, err) = input.expect_fragment(fragment);
381 input.expect_fragment(fragment).map_err(|()| err!("fragment did not parse as {}", kind))?;
382 let fragment = if kind == "expr" { Fragment::Ast(tt) } else { Fragment::Tokens(tt) }; 422 let fragment = if kind == "expr" { Fragment::Ast(tt) } else { Fragment::Tokens(tt) };
383 Ok(Some(fragment)) 423 (Some(fragment), err)
384} 424}
385 425
386fn collect_vars(buf: &mut Vec<SmolStr>, pattern: &tt::Subtree) -> Result<(), ExpandError> { 426fn collect_vars(buf: &mut Vec<SmolStr>, pattern: &tt::Subtree) -> Result<(), ExpandError> {
@@ -394,3 +434,7 @@ fn collect_vars(buf: &mut Vec<SmolStr>, pattern: &tt::Subtree) -> Result<(), Exp
394 } 434 }
395 Ok(()) 435 Ok(())
396} 436}
437
438fn to_expand_result<T: Default>(result: Result<T, ExpandError>) -> ExpandResult<T> {
439 result.map_or_else(|e| (Default::default(), Some(e)), |it| (it, None))
440}