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,
|
|
|
|
|
};
|
|
|
|
|
|
2019-09-17 02:54:22 +03:00
|
|
|
use ra_parser::{FragmentKind::*, TreeSink};
|
|
|
|
|
use ra_syntax::{SmolStr, SyntaxKind};
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2019-09-17 02:54:22 +03:00
|
|
|
macro_rules! bail {
|
|
|
|
|
($($tt:tt)*) => {
|
|
|
|
|
return Err(err!($($tt)*))
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(super) fn match_(pattern: &tt::Subtree, src: &tt::Subtree) -> Result<Bindings, ExpandError> {
|
2019-12-13 21:53:34 +08:00
|
|
|
assert!(pattern.delimiter == None);
|
2019-09-17 02:54:22 +03:00
|
|
|
|
2019-09-17 02:06:14 +03:00
|
|
|
let mut res = Bindings::default();
|
2019-09-17 02:54:22 +03:00
|
|
|
let mut src = TtIter::new(src);
|
|
|
|
|
|
|
|
|
|
match_subtree(&mut res, pattern, &mut src)?;
|
|
|
|
|
|
|
|
|
|
if src.len() > 0 {
|
|
|
|
|
bail!("leftover tokens");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(res)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn match_subtree(
|
|
|
|
|
bindings: &mut Bindings,
|
|
|
|
|
pattern: &tt::Subtree,
|
|
|
|
|
src: &mut TtIter,
|
|
|
|
|
) -> Result<(), ExpandError> {
|
|
|
|
|
for op in parse_pattern(pattern) {
|
|
|
|
|
match op? {
|
|
|
|
|
Op::TokenTree(tt::TokenTree::Leaf(lhs)) => {
|
|
|
|
|
let rhs = src.expect_leaf().map_err(|()| err!("expected leaf: `{}`", lhs))?;
|
|
|
|
|
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-02-18 14:53:02 +02:00
|
|
|
_ => return Err(ExpandError::UnexpectedToken),
|
2019-09-17 02:06:14 +03:00
|
|
|
}
|
2019-09-17 02:54:22 +03:00
|
|
|
}
|
|
|
|
|
Op::TokenTree(tt::TokenTree::Subtree(lhs)) => {
|
|
|
|
|
let rhs = src.expect_subtree().map_err(|()| err!("expected subtree"))?;
|
2019-12-18 11:47:26 +08:00
|
|
|
if lhs.delimiter_kind() != rhs.delimiter_kind() {
|
2019-09-17 02:54:22 +03:00
|
|
|
bail!("mismatched delimiter")
|
2019-09-17 02:06:14 +03:00
|
|
|
}
|
2019-09-17 02:54:22 +03:00
|
|
|
let mut src = TtIter::new(rhs);
|
|
|
|
|
match_subtree(bindings, lhs, &mut src)?;
|
|
|
|
|
if src.len() > 0 {
|
|
|
|
|
bail!("leftover tokens");
|
2019-09-17 02:06:14 +03:00
|
|
|
}
|
2019-09-17 02:54:22 +03:00
|
|
|
}
|
|
|
|
|
Op::Var { name, kind } => {
|
|
|
|
|
let kind = kind.as_ref().ok_or(ExpandError::UnexpectedToken)?;
|
|
|
|
|
match match_meta_var(kind.as_str(), src)? {
|
|
|
|
|
Some(fragment) => {
|
|
|
|
|
bindings.inner.insert(name.clone(), Binding::Fragment(fragment));
|
2019-09-17 02:06:14 +03:00
|
|
|
}
|
2019-09-17 02:54:22 +03:00
|
|
|
None => bindings.push_optional(name),
|
2019-09-17 02:06:14 +03:00
|
|
|
}
|
2019-09-17 02:54:22 +03:00
|
|
|
}
|
|
|
|
|
Op::Repeat { subtree, kind, separator } => {
|
|
|
|
|
match_repeat(bindings, subtree, kind, separator, src)?
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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() {
|
|
|
|
|
Ok(rhs) => rhs.text == lhs.text,
|
|
|
|
|
_ => 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
|
|
|
|
2019-09-17 02:54:22 +03:00
|
|
|
pub(crate) fn expect_lifetime(&mut self) -> Result<&tt::Ident, ()> {
|
|
|
|
|
let ident = self.expect_ident()?;
|
|
|
|
|
// check if it start from "`"
|
2019-10-30 13:36:37 -04:00
|
|
|
if !ident.text.starts_with('\'') {
|
2019-09-17 02:54:22 +03:00
|
|
|
return Err(());
|
|
|
|
|
}
|
|
|
|
|
Ok(ident)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn expect_fragment(
|
|
|
|
|
&mut self,
|
|
|
|
|
fragment_kind: ra_parser::FragmentKind,
|
|
|
|
|
) -> Result<tt::TokenTree, ()> {
|
|
|
|
|
pub(crate) struct OffsetTokenSink<'a> {
|
|
|
|
|
pub(crate) cursor: Cursor<'a>,
|
|
|
|
|
pub(crate) error: bool,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a> TreeSink for OffsetTokenSink<'a> {
|
|
|
|
|
fn token(&mut self, _kind: SyntaxKind, n_tokens: u8) {
|
|
|
|
|
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) {}
|
|
|
|
|
fn error(&mut self, _error: ra_parser::ParseError) {
|
|
|
|
|
self.error = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let buffer = TokenBuffer::new(self.inner.as_slice());
|
|
|
|
|
let mut src = SubtreeTokenSource::new(&buffer);
|
|
|
|
|
let mut sink = OffsetTokenSink { cursor: buffer.begin(), error: false };
|
|
|
|
|
|
|
|
|
|
ra_parser::parse_fragment(&mut src, &mut sink, fragment_kind);
|
|
|
|
|
|
|
|
|
|
if !sink.cursor.is_root() || sink.error {
|
|
|
|
|
return Err(());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut curr = buffer.begin();
|
|
|
|
|
let mut res = vec![];
|
|
|
|
|
|
|
|
|
|
while curr != sink.cursor {
|
|
|
|
|
if let Some(token) = curr.token_tree() {
|
|
|
|
|
res.push(token);
|
|
|
|
|
}
|
|
|
|
|
curr = curr.bump();
|
|
|
|
|
}
|
|
|
|
|
self.inner = self.inner.as_slice()[res.len()..].iter();
|
|
|
|
|
match res.len() {
|
|
|
|
|
0 => Err(()),
|
|
|
|
|
1 => Ok(res[0].clone()),
|
|
|
|
|
_ => Ok(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(),
|
|
|
|
|
})),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn eat_vis(&mut self) -> Option<tt::TokenTree> {
|
|
|
|
|
let mut fork = self.clone();
|
|
|
|
|
match fork.expect_fragment(Visibility) {
|
|
|
|
|
Ok(tt) => {
|
|
|
|
|
*self = fork;
|
|
|
|
|
Some(tt)
|
|
|
|
|
}
|
|
|
|
|
Err(()) => None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(super) fn match_repeat(
|
|
|
|
|
bindings: &mut Bindings,
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut nested = Bindings::default();
|
|
|
|
|
match match_subtree(&mut nested, pattern, &mut fork) {
|
|
|
|
|
Ok(()) => {
|
|
|
|
|
limit -= 1;
|
|
|
|
|
if limit == 0 {
|
|
|
|
|
log::warn!("match_lhs excced in repeat pattern exceed limit => {:#?}\n{:#?}\n{:#?}\n{:#?}", pattern, src, kind, separator);
|
|
|
|
|
break;
|
2019-09-17 02:06:14 +03:00
|
|
|
}
|
2019-09-17 02:54:22 +03:00
|
|
|
*src = fork;
|
2019-09-17 02:06:14 +03:00
|
|
|
|
2019-09-17 02:54:22 +03:00
|
|
|
bindings.push_nested(counter, nested)?;
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
Err(_) => break,
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-09-17 02:06:14 +03:00
|
|
|
|
2019-09-17 02:54:22 +03:00
|
|
|
match (kind, counter) {
|
|
|
|
|
(RepeatKind::OneOrMore, 0) => return Err(ExpandError::UnexpectedToken),
|
|
|
|
|
(_, 0) => {
|
|
|
|
|
// Collect all empty variables in subtrees
|
|
|
|
|
let mut vars = Vec::new();
|
|
|
|
|
collect_vars(&mut vars, pattern)?;
|
|
|
|
|
for var in vars {
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2019-09-17 02:54:22 +03:00
|
|
|
fn match_meta_var(kind: &str, input: &mut TtIter) -> Result<Option<Fragment>, ExpandError> {
|
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,
|
|
|
|
|
_ => {
|
|
|
|
|
let tt = match kind {
|
|
|
|
|
"ident" => {
|
2019-09-17 02:54:22 +03:00
|
|
|
let ident = input.expect_ident().map_err(|()| err!("expected ident"))?.clone();
|
2019-09-17 02:06:14 +03:00
|
|
|
tt::Leaf::from(ident).into()
|
|
|
|
|
}
|
2019-09-17 02:54:22 +03:00
|
|
|
"tt" => input.next().ok_or_else(|| err!())?.clone(),
|
|
|
|
|
"lifetime" => {
|
|
|
|
|
let ident = input.expect_lifetime().map_err(|()| err!())?;
|
|
|
|
|
tt::Leaf::Ident(ident.clone()).into()
|
|
|
|
|
}
|
2019-09-17 02:06:14 +03:00
|
|
|
"literal" => {
|
2019-09-17 02:54:22 +03:00
|
|
|
let literal = input.expect_literal().map_err(|()| err!())?.clone();
|
2019-09-17 02:06:14 +03:00
|
|
|
tt::Leaf::from(literal).into()
|
|
|
|
|
}
|
|
|
|
|
// `vis` is optional
|
2019-09-17 02:54:22 +03:00
|
|
|
"vis" => match input.eat_vis() {
|
2019-09-17 02:06:14 +03:00
|
|
|
Some(vis) => vis,
|
|
|
|
|
None => return Ok(None),
|
|
|
|
|
},
|
|
|
|
|
_ => return Err(ExpandError::UnexpectedToken),
|
|
|
|
|
};
|
|
|
|
|
return Ok(Some(Fragment::Tokens(tt)));
|
|
|
|
|
}
|
|
|
|
|
};
|
2019-09-17 02:54:22 +03:00
|
|
|
let tt = input.expect_fragment(fragment).map_err(|()| err!())?;
|
2019-09-17 02:06:14 +03:00
|
|
|
let fragment = if kind == "expr" { Fragment::Ast(tt) } else { Fragment::Tokens(tt) };
|
|
|
|
|
Ok(Some(fragment))
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
}
|