aboutsummaryrefslogtreecommitdiff
path: root/crates/mbe/src/expander
diff options
context:
space:
mode:
authorEdwin Cheng <[email protected]>2021-01-29 16:21:43 +0000
committerEdwin Cheng <[email protected]>2021-01-29 16:21:43 +0000
commit706ac8256d878626126756969b48b262d2e187b5 (patch)
tree8adb77484d4563ad61fc76ed9796d38a42a161e8 /crates/mbe/src/expander
parent3ecd5112bbc2cc1a45f423e0256230507f159162 (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.rs286
-rw-r--r--crates/mbe/src/expander/transcriber.rs7
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 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) => {