Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/mbe/src/lib.rs')
-rw-r--r--crates/mbe/src/lib.rs86
1 files changed, 38 insertions, 48 deletions
diff --git a/crates/mbe/src/lib.rs b/crates/mbe/src/lib.rs
index 62e7509eb3..8d223c375a 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<tt::TokenId> {
@@ -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)?