2019-09-30 11:58:53 +03:00
|
|
|
//! FIXME: write short doc here
|
|
|
|
|
|
2019-09-17 02:06:14 +03:00
|
|
|
use crate::{
|
|
|
|
|
mbe_expander::{Binding, Bindings, Fragment},
|
2019-09-17 02:54:22 +03:00
|
|
|
parser::{parse_pattern, Op, RepeatKind, Separator},
|
|
|
|
|
subtree_source::SubtreeTokenSource,
|
|
|
|
|
tt_iter::TtIter,
|
2019-09-17 02:06:14 +03:00
|
|
|
ExpandError,
|
|
|
|
|
};
|
|
|
|
|
|
2020-03-14 20:24:18 +01:00
|
|
|
use super::ExpandResult;
|
2020-08-12 17:06:49 +02:00
|
|
|
use parser::{FragmentKind::*, TreeSink};
|
2020-08-12 18:26:51 +02:00
|
|
|
use syntax::{SmolStr, SyntaxKind};
|
2019-09-17 02:54:22 +03:00
|
|
|
use tt::buffer::{Cursor, TokenBuffer};
|
2019-09-17 02:06:14 +03:00
|
|
|
|
|
|
|
|
impl Bindings {
|
|
|
|
|
fn push_optional(&mut self, name: &SmolStr) {
|
|
|
|
|
// FIXME: Do we have a better way to represent an empty token ?
|
|
|
|
|
// Insert an empty subtree for empty token
|
2019-12-13 21:53:34 +08:00
|
|
|
let tt = tt::Subtree::default().into();
|
2019-09-17 02:06:14 +03:00
|
|
|
self.inner.insert(name.clone(), Binding::Fragment(Fragment::Tokens(tt)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn push_empty(&mut self, name: &SmolStr) {
|
|
|
|
|
self.inner.insert(name.clone(), Binding::Empty);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn push_nested(&mut self, idx: usize, nested: Bindings) -> Result<(), ExpandError> {
|
|
|
|
|
for (key, value) in nested.inner {
|
|
|
|
|
if !self.inner.contains_key(&key) {
|
|
|
|
|
self.inner.insert(key.clone(), Binding::Nested(Vec::new()));
|
|
|
|
|
}
|
|
|
|
|
match self.inner.get_mut(&key) {
|
|
|
|
|
Some(Binding::Nested(it)) => {
|
|
|
|
|
// insert empty nested bindings before this one
|
|
|
|
|
while it.len() < idx {
|
|
|
|
|
it.push(Binding::Nested(vec![]));
|
|
|
|
|
}
|
|
|
|
|
it.push(value);
|
|
|
|
|
}
|
|
|
|
|
_ => {
|
|
|
|
|
return Err(ExpandError::BindingError(format!(
|
|
|
|
|
"could not find binding `{}`",
|
|
|
|
|
key
|
|
|
|
|
)));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
2019-09-17 02:54:22 +03:00
|
|
|
}
|
2019-09-17 02:06:14 +03:00
|
|
|
|
2019-09-17 02:54:22 +03:00
|
|
|
macro_rules! err {
|
|
|
|
|
() => {
|
|
|
|
|
ExpandError::BindingError(format!(""))
|
|
|
|
|
};
|
|
|
|
|
($($tt:tt)*) => {
|
|
|
|
|
ExpandError::BindingError(format!($($tt)*))
|
|
|
|
|
};
|
2019-09-17 02:06:14 +03:00
|
|
|
}
|
|
|
|
|
|
2020-03-14 20:24:18 +01:00
|
|
|
#[derive(Debug, Default)]
|
|
|
|
|
pub(super) struct Match {
|
2020-11-02 13:13:32 +01:00
|
|
|
pub(super) bindings: Bindings,
|
2020-03-16 18:38:10 +01:00
|
|
|
/// We currently just keep the first error and count the rest to compare matches.
|
2020-11-02 13:13:32 +01:00
|
|
|
pub(super) err: Option<ExpandError>,
|
|
|
|
|
pub(super) err_count: usize,
|
2020-03-16 18:38:10 +01:00
|
|
|
/// How many top-level token trees were left to match.
|
2020-11-02 13:13:32 +01:00
|
|
|
pub(super) unmatched_tts: usize,
|
2019-09-17 02:54:22 +03:00
|
|
|
}
|
|
|
|
|
|
2020-03-16 18:38:10 +01:00
|
|
|
impl Match {
|
2020-11-02 13:13:32 +01:00
|
|
|
pub(super) fn add_err(&mut self, err: ExpandError) {
|
2020-03-16 18:38:10 +01:00
|
|
|
let prev_err = self.err.take();
|
|
|
|
|
self.err = prev_err.or(Some(err));
|
|
|
|
|
self.err_count += 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// General note: These functions have two channels to return errors, a `Result`
|
|
|
|
|
// return value and the `&mut Match`. The returned Result is for pattern parsing
|
|
|
|
|
// errors; if a branch of the macro definition doesn't parse, it doesn't make
|
|
|
|
|
// sense to try using it. Matching errors are added to the `Match`. It might
|
|
|
|
|
// make sense to make pattern parsing a separate step?
|
|
|
|
|
|
|
|
|
|
pub(super) fn match_(pattern: &tt::Subtree, src: &tt::Subtree) -> Result<Match, ExpandError> {
|
2019-12-13 21:53:34 +08:00
|
|
|
assert!(pattern.delimiter == None);
|
2019-09-17 02:54:22 +03:00
|
|
|
|
2020-03-14 20:24:18 +01:00
|
|
|
let mut res = Match::default();
|
2019-09-17 02:54:22 +03:00
|
|
|
let mut src = TtIter::new(src);
|
|
|
|
|
|
2020-03-16 18:38:10 +01:00
|
|
|
match_subtree(&mut res, pattern, &mut src)?;
|
2019-09-17 02:54:22 +03:00
|
|
|
|
2020-03-16 18:38:10 +01:00
|
|
|
if src.len() > 0 {
|
|
|
|
|
res.unmatched_tts += src.len();
|
|
|
|
|
res.add_err(err!("leftover tokens"));
|
2019-09-17 02:54:22 +03:00
|
|
|
}
|
|
|
|
|
|
2020-03-16 18:38:10 +01:00
|
|
|
Ok(res)
|
2019-09-17 02:54:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn match_subtree(
|
2020-03-14 20:24:18 +01:00
|
|
|
res: &mut Match,
|
2019-09-17 02:54:22 +03:00
|
|
|
pattern: &tt::Subtree,
|
|
|
|
|
src: &mut TtIter,
|
|
|
|
|
) -> Result<(), ExpandError> {
|
|
|
|
|
for op in parse_pattern(pattern) {
|
|
|
|
|
match op? {
|
|
|
|
|
Op::TokenTree(tt::TokenTree::Leaf(lhs)) => {
|
2020-03-14 20:24:18 +01:00
|
|
|
let rhs = match src.expect_leaf() {
|
|
|
|
|
Ok(l) => l,
|
|
|
|
|
Err(()) => {
|
2020-03-16 18:38:10 +01:00
|
|
|
res.add_err(err!("expected leaf: `{}`", lhs));
|
2020-03-14 20:24:18 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
};
|
2019-09-17 02:54:22 +03:00
|
|
|
match (lhs, rhs) {
|
|
|
|
|
(
|
|
|
|
|
tt::Leaf::Punct(tt::Punct { char: lhs, .. }),
|
|
|
|
|
tt::Leaf::Punct(tt::Punct { char: rhs, .. }),
|
|
|
|
|
) if lhs == rhs => (),
|
|
|
|
|
(
|
|
|
|
|
tt::Leaf::Ident(tt::Ident { text: lhs, .. }),
|
|
|
|
|
tt::Leaf::Ident(tt::Ident { text: rhs, .. }),
|
|
|
|
|
) if lhs == rhs => (),
|
|
|
|
|
(
|
|
|
|
|
tt::Leaf::Literal(tt::Literal { text: lhs, .. }),
|
|
|
|
|
tt::Leaf::Literal(tt::Literal { text: rhs, .. }),
|
|
|
|
|
) if lhs == rhs => (),
|
2020-03-14 20:24:18 +01:00
|
|
|
_ => {
|
2020-03-16 18:38:10 +01:00
|
|
|
res.add_err(ExpandError::UnexpectedToken);
|
2020-03-14 20:24:18 +01:00
|
|
|
}
|
2019-09-17 02:06:14 +03:00
|
|
|
}
|
2019-09-17 02:54:22 +03:00
|
|
|
}
|
|
|
|
|
Op::TokenTree(tt::TokenTree::Subtree(lhs)) => {
|
2020-03-14 20:24:18 +01:00
|
|
|
let rhs = match src.expect_subtree() {
|
|
|
|
|
Ok(s) => s,
|
|
|
|
|
Err(()) => {
|
2020-03-16 18:38:10 +01:00
|
|
|
res.add_err(err!("expected subtree"));
|
2020-03-14 20:24:18 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
};
|
2019-12-18 11:47:26 +08:00
|
|
|
if lhs.delimiter_kind() != rhs.delimiter_kind() {
|
2020-03-16 18:38:10 +01:00
|
|
|
res.add_err(err!("mismatched delimiter"));
|
2020-03-14 20:24:18 +01:00
|
|
|
continue;
|
2019-09-17 02:06:14 +03:00
|
|
|
}
|
2019-09-17 02:54:22 +03:00
|
|
|
let mut src = TtIter::new(rhs);
|
2020-03-16 18:38:10 +01:00
|
|
|
match_subtree(res, lhs, &mut src)?;
|
|
|
|
|
if src.len() > 0 {
|
|
|
|
|
res.add_err(err!("leftover tokens"));
|
2019-09-17 02:06:14 +03:00
|
|
|
}
|
2019-09-17 02:54:22 +03:00
|
|
|
}
|
|
|
|
|
Op::Var { name, kind } => {
|
2020-03-14 20:24:18 +01:00
|
|
|
let kind = match kind {
|
|
|
|
|
Some(k) => k,
|
|
|
|
|
None => {
|
2020-03-16 18:38:10 +01:00
|
|
|
res.add_err(ExpandError::UnexpectedToken);
|
2020-03-14 20:24:18 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
};
|
2020-03-16 12:22:10 +01:00
|
|
|
let ExpandResult(matched, match_err) = match_meta_var(kind.as_str(), src);
|
2020-03-14 20:24:18 +01:00
|
|
|
match matched {
|
2019-09-17 02:54:22 +03:00
|
|
|
Some(fragment) => {
|
2020-03-14 20:24:18 +01:00
|
|
|
res.bindings.inner.insert(name.clone(), Binding::Fragment(fragment));
|
2019-09-17 02:06:14 +03:00
|
|
|
}
|
2020-03-14 20:24:18 +01:00
|
|
|
None if match_err.is_none() => res.bindings.push_optional(name),
|
|
|
|
|
_ => {}
|
2019-09-17 02:06:14 +03:00
|
|
|
}
|
2020-03-16 18:38:10 +01:00
|
|
|
if let Some(err) = match_err {
|
|
|
|
|
res.add_err(err);
|
|
|
|
|
}
|
2019-09-17 02:54:22 +03:00
|
|
|
}
|
|
|
|
|
Op::Repeat { subtree, kind, separator } => {
|
2020-03-16 18:38:10 +01:00
|
|
|
match_repeat(res, subtree, kind, separator, src)?;
|
2019-09-17 02:54:22 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-03-16 18:38:10 +01:00
|
|
|
Ok(())
|
2019-09-17 02:54:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a> TtIter<'a> {
|
|
|
|
|
fn eat_separator(&mut self, separator: &Separator) -> bool {
|
|
|
|
|
let mut fork = self.clone();
|
|
|
|
|
let ok = match separator {
|
|
|
|
|
Separator::Ident(lhs) => match fork.expect_ident() {
|
|
|
|
|
Ok(rhs) => rhs.text == lhs.text,
|
|
|
|
|
_ => false,
|
2019-09-17 02:06:14 +03:00
|
|
|
},
|
2019-09-17 02:54:22 +03:00
|
|
|
Separator::Literal(lhs) => match fork.expect_literal() {
|
2020-04-19 03:24:17 +08:00
|
|
|
Ok(rhs) => match rhs {
|
|
|
|
|
tt::Leaf::Literal(rhs) => rhs.text == lhs.text,
|
|
|
|
|
tt::Leaf::Ident(rhs) => rhs.text == lhs.text,
|
|
|
|
|
tt::Leaf::Punct(_) => false,
|
|
|
|
|
},
|
2019-09-17 02:54:22 +03:00
|
|
|
_ => false,
|
|
|
|
|
},
|
|
|
|
|
Separator::Puncts(lhss) => lhss.iter().all(|lhs| match fork.expect_punct() {
|
|
|
|
|
Ok(rhs) => rhs.char == lhs.char,
|
|
|
|
|
_ => false,
|
|
|
|
|
}),
|
|
|
|
|
};
|
|
|
|
|
if ok {
|
|
|
|
|
*self = fork;
|
|
|
|
|
}
|
|
|
|
|
ok
|
|
|
|
|
}
|
2019-09-17 02:06:14 +03:00
|
|
|
|
2020-03-04 22:29:55 +08:00
|
|
|
pub(crate) fn expect_tt(&mut self) -> Result<tt::TokenTree, ()> {
|
2020-04-18 19:28:07 +08:00
|
|
|
match self.peek_n(0) {
|
|
|
|
|
Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) if punct.char == '\'' => {
|
|
|
|
|
return self.expect_lifetime();
|
|
|
|
|
}
|
|
|
|
|
_ => (),
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-04 22:29:55 +08:00
|
|
|
let tt = self.next().ok_or_else(|| ())?.clone();
|
|
|
|
|
let punct = match tt {
|
|
|
|
|
tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if punct.spacing == tt::Spacing::Joint => {
|
|
|
|
|
punct
|
|
|
|
|
}
|
|
|
|
|
_ => return Ok(tt),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let (second, third) = match (self.peek_n(0), self.peek_n(1)) {
|
|
|
|
|
(
|
|
|
|
|
Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p2))),
|
|
|
|
|
Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p3))),
|
|
|
|
|
) if p2.spacing == tt::Spacing::Joint => (p2.char, Some(p3.char)),
|
|
|
|
|
(Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p2))), _) => (p2.char, None),
|
|
|
|
|
_ => return Ok(tt),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
match (punct.char, second, third) {
|
|
|
|
|
('.', '.', Some('.'))
|
|
|
|
|
| ('.', '.', Some('='))
|
|
|
|
|
| ('<', '<', Some('='))
|
|
|
|
|
| ('>', '>', Some('=')) => {
|
|
|
|
|
let tt2 = self.next().unwrap().clone();
|
|
|
|
|
let tt3 = self.next().unwrap().clone();
|
|
|
|
|
Ok(tt::Subtree { delimiter: None, token_trees: vec![tt, tt2, tt3] }.into())
|
|
|
|
|
}
|
|
|
|
|
('-', '=', None)
|
|
|
|
|
| ('-', '>', None)
|
|
|
|
|
| (':', ':', None)
|
|
|
|
|
| ('!', '=', None)
|
|
|
|
|
| ('.', '.', None)
|
|
|
|
|
| ('*', '=', None)
|
|
|
|
|
| ('/', '=', None)
|
|
|
|
|
| ('&', '&', None)
|
|
|
|
|
| ('&', '=', None)
|
|
|
|
|
| ('%', '=', None)
|
|
|
|
|
| ('^', '=', None)
|
|
|
|
|
| ('+', '=', None)
|
|
|
|
|
| ('<', '<', None)
|
|
|
|
|
| ('<', '=', None)
|
|
|
|
|
| ('=', '=', None)
|
|
|
|
|
| ('=', '>', None)
|
|
|
|
|
| ('>', '=', None)
|
|
|
|
|
| ('>', '>', None)
|
|
|
|
|
| ('|', '=', None)
|
|
|
|
|
| ('|', '|', None) => {
|
|
|
|
|
let tt2 = self.next().unwrap().clone();
|
2020-07-08 09:45:29 -04:00
|
|
|
Ok(tt::Subtree { delimiter: None, token_trees: vec![tt, tt2] }.into())
|
2020-03-04 22:29:55 +08:00
|
|
|
}
|
|
|
|
|
_ => Ok(tt),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-18 19:28:07 +08:00
|
|
|
pub(crate) fn expect_lifetime(&mut self) -> Result<tt::TokenTree, ()> {
|
|
|
|
|
let punct = self.expect_punct()?;
|
|
|
|
|
if punct.char != '\'' {
|
2019-09-17 02:54:22 +03:00
|
|
|
return Err(());
|
|
|
|
|
}
|
2020-04-18 19:28:07 +08:00
|
|
|
let ident = self.expect_ident()?;
|
|
|
|
|
|
|
|
|
|
Ok(tt::Subtree {
|
|
|
|
|
delimiter: None,
|
|
|
|
|
token_trees: vec![
|
2020-08-10 15:05:01 +03:00
|
|
|
tt::Leaf::Punct(*punct).into(),
|
2020-04-18 19:28:07 +08:00
|
|
|
tt::Leaf::Ident(ident.clone()).into(),
|
|
|
|
|
],
|
|
|
|
|
}
|
|
|
|
|
.into())
|
2019-09-17 02:54:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn expect_fragment(
|
|
|
|
|
&mut self,
|
2020-08-12 17:06:49 +02:00
|
|
|
fragment_kind: parser::FragmentKind,
|
2020-03-15 15:15:56 +01:00
|
|
|
) -> ExpandResult<Option<tt::TokenTree>> {
|
2019-09-17 02:54:22 +03:00
|
|
|
pub(crate) struct OffsetTokenSink<'a> {
|
|
|
|
|
pub(crate) cursor: Cursor<'a>,
|
|
|
|
|
pub(crate) error: bool,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a> TreeSink for OffsetTokenSink<'a> {
|
2020-04-18 19:28:07 +08:00
|
|
|
fn token(&mut self, kind: SyntaxKind, mut n_tokens: u8) {
|
|
|
|
|
if kind == SyntaxKind::LIFETIME {
|
|
|
|
|
n_tokens = 2;
|
|
|
|
|
}
|
2019-09-17 02:54:22 +03:00
|
|
|
for _ in 0..n_tokens {
|
|
|
|
|
self.cursor = self.cursor.bump_subtree();
|
2019-09-17 02:06:14 +03:00
|
|
|
}
|
|
|
|
|
}
|
2019-09-17 02:54:22 +03:00
|
|
|
fn start_node(&mut self, _kind: SyntaxKind) {}
|
|
|
|
|
fn finish_node(&mut self) {}
|
2020-08-12 17:06:49 +02:00
|
|
|
fn error(&mut self, _error: parser::ParseError) {
|
2019-09-17 02:54:22 +03:00
|
|
|
self.error = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-18 19:28:07 +08:00
|
|
|
let buffer = TokenBuffer::new(&self.inner.as_slice());
|
2019-09-17 02:54:22 +03:00
|
|
|
let mut src = SubtreeTokenSource::new(&buffer);
|
|
|
|
|
let mut sink = OffsetTokenSink { cursor: buffer.begin(), error: false };
|
|
|
|
|
|
2020-08-12 17:06:49 +02:00
|
|
|
parser::parse_fragment(&mut src, &mut sink, fragment_kind);
|
2019-09-17 02:54:22 +03:00
|
|
|
|
2020-03-14 20:24:18 +01:00
|
|
|
let mut err = None;
|
2019-09-17 02:54:22 +03:00
|
|
|
if !sink.cursor.is_root() || sink.error {
|
2020-03-14 20:24:18 +01:00
|
|
|
err = Some(err!("expected {:?}", fragment_kind));
|
2019-09-17 02:54:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut curr = buffer.begin();
|
|
|
|
|
let mut res = vec![];
|
|
|
|
|
|
2020-03-14 20:24:18 +01:00
|
|
|
if sink.cursor.is_root() {
|
|
|
|
|
while curr != sink.cursor {
|
|
|
|
|
if let Some(token) = curr.token_tree() {
|
|
|
|
|
res.push(token);
|
|
|
|
|
}
|
|
|
|
|
curr = curr.bump();
|
2019-09-17 02:54:22 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
self.inner = self.inner.as_slice()[res.len()..].iter();
|
2020-03-15 15:15:56 +01:00
|
|
|
if res.len() == 0 && err.is_none() {
|
|
|
|
|
err = Some(err!("no tokens consumed"));
|
|
|
|
|
}
|
2020-03-14 20:24:18 +01:00
|
|
|
let res = match res.len() {
|
2020-03-15 15:15:56 +01:00
|
|
|
1 => Some(res[0].clone()),
|
|
|
|
|
0 => None,
|
|
|
|
|
_ => Some(tt::TokenTree::Subtree(tt::Subtree {
|
2019-12-13 21:53:34 +08:00
|
|
|
delimiter: None,
|
2019-09-17 02:54:22 +03:00
|
|
|
token_trees: res.into_iter().cloned().collect(),
|
2020-03-15 15:15:56 +01:00
|
|
|
})),
|
2020-03-14 20:24:18 +01:00
|
|
|
};
|
2020-03-16 12:22:10 +01:00
|
|
|
ExpandResult(res, err)
|
2019-09-17 02:54:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn eat_vis(&mut self) -> Option<tt::TokenTree> {
|
|
|
|
|
let mut fork = self.clone();
|
|
|
|
|
match fork.expect_fragment(Visibility) {
|
2020-03-16 12:22:10 +01:00
|
|
|
ExpandResult(tt, None) => {
|
2019-09-17 02:54:22 +03:00
|
|
|
*self = fork;
|
2020-03-15 15:15:56 +01:00
|
|
|
tt
|
2019-09-17 02:54:22 +03:00
|
|
|
}
|
2020-03-16 12:22:10 +01:00
|
|
|
ExpandResult(_, Some(_)) => None,
|
2019-09-17 02:54:22 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(super) fn match_repeat(
|
2020-03-14 20:24:18 +01:00
|
|
|
res: &mut Match,
|
2019-09-17 02:54:22 +03:00
|
|
|
pattern: &tt::Subtree,
|
|
|
|
|
kind: RepeatKind,
|
|
|
|
|
separator: Option<Separator>,
|
|
|
|
|
src: &mut TtIter,
|
|
|
|
|
) -> Result<(), ExpandError> {
|
|
|
|
|
// Dirty hack to make macro-expansion terminate.
|
|
|
|
|
// This should be replaced by a propper macro-by-example implementation
|
|
|
|
|
let mut limit = 65536;
|
|
|
|
|
let mut counter = 0;
|
|
|
|
|
|
|
|
|
|
for i in 0.. {
|
|
|
|
|
let mut fork = src.clone();
|
|
|
|
|
|
|
|
|
|
if let Some(separator) = &separator {
|
|
|
|
|
if i != 0 && !fork.eat_separator(separator) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-14 20:24:18 +01:00
|
|
|
let mut nested = Match::default();
|
2020-03-16 18:38:10 +01:00
|
|
|
match_subtree(&mut nested, pattern, &mut fork)?;
|
|
|
|
|
if nested.err.is_none() {
|
|
|
|
|
limit -= 1;
|
|
|
|
|
if limit == 0 {
|
|
|
|
|
log::warn!(
|
|
|
|
|
"match_lhs exceeded repeat pattern limit => {:#?}\n{:#?}\n{:#?}\n{:#?}",
|
|
|
|
|
pattern,
|
|
|
|
|
src,
|
|
|
|
|
kind,
|
|
|
|
|
separator
|
|
|
|
|
);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
*src = fork;
|
2019-09-17 02:06:14 +03:00
|
|
|
|
2020-03-16 18:38:10 +01:00
|
|
|
if let Err(err) = res.bindings.push_nested(counter, nested.bindings) {
|
|
|
|
|
res.add_err(err);
|
|
|
|
|
}
|
|
|
|
|
counter += 1;
|
|
|
|
|
if counter == 1 {
|
|
|
|
|
if let RepeatKind::ZeroOrOne = kind {
|
|
|
|
|
break;
|
2019-09-17 02:06:14 +03:00
|
|
|
}
|
2019-09-17 02:54:22 +03:00
|
|
|
}
|
2020-03-16 18:38:10 +01:00
|
|
|
} else {
|
|
|
|
|
break;
|
2019-09-17 02:54:22 +03:00
|
|
|
}
|
|
|
|
|
}
|
2019-09-17 02:06:14 +03:00
|
|
|
|
2019-09-17 02:54:22 +03:00
|
|
|
match (kind, counter) {
|
2020-03-16 18:38:10 +01:00
|
|
|
(RepeatKind::OneOrMore, 0) => {
|
|
|
|
|
res.add_err(ExpandError::UnexpectedToken);
|
|
|
|
|
}
|
2019-09-17 02:54:22 +03:00
|
|
|
(_, 0) => {
|
|
|
|
|
// Collect all empty variables in subtrees
|
|
|
|
|
let mut vars = Vec::new();
|
|
|
|
|
collect_vars(&mut vars, pattern)?;
|
|
|
|
|
for var in vars {
|
2020-03-14 20:24:18 +01:00
|
|
|
res.bindings.push_empty(&var)
|
2019-09-17 02:06:14 +03:00
|
|
|
}
|
|
|
|
|
}
|
2019-09-17 02:54:22 +03:00
|
|
|
_ => (),
|
2019-09-17 02:06:14 +03:00
|
|
|
}
|
2019-09-17 02:54:22 +03:00
|
|
|
Ok(())
|
2019-09-17 02:06:14 +03:00
|
|
|
}
|
|
|
|
|
|
2020-03-14 20:24:18 +01:00
|
|
|
fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult<Option<Fragment>> {
|
2019-09-17 02:06:14 +03:00
|
|
|
let fragment = match kind {
|
|
|
|
|
"path" => Path,
|
|
|
|
|
"expr" => Expr,
|
|
|
|
|
"ty" => Type,
|
|
|
|
|
"pat" => Pattern,
|
|
|
|
|
"stmt" => Statement,
|
|
|
|
|
"block" => Block,
|
|
|
|
|
"meta" => MetaItem,
|
|
|
|
|
"item" => Item,
|
|
|
|
|
_ => {
|
2020-03-14 20:24:18 +01:00
|
|
|
let tt_result = match kind {
|
|
|
|
|
"ident" => input
|
|
|
|
|
.expect_ident()
|
|
|
|
|
.map(|ident| Some(tt::Leaf::from(ident.clone()).into()))
|
|
|
|
|
.map_err(|()| err!("expected ident")),
|
|
|
|
|
"tt" => input.expect_tt().map(Some).map_err(|()| err!()),
|
|
|
|
|
"lifetime" => input
|
|
|
|
|
.expect_lifetime()
|
2020-04-18 19:28:07 +08:00
|
|
|
.map(|tt| Some(tt))
|
2020-03-14 20:24:18 +01:00
|
|
|
.map_err(|()| err!("expected lifetime")),
|
|
|
|
|
"literal" => input
|
|
|
|
|
.expect_literal()
|
|
|
|
|
.map(|literal| Some(tt::Leaf::from(literal.clone()).into()))
|
|
|
|
|
.map_err(|()| err!()),
|
2019-09-17 02:06:14 +03:00
|
|
|
// `vis` is optional
|
2019-09-17 02:54:22 +03:00
|
|
|
"vis" => match input.eat_vis() {
|
2020-03-14 20:24:18 +01:00
|
|
|
Some(vis) => Ok(Some(vis)),
|
|
|
|
|
None => Ok(None),
|
2019-09-17 02:06:14 +03:00
|
|
|
},
|
2020-03-14 20:24:18 +01:00
|
|
|
_ => Err(ExpandError::UnexpectedToken),
|
2019-09-17 02:06:14 +03:00
|
|
|
};
|
2020-03-16 12:22:10 +01:00
|
|
|
return tt_result.map(|it| it.map(Fragment::Tokens)).into();
|
2019-09-17 02:06:14 +03:00
|
|
|
}
|
|
|
|
|
};
|
2020-03-16 12:22:10 +01:00
|
|
|
let result = input.expect_fragment(fragment);
|
|
|
|
|
result.map(|tt| if kind == "expr" { tt.map(Fragment::Ast) } else { tt.map(Fragment::Tokens) })
|
2019-09-17 02:06:14 +03:00
|
|
|
}
|
|
|
|
|
|
2019-09-17 02:54:22 +03:00
|
|
|
fn collect_vars(buf: &mut Vec<SmolStr>, pattern: &tt::Subtree) -> Result<(), ExpandError> {
|
|
|
|
|
for op in parse_pattern(pattern) {
|
|
|
|
|
match op? {
|
|
|
|
|
Op::Var { name, .. } => buf.push(name.clone()),
|
|
|
|
|
Op::TokenTree(tt::TokenTree::Leaf(_)) => (),
|
|
|
|
|
Op::TokenTree(tt::TokenTree::Subtree(subtree)) => collect_vars(buf, subtree)?,
|
|
|
|
|
Op::Repeat { subtree, .. } => collect_vars(buf, subtree)?,
|
2019-09-17 02:06:14 +03:00
|
|
|
}
|
|
|
|
|
}
|
2019-09-17 02:54:22 +03:00
|
|
|
Ok(())
|
2019-09-17 02:06:14 +03:00
|
|
|
}
|