diff --git a/crates/mbe/src/lib.rs b/crates/mbe/src/lib.rs index 62e7509eb37..8d223c375a3 100644 --- a/crates/mbe/src/lib.rs +++ b/crates/mbe/src/lib.rs @@ -27,6 +27,14 @@ use crate::{ pub use ::parser::TopEntryPoint; pub use tt::{Delimiter, DelimiterKind, Punct}; +pub use crate::{ + syntax_bridge::{ + parse_exprs_with_sep, parse_to_token_tree, syntax_node_to_token_tree, + syntax_node_to_token_tree_censored, token_tree_to_syntax_node, + }, + token_map::TokenMap, +}; + #[derive(Debug, PartialEq, Eq, Clone)] pub enum ParseError { UnexpectedToken(String), @@ -70,14 +78,6 @@ impl fmt::Display for ExpandError { } } -pub use crate::{ - syntax_bridge::{ - parse_exprs_with_sep, parse_to_token_tree, syntax_node_to_token_tree, - syntax_node_to_token_tree_censored, token_tree_to_syntax_node, - }, - token_map::TokenMap, -}; - /// This struct contains AST for a single `macro_rules` definition. What might /// be very confusing is that AST has almost exactly the same shape as /// `tt::TokenTree`, but there's a crucial difference: in macro rules, `$ident` @@ -121,11 +121,9 @@ impl Shift { } } tt::TokenTree::Leaf(leaf) => { - let id = match leaf { - tt::Leaf::Literal(it) => it.id, - tt::Leaf::Punct(it) => it.id, - tt::Leaf::Ident(it) => it.id, - }; + let &(tt::Leaf::Ident(tt::Ident { id, .. }) + | tt::Leaf::Punct(tt::Punct { id, .. }) + | tt::Leaf::Literal(tt::Literal { id, .. })) = leaf; (id != tt::TokenId::unspecified()).then(|| id.0) } @@ -138,15 +136,15 @@ impl Shift { pub fn shift_all(self, tt: &mut tt::Subtree) { for t in &mut tt.token_trees { match t { - tt::TokenTree::Leaf(leaf) => match leaf { - tt::Leaf::Ident(ident) => ident.id = self.shift(ident.id), - tt::Leaf::Punct(punct) => punct.id = self.shift(punct.id), - tt::Leaf::Literal(lit) => lit.id = self.shift(lit.id), - }, + tt::TokenTree::Leaf( + tt::Leaf::Ident(tt::Ident { id, .. }) + | tt::Leaf::Punct(tt::Punct { id, .. }) + | tt::Leaf::Literal(tt::Literal { id, .. }), + ) => *id = self.shift(*id), tt::TokenTree::Subtree(tt) => { if let Some(it) = tt.delimiter.as_mut() { it.id = self.shift(it.id); - }; + } self.shift_all(tt) } } @@ -155,9 +153,10 @@ impl Shift { pub fn shift(self, id: tt::TokenId) -> tt::TokenId { if id == tt::TokenId::unspecified() { - return id; + id + } else { + tt::TokenId(id.0 + self.0) } - tt::TokenId(id.0 + self.0) } pub fn unshift(self, id: tt::TokenId) -> Option { @@ -190,8 +189,8 @@ impl DeclarativeMacro { } } - for rule in &rules { - validate(&rule.lhs)?; + for Rule { lhs, .. } in &rules { + validate(lhs)?; } Ok(DeclarativeMacro { rules, shift: Shift::new(tt) }) @@ -220,12 +219,13 @@ impl DeclarativeMacro { cov_mark::hit!(parse_macro_def_simple); let rule = Rule::parse(&mut src, false)?; if src.len() != 0 { - return Err(ParseError::Expected("remain tokens in macro def".to_string())); + return Err(ParseError::Expected("remaining tokens in macro def".to_string())); } rules.push(rule); } - for rule in &rules { - validate(&rule.lhs)?; + + for Rule { lhs, .. } in &rules { + validate(lhs)?; } Ok(DeclarativeMacro { rules, shift: Shift::new(tt) }) @@ -281,28 +281,18 @@ fn validate(pattern: &MetaTemplate) -> Result<(), ParseError> { Op::Repeat { tokens: subtree, separator, .. } => { // Checks that no repetition which could match an empty token // https://github.com/rust-lang/rust/blob/a58b1ed44f5e06976de2bdc4d7dc81c36a96934f/src/librustc_expand/mbe/macro_rules.rs#L558 - - if separator.is_none() - && subtree.iter().all(|child_op| { - match child_op { - Op::Var { kind, .. } => { - // vis is optional - if kind.as_ref().map_or(false, |it| it == "vis") { - return true; - } - } - Op::Repeat { kind, .. } => { - return matches!( - kind, - parser::RepeatKind::ZeroOrMore | parser::RepeatKind::ZeroOrOne - ) - } - Op::Leaf(_) => {} - Op::Subtree { .. } => {} - } - false - }) - { + let lsh_is_empty_seq = separator.is_none() && subtree.iter().all(|child_op| { + match child_op { + // vis is optional + Op::Var { kind: Some(kind), .. } => kind == "vis", + Op::Repeat { + kind: parser::RepeatKind::ZeroOrMore | parser::RepeatKind::ZeroOrOne, + .. + } => true, + _ => false, + } + }); + if lsh_is_empty_seq { return Err(ParseError::RepetitionEmptyTokenTree); } validate(subtree)? diff --git a/crates/mbe/src/parser.rs b/crates/mbe/src/parser.rs index 4ce818f9b00..7543054494a 100644 --- a/crates/mbe/src/parser.rs +++ b/crates/mbe/src/parser.rs @@ -76,9 +76,9 @@ impl PartialEq for Separator { use Separator::*; match (self, other) { - (Ident(ref a), Ident(ref b)) => a.text == b.text, - (Literal(ref a), Literal(ref b)) => a.text == b.text, - (Puncts(ref a), Puncts(ref b)) if a.len() == b.len() => { + (Ident(a), Ident(b)) => a.text == b.text, + (Literal(a), Literal(b)) => a.text == b.text, + (Puncts(a), Puncts(b)) if a.len() == b.len() => { let a_iter = a.iter().map(|a| a.char); let b_iter = b.iter().map(|b| b.char); a_iter.eq(b_iter) @@ -131,9 +131,7 @@ fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Resul Op::Repeat { tokens, separator, kind } } tt::TokenTree::Leaf(leaf) => match leaf { - tt::Leaf::Punct(_) => { - return Err(ParseError::Expected("ident".to_string())); - } + tt::Leaf::Punct(_) => return Err(ParseError::Expected("ident".to_string())), tt::Leaf::Ident(ident) if ident.text == "crate" => { // We simply produce identifier `$crate` here. And it will be resolved when lowering ast to Path. Op::Leaf(tt::Leaf::from(tt::Ident { text: "$crate".into(), id: ident.id })) diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs index 8bdc5e6e946..3b97bc8ba60 100644 --- a/crates/mbe/src/syntax_bridge.rs +++ b/crates/mbe/src/syntax_bridge.rs @@ -81,7 +81,7 @@ pub fn parse_to_token_tree(text: &str) -> Option<(tt::Subtree, TokenMap)> { } let mut conv = RawConvertor { - lexed: lexed, + lexed, pos: 0, id_alloc: TokenIdAlloc { map: Default::default(), @@ -147,8 +147,8 @@ fn convert_tokens(conv: &mut C) -> tt::Subtree { let entry = stack.last_mut().unwrap(); let result = &mut entry.subtree.token_trees; let (token, range) = match conv.bump() { - None => break, Some(it) => it, + None => break, }; let k: SyntaxKind = token.kind(&conv); diff --git a/crates/mbe/src/tt_iter.rs b/crates/mbe/src/tt_iter.rs index 6c9f615c7a9..172916c5a14 100644 --- a/crates/mbe/src/tt_iter.rs +++ b/crates/mbe/src/tt_iter.rs @@ -1,11 +1,11 @@ //! A "Parser" structure for token trees. We use this when parsing a declarative //! macro definition into a list of patterns and templates. -use crate::{to_parser_input::to_parser_input, ExpandError, ExpandResult}; - use syntax::SyntaxKind; use tt::buffer::TokenBuffer; +use crate::{to_parser_input::to_parser_input, ExpandError, ExpandResult}; + macro_rules! err { () => { ExpandError::BindingError(format!("")) @@ -27,7 +27,7 @@ impl<'a> TtIter<'a> { pub(crate) fn expect_char(&mut self, char: char) -> Result<(), ()> { match self.next() { - Some(tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: c, .. }))) if *c == char => { + Some(&tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: c, .. }))) if c == char => { Ok(()) } _ => Err(()),