aboutsummaryrefslogtreecommitdiff
path: root/crates/mbe/src/mbe_expander/matcher.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/mbe/src/mbe_expander/matcher.rs')
-rw-r--r--crates/mbe/src/mbe_expander/matcher.rs477
1 files changed, 477 insertions, 0 deletions
diff --git a/crates/mbe/src/mbe_expander/matcher.rs b/crates/mbe/src/mbe_expander/matcher.rs
new file mode 100644
index 000000000..b698b9832
--- /dev/null
+++ b/crates/mbe/src/mbe_expander/matcher.rs
@@ -0,0 +1,477 @@
1//! FIXME: write short doc here
2
3use crate::{
4 mbe_expander::{Binding, Bindings, Fragment},
5 parser::{parse_pattern, Op, RepeatKind, Separator},
6 subtree_source::SubtreeTokenSource,
7 tt_iter::TtIter,
8 ExpandError,
9};
10
11use super::ExpandResult;
12use parser::{FragmentKind::*, TreeSink};
13use syntax::{SmolStr, SyntaxKind};
14use tt::buffer::{Cursor, TokenBuffer};
15
16impl Bindings {
17 fn push_optional(&mut self, name: &SmolStr) {
18 // FIXME: Do we have a better way to represent an empty token ?
19 // Insert an empty subtree for empty token
20 let tt = tt::Subtree::default().into();
21 self.inner.insert(name.clone(), Binding::Fragment(Fragment::Tokens(tt)));
22 }
23
24 fn push_empty(&mut self, name: &SmolStr) {
25 self.inner.insert(name.clone(), Binding::Empty);
26 }
27
28 fn push_nested(&mut self, idx: usize, nested: Bindings) -> Result<(), ExpandError> {
29 for (key, value) in nested.inner {
30 if !self.inner.contains_key(&key) {
31 self.inner.insert(key.clone(), Binding::Nested(Vec::new()));
32 }
33 match self.inner.get_mut(&key) {
34 Some(Binding::Nested(it)) => {
35 // insert empty nested bindings before this one
36 while it.len() < idx {
37 it.push(Binding::Nested(vec![]));
38 }
39 it.push(value);
40 }
41 _ => {
42 return Err(ExpandError::BindingError(format!(
43 "could not find binding `{}`",
44 key
45 )));
46 }
47 }
48 }
49 Ok(())
50 }
51}
52
53macro_rules! err {
54 () => {
55 ExpandError::BindingError(format!(""))
56 };
57 ($($tt:tt)*) => {
58 ExpandError::BindingError(format!($($tt)*))
59 };
60}
61
62#[derive(Debug, Default)]
63pub(super) struct Match {
64 pub bindings: Bindings,
65 /// We currently just keep the first error and count the rest to compare matches.
66 pub err: Option<ExpandError>,
67 pub err_count: usize,
68 /// How many top-level token trees were left to match.
69 pub unmatched_tts: usize,
70}
71
72impl Match {
73 pub fn add_err(&mut self, err: ExpandError) {
74 let prev_err = self.err.take();
75 self.err = prev_err.or(Some(err));
76 self.err_count += 1;
77 }
78}
79
80// General note: These functions have two channels to return errors, a `Result`
81// return value and the `&mut Match`. The returned Result is for pattern parsing
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: &tt::Subtree, src: &tt::Subtree) -> Result<Match, ExpandError> {
87 assert!(pattern.delimiter == None);
88
89 let mut res = Match::default();
90 let mut src = TtIter::new(src);
91
92 match_subtree(&mut res, pattern, &mut src)?;
93
94 if src.len() > 0 {
95 res.unmatched_tts += src.len();
96 res.add_err(err!("leftover tokens"));
97 }
98
99 Ok(res)
100}
101
102fn match_subtree(
103 res: &mut Match,
104 pattern: &tt::Subtree,
105 src: &mut TtIter,
106) -> Result<(), ExpandError> {
107 for op in parse_pattern(pattern) {
108 match op? {
109 Op::TokenTree(tt::TokenTree::Leaf(lhs)) => {
110 let rhs = match src.expect_leaf() {
111 Ok(l) => l,
112 Err(()) => {
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 }
134 }
135 Op::TokenTree(tt::TokenTree::Subtree(lhs)) => {
136 let rhs = match src.expect_subtree() {
137 Ok(s) => s,
138 Err(()) => {
139 res.add_err(err!("expected subtree"));
140 continue;
141 }
142 };
143 if lhs.delimiter_kind() != rhs.delimiter_kind() {
144 res.add_err(err!("mismatched delimiter"));
145 continue;
146 }
147 let mut src = TtIter::new(rhs);
148 match_subtree(res, lhs, &mut src)?;
149 if src.len() > 0 {
150 res.add_err(err!("leftover tokens"));
151 }
152 }
153 Op::Var { name, kind } => {
154 let kind = match kind {
155 Some(k) => k,
156 None => {
157 res.add_err(ExpandError::UnexpectedToken);
158 continue;
159 }
160 };
161 let ExpandResult(matched, match_err) = match_meta_var(kind.as_str(), src);
162 match matched {
163 Some(fragment) => {
164 res.bindings.inner.insert(name.clone(), Binding::Fragment(fragment));
165 }
166 None if match_err.is_none() => res.bindings.push_optional(name),
167 _ => {}
168 }
169 if let Some(err) = match_err {
170 res.add_err(err);
171 }
172 }
173 Op::Repeat { subtree, kind, separator } => {
174 match_repeat(res, subtree, kind, separator, src)?;
175 }
176 }
177 }
178 Ok(())
179}
180
181impl<'a> TtIter<'a> {
182 fn eat_separator(&mut self, separator: &Separator) -> bool {
183 let mut fork = self.clone();
184 let ok = match separator {
185 Separator::Ident(lhs) => match fork.expect_ident() {
186 Ok(rhs) => rhs.text == lhs.text,
187 _ => false,
188 },
189 Separator::Literal(lhs) => match fork.expect_literal() {
190 Ok(rhs) => match rhs {
191 tt::Leaf::Literal(rhs) => rhs.text == lhs.text,
192 tt::Leaf::Ident(rhs) => rhs.text == lhs.text,
193 tt::Leaf::Punct(_) => false,
194 },
195 _ => false,
196 },
197 Separator::Puncts(lhss) => lhss.iter().all(|lhs| match fork.expect_punct() {
198 Ok(rhs) => rhs.char == lhs.char,
199 _ => false,
200 }),
201 };
202 if ok {
203 *self = fork;
204 }
205 ok
206 }
207
208 pub(crate) fn expect_tt(&mut self) -> Result<tt::TokenTree, ()> {
209 match self.peek_n(0) {
210 Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) if punct.char == '\'' => {
211 return self.expect_lifetime();
212 }
213 _ => (),
214 }
215
216 let tt = self.next().ok_or_else(|| ())?.clone();
217 let punct = match tt {
218 tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if punct.spacing == tt::Spacing::Joint => {
219 punct
220 }
221 _ => return Ok(tt),
222 };
223
224 let (second, third) = match (self.peek_n(0), self.peek_n(1)) {
225 (
226 Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p2))),
227 Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p3))),
228 ) if p2.spacing == tt::Spacing::Joint => (p2.char, Some(p3.char)),
229 (Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p2))), _) => (p2.char, None),
230 _ => return Ok(tt),
231 };
232
233 match (punct.char, second, third) {
234 ('.', '.', Some('.'))
235 | ('.', '.', Some('='))
236 | ('<', '<', Some('='))
237 | ('>', '>', Some('=')) => {
238 let tt2 = self.next().unwrap().clone();
239 let tt3 = self.next().unwrap().clone();
240 Ok(tt::Subtree { delimiter: None, token_trees: vec![tt, tt2, tt3] }.into())
241 }
242 ('-', '=', None)
243 | ('-', '>', None)
244 | (':', ':', None)
245 | ('!', '=', None)
246 | ('.', '.', None)
247 | ('*', '=', None)
248 | ('/', '=', None)
249 | ('&', '&', None)
250 | ('&', '=', None)
251 | ('%', '=', None)
252 | ('^', '=', None)
253 | ('+', '=', None)
254 | ('<', '<', None)
255 | ('<', '=', None)
256 | ('=', '=', None)
257 | ('=', '>', None)
258 | ('>', '=', None)
259 | ('>', '>', None)
260 | ('|', '=', None)
261 | ('|', '|', None) => {
262 let tt2 = self.next().unwrap().clone();
263 Ok(tt::Subtree { delimiter: None, token_trees: vec![tt, tt2] }.into())
264 }
265 _ => Ok(tt),
266 }
267 }
268
269 pub(crate) fn expect_lifetime(&mut self) -> Result<tt::TokenTree, ()> {
270 let punct = self.expect_punct()?;
271 if punct.char != '\'' {
272 return Err(());
273 }
274 let ident = self.expect_ident()?;
275
276 Ok(tt::Subtree {
277 delimiter: None,
278 token_trees: vec![
279 tt::Leaf::Punct(*punct).into(),
280 tt::Leaf::Ident(ident.clone()).into(),
281 ],
282 }
283 .into())
284 }
285
286 pub(crate) fn expect_fragment(
287 &mut self,
288 fragment_kind: parser::FragmentKind,
289 ) -> ExpandResult<Option<tt::TokenTree>> {
290 pub(crate) struct OffsetTokenSink<'a> {
291 pub(crate) cursor: Cursor<'a>,
292 pub(crate) error: bool,
293 }
294
295 impl<'a> TreeSink for OffsetTokenSink<'a> {
296 fn token(&mut self, kind: SyntaxKind, mut n_tokens: u8) {
297 if kind == SyntaxKind::LIFETIME {
298 n_tokens = 2;
299 }
300 for _ in 0..n_tokens {
301 self.cursor = self.cursor.bump_subtree();
302 }
303 }
304 fn start_node(&mut self, _kind: SyntaxKind) {}
305 fn finish_node(&mut self) {}
306 fn error(&mut self, _error: parser::ParseError) {
307 self.error = true;
308 }
309 }
310
311 let buffer = TokenBuffer::new(&self.inner.as_slice());
312 let mut src = SubtreeTokenSource::new(&buffer);
313 let mut sink = OffsetTokenSink { cursor: buffer.begin(), error: false };
314
315 parser::parse_fragment(&mut src, &mut sink, fragment_kind);
316
317 let mut err = None;
318 if !sink.cursor.is_root() || sink.error {
319 err = Some(err!("expected {:?}", fragment_kind));
320 }
321
322 let mut curr = buffer.begin();
323 let mut res = vec![];
324
325 if sink.cursor.is_root() {
326 while curr != sink.cursor {
327 if let Some(token) = curr.token_tree() {
328 res.push(token);
329 }
330 curr = curr.bump();
331 }
332 }
333 self.inner = self.inner.as_slice()[res.len()..].iter();
334 if res.len() == 0 && err.is_none() {
335 err = Some(err!("no tokens consumed"));
336 }
337 let res = match res.len() {
338 1 => Some(res[0].clone()),
339 0 => None,
340 _ => Some(tt::TokenTree::Subtree(tt::Subtree {
341 delimiter: None,
342 token_trees: res.into_iter().cloned().collect(),
343 })),
344 };
345 ExpandResult(res, err)
346 }
347
348 pub(crate) fn eat_vis(&mut self) -> Option<tt::TokenTree> {
349 let mut fork = self.clone();
350 match fork.expect_fragment(Visibility) {
351 ExpandResult(tt, None) => {
352 *self = fork;
353 tt
354 }
355 ExpandResult(_, Some(_)) => None,
356 }
357 }
358}
359
360pub(super) fn match_repeat(
361 res: &mut Match,
362 pattern: &tt::Subtree,
363 kind: RepeatKind,
364 separator: Option<Separator>,
365 src: &mut TtIter,
366) -> Result<(), ExpandError> {
367 // Dirty hack to make macro-expansion terminate.
368 // This should be replaced by a propper macro-by-example implementation
369 let mut limit = 65536;
370 let mut counter = 0;
371
372 for i in 0.. {
373 let mut fork = src.clone();
374
375 if let Some(separator) = &separator {
376 if i != 0 && !fork.eat_separator(separator) {
377 break;
378 }
379 }
380
381 let mut nested = Match::default();
382 match_subtree(&mut nested, pattern, &mut fork)?;
383 if nested.err.is_none() {
384 limit -= 1;
385 if limit == 0 {
386 log::warn!(
387 "match_lhs exceeded repeat pattern limit => {:#?}\n{:#?}\n{:#?}\n{:#?}",
388 pattern,
389 src,
390 kind,
391 separator
392 );
393 break;
394 }
395 *src = fork;
396
397 if let Err(err) = res.bindings.push_nested(counter, nested.bindings) {
398 res.add_err(err);
399 }
400 counter += 1;
401 if counter == 1 {
402 if let RepeatKind::ZeroOrOne = kind {
403 break;
404 }
405 }
406 } else {
407 break;
408 }
409 }
410
411 match (kind, counter) {
412 (RepeatKind::OneOrMore, 0) => {
413 res.add_err(ExpandError::UnexpectedToken);
414 }
415 (_, 0) => {
416 // Collect all empty variables in subtrees
417 let mut vars = Vec::new();
418 collect_vars(&mut vars, pattern)?;
419 for var in vars {
420 res.bindings.push_empty(&var)
421 }
422 }
423 _ => (),
424 }
425 Ok(())
426}
427
428fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult<Option<Fragment>> {
429 let fragment = match kind {
430 "path" => Path,
431 "expr" => Expr,
432 "ty" => Type,
433 "pat" => Pattern,
434 "stmt" => Statement,
435 "block" => Block,
436 "meta" => MetaItem,
437 "item" => Item,
438 _ => {
439 let tt_result = match kind {
440 "ident" => input
441 .expect_ident()
442 .map(|ident| Some(tt::Leaf::from(ident.clone()).into()))
443 .map_err(|()| err!("expected ident")),
444 "tt" => input.expect_tt().map(Some).map_err(|()| err!()),
445 "lifetime" => input
446 .expect_lifetime()
447 .map(|tt| Some(tt))
448 .map_err(|()| err!("expected lifetime")),
449 "literal" => input
450 .expect_literal()
451 .map(|literal| Some(tt::Leaf::from(literal.clone()).into()))
452 .map_err(|()| err!()),
453 // `vis` is optional
454 "vis" => match input.eat_vis() {
455 Some(vis) => Ok(Some(vis)),
456 None => Ok(None),
457 },
458 _ => Err(ExpandError::UnexpectedToken),
459 };
460 return tt_result.map(|it| it.map(Fragment::Tokens)).into();
461 }
462 };
463 let result = input.expect_fragment(fragment);
464 result.map(|tt| if kind == "expr" { tt.map(Fragment::Ast) } else { tt.map(Fragment::Tokens) })
465}
466
467fn collect_vars(buf: &mut Vec<SmolStr>, pattern: &tt::Subtree) -> Result<(), ExpandError> {
468 for op in parse_pattern(pattern) {
469 match op? {
470 Op::Var { name, .. } => buf.push(name.clone()),
471 Op::TokenTree(tt::TokenTree::Leaf(_)) => (),
472 Op::TokenTree(tt::TokenTree::Subtree(subtree)) => collect_vars(buf, subtree)?,
473 Op::Repeat { subtree, .. } => collect_vars(buf, subtree)?,
474 }
475 }
476 Ok(())
477}