diff options
Diffstat (limited to 'crates/mbe')
-rw-r--r-- | crates/mbe/src/expander.rs (renamed from crates/mbe/src/mbe_expander.rs) | 9 | ||||
-rw-r--r-- | crates/mbe/src/expander/matcher.rs (renamed from crates/mbe/src/mbe_expander/matcher.rs) | 366 | ||||
-rw-r--r-- | crates/mbe/src/expander/transcriber.rs (renamed from crates/mbe/src/mbe_expander/transcriber.rs) | 25 | ||||
-rw-r--r-- | crates/mbe/src/lib.rs | 50 | ||||
-rw-r--r-- | crates/mbe/src/parser.rs | 52 | ||||
-rw-r--r-- | crates/mbe/src/tests.rs | 17 |
6 files changed, 243 insertions, 276 deletions
diff --git a/crates/mbe/src/mbe_expander.rs b/crates/mbe/src/expander.rs index 802c8fb0f..e7e14b3cc 100644 --- a/crates/mbe/src/mbe_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/mbe_expander/matcher.rs b/crates/mbe/src/expander/matcher.rs index d32e60521..800931cd1 100644 --- a/crates/mbe/src/mbe_expander/matcher.rs +++ b/crates/mbe/src/expander/matcher.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use crate::{ | 3 | use crate::{ |
4 | mbe_expander::{Binding, Bindings, Fragment}, | 4 | expander::{Binding, Bindings, Fragment}, |
5 | parser::{Op, RepeatKind, Separator}, | 5 | parser::{Op, RepeatKind, Separator}, |
6 | subtree_source::SubtreeTokenSource, | 6 | subtree_source::SubtreeTokenSource, |
7 | tt_iter::TtIter, | 7 | tt_iter::TtIter, |
@@ -70,69 +70,38 @@ pub(super) struct Match { | |||
70 | } | 70 | } |
71 | 71 | ||
72 | impl Match { | 72 | impl Match { |
73 | pub(super) fn add_err(&mut self, err: ExpandError) { | 73 | fn add_err(&mut self, err: ExpandError) { |
74 | let prev_err = self.err.take(); | 74 | let prev_err = self.err.take(); |
75 | self.err = prev_err.or(Some(err)); | 75 | self.err = prev_err.or(Some(err)); |
76 | self.err_count += 1; | 76 | self.err_count += 1; |
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 | 81 | pub(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 | |||
86 | pub(super) fn match_(pattern: &MetaTemplate, src: &tt::Subtree) -> Result<Match, ExpandError> { | ||
87 | assert!(pattern.delimiter == None); | ||
88 | |||
89 | let mut res = Match::default(); | 82 | let mut res = Match::default(); |
90 | let mut src = TtIter::new(src); | 83 | let mut src = TtIter::new(src); |
91 | 84 | ||
92 | match_subtree(&mut res, pattern, &mut src)?; | 85 | match_tokens(&mut res, pattern, &mut src); |
93 | 86 | ||
94 | if src.len() > 0 { | 87 | if src.len() > 0 { |
95 | res.unmatched_tts += src.len(); | 88 | res.unmatched_tts += src.len(); |
96 | res.add_err(err!("leftover tokens")); | 89 | res.add_err(err!("leftover tokens")); |
97 | } | 90 | } |
98 | 91 | ||
99 | Ok(res) | 92 | res |
100 | } | 93 | } |
101 | 94 | ||
102 | fn match_subtree( | 95 | fn match_tokens(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() { | 96 | for op in pattern.iter() { |
108 | match op.as_ref().map_err(|err| err.clone())? { | 97 | match op { |
109 | Op::Leaf(lhs) => { | 98 | Op::Leaf(lhs) => { |
110 | let rhs = match src.expect_leaf() { | 99 | if let Err(err) = match_leaf(lhs, src) { |
111 | Ok(l) => l, | 100 | res.add_err(err); |
112 | Err(()) => { | 101 | continue; |
113 | res.add_err(err!("expected leaf: `{}`", lhs)); | ||
114 | continue; | ||
115 | } | ||
116 | }; | ||
117 | match (lhs, rhs) { | ||
118 | ( | ||
119 | tt::Leaf::Punct(tt::Punct { char: lhs, .. }), | ||
120 | tt::Leaf::Punct(tt::Punct { char: rhs, .. }), | ||
121 | ) if lhs == rhs => (), | ||
122 | ( | ||
123 | tt::Leaf::Ident(tt::Ident { text: lhs, .. }), | ||
124 | tt::Leaf::Ident(tt::Ident { text: rhs, .. }), | ||
125 | ) if lhs == rhs => (), | ||
126 | ( | ||
127 | tt::Leaf::Literal(tt::Literal { text: lhs, .. }), | ||
128 | tt::Leaf::Literal(tt::Literal { text: rhs, .. }), | ||
129 | ) if lhs == rhs => (), | ||
130 | _ => { | ||
131 | res.add_err(ExpandError::UnexpectedToken); | ||
132 | } | ||
133 | } | 102 | } |
134 | } | 103 | } |
135 | Op::Subtree(lhs) => { | 104 | Op::Subtree { tokens, delimiter: delim } => { |
136 | let rhs = match src.expect_subtree() { | 105 | let rhs = match src.expect_subtree() { |
137 | Ok(s) => s, | 106 | Ok(s) => s, |
138 | Err(()) => { | 107 | Err(()) => { |
@@ -140,12 +109,12 @@ fn match_subtree( | |||
140 | continue; | 109 | continue; |
141 | } | 110 | } |
142 | }; | 111 | }; |
143 | if lhs.delimiter_kind() != rhs.delimiter_kind() { | 112 | if delim.map(|it| it.kind) != rhs.delimiter_kind() { |
144 | res.add_err(err!("mismatched delimiter")); | 113 | res.add_err(err!("mismatched delimiter")); |
145 | continue; | 114 | continue; |
146 | } | 115 | } |
147 | let mut src = TtIter::new(rhs); | 116 | let mut src = TtIter::new(rhs); |
148 | match_subtree(res, lhs, &mut src)?; | 117 | match_tokens(res, tokens, &mut src); |
149 | if src.len() > 0 { | 118 | if src.len() > 0 { |
150 | res.add_err(err!("leftover tokens")); | 119 | res.add_err(err!("leftover tokens")); |
151 | } | 120 | } |
@@ -171,14 +140,170 @@ fn match_subtree( | |||
171 | res.add_err(err); | 140 | res.add_err(err); |
172 | } | 141 | } |
173 | } | 142 | } |
174 | Op::Repeat { subtree, kind, separator } => { | 143 | Op::Repeat { tokens: subtree, kind, separator } => { |
175 | match_repeat(res, subtree, *kind, separator, src)?; | 144 | match_repeat(res, subtree, *kind, separator, src); |
176 | } | 145 | } |
177 | } | 146 | } |
178 | } | 147 | } |
148 | } | ||
149 | |||
150 | fn match_leaf(lhs: &tt::Leaf, src: &mut TtIter) -> Result<(), ExpandError> { | ||
151 | let rhs = match src.expect_leaf() { | ||
152 | Ok(l) => l, | ||
153 | Err(()) => { | ||
154 | return Err(err!("expected leaf: `{}`", lhs)); | ||
155 | } | ||
156 | }; | ||
157 | match (lhs, rhs) { | ||
158 | ( | ||
159 | tt::Leaf::Punct(tt::Punct { char: lhs, .. }), | ||
160 | tt::Leaf::Punct(tt::Punct { char: rhs, .. }), | ||
161 | ) if lhs == rhs => (), | ||
162 | ( | ||
163 | tt::Leaf::Ident(tt::Ident { text: lhs, .. }), | ||
164 | tt::Leaf::Ident(tt::Ident { text: rhs, .. }), | ||
165 | ) if lhs == rhs => (), | ||
166 | ( | ||
167 | tt::Leaf::Literal(tt::Literal { text: lhs, .. }), | ||
168 | tt::Leaf::Literal(tt::Literal { text: rhs, .. }), | ||
169 | ) if lhs == rhs => (), | ||
170 | _ => { | ||
171 | return Err(ExpandError::UnexpectedToken); | ||
172 | } | ||
173 | } | ||
174 | |||
179 | Ok(()) | 175 | Ok(()) |
180 | } | 176 | } |
181 | 177 | ||
178 | fn match_repeat( | ||
179 | res: &mut Match, | ||
180 | pattern: &MetaTemplate, | ||
181 | kind: RepeatKind, | ||
182 | separator: &Option<Separator>, | ||
183 | src: &mut TtIter, | ||
184 | ) { | ||
185 | // Dirty hack to make macro-expansion terminate. | ||
186 | // This should be replaced by a proper macro-by-example implementation | ||
187 | let mut limit = 65536; | ||
188 | let mut counter = 0; | ||
189 | |||
190 | for i in 0.. { | ||
191 | let mut fork = src.clone(); | ||
192 | |||
193 | if let Some(separator) = &separator { | ||
194 | if i != 0 && !fork.eat_separator(separator) { | ||
195 | break; | ||
196 | } | ||
197 | } | ||
198 | |||
199 | let mut nested = Match::default(); | ||
200 | match_tokens(&mut nested, pattern, &mut fork); | ||
201 | if nested.err.is_none() { | ||
202 | limit -= 1; | ||
203 | if limit == 0 { | ||
204 | log::warn!( | ||
205 | "match_lhs exceeded repeat pattern limit => {:#?}\n{:#?}\n{:#?}\n{:#?}", | ||
206 | pattern, | ||
207 | src, | ||
208 | kind, | ||
209 | separator | ||
210 | ); | ||
211 | break; | ||
212 | } | ||
213 | *src = fork; | ||
214 | |||
215 | if let Err(err) = res.bindings.push_nested(counter, nested.bindings) { | ||
216 | res.add_err(err); | ||
217 | } | ||
218 | counter += 1; | ||
219 | if counter == 1 { | ||
220 | if let RepeatKind::ZeroOrOne = kind { | ||
221 | break; | ||
222 | } | ||
223 | } | ||
224 | } else { | ||
225 | break; | ||
226 | } | ||
227 | } | ||
228 | |||
229 | match (kind, counter) { | ||
230 | (RepeatKind::OneOrMore, 0) => { | ||
231 | res.add_err(ExpandError::UnexpectedToken); | ||
232 | } | ||
233 | (_, 0) => { | ||
234 | // Collect all empty variables in subtrees | ||
235 | let mut vars = Vec::new(); | ||
236 | collect_vars(&mut vars, pattern); | ||
237 | for var in vars { | ||
238 | res.bindings.push_empty(&var) | ||
239 | } | ||
240 | } | ||
241 | _ => (), | ||
242 | } | ||
243 | } | ||
244 | |||
245 | fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult<Option<Fragment>> { | ||
246 | let fragment = match kind { | ||
247 | "path" => Path, | ||
248 | "expr" => Expr, | ||
249 | "ty" => Type, | ||
250 | "pat" => Pattern, | ||
251 | "stmt" => Statement, | ||
252 | "block" => Block, | ||
253 | "meta" => MetaItem, | ||
254 | "item" => Item, | ||
255 | _ => { | ||
256 | let tt_result = match kind { | ||
257 | "ident" => input | ||
258 | .expect_ident() | ||
259 | .map(|ident| Some(tt::Leaf::from(ident.clone()).into())) | ||
260 | .map_err(|()| err!("expected ident")), | ||
261 | "tt" => input.expect_tt().map(Some).map_err(|()| err!()), | ||
262 | "lifetime" => input | ||
263 | .expect_lifetime() | ||
264 | .map(|tt| Some(tt)) | ||
265 | .map_err(|()| err!("expected lifetime")), | ||
266 | "literal" => { | ||
267 | let neg = input.eat_char('-'); | ||
268 | input | ||
269 | .expect_literal() | ||
270 | .map(|literal| { | ||
271 | let lit = tt::Leaf::from(literal.clone()); | ||
272 | match neg { | ||
273 | None => Some(lit.into()), | ||
274 | Some(neg) => Some(tt::TokenTree::Subtree(tt::Subtree { | ||
275 | delimiter: None, | ||
276 | token_trees: vec![neg, lit.into()], | ||
277 | })), | ||
278 | } | ||
279 | }) | ||
280 | .map_err(|()| err!()) | ||
281 | } | ||
282 | // `vis` is optional | ||
283 | "vis" => match input.eat_vis() { | ||
284 | Some(vis) => Ok(Some(vis)), | ||
285 | None => Ok(None), | ||
286 | }, | ||
287 | _ => Err(ExpandError::UnexpectedToken), | ||
288 | }; | ||
289 | return tt_result.map(|it| it.map(Fragment::Tokens)).into(); | ||
290 | } | ||
291 | }; | ||
292 | let result = input.expect_fragment(fragment); | ||
293 | result.map(|tt| if kind == "expr" { tt.map(Fragment::Ast) } else { tt.map(Fragment::Tokens) }) | ||
294 | } | ||
295 | |||
296 | fn collect_vars(buf: &mut Vec<SmolStr>, pattern: &MetaTemplate) { | ||
297 | for op in pattern.iter() { | ||
298 | match op { | ||
299 | Op::Var { name, .. } => buf.push(name.clone()), | ||
300 | Op::Leaf(_) => (), | ||
301 | Op::Subtree { tokens, .. } => collect_vars(buf, tokens), | ||
302 | Op::Repeat { tokens, .. } => collect_vars(buf, tokens), | ||
303 | } | ||
304 | } | ||
305 | } | ||
306 | |||
182 | impl<'a> TtIter<'a> { | 307 | impl<'a> TtIter<'a> { |
183 | fn eat_separator(&mut self, separator: &Separator) -> bool { | 308 | fn eat_separator(&mut self, separator: &Separator) -> bool { |
184 | let mut fork = self.clone(); | 309 | let mut fork = self.clone(); |
@@ -206,7 +331,7 @@ impl<'a> TtIter<'a> { | |||
206 | ok | 331 | ok |
207 | } | 332 | } |
208 | 333 | ||
209 | pub(crate) fn expect_tt(&mut self) -> Result<tt::TokenTree, ()> { | 334 | fn expect_tt(&mut self) -> Result<tt::TokenTree, ()> { |
210 | match self.peek_n(0) { | 335 | match self.peek_n(0) { |
211 | Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) if punct.char == '\'' => { | 336 | Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) if punct.char == '\'' => { |
212 | return self.expect_lifetime(); | 337 | return self.expect_lifetime(); |
@@ -267,7 +392,7 @@ impl<'a> TtIter<'a> { | |||
267 | } | 392 | } |
268 | } | 393 | } |
269 | 394 | ||
270 | pub(crate) fn expect_lifetime(&mut self) -> Result<tt::TokenTree, ()> { | 395 | fn expect_lifetime(&mut self) -> Result<tt::TokenTree, ()> { |
271 | let punct = self.expect_punct()?; | 396 | let punct = self.expect_punct()?; |
272 | if punct.char != '\'' { | 397 | if punct.char != '\'' { |
273 | return Err(()); | 398 | return Err(()); |
@@ -284,13 +409,13 @@ impl<'a> TtIter<'a> { | |||
284 | .into()) | 409 | .into()) |
285 | } | 410 | } |
286 | 411 | ||
287 | pub(crate) fn expect_fragment( | 412 | fn expect_fragment( |
288 | &mut self, | 413 | &mut self, |
289 | fragment_kind: parser::FragmentKind, | 414 | fragment_kind: parser::FragmentKind, |
290 | ) -> ExpandResult<Option<tt::TokenTree>> { | 415 | ) -> ExpandResult<Option<tt::TokenTree>> { |
291 | pub(crate) struct OffsetTokenSink<'a> { | 416 | struct OffsetTokenSink<'a> { |
292 | pub(crate) cursor: Cursor<'a>, | 417 | cursor: Cursor<'a>, |
293 | pub(crate) error: bool, | 418 | error: bool, |
294 | } | 419 | } |
295 | 420 | ||
296 | impl<'a> TreeSink for OffsetTokenSink<'a> { | 421 | impl<'a> TreeSink for OffsetTokenSink<'a> { |
@@ -346,7 +471,7 @@ impl<'a> TtIter<'a> { | |||
346 | ExpandResult { value: res, err } | 471 | ExpandResult { value: res, err } |
347 | } | 472 | } |
348 | 473 | ||
349 | pub(crate) fn eat_vis(&mut self) -> Option<tt::TokenTree> { | 474 | fn eat_vis(&mut self) -> Option<tt::TokenTree> { |
350 | let mut fork = self.clone(); | 475 | let mut fork = self.clone(); |
351 | match fork.expect_fragment(Visibility) { | 476 | match fork.expect_fragment(Visibility) { |
352 | ExpandResult { value: tt, err: None } => { | 477 | ExpandResult { value: tt, err: None } => { |
@@ -357,7 +482,7 @@ impl<'a> TtIter<'a> { | |||
357 | } | 482 | } |
358 | } | 483 | } |
359 | 484 | ||
360 | pub(crate) fn eat_char(&mut self, c: char) -> Option<tt::TokenTree> { | 485 | fn eat_char(&mut self, c: char) -> Option<tt::TokenTree> { |
361 | let mut fork = self.clone(); | 486 | let mut fork = self.clone(); |
362 | match fork.expect_char(c) { | 487 | match fork.expect_char(c) { |
363 | Ok(_) => { | 488 | Ok(_) => { |
@@ -369,134 +494,3 @@ impl<'a> TtIter<'a> { | |||
369 | } | 494 | } |
370 | } | 495 | } |
371 | } | 496 | } |
372 | |||
373 | pub(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 | |||
441 | fn 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 | |||
492 | fn 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/mbe_expander/transcriber.rs b/crates/mbe/src/expander/transcriber.rs index 59a3c80a8..78368a33e 100644 --- a/crates/mbe/src/mbe_expander/transcriber.rs +++ b/crates/mbe/src/expander/transcriber.rs | |||
@@ -2,10 +2,11 @@ | |||
2 | //! `$ident => foo`, interpolates variables in the template, to get `fn foo() {}` | 2 | //! `$ident => foo`, interpolates variables in the template, to get `fn foo() {}` |
3 | 3 | ||
4 | use syntax::SmolStr; | 4 | use syntax::SmolStr; |
5 | use tt::Delimiter; | ||
5 | 6 | ||
6 | use super::ExpandResult; | 7 | use super::ExpandResult; |
7 | use crate::{ | 8 | use crate::{ |
8 | mbe_expander::{Binding, Bindings, Fragment}, | 9 | expander::{Binding, Bindings, Fragment}, |
9 | parser::{Op, RepeatKind, Separator}, | 10 | parser::{Op, RepeatKind, Separator}, |
10 | ExpandError, MetaTemplate, | 11 | ExpandError, MetaTemplate, |
11 | }; | 12 | }; |
@@ -54,10 +55,9 @@ pub(super) fn transcribe( | |||
54 | template: &MetaTemplate, | 55 | template: &MetaTemplate, |
55 | bindings: &Bindings, | 56 | bindings: &Bindings, |
56 | ) -> ExpandResult<tt::Subtree> { | 57 | ) -> ExpandResult<tt::Subtree> { |
57 | assert!(template.delimiter == None); | ||
58 | let mut ctx = ExpandCtx { bindings: &bindings, nesting: Vec::new() }; | 58 | let mut ctx = ExpandCtx { bindings: &bindings, nesting: Vec::new() }; |
59 | let mut arena: Vec<tt::TokenTree> = Vec::new(); | 59 | let mut arena: Vec<tt::TokenTree> = Vec::new(); |
60 | expand_subtree(&mut ctx, template, &mut arena) | 60 | expand_subtree(&mut ctx, template, None, &mut arena) |
61 | } | 61 | } |
62 | 62 | ||
63 | #[derive(Debug)] | 63 | #[derive(Debug)] |
@@ -80,23 +80,18 @@ struct ExpandCtx<'a> { | |||
80 | fn expand_subtree( | 80 | fn expand_subtree( |
81 | ctx: &mut ExpandCtx, | 81 | ctx: &mut ExpandCtx, |
82 | template: &MetaTemplate, | 82 | template: &MetaTemplate, |
83 | delimiter: Option<Delimiter>, | ||
83 | arena: &mut Vec<tt::TokenTree>, | 84 | arena: &mut Vec<tt::TokenTree>, |
84 | ) -> ExpandResult<tt::Subtree> { | 85 | ) -> ExpandResult<tt::Subtree> { |
85 | // remember how many elements are in the arena now - when returning, we want to drain exactly how many elements we added. This way, the recursive uses of the arena get their own "view" of the arena, but will reuse the allocation | 86 | // remember how many elements are in the arena now - when returning, we want to drain exactly how many elements we added. This way, the recursive uses of the arena get their own "view" of the arena, but will reuse the allocation |
86 | let start_elements = arena.len(); | 87 | let start_elements = arena.len(); |
87 | let mut err = None; | 88 | let mut err = None; |
88 | for op in template.iter() { | 89 | 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 { | 90 | match op { |
97 | Op::Leaf(tt) => arena.push(tt.clone().into()), | 91 | Op::Leaf(tt) => arena.push(tt.clone().into()), |
98 | Op::Subtree(tt) => { | 92 | Op::Subtree { tokens, delimiter } => { |
99 | let ExpandResult { value: tt, err: e } = expand_subtree(ctx, &tt, arena); | 93 | let ExpandResult { value: tt, err: e } = |
94 | expand_subtree(ctx, &tokens, *delimiter, arena); | ||
100 | err = err.or(e); | 95 | err = err.or(e); |
101 | arena.push(tt.into()); | 96 | arena.push(tt.into()); |
102 | } | 97 | } |
@@ -105,7 +100,7 @@ fn expand_subtree( | |||
105 | err = err.or(e); | 100 | err = err.or(e); |
106 | push_fragment(arena, fragment); | 101 | push_fragment(arena, fragment); |
107 | } | 102 | } |
108 | Op::Repeat { subtree, kind, separator } => { | 103 | Op::Repeat { tokens: subtree, kind, separator } => { |
109 | let ExpandResult { value: fragment, err: e } = | 104 | let ExpandResult { value: fragment, err: e } = |
110 | expand_repeat(ctx, subtree, *kind, separator, arena); | 105 | expand_repeat(ctx, subtree, *kind, separator, arena); |
111 | err = err.or(e); | 106 | err = err.or(e); |
@@ -115,7 +110,7 @@ fn expand_subtree( | |||
115 | } | 110 | } |
116 | // drain the elements added in this instance of expand_subtree | 111 | // drain the elements added in this instance of expand_subtree |
117 | let tts = arena.drain(start_elements..arena.len()).collect(); | 112 | let tts = arena.drain(start_elements..arena.len()).collect(); |
118 | ExpandResult { value: tt::Subtree { delimiter: template.delimiter, token_trees: tts }, err } | 113 | ExpandResult { value: tt::Subtree { delimiter, token_trees: tts }, err } |
119 | } | 114 | } |
120 | 115 | ||
121 | fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr, id: tt::TokenId) -> ExpandResult<Fragment> { | 116 | fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr, id: tt::TokenId) -> ExpandResult<Fragment> { |
@@ -169,7 +164,7 @@ fn expand_repeat( | |||
169 | let mut counter = 0; | 164 | let mut counter = 0; |
170 | 165 | ||
171 | loop { | 166 | loop { |
172 | let ExpandResult { value: mut t, err: e } = expand_subtree(ctx, template, arena); | 167 | let ExpandResult { value: mut t, err: e } = expand_subtree(ctx, template, None, arena); |
173 | let nesting_state = ctx.nesting.last_mut().unwrap(); | 168 | let nesting_state = ctx.nesting.last_mut().unwrap(); |
174 | if nesting_state.at_end || !nesting_state.hit { | 169 | if nesting_state.at_end || !nesting_state.hit { |
175 | break; | 170 | break; |
diff --git a/crates/mbe/src/lib.rs b/crates/mbe/src/lib.rs index 35cde5f10..d80bd7a33 100644 --- a/crates/mbe/src/lib.rs +++ b/crates/mbe/src/lib.rs | |||
@@ -4,7 +4,7 @@ | |||
4 | //! `TokenTree`s as well! | 4 | //! `TokenTree`s as well! |
5 | 5 | ||
6 | mod parser; | 6 | mod parser; |
7 | mod mbe_expander; | 7 | mod expander; |
8 | mod syntax_bridge; | 8 | mod syntax_bridge; |
9 | mod tt_iter; | 9 | mod tt_iter; |
10 | mod subtree_source; | 10 | mod subtree_source; |
@@ -24,7 +24,9 @@ use crate::{ | |||
24 | 24 | ||
25 | #[derive(Debug, PartialEq, Eq)] | 25 | #[derive(Debug, PartialEq, Eq)] |
26 | pub enum ParseError { | 26 | pub 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), |
@@ -92,18 +92,11 @@ struct Rule { | |||
92 | } | 92 | } |
93 | 93 | ||
94 | #[derive(Clone, Debug, PartialEq, Eq)] | 94 | #[derive(Clone, Debug, PartialEq, Eq)] |
95 | struct MetaTemplate { | 95 | struct MetaTemplate(Vec<Op>); |
96 | delimiter: Option<Delimiter>, | ||
97 | tokens: Vec<Result<Op, ExpandError>>, | ||
98 | } | ||
99 | 96 | ||
100 | impl<'a> MetaTemplate { | 97 | impl<'a> MetaTemplate { |
101 | fn iter(&self) -> impl Iterator<Item = &Result<Op, ExpandError>> { | 98 | fn iter(&self) -> impl Iterator<Item = &Op> { |
102 | self.tokens.iter() | 99 | self.0.iter() |
103 | } | ||
104 | |||
105 | fn delimiter_kind(&self) -> Option<DelimiterKind> { | ||
106 | self.delimiter.map(|it| it.kind) | ||
107 | } | 100 | } |
108 | } | 101 | } |
109 | 102 | ||
@@ -209,7 +202,7 @@ impl MacroRules { | |||
209 | // apply shift | 202 | // apply shift |
210 | let mut tt = tt.clone(); | 203 | let mut tt = tt.clone(); |
211 | self.shift.shift_all(&mut tt); | 204 | self.shift.shift_all(&mut tt); |
212 | mbe_expander::expand_rules(&self.rules, &tt) | 205 | expander::expand_rules(&self.rules, &tt) |
213 | } | 206 | } |
214 | 207 | ||
215 | pub fn map_id_down(&self, id: tt::TokenId) -> tt::TokenId { | 208 | pub fn map_id_down(&self, id: tt::TokenId) -> tt::TokenId { |
@@ -260,7 +253,7 @@ impl MacroDef { | |||
260 | // apply shift | 253 | // apply shift |
261 | let mut tt = tt.clone(); | 254 | let mut tt = tt.clone(); |
262 | self.shift.shift_all(&mut tt); | 255 | self.shift.shift_all(&mut tt); |
263 | mbe_expander::expand_rules(&self.rules, &tt) | 256 | expander::expand_rules(&self.rules, &tt) |
264 | } | 257 | } |
265 | 258 | ||
266 | pub fn map_id_down(&self, id: tt::TokenId) -> tt::TokenId { | 259 | pub fn map_id_down(&self, id: tt::TokenId) -> tt::TokenId { |
@@ -288,47 +281,38 @@ impl Rule { | |||
288 | .expect_subtree() | 281 | .expect_subtree() |
289 | .map_err(|()| ParseError::Expected("expected subtree".to_string()))?; | 282 | .map_err(|()| ParseError::Expected("expected subtree".to_string()))?; |
290 | 283 | ||
291 | let lhs = MetaTemplate { tokens: parse_pattern(&lhs), delimiter: None }; | 284 | let lhs = MetaTemplate(parse_pattern(&lhs)?); |
292 | let rhs = MetaTemplate { tokens: parse_template(&rhs), delimiter: None }; | 285 | let rhs = MetaTemplate(parse_template(&rhs)?); |
293 | 286 | ||
294 | Ok(crate::Rule { lhs, rhs }) | 287 | Ok(crate::Rule { lhs, rhs }) |
295 | } | 288 | } |
296 | } | 289 | } |
297 | 290 | ||
298 | fn 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 | |||
306 | fn validate(pattern: &MetaTemplate) -> Result<(), ParseError> { | 291 | fn validate(pattern: &MetaTemplate) -> Result<(), ParseError> { |
307 | for op in pattern.iter() { | 292 | for op in pattern.iter() { |
308 | let op = op.as_ref().map_err(|e| to_parse_error(&e))?; | ||
309 | |||
310 | match op { | 293 | match op { |
311 | Op::Subtree(subtree) => validate(&subtree)?, | 294 | Op::Subtree { tokens, .. } => validate(&tokens)?, |
312 | Op::Repeat { subtree, separator, .. } => { | 295 | Op::Repeat { tokens: subtree, separator, .. } => { |
313 | // Checks that no repetition which could match an empty token | 296 | // Checks that no repetition which could match an empty token |
314 | // https://github.com/rust-lang/rust/blob/a58b1ed44f5e06976de2bdc4d7dc81c36a96934f/src/librustc_expand/mbe/macro_rules.rs#L558 | 297 | // https://github.com/rust-lang/rust/blob/a58b1ed44f5e06976de2bdc4d7dc81c36a96934f/src/librustc_expand/mbe/macro_rules.rs#L558 |
315 | 298 | ||
316 | if separator.is_none() { | 299 | if separator.is_none() { |
317 | if subtree.iter().all(|child_op| { | 300 | if subtree.iter().all(|child_op| { |
318 | match child_op.as_ref().map_err(to_parse_error) { | 301 | match child_op { |
319 | Ok(Op::Var { kind, .. }) => { | 302 | Op::Var { kind, .. } => { |
320 | // vis is optional | 303 | // vis is optional |
321 | if kind.as_ref().map_or(false, |it| it == "vis") { | 304 | if kind.as_ref().map_or(false, |it| it == "vis") { |
322 | return true; | 305 | return true; |
323 | } | 306 | } |
324 | } | 307 | } |
325 | Ok(Op::Repeat { kind, .. }) => { | 308 | Op::Repeat { kind, .. } => { |
326 | return matches!( | 309 | return matches!( |
327 | kind, | 310 | kind, |
328 | parser::RepeatKind::ZeroOrMore | parser::RepeatKind::ZeroOrOne | 311 | parser::RepeatKind::ZeroOrMore | parser::RepeatKind::ZeroOrOne |
329 | ) | 312 | ) |
330 | } | 313 | } |
331 | _ => {} | 314 | Op::Leaf(_) => {} |
315 | Op::Subtree { .. } => {} | ||
332 | } | 316 | } |
333 | false | 317 | false |
334 | }) { | 318 | }) { |
diff --git a/crates/mbe/src/parser.rs b/crates/mbe/src/parser.rs index f3047972d..f891ec29c 100644 --- a/crates/mbe/src/parser.rs +++ b/crates/mbe/src/parser.rs | |||
@@ -3,15 +3,16 @@ | |||
3 | 3 | ||
4 | use smallvec::SmallVec; | 4 | use smallvec::SmallVec; |
5 | use syntax::SmolStr; | 5 | use syntax::SmolStr; |
6 | use tt::Delimiter; | ||
6 | 7 | ||
7 | use crate::{tt_iter::TtIter, ExpandError, MetaTemplate}; | 8 | use crate::{tt_iter::TtIter, MetaTemplate, ParseError}; |
8 | 9 | ||
9 | #[derive(Clone, Debug, PartialEq, Eq)] | 10 | #[derive(Clone, Debug, PartialEq, Eq)] |
10 | pub(crate) enum Op { | 11 | pub(crate) enum Op { |
11 | Var { name: SmolStr, kind: Option<SmolStr>, id: tt::TokenId }, | 12 | Var { name: SmolStr, kind: Option<SmolStr>, id: tt::TokenId }, |
12 | Repeat { subtree: MetaTemplate, kind: RepeatKind, separator: Option<Separator> }, | 13 | Repeat { tokens: MetaTemplate, kind: RepeatKind, separator: Option<Separator> }, |
13 | Leaf(tt::Leaf), | 14 | Leaf(tt::Leaf), |
14 | Subtree(MetaTemplate), | 15 | Subtree { tokens: MetaTemplate, delimiter: Option<Delimiter> }, |
15 | } | 16 | } |
16 | 17 | ||
17 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] | 18 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
@@ -46,12 +47,12 @@ impl PartialEq for Separator { | |||
46 | } | 47 | } |
47 | } | 48 | } |
48 | 49 | ||
49 | pub(crate) fn parse_template(template: &tt::Subtree) -> Vec<Result<Op, ExpandError>> { | 50 | pub(crate) fn parse_template(template: &tt::Subtree) -> Result<Vec<Op>, ParseError> { |
50 | parse_inner(&template, Mode::Template) | 51 | parse_inner(&template, Mode::Template).into_iter().collect() |
51 | } | 52 | } |
52 | 53 | ||
53 | pub(crate) fn parse_pattern(pattern: &tt::Subtree) -> Vec<Result<Op, ExpandError>> { | 54 | pub(crate) fn parse_pattern(pattern: &tt::Subtree) -> Result<Vec<Op>, ParseError> { |
54 | parse_inner(&pattern, Mode::Pattern) | 55 | parse_inner(&pattern, Mode::Pattern).into_iter().collect() |
55 | } | 56 | } |
56 | 57 | ||
57 | #[derive(Clone, Copy)] | 58 | #[derive(Clone, Copy)] |
@@ -60,7 +61,7 @@ enum Mode { | |||
60 | Template, | 61 | Template, |
61 | } | 62 | } |
62 | 63 | ||
63 | fn parse_inner(tt: &tt::Subtree, mode: Mode) -> Vec<Result<Op, ExpandError>> { | 64 | fn parse_inner(tt: &tt::Subtree, mode: Mode) -> Vec<Result<Op, ParseError>> { |
64 | let mut src = TtIter::new(&tt); | 65 | let mut src = TtIter::new(&tt); |
65 | std::iter::from_fn(move || { | 66 | std::iter::from_fn(move || { |
66 | let first = src.next()?; | 67 | let first = src.next()?; |
@@ -71,7 +72,7 @@ fn parse_inner(tt: &tt::Subtree, mode: Mode) -> Vec<Result<Op, ExpandError>> { | |||
71 | 72 | ||
72 | macro_rules! err { | 73 | macro_rules! err { |
73 | ($($tt:tt)*) => { | 74 | ($($tt:tt)*) => { |
74 | ExpandError::UnexpectedToken | 75 | ParseError::UnexpectedToken(($($tt)*).to_string()) |
75 | }; | 76 | }; |
76 | } | 77 | } |
77 | 78 | ||
@@ -81,7 +82,7 @@ macro_rules! bail { | |||
81 | }; | 82 | }; |
82 | } | 83 | } |
83 | 84 | ||
84 | fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Result<Op, ExpandError> { | 85 | fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Result<Op, ParseError> { |
85 | let res = match first { | 86 | let res = match first { |
86 | tt::TokenTree::Leaf(leaf @ tt::Leaf::Punct(tt::Punct { char: '$', .. })) => { | 87 | tt::TokenTree::Leaf(leaf @ tt::Leaf::Punct(tt::Punct { char: '$', .. })) => { |
87 | // Note that the '$' itself is a valid token inside macro_rules. | 88 | // Note that the '$' itself is a valid token inside macro_rules. |
@@ -92,17 +93,17 @@ fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Resul | |||
92 | match second { | 93 | match second { |
93 | tt::TokenTree::Subtree(subtree) => { | 94 | tt::TokenTree::Subtree(subtree) => { |
94 | let (separator, kind) = parse_repeat(src)?; | 95 | let (separator, kind) = parse_repeat(src)?; |
95 | let delimiter = subtree.delimiter; | 96 | let tokens = parse_inner(&subtree, mode) |
96 | let tokens = parse_inner(&subtree, mode); | 97 | .into_iter() |
97 | let subtree = MetaTemplate { tokens, delimiter }; | 98 | .collect::<Result<Vec<Op>, ParseError>>()?; |
98 | Op::Repeat { subtree, separator, kind } | 99 | Op::Repeat { tokens: MetaTemplate(tokens), separator, kind } |
99 | } | 100 | } |
100 | tt::TokenTree::Leaf(leaf) => match leaf { | 101 | tt::TokenTree::Leaf(leaf) => match leaf { |
101 | tt::Leaf::Punct(punct) => { | 102 | tt::Leaf::Punct(punct) => { |
102 | static UNDERSCORE: SmolStr = SmolStr::new_inline("_"); | 103 | static UNDERSCORE: SmolStr = SmolStr::new_inline("_"); |
103 | 104 | ||
104 | if punct.char != '_' { | 105 | if punct.char != '_' { |
105 | return Err(ExpandError::UnexpectedToken); | 106 | return Err(ParseError::Expected("_".to_string())); |
106 | } | 107 | } |
107 | let name = UNDERSCORE.clone(); | 108 | let name = UNDERSCORE.clone(); |
108 | let kind = eat_fragment_kind(src, mode)?; | 109 | let kind = eat_fragment_kind(src, mode)?; |
@@ -134,16 +135,15 @@ fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Resul | |||
134 | } | 135 | } |
135 | tt::TokenTree::Leaf(tt) => Op::Leaf(tt.clone()), | 136 | tt::TokenTree::Leaf(tt) => Op::Leaf(tt.clone()), |
136 | tt::TokenTree::Subtree(subtree) => { | 137 | tt::TokenTree::Subtree(subtree) => { |
137 | let delimiter = subtree.delimiter; | 138 | let tokens = |
138 | let tokens = parse_inner(&subtree, mode); | 139 | parse_inner(&subtree, mode).into_iter().collect::<Result<Vec<Op>, ParseError>>()?; |
139 | let subtree = MetaTemplate { tokens, delimiter }; | 140 | Op::Subtree { tokens: MetaTemplate(tokens), delimiter: subtree.delimiter } |
140 | Op::Subtree(subtree) | ||
141 | } | 141 | } |
142 | }; | 142 | }; |
143 | Ok(res) | 143 | Ok(res) |
144 | } | 144 | } |
145 | 145 | ||
146 | fn eat_fragment_kind<'a>(src: &mut TtIter<'a>, mode: Mode) -> Result<Option<SmolStr>, ExpandError> { | 146 | fn eat_fragment_kind<'a>(src: &mut TtIter<'a>, mode: Mode) -> Result<Option<SmolStr>, ParseError> { |
147 | if let Mode::Pattern = mode { | 147 | if let Mode::Pattern = mode { |
148 | src.expect_char(':').map_err(|()| err!("bad fragment specifier 1"))?; | 148 | src.expect_char(':').map_err(|()| err!("bad fragment specifier 1"))?; |
149 | let ident = src.expect_ident().map_err(|()| err!("bad fragment specifier 1"))?; | 149 | let ident = src.expect_ident().map_err(|()| err!("bad fragment specifier 1"))?; |
@@ -156,12 +156,12 @@ fn is_boolean_literal(lit: &tt::Literal) -> bool { | |||
156 | matches!(lit.text.as_str(), "true" | "false") | 156 | matches!(lit.text.as_str(), "true" | "false") |
157 | } | 157 | } |
158 | 158 | ||
159 | fn parse_repeat(src: &mut TtIter) -> Result<(Option<Separator>, RepeatKind), ExpandError> { | 159 | fn parse_repeat(src: &mut TtIter) -> Result<(Option<Separator>, RepeatKind), ParseError> { |
160 | let mut separator = Separator::Puncts(SmallVec::new()); | 160 | let mut separator = Separator::Puncts(SmallVec::new()); |
161 | for tt in src { | 161 | for tt in src { |
162 | let tt = match tt { | 162 | let tt = match tt { |
163 | tt::TokenTree::Leaf(leaf) => leaf, | 163 | tt::TokenTree::Leaf(leaf) => leaf, |
164 | tt::TokenTree::Subtree(_) => return Err(ExpandError::InvalidRepeat), | 164 | tt::TokenTree::Subtree(_) => return Err(ParseError::InvalidRepeat), |
165 | }; | 165 | }; |
166 | let has_sep = match &separator { | 166 | let has_sep = match &separator { |
167 | Separator::Puncts(puncts) => !puncts.is_empty(), | 167 | Separator::Puncts(puncts) => !puncts.is_empty(), |
@@ -169,7 +169,7 @@ fn parse_repeat(src: &mut TtIter) -> Result<(Option<Separator>, RepeatKind), Exp | |||
169 | }; | 169 | }; |
170 | match tt { | 170 | match tt { |
171 | tt::Leaf::Ident(_) | tt::Leaf::Literal(_) if has_sep => { | 171 | tt::Leaf::Ident(_) | tt::Leaf::Literal(_) if has_sep => { |
172 | return Err(ExpandError::InvalidRepeat) | 172 | return Err(ParseError::InvalidRepeat) |
173 | } | 173 | } |
174 | tt::Leaf::Ident(ident) => separator = Separator::Ident(ident.clone()), | 174 | tt::Leaf::Ident(ident) => separator = Separator::Ident(ident.clone()), |
175 | tt::Leaf::Literal(lit) => separator = Separator::Literal(lit.clone()), | 175 | tt::Leaf::Literal(lit) => separator = Separator::Literal(lit.clone()), |
@@ -182,11 +182,11 @@ fn parse_repeat(src: &mut TtIter) -> Result<(Option<Separator>, RepeatKind), Exp | |||
182 | match &mut separator { | 182 | match &mut separator { |
183 | Separator::Puncts(puncts) => { | 183 | Separator::Puncts(puncts) => { |
184 | if puncts.len() == 3 { | 184 | if puncts.len() == 3 { |
185 | return Err(ExpandError::InvalidRepeat); | 185 | return Err(ParseError::InvalidRepeat); |
186 | } | 186 | } |
187 | puncts.push(punct.clone()) | 187 | puncts.push(punct.clone()) |
188 | } | 188 | } |
189 | _ => return Err(ExpandError::InvalidRepeat), | 189 | _ => return Err(ParseError::InvalidRepeat), |
190 | } | 190 | } |
191 | continue; | 191 | continue; |
192 | } | 192 | } |
@@ -196,5 +196,5 @@ fn parse_repeat(src: &mut TtIter) -> Result<(Option<Separator>, RepeatKind), Exp | |||
196 | } | 196 | } |
197 | } | 197 | } |
198 | } | 198 | } |
199 | Err(ExpandError::InvalidRepeat) | 199 | Err(ParseError::InvalidRepeat) |
200 | } | 200 | } |
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> { |