diff options
author | Edwin Cheng <[email protected]> | 2021-01-29 16:21:43 +0000 |
---|---|---|
committer | Edwin Cheng <[email protected]> | 2021-01-29 16:21:43 +0000 |
commit | 706ac8256d878626126756969b48b262d2e187b5 (patch) | |
tree | 8adb77484d4563ad61fc76ed9796d38a42a161e8 /crates/mbe/src/expander | |
parent | 3ecd5112bbc2cc1a45f423e0256230507f159162 (diff) |
Simplify mbe match error.
Handle parse error in rule parsing instead of match in mbe
Diffstat (limited to 'crates/mbe/src/expander')
-rw-r--r-- | crates/mbe/src/expander/matcher.rs | 286 | ||||
-rw-r--r-- | crates/mbe/src/expander/transcriber.rs | 7 |
2 files changed, 137 insertions, 156 deletions
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 | 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); | 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 | ||
102 | fn match_subtree( | 97 | fn 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 | |||
172 | pub(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 | |||
239 | fn 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 | |||
290 | fn 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 | ||
182 | impl<'a> TtIter<'a> { | 301 | impl<'a> TtIter<'a> { |
@@ -369,134 +488,3 @@ impl<'a> TtIter<'a> { | |||
369 | } | 488 | } |
370 | } | 489 | } |
371 | } | 490 | } |
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/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) => { |