diff options
Diffstat (limited to 'crates/mbe/src')
-rw-r--r-- | crates/mbe/src/expander/matcher.rs | 13 | ||||
-rw-r--r-- | crates/mbe/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/mbe/src/parser.rs | 14 | ||||
-rw-r--r-- | crates/mbe/src/subtree_source.rs | 1 | ||||
-rw-r--r-- | crates/mbe/src/syntax_bridge.rs | 9 | ||||
-rw-r--r-- | crates/mbe/src/tests/expand.rs | 9 | ||||
-rw-r--r-- | crates/mbe/src/tests/rule.rs | 4 | ||||
-rw-r--r-- | crates/mbe/src/tt_iter.rs | 7 |
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 | ||
357 | impl<T: Default> From<Result<T, ExpandError>> for ExpandResult<T> { | 357 | impl<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] |
1083 | fn 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] | ||
1083 | fn test_vertical_bar_with_pat() { | 1089 | fn 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 | ||
37 | fn parse_macro_arm(arm_definition: &str) -> Result<crate::MacroRules, ParseError> { | 41 | fn 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 | } |