aboutsummaryrefslogtreecommitdiff
path: root/crates/mbe
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-01-29 16:24:16 +0000
committerGitHub <[email protected]>2021-01-29 16:24:16 +0000
commite7108fb5b198d4fe416ce2408afaa86f1020c37d (patch)
tree95766e6af68b0bd0d832180ce640ef0da868a76e /crates/mbe
parentd2a73c61641d065fd70e54a37442386deee6f013 (diff)
parent706ac8256d878626126756969b48b262d2e187b5 (diff)
Merge #7491
7491: Simplify mbe match error. r=edwin0cheng a=edwin0cheng Handle parse error in rule parsing instead of matching in mbe. bors r+ Co-authored-by: Edwin Cheng <[email protected]>
Diffstat (limited to 'crates/mbe')
-rw-r--r--crates/mbe/src/expander.rs9
-rw-r--r--crates/mbe/src/expander/matcher.rs286
-rw-r--r--crates/mbe/src/expander/transcriber.rs7
-rw-r--r--crates/mbe/src/lib.rs31
-rw-r--r--crates/mbe/src/parser.rs40
-rw-r--r--crates/mbe/src/tests.rs17
6 files changed, 180 insertions, 210 deletions
diff --git a/crates/mbe/src/expander.rs b/crates/mbe/src/expander.rs
index 802c8fb0f..e7e14b3cc 100644
--- a/crates/mbe/src/expander.rs
+++ b/crates/mbe/src/expander.rs
@@ -16,13 +16,8 @@ pub(crate) fn expand_rules(
16) -> ExpandResult<tt::Subtree> { 16) -> ExpandResult<tt::Subtree> {
17 let mut match_: Option<(matcher::Match, &crate::Rule)> = None; 17 let mut match_: Option<(matcher::Match, &crate::Rule)> = None;
18 for rule in rules { 18 for rule in rules {
19 let new_match = match matcher::match_(&rule.lhs, input) { 19 let new_match = matcher::match_(&rule.lhs, input);
20 Ok(m) => m, 20
21 Err(_e) => {
22 // error in pattern parsing
23 continue;
24 }
25 };
26 if new_match.err.is_none() { 21 if new_match.err.is_none() {
27 // If we find a rule that applies without errors, we're done. 22 // If we find a rule that applies without errors, we're done.
28 // Unconditionally returning the transcription here makes the 23 // Unconditionally returning the transcription here makes the
diff --git a/crates/mbe/src/expander/matcher.rs b/crates/mbe/src/expander/matcher.rs
index 5b5845850..987a4f676 100644
--- a/crates/mbe/src/expander/matcher.rs
+++ b/crates/mbe/src/expander/matcher.rs
@@ -77,35 +77,26 @@ impl Match {
77 } 77 }
78} 78}
79 79
80// General note: These functions have two channels to return errors, a `Result` 80/// Matching errors are added to the `Match`.
81// return value and the `&mut Match`. The returned Result is for pattern parsing 81pub(super) fn match_(pattern: &MetaTemplate, src: &tt::Subtree) -> Match {
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: &MetaTemplate, src: &tt::Subtree) -> Result<Match, ExpandError> {
87 assert!(pattern.delimiter == None); 82 assert!(pattern.delimiter == None);
88 83
89 let mut res = Match::default(); 84 let mut res = Match::default();
90 let mut src = TtIter::new(src); 85 let mut src = TtIter::new(src);
91 86
92 match_subtree(&mut res, pattern, &mut src)?; 87 match_subtree(&mut res, pattern, &mut src);
93 88
94 if src.len() > 0 { 89 if src.len() > 0 {
95 res.unmatched_tts += src.len(); 90 res.unmatched_tts += src.len();
96 res.add_err(err!("leftover tokens")); 91 res.add_err(err!("leftover tokens"));
97 } 92 }
98 93
99 Ok(res) 94 res
100} 95}
101 96
102fn match_subtree( 97fn match_subtree(res: &mut Match, pattern: &MetaTemplate, src: &mut TtIter) {
103 res: &mut Match,
104 pattern: &MetaTemplate,
105 src: &mut TtIter,
106) -> Result<(), ExpandError> {
107 for op in pattern.iter() { 98 for op in pattern.iter() {
108 match op.as_ref().map_err(|err| err.clone())? { 99 match op {
109 Op::Leaf(lhs) => { 100 Op::Leaf(lhs) => {
110 let rhs = match src.expect_leaf() { 101 let rhs = match src.expect_leaf() {
111 Ok(l) => l, 102 Ok(l) => l,
@@ -145,7 +136,7 @@ fn match_subtree(
145 continue; 136 continue;
146 } 137 }
147 let mut src = TtIter::new(rhs); 138 let mut src = TtIter::new(rhs);
148 match_subtree(res, lhs, &mut src)?; 139 match_subtree(res, lhs, &mut src);
149 if src.len() > 0 { 140 if src.len() > 0 {
150 res.add_err(err!("leftover tokens")); 141 res.add_err(err!("leftover tokens"));
151 } 142 }
@@ -172,11 +163,139 @@ fn match_subtree(
172 } 163 }
173 } 164 }
174 Op::Repeat { subtree, kind, separator } => { 165 Op::Repeat { subtree, kind, separator } => {
175 match_repeat(res, subtree, *kind, separator, src)?; 166 match_repeat(res, subtree, *kind, separator, src);
167 }
168 }
169 }
170}
171
172pub(super) fn match_repeat(
173 res: &mut Match,
174 pattern: &MetaTemplate,
175 kind: RepeatKind,
176 separator: &Option<Separator>,
177 src: &mut TtIter,
178) {
179 // Dirty hack to make macro-expansion terminate.
180 // This should be replaced by a proper macro-by-example implementation
181 let mut limit = 65536;
182 let mut counter = 0;
183
184 for i in 0.. {
185 let mut fork = src.clone();
186
187 if let Some(separator) = &separator {
188 if i != 0 && !fork.eat_separator(separator) {
189 break;
190 }
191 }
192
193 let mut nested = Match::default();
194 match_subtree(&mut nested, pattern, &mut fork);
195 if nested.err.is_none() {
196 limit -= 1;
197 if limit == 0 {
198 log::warn!(
199 "match_lhs exceeded repeat pattern limit => {:#?}\n{:#?}\n{:#?}\n{:#?}",
200 pattern,
201 src,
202 kind,
203 separator
204 );
205 break;
206 }
207 *src = fork;
208
209 if let Err(err) = res.bindings.push_nested(counter, nested.bindings) {
210 res.add_err(err);
211 }
212 counter += 1;
213 if counter == 1 {
214 if let RepeatKind::ZeroOrOne = kind {
215 break;
216 }
217 }
218 } else {
219 break;
220 }
221 }
222
223 match (kind, counter) {
224 (RepeatKind::OneOrMore, 0) => {
225 res.add_err(ExpandError::UnexpectedToken);
226 }
227 (_, 0) => {
228 // Collect all empty variables in subtrees
229 let mut vars = Vec::new();
230 collect_vars(&mut vars, pattern);
231 for var in vars {
232 res.bindings.push_empty(&var)
176 } 233 }
177 } 234 }
235 _ => (),
236 }
237}
238
239fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult<Option<Fragment>> {
240 let fragment = match kind {
241 "path" => Path,
242 "expr" => Expr,
243 "ty" => Type,
244 "pat" => Pattern,
245 "stmt" => Statement,
246 "block" => Block,
247 "meta" => MetaItem,
248 "item" => Item,
249 _ => {
250 let tt_result = match kind {
251 "ident" => input
252 .expect_ident()
253 .map(|ident| Some(tt::Leaf::from(ident.clone()).into()))
254 .map_err(|()| err!("expected ident")),
255 "tt" => input.expect_tt().map(Some).map_err(|()| err!()),
256 "lifetime" => input
257 .expect_lifetime()
258 .map(|tt| Some(tt))
259 .map_err(|()| err!("expected lifetime")),
260 "literal" => {
261 let neg = input.eat_char('-');
262 input
263 .expect_literal()
264 .map(|literal| {
265 let lit = tt::Leaf::from(literal.clone());
266 match neg {
267 None => Some(lit.into()),
268 Some(neg) => Some(tt::TokenTree::Subtree(tt::Subtree {
269 delimiter: None,
270 token_trees: vec![neg, lit.into()],
271 })),
272 }
273 })
274 .map_err(|()| err!())
275 }
276 // `vis` is optional
277 "vis" => match input.eat_vis() {
278 Some(vis) => Ok(Some(vis)),
279 None => Ok(None),
280 },
281 _ => Err(ExpandError::UnexpectedToken),
282 };
283 return tt_result.map(|it| it.map(Fragment::Tokens)).into();
284 }
285 };
286 let result = input.expect_fragment(fragment);
287 result.map(|tt| if kind == "expr" { tt.map(Fragment::Ast) } else { tt.map(Fragment::Tokens) })
288}
289
290fn collect_vars(buf: &mut Vec<SmolStr>, pattern: &MetaTemplate) {
291 for op in pattern.iter() {
292 match op {
293 Op::Var { name, .. } => buf.push(name.clone()),
294 Op::Leaf(_) => (),
295 Op::Subtree(subtree) => collect_vars(buf, subtree),
296 Op::Repeat { subtree, .. } => collect_vars(buf, subtree),
297 }
178 } 298 }
179 Ok(())
180} 299}
181 300
182impl<'a> TtIter<'a> { 301impl<'a> TtIter<'a> {
@@ -369,134 +488,3 @@ impl<'a> TtIter<'a> {
369 } 488 }
370 } 489 }
371} 490}
372
373pub(super) fn match_repeat(
374 res: &mut Match,
375 pattern: &MetaTemplate,
376 kind: RepeatKind,
377 separator: &Option<Separator>,
378 src: &mut TtIter,
379) -> Result<(), ExpandError> {
380 // Dirty hack to make macro-expansion terminate.
381 // This should be replaced by a proper macro-by-example implementation
382 let mut limit = 65536;
383 let mut counter = 0;
384
385 for i in 0.. {
386 let mut fork = src.clone();
387
388 if let Some(separator) = &separator {
389 if i != 0 && !fork.eat_separator(separator) {
390 break;
391 }
392 }
393
394 let mut nested = Match::default();
395 match_subtree(&mut nested, pattern, &mut fork)?;
396 if nested.err.is_none() {
397 limit -= 1;
398 if limit == 0 {
399 log::warn!(
400 "match_lhs exceeded repeat pattern limit => {:#?}\n{:#?}\n{:#?}\n{:#?}",
401 pattern,
402 src,
403 kind,
404 separator
405 );
406 break;
407 }
408 *src = fork;
409
410 if let Err(err) = res.bindings.push_nested(counter, nested.bindings) {
411 res.add_err(err);
412 }
413 counter += 1;
414 if counter == 1 {
415 if let RepeatKind::ZeroOrOne = kind {
416 break;
417 }
418 }
419 } else {
420 break;
421 }
422 }
423
424 match (kind, counter) {
425 (RepeatKind::OneOrMore, 0) => {
426 res.add_err(ExpandError::UnexpectedToken);
427 }
428 (_, 0) => {
429 // Collect all empty variables in subtrees
430 let mut vars = Vec::new();
431 collect_vars(&mut vars, pattern)?;
432 for var in vars {
433 res.bindings.push_empty(&var)
434 }
435 }
436 _ => (),
437 }
438 Ok(())
439}
440
441fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult<Option<Fragment>> {
442 let fragment = match kind {
443 "path" => Path,
444 "expr" => Expr,
445 "ty" => Type,
446 "pat" => Pattern,
447 "stmt" => Statement,
448 "block" => Block,
449 "meta" => MetaItem,
450 "item" => Item,
451 _ => {
452 let tt_result = match kind {
453 "ident" => input
454 .expect_ident()
455 .map(|ident| Some(tt::Leaf::from(ident.clone()).into()))
456 .map_err(|()| err!("expected ident")),
457 "tt" => input.expect_tt().map(Some).map_err(|()| err!()),
458 "lifetime" => input
459 .expect_lifetime()
460 .map(|tt| Some(tt))
461 .map_err(|()| err!("expected lifetime")),
462 "literal" => {
463 let neg = input.eat_char('-');
464 input
465 .expect_literal()
466 .map(|literal| {
467 let lit = tt::Leaf::from(literal.clone());
468 match neg {
469 None => Some(lit.into()),
470 Some(neg) => Some(tt::TokenTree::Subtree(tt::Subtree {
471 delimiter: None,
472 token_trees: vec![neg, lit.into()],
473 })),
474 }
475 })
476 .map_err(|()| err!())
477 }
478 // `vis` is optional
479 "vis" => match input.eat_vis() {
480 Some(vis) => Ok(Some(vis)),
481 None => Ok(None),
482 },
483 _ => Err(ExpandError::UnexpectedToken),
484 };
485 return tt_result.map(|it| it.map(Fragment::Tokens)).into();
486 }
487 };
488 let result = input.expect_fragment(fragment);
489 result.map(|tt| if kind == "expr" { tt.map(Fragment::Ast) } else { tt.map(Fragment::Tokens) })
490}
491
492fn collect_vars(buf: &mut Vec<SmolStr>, pattern: &MetaTemplate) -> Result<(), ExpandError> {
493 for op in pattern.iter() {
494 match op.as_ref().map_err(|e| e.clone())? {
495 Op::Var { name, .. } => buf.push(name.clone()),
496 Op::Leaf(_) => (),
497 Op::Subtree(subtree) => collect_vars(buf, subtree)?,
498 Op::Repeat { subtree, .. } => collect_vars(buf, subtree)?,
499 }
500 }
501 Ok(())
502}
diff --git a/crates/mbe/src/expander/transcriber.rs b/crates/mbe/src/expander/transcriber.rs
index 82bace110..30c090f32 100644
--- a/crates/mbe/src/expander/transcriber.rs
+++ b/crates/mbe/src/expander/transcriber.rs
@@ -86,13 +86,6 @@ fn expand_subtree(
86 let start_elements = arena.len(); 86 let start_elements = arena.len();
87 let mut err = None; 87 let mut err = None;
88 for op in template.iter() { 88 for op in template.iter() {
89 let op = match op {
90 Ok(op) => op,
91 Err(e) => {
92 err = Some(e.clone());
93 break;
94 }
95 };
96 match op { 89 match op {
97 Op::Leaf(tt) => arena.push(tt.clone().into()), 90 Op::Leaf(tt) => arena.push(tt.clone().into()),
98 Op::Subtree(tt) => { 91 Op::Subtree(tt) => {
diff --git a/crates/mbe/src/lib.rs b/crates/mbe/src/lib.rs
index bbe71ce3e..56c632665 100644
--- a/crates/mbe/src/lib.rs
+++ b/crates/mbe/src/lib.rs
@@ -24,7 +24,9 @@ use crate::{
24 24
25#[derive(Debug, PartialEq, Eq)] 25#[derive(Debug, PartialEq, Eq)]
26pub enum ParseError { 26pub enum ParseError {
27 UnexpectedToken(String),
27 Expected(String), 28 Expected(String),
29 InvalidRepeat,
28 RepetitionEmptyTokenTree, 30 RepetitionEmptyTokenTree,
29} 31}
30 32
@@ -34,7 +36,6 @@ pub enum ExpandError {
34 UnexpectedToken, 36 UnexpectedToken,
35 BindingError(String), 37 BindingError(String),
36 ConversionError, 38 ConversionError,
37 InvalidRepeat,
38 ProcMacroError(tt::ExpansionError), 39 ProcMacroError(tt::ExpansionError),
39 UnresolvedProcMacro, 40 UnresolvedProcMacro,
40 Other(String), 41 Other(String),
@@ -53,7 +54,6 @@ impl fmt::Display for ExpandError {
53 ExpandError::UnexpectedToken => f.write_str("unexpected token in input"), 54 ExpandError::UnexpectedToken => f.write_str("unexpected token in input"),
54 ExpandError::BindingError(e) => f.write_str(e), 55 ExpandError::BindingError(e) => f.write_str(e),
55 ExpandError::ConversionError => f.write_str("could not convert tokens"), 56 ExpandError::ConversionError => f.write_str("could not convert tokens"),
56 ExpandError::InvalidRepeat => f.write_str("invalid repeat expression"),
57 ExpandError::ProcMacroError(e) => e.fmt(f), 57 ExpandError::ProcMacroError(e) => e.fmt(f),
58 ExpandError::UnresolvedProcMacro => f.write_str("unresolved proc macro"), 58 ExpandError::UnresolvedProcMacro => f.write_str("unresolved proc macro"),
59 ExpandError::Other(e) => f.write_str(e), 59 ExpandError::Other(e) => f.write_str(e),
@@ -94,11 +94,11 @@ struct Rule {
94#[derive(Clone, Debug, PartialEq, Eq)] 94#[derive(Clone, Debug, PartialEq, Eq)]
95struct MetaTemplate { 95struct MetaTemplate {
96 delimiter: Option<Delimiter>, 96 delimiter: Option<Delimiter>,
97 tokens: Vec<Result<Op, ExpandError>>, 97 tokens: Vec<Op>,
98} 98}
99 99
100impl<'a> MetaTemplate { 100impl<'a> MetaTemplate {
101 fn iter(&self) -> impl Iterator<Item = &Result<Op, ExpandError>> { 101 fn iter(&self) -> impl Iterator<Item = &Op> {
102 self.tokens.iter() 102 self.tokens.iter()
103 } 103 }
104 104
@@ -288,25 +288,15 @@ impl Rule {
288 .expect_subtree() 288 .expect_subtree()
289 .map_err(|()| ParseError::Expected("expected subtree".to_string()))?; 289 .map_err(|()| ParseError::Expected("expected subtree".to_string()))?;
290 290
291 let lhs = MetaTemplate { tokens: parse_pattern(&lhs), delimiter: None }; 291 let lhs = MetaTemplate { tokens: parse_pattern(&lhs)?, delimiter: None };
292 let rhs = MetaTemplate { tokens: parse_template(&rhs), delimiter: None }; 292 let rhs = MetaTemplate { tokens: parse_template(&rhs)?, delimiter: None };
293 293
294 Ok(crate::Rule { lhs, rhs }) 294 Ok(crate::Rule { lhs, rhs })
295 } 295 }
296} 296}
297 297
298fn to_parse_error(e: &ExpandError) -> ParseError {
299 let msg = match e {
300 ExpandError::InvalidRepeat => "invalid repeat".to_string(),
301 _ => "invalid macro definition".to_string(),
302 };
303 ParseError::Expected(msg)
304}
305
306fn validate(pattern: &MetaTemplate) -> Result<(), ParseError> { 298fn validate(pattern: &MetaTemplate) -> Result<(), ParseError> {
307 for op in pattern.iter() { 299 for op in pattern.iter() {
308 let op = op.as_ref().map_err(|e| to_parse_error(&e))?;
309
310 match op { 300 match op {
311 Op::Subtree(subtree) => validate(&subtree)?, 301 Op::Subtree(subtree) => validate(&subtree)?,
312 Op::Repeat { subtree, separator, .. } => { 302 Op::Repeat { subtree, separator, .. } => {
@@ -315,20 +305,21 @@ fn validate(pattern: &MetaTemplate) -> Result<(), ParseError> {
315 305
316 if separator.is_none() { 306 if separator.is_none() {
317 if subtree.iter().all(|child_op| { 307 if subtree.iter().all(|child_op| {
318 match child_op.as_ref().map_err(to_parse_error) { 308 match child_op {
319 Ok(Op::Var { kind, .. }) => { 309 Op::Var { kind, .. } => {
320 // vis is optional 310 // vis is optional
321 if kind.as_ref().map_or(false, |it| it == "vis") { 311 if kind.as_ref().map_or(false, |it| it == "vis") {
322 return true; 312 return true;
323 } 313 }
324 } 314 }
325 Ok(Op::Repeat { kind, .. }) => { 315 Op::Repeat { kind, .. } => {
326 return matches!( 316 return matches!(
327 kind, 317 kind,
328 parser::RepeatKind::ZeroOrMore | parser::RepeatKind::ZeroOrOne 318 parser::RepeatKind::ZeroOrMore | parser::RepeatKind::ZeroOrOne
329 ) 319 )
330 } 320 }
331 _ => {} 321 Op::Leaf(_) => {}
322 Op::Subtree(_) => {}
332 } 323 }
333 false 324 false
334 }) { 325 }) {
diff --git a/crates/mbe/src/parser.rs b/crates/mbe/src/parser.rs
index f3047972d..b90ae7015 100644
--- a/crates/mbe/src/parser.rs
+++ b/crates/mbe/src/parser.rs
@@ -4,7 +4,7 @@
4use smallvec::SmallVec; 4use smallvec::SmallVec;
5use syntax::SmolStr; 5use syntax::SmolStr;
6 6
7use crate::{tt_iter::TtIter, ExpandError, MetaTemplate}; 7use crate::{tt_iter::TtIter, MetaTemplate, ParseError};
8 8
9#[derive(Clone, Debug, PartialEq, Eq)] 9#[derive(Clone, Debug, PartialEq, Eq)]
10pub(crate) enum Op { 10pub(crate) enum Op {
@@ -46,12 +46,12 @@ impl PartialEq for Separator {
46 } 46 }
47} 47}
48 48
49pub(crate) fn parse_template(template: &tt::Subtree) -> Vec<Result<Op, ExpandError>> { 49pub(crate) fn parse_template(template: &tt::Subtree) -> Result<Vec<Op>, ParseError> {
50 parse_inner(&template, Mode::Template) 50 parse_inner(&template, Mode::Template).into_iter().collect()
51} 51}
52 52
53pub(crate) fn parse_pattern(pattern: &tt::Subtree) -> Vec<Result<Op, ExpandError>> { 53pub(crate) fn parse_pattern(pattern: &tt::Subtree) -> Result<Vec<Op>, ParseError> {
54 parse_inner(&pattern, Mode::Pattern) 54 parse_inner(&pattern, Mode::Pattern).into_iter().collect()
55} 55}
56 56
57#[derive(Clone, Copy)] 57#[derive(Clone, Copy)]
@@ -60,7 +60,7 @@ enum Mode {
60 Template, 60 Template,
61} 61}
62 62
63fn parse_inner(tt: &tt::Subtree, mode: Mode) -> Vec<Result<Op, ExpandError>> { 63fn parse_inner(tt: &tt::Subtree, mode: Mode) -> Vec<Result<Op, ParseError>> {
64 let mut src = TtIter::new(&tt); 64 let mut src = TtIter::new(&tt);
65 std::iter::from_fn(move || { 65 std::iter::from_fn(move || {
66 let first = src.next()?; 66 let first = src.next()?;
@@ -71,7 +71,7 @@ fn parse_inner(tt: &tt::Subtree, mode: Mode) -> Vec<Result<Op, ExpandError>> {
71 71
72macro_rules! err { 72macro_rules! err {
73 ($($tt:tt)*) => { 73 ($($tt:tt)*) => {
74 ExpandError::UnexpectedToken 74 ParseError::UnexpectedToken(($($tt)*).to_string())
75 }; 75 };
76} 76}
77 77
@@ -81,7 +81,7 @@ macro_rules! bail {
81 }; 81 };
82} 82}
83 83
84fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Result<Op, ExpandError> { 84fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Result<Op, ParseError> {
85 let res = match first { 85 let res = match first {
86 tt::TokenTree::Leaf(leaf @ tt::Leaf::Punct(tt::Punct { char: '$', .. })) => { 86 tt::TokenTree::Leaf(leaf @ tt::Leaf::Punct(tt::Punct { char: '$', .. })) => {
87 // Note that the '$' itself is a valid token inside macro_rules. 87 // Note that the '$' itself is a valid token inside macro_rules.
@@ -93,7 +93,9 @@ fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Resul
93 tt::TokenTree::Subtree(subtree) => { 93 tt::TokenTree::Subtree(subtree) => {
94 let (separator, kind) = parse_repeat(src)?; 94 let (separator, kind) = parse_repeat(src)?;
95 let delimiter = subtree.delimiter; 95 let delimiter = subtree.delimiter;
96 let tokens = parse_inner(&subtree, mode); 96 let tokens = parse_inner(&subtree, mode)
97 .into_iter()
98 .collect::<Result<Vec<Op>, ParseError>>()?;
97 let subtree = MetaTemplate { tokens, delimiter }; 99 let subtree = MetaTemplate { tokens, delimiter };
98 Op::Repeat { subtree, separator, kind } 100 Op::Repeat { subtree, separator, kind }
99 } 101 }
@@ -102,7 +104,7 @@ fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Resul
102 static UNDERSCORE: SmolStr = SmolStr::new_inline("_"); 104 static UNDERSCORE: SmolStr = SmolStr::new_inline("_");
103 105
104 if punct.char != '_' { 106 if punct.char != '_' {
105 return Err(ExpandError::UnexpectedToken); 107 return Err(ParseError::Expected("_".to_string()));
106 } 108 }
107 let name = UNDERSCORE.clone(); 109 let name = UNDERSCORE.clone();
108 let kind = eat_fragment_kind(src, mode)?; 110 let kind = eat_fragment_kind(src, mode)?;
@@ -135,7 +137,9 @@ fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Resul
135 tt::TokenTree::Leaf(tt) => Op::Leaf(tt.clone()), 137 tt::TokenTree::Leaf(tt) => Op::Leaf(tt.clone()),
136 tt::TokenTree::Subtree(subtree) => { 138 tt::TokenTree::Subtree(subtree) => {
137 let delimiter = subtree.delimiter; 139 let delimiter = subtree.delimiter;
138 let tokens = parse_inner(&subtree, mode); 140 let tokens =
141 parse_inner(&subtree, mode).into_iter().collect::<Result<Vec<Op>, ParseError>>()?;
142
139 let subtree = MetaTemplate { tokens, delimiter }; 143 let subtree = MetaTemplate { tokens, delimiter };
140 Op::Subtree(subtree) 144 Op::Subtree(subtree)
141 } 145 }
@@ -143,7 +147,7 @@ fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Resul
143 Ok(res) 147 Ok(res)
144} 148}
145 149
146fn eat_fragment_kind<'a>(src: &mut TtIter<'a>, mode: Mode) -> Result<Option<SmolStr>, ExpandError> { 150fn eat_fragment_kind<'a>(src: &mut TtIter<'a>, mode: Mode) -> Result<Option<SmolStr>, ParseError> {
147 if let Mode::Pattern = mode { 151 if let Mode::Pattern = mode {
148 src.expect_char(':').map_err(|()| err!("bad fragment specifier 1"))?; 152 src.expect_char(':').map_err(|()| err!("bad fragment specifier 1"))?;
149 let ident = src.expect_ident().map_err(|()| err!("bad fragment specifier 1"))?; 153 let ident = src.expect_ident().map_err(|()| err!("bad fragment specifier 1"))?;
@@ -156,12 +160,12 @@ fn is_boolean_literal(lit: &tt::Literal) -> bool {
156 matches!(lit.text.as_str(), "true" | "false") 160 matches!(lit.text.as_str(), "true" | "false")
157} 161}
158 162
159fn parse_repeat(src: &mut TtIter) -> Result<(Option<Separator>, RepeatKind), ExpandError> { 163fn parse_repeat(src: &mut TtIter) -> Result<(Option<Separator>, RepeatKind), ParseError> {
160 let mut separator = Separator::Puncts(SmallVec::new()); 164 let mut separator = Separator::Puncts(SmallVec::new());
161 for tt in src { 165 for tt in src {
162 let tt = match tt { 166 let tt = match tt {
163 tt::TokenTree::Leaf(leaf) => leaf, 167 tt::TokenTree::Leaf(leaf) => leaf,
164 tt::TokenTree::Subtree(_) => return Err(ExpandError::InvalidRepeat), 168 tt::TokenTree::Subtree(_) => return Err(ParseError::InvalidRepeat),
165 }; 169 };
166 let has_sep = match &separator { 170 let has_sep = match &separator {
167 Separator::Puncts(puncts) => !puncts.is_empty(), 171 Separator::Puncts(puncts) => !puncts.is_empty(),
@@ -169,7 +173,7 @@ fn parse_repeat(src: &mut TtIter) -> Result<(Option<Separator>, RepeatKind), Exp
169 }; 173 };
170 match tt { 174 match tt {
171 tt::Leaf::Ident(_) | tt::Leaf::Literal(_) if has_sep => { 175 tt::Leaf::Ident(_) | tt::Leaf::Literal(_) if has_sep => {
172 return Err(ExpandError::InvalidRepeat) 176 return Err(ParseError::InvalidRepeat)
173 } 177 }
174 tt::Leaf::Ident(ident) => separator = Separator::Ident(ident.clone()), 178 tt::Leaf::Ident(ident) => separator = Separator::Ident(ident.clone()),
175 tt::Leaf::Literal(lit) => separator = Separator::Literal(lit.clone()), 179 tt::Leaf::Literal(lit) => separator = Separator::Literal(lit.clone()),
@@ -182,11 +186,11 @@ fn parse_repeat(src: &mut TtIter) -> Result<(Option<Separator>, RepeatKind), Exp
182 match &mut separator { 186 match &mut separator {
183 Separator::Puncts(puncts) => { 187 Separator::Puncts(puncts) => {
184 if puncts.len() == 3 { 188 if puncts.len() == 3 {
185 return Err(ExpandError::InvalidRepeat); 189 return Err(ParseError::InvalidRepeat);
186 } 190 }
187 puncts.push(punct.clone()) 191 puncts.push(punct.clone())
188 } 192 }
189 _ => return Err(ExpandError::InvalidRepeat), 193 _ => return Err(ParseError::InvalidRepeat),
190 } 194 }
191 continue; 195 continue;
192 } 196 }
@@ -196,5 +200,5 @@ fn parse_repeat(src: &mut TtIter) -> Result<(Option<Separator>, RepeatKind), Exp
196 } 200 }
197 } 201 }
198 } 202 }
199 Err(ExpandError::InvalidRepeat) 203 Err(ParseError::InvalidRepeat)
200} 204}
diff --git a/crates/mbe/src/tests.rs b/crates/mbe/src/tests.rs
index 8d978163d..1c467facd 100644
--- a/crates/mbe/src/tests.rs
+++ b/crates/mbe/src/tests.rs
@@ -33,19 +33,18 @@ mod rule_parsing {
33 33
34 #[test] 34 #[test]
35 fn test_invalid_arms() { 35 fn test_invalid_arms() {
36 fn check(macro_body: &str, err: &str) { 36 fn check(macro_body: &str, err: ParseError) {
37 let m = parse_macro_arm(macro_body); 37 let m = parse_macro_arm(macro_body);
38 assert_eq!(m, Err(ParseError::Expected(String::from(err)))); 38 assert_eq!(m, Err(err.into()));
39 } 39 }
40 check("invalid", ParseError::Expected("expected subtree".into()));
40 41
41 check("invalid", "expected subtree"); 42 check("$i:ident => ()", ParseError::Expected("expected subtree".into()));
43 check("($i:ident) ()", ParseError::Expected("expected `=`".into()));
44 check("($($i:ident)_) => ()", ParseError::InvalidRepeat);
42 45
43 check("$i:ident => ()", "expected subtree"); 46 check("($i) => ($i)", ParseError::UnexpectedToken("bad fragment specifier 1".into()));
44 check("($i:ident) ()", "expected `=`"); 47 check("($i:) => ($i)", ParseError::UnexpectedToken("bad fragment specifier 1".into()));
45 check("($($i:ident)_) => ()", "invalid repeat");
46
47 check("($i) => ($i)", "invalid macro definition");
48 check("($i:) => ($i)", "invalid macro definition");
49 } 48 }
50 49
51 fn parse_macro_arm(arm_definition: &str) -> Result<crate::MacroRules, ParseError> { 50 fn parse_macro_arm(arm_definition: &str) -> Result<crate::MacroRules, ParseError> {