aboutsummaryrefslogtreecommitdiff
path: root/crates/mbe/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/mbe/src')
-rw-r--r--crates/mbe/src/expander/matcher.rs13
-rw-r--r--crates/mbe/src/lib.rs2
-rw-r--r--crates/mbe/src/parser.rs14
-rw-r--r--crates/mbe/src/subtree_source.rs1
-rw-r--r--crates/mbe/src/syntax_bridge.rs9
-rw-r--r--crates/mbe/src/tests/expand.rs9
-rw-r--r--crates/mbe/src/tests/rule.rs4
-rw-r--r--crates/mbe/src/tt_iter.rs7
8 files changed, 35 insertions, 24 deletions
diff --git a/crates/mbe/src/expander/matcher.rs b/crates/mbe/src/expander/matcher.rs
index b6782b4ba..75d2f2eed 100644
--- a/crates/mbe/src/expander/matcher.rs
+++ b/crates/mbe/src/expander/matcher.rs
@@ -304,7 +304,7 @@ impl BindingsBuilder {
304 link_nodes: &'a Vec<LinkNode<Rc<BindingKind>>>, 304 link_nodes: &'a Vec<LinkNode<Rc<BindingKind>>>,
305 nodes: &mut Vec<&'a Rc<BindingKind>>, 305 nodes: &mut Vec<&'a Rc<BindingKind>>,
306 ) { 306 ) {
307 link_nodes.into_iter().for_each(|it| match it { 307 link_nodes.iter().for_each(|it| match it {
308 LinkNode::Node(it) => nodes.push(it), 308 LinkNode::Node(it) => nodes.push(it),
309 LinkNode::Parent { idx, len } => self.collect_nodes_ref(*idx, *len, nodes), 309 LinkNode::Parent { idx, len } => self.collect_nodes_ref(*idx, *len, nodes),
310 }); 310 });
@@ -713,10 +713,9 @@ fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult<Option<Fragmen
713 .map(|ident| Some(tt::Leaf::from(ident.clone()).into())) 713 .map(|ident| Some(tt::Leaf::from(ident.clone()).into()))
714 .map_err(|()| err!("expected ident")), 714 .map_err(|()| err!("expected ident")),
715 "tt" => input.expect_tt().map(Some).map_err(|()| err!()), 715 "tt" => input.expect_tt().map(Some).map_err(|()| err!()),
716 "lifetime" => input 716 "lifetime" => {
717 .expect_lifetime() 717 input.expect_lifetime().map(Some).map_err(|()| err!("expected lifetime"))
718 .map(|tt| Some(tt)) 718 }
719 .map_err(|()| err!("expected lifetime")),
720 "literal" => { 719 "literal" => {
721 let neg = input.eat_char('-'); 720 let neg = input.eat_char('-');
722 input 721 input
@@ -762,7 +761,7 @@ impl<'a> TtIter<'a> {
762 fn expect_separator(&mut self, separator: &Separator, idx: usize) -> bool { 761 fn expect_separator(&mut self, separator: &Separator, idx: usize) -> bool {
763 let mut fork = self.clone(); 762 let mut fork = self.clone();
764 let ok = match separator { 763 let ok = match separator {
765 Separator::Ident(lhs) if idx == 0 => match fork.expect_ident() { 764 Separator::Ident(lhs) if idx == 0 => match fork.expect_ident_or_underscore() {
766 Ok(rhs) => rhs.text == lhs.text, 765 Ok(rhs) => rhs.text == lhs.text,
767 _ => false, 766 _ => false,
768 }, 767 },
@@ -852,7 +851,7 @@ impl<'a> TtIter<'a> {
852 if punct.char != '\'' { 851 if punct.char != '\'' {
853 return Err(()); 852 return Err(());
854 } 853 }
855 let ident = self.expect_ident()?; 854 let ident = self.expect_ident_or_underscore()?;
856 855
857 Ok(tt::Subtree { 856 Ok(tt::Subtree {
858 delimiter: None, 857 delimiter: None,
diff --git a/crates/mbe/src/lib.rs b/crates/mbe/src/lib.rs
index 33b85e23d..e74f8cf3f 100644
--- a/crates/mbe/src/lib.rs
+++ b/crates/mbe/src/lib.rs
@@ -356,6 +356,6 @@ impl<T> ExpandResult<T> {
356 356
357impl<T: Default> From<Result<T, ExpandError>> for ExpandResult<T> { 357impl<T: Default> From<Result<T, ExpandError>> for ExpandResult<T> {
358 fn from(result: Result<T, ExpandError>) -> Self { 358 fn from(result: Result<T, ExpandError>) -> Self {
359 result.map_or_else(|e| Self::only_err(e), |it| Self::ok(it)) 359 result.map_or_else(Self::only_err, Self::ok)
360 } 360 }
361} 361}
diff --git a/crates/mbe/src/parser.rs b/crates/mbe/src/parser.rs
index 7b5b8ec16..61b2a4955 100644
--- a/crates/mbe/src/parser.rs
+++ b/crates/mbe/src/parser.rs
@@ -57,7 +57,7 @@ impl<'a> Iterator for OpDelimitedIter<'a> {
57 57
58 fn size_hint(&self) -> (usize, Option<usize>) { 58 fn size_hint(&self) -> (usize, Option<usize>) {
59 let len = self.inner.len() + if self.delimited.is_some() { 2 } else { 0 }; 59 let len = self.inner.len() + if self.delimited.is_some() { 2 } else { 0 };
60 let remain = len.checked_sub(self.idx).unwrap_or(0); 60 let remain = len.saturating_sub(self.idx);
61 (remain, Some(remain)) 61 (remain, Some(remain))
62 } 62 }
63} 63}
@@ -177,16 +177,8 @@ fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Resul
177 Op::Repeat { tokens: MetaTemplate(tokens), separator, kind } 177 Op::Repeat { tokens: MetaTemplate(tokens), separator, kind }
178 } 178 }
179 tt::TokenTree::Leaf(leaf) => match leaf { 179 tt::TokenTree::Leaf(leaf) => match leaf {
180 tt::Leaf::Punct(punct) => { 180 tt::Leaf::Punct(_) => {
181 static UNDERSCORE: SmolStr = SmolStr::new_inline("_"); 181 return Err(ParseError::Expected("ident".to_string()));
182
183 if punct.char != '_' {
184 return Err(ParseError::Expected("_".to_string()));
185 }
186 let name = UNDERSCORE.clone();
187 let kind = eat_fragment_kind(src, mode)?;
188 let id = punct.id;
189 Op::Var { name, kind, id }
190 } 182 }
191 tt::Leaf::Ident(ident) if ident.text == "crate" => { 183 tt::Leaf::Ident(ident) if ident.text == "crate" => {
192 // We simply produce identifier `$crate` here. And it will be resolved when lowering ast to Path. 184 // We simply produce identifier `$crate` here. And it will be resolved when lowering ast to Path.
diff --git a/crates/mbe/src/subtree_source.rs b/crates/mbe/src/subtree_source.rs
index d7433bd35..a05cab0f3 100644
--- a/crates/mbe/src/subtree_source.rs
+++ b/crates/mbe/src/subtree_source.rs
@@ -150,6 +150,7 @@ fn convert_ident(ident: &tt::Ident) -> TtToken {
150 let kind = match ident.text.as_ref() { 150 let kind = match ident.text.as_ref() {
151 "true" => T![true], 151 "true" => T![true],
152 "false" => T![false], 152 "false" => T![false],
153 "_" => UNDERSCORE,
153 i if i.starts_with('\'') => LIFETIME_IDENT, 154 i if i.starts_with('\'') => LIFETIME_IDENT,
154 _ => SyntaxKind::from_keyword(ident.text.as_str()).unwrap_or(IDENT), 155 _ => SyntaxKind::from_keyword(ident.text.as_str()).unwrap_or(IDENT),
155 }; 156 };
diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs
index 85163c4b3..9d433b3b0 100644
--- a/crates/mbe/src/syntax_bridge.rs
+++ b/crates/mbe/src/syntax_bridge.rs
@@ -350,7 +350,7 @@ trait TokenConvertor {
350 return; 350 return;
351 } 351 }
352 352
353 result.push(if k.is_punct() { 353 result.push(if k.is_punct() && k != UNDERSCORE {
354 assert_eq!(range.len(), TextSize::of('.')); 354 assert_eq!(range.len(), TextSize::of('.'));
355 let delim = match k { 355 let delim = match k {
356 T!['('] => Some((tt::DelimiterKind::Parenthesis, T![')'])), 356 T!['('] => Some((tt::DelimiterKind::Parenthesis, T![')'])),
@@ -362,7 +362,7 @@ trait TokenConvertor {
362 if let Some((kind, closed)) = delim { 362 if let Some((kind, closed)) = delim {
363 let mut subtree = tt::Subtree::default(); 363 let mut subtree = tt::Subtree::default();
364 let (id, idx) = self.id_alloc().open_delim(range); 364 let (id, idx) = self.id_alloc().open_delim(range);
365 subtree.delimiter = Some(tt::Delimiter { kind, id }); 365 subtree.delimiter = Some(tt::Delimiter { id, kind });
366 366
367 while self.peek().map(|it| it.kind() != closed).unwrap_or(false) { 367 while self.peek().map(|it| it.kind() != closed).unwrap_or(false) {
368 self.collect_leaf(&mut subtree.token_trees); 368 self.collect_leaf(&mut subtree.token_trees);
@@ -395,7 +395,9 @@ trait TokenConvertor {
395 { 395 {
396 tt::Spacing::Alone 396 tt::Spacing::Alone
397 } 397 }
398 Some(next) if next.kind().is_punct() => tt::Spacing::Joint, 398 Some(next) if next.kind().is_punct() && next.kind() != UNDERSCORE => {
399 tt::Spacing::Joint
400 }
399 _ => tt::Spacing::Alone, 401 _ => tt::Spacing::Alone,
400 }; 402 };
401 let char = match token.to_char() { 403 let char = match token.to_char() {
@@ -415,6 +417,7 @@ trait TokenConvertor {
415 let leaf: tt::Leaf = match k { 417 let leaf: tt::Leaf = match k {
416 T![true] | T![false] => make_leaf!(Ident), 418 T![true] | T![false] => make_leaf!(Ident),
417 IDENT => make_leaf!(Ident), 419 IDENT => make_leaf!(Ident),
420 UNDERSCORE => make_leaf!(Ident),
418 k if k.is_keyword() => make_leaf!(Ident), 421 k if k.is_keyword() => make_leaf!(Ident),
419 k if k.is_literal() => make_leaf!(Literal), 422 k if k.is_literal() => make_leaf!(Literal),
420 LIFETIME_IDENT => { 423 LIFETIME_IDENT => {
diff --git a/crates/mbe/src/tests/expand.rs b/crates/mbe/src/tests/expand.rs
index 9dd8ff75b..8951f3813 100644
--- a/crates/mbe/src/tests/expand.rs
+++ b/crates/mbe/src/tests/expand.rs
@@ -1080,6 +1080,12 @@ macro_rules! q {
1080} 1080}
1081 1081
1082#[test] 1082#[test]
1083fn test_underscore_lifetime() {
1084 parse_macro(r#"macro_rules! q { ($a:lifetime) => {0}; }"#)
1085 .assert_expand_items(r#"q!['_]"#, r#"0"#);
1086}
1087
1088#[test]
1083fn test_vertical_bar_with_pat() { 1089fn test_vertical_bar_with_pat() {
1084 parse_macro( 1090 parse_macro(
1085 r#" 1091 r#"
@@ -1219,8 +1225,7 @@ macro_rules! m {
1219 ) 1225 )
1220 .expand_statements(r#"m!(C("0"))"#) 1226 .expand_statements(r#"m!(C("0"))"#)
1221 .descendants() 1227 .descendants()
1222 .find(|token| token.kind() == ERROR) 1228 .any(|token| token.kind() == ERROR));
1223 .is_some());
1224} 1229}
1225 1230
1226#[test] 1231#[test]
diff --git a/crates/mbe/src/tests/rule.rs b/crates/mbe/src/tests/rule.rs
index 07277966d..bf48112b3 100644
--- a/crates/mbe/src/tests/rule.rs
+++ b/crates/mbe/src/tests/rule.rs
@@ -12,6 +12,9 @@ fn test_valid_arms() {
12 } 12 }
13 13
14 check("($i:ident) => ()"); 14 check("($i:ident) => ()");
15 check("($(x),*) => ()");
16 check("($(x)_*) => ()");
17 check("($(x)i*) => ()");
15 check("($($i:ident)*) => ($_)"); 18 check("($($i:ident)*) => ($_)");
16 check("($($true:ident)*) => ($true)"); 19 check("($($true:ident)*) => ($true)");
17 check("($($false:ident)*) => ($false)"); 20 check("($($false:ident)*) => ($false)");
@@ -32,6 +35,7 @@ fn test_invalid_arms() {
32 35
33 check("($i) => ($i)", ParseError::UnexpectedToken("bad fragment specifier 1".into())); 36 check("($i) => ($i)", ParseError::UnexpectedToken("bad fragment specifier 1".into()));
34 check("($i:) => ($i)", ParseError::UnexpectedToken("bad fragment specifier 1".into())); 37 check("($i:) => ($i)", ParseError::UnexpectedToken("bad fragment specifier 1".into()));
38 check("($i:_) => ()", ParseError::UnexpectedToken("bad fragment specifier 1".into()));
35} 39}
36 40
37fn parse_macro_arm(arm_definition: &str) -> Result<crate::MacroRules, ParseError> { 41fn parse_macro_arm(arm_definition: &str) -> Result<crate::MacroRules, ParseError> {
diff --git a/crates/mbe/src/tt_iter.rs b/crates/mbe/src/tt_iter.rs
index a362d31fc..319a40f2a 100644
--- a/crates/mbe/src/tt_iter.rs
+++ b/crates/mbe/src/tt_iter.rs
@@ -50,6 +50,13 @@ impl<'a> TtIter<'a> {
50 50
51 pub(crate) fn expect_ident(&mut self) -> Result<&'a tt::Ident, ()> { 51 pub(crate) fn expect_ident(&mut self) -> Result<&'a tt::Ident, ()> {
52 match self.expect_leaf()? { 52 match self.expect_leaf()? {
53 tt::Leaf::Ident(it) if it.text != "_" => Ok(it),
54 _ => Err(()),
55 }
56 }
57
58 pub(crate) fn expect_ident_or_underscore(&mut self) -> Result<&'a tt::Ident, ()> {
59 match self.expect_leaf()? {
53 tt::Leaf::Ident(it) => Ok(it), 60 tt::Leaf::Ident(it) => Ok(it),
54 _ => Err(()), 61 _ => Err(()),
55 } 62 }