mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 21:05:02 +00:00
Fix incorrect repeat sep eating
This commit is contained in:
parent
5bbd9f43cc
commit
e4e2338f97
3 changed files with 304 additions and 24 deletions
|
@ -384,7 +384,7 @@ impl_froms!(TokenTree: Leaf, Subtree);
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_expansion(&rules, "foo! { foo, bar }", "fn baz {foo () ; bar () ;}");
|
assert_expansion(&rules, "foo! { foo, bar }", "fn baz {foo () ; bar ()}");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1066,4 +1066,260 @@ macro_rules! int_base {
|
||||||
"# [stable (feature = \"rust1\" , since = \"1.0.0\")] impl fmt :: Binary for isize {fn fmt (& self , f : & mut fmt :: Formatter < \'_ >) -> fmt :: Result {Binary . fmt_int (* self as usize , f)}}"
|
"# [stable (feature = \"rust1\" , since = \"1.0.0\")] impl fmt :: Binary for isize {fn fmt (& self , f : & mut fmt :: Formatter < \'_ >) -> fmt :: Result {Binary . fmt_int (* self as usize , f)}}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_generate_pattern_iterators() {
|
||||||
|
// from https://github.com/rust-lang/rust/blob/316a391dcb7d66dc25f1f9a4ec9d368ef7615005/src/libcore/str/mod.rs
|
||||||
|
let rules = create_rules(
|
||||||
|
r#"
|
||||||
|
macro_rules! generate_pattern_iterators {
|
||||||
|
{ double ended; with $(#[$common_stability_attribute:meta])*,
|
||||||
|
$forward_iterator:ident,
|
||||||
|
$reverse_iterator:ident, $iterty:ty
|
||||||
|
} => {
|
||||||
|
fn foo(){}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_expansion(&rules, r#"generate_pattern_iterators ! ( double ended ; with # [ stable ( feature = "rust1" , since = "1.0.0" ) ] , Split , RSplit , & 'a str )"#,
|
||||||
|
"fn foo () {}");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_impl_fn_for_zst() {
|
||||||
|
// from https://github.com/rust-lang/rust/blob/5d20ff4d2718c820632b38c1e49d4de648a9810b/src/libcore/internal_macros.rs
|
||||||
|
let rules = create_rules(
|
||||||
|
r#"
|
||||||
|
macro_rules! impl_fn_for_zst {
|
||||||
|
{ $( $( #[$attr: meta] )*
|
||||||
|
struct $Name: ident impl$( <$( $lifetime : lifetime ),+> )? Fn =
|
||||||
|
|$( $arg: ident: $ArgTy: ty ),*| -> $ReturnTy: ty
|
||||||
|
$body: block; )+
|
||||||
|
} => {
|
||||||
|
fn foo(){}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_expansion(&rules, r#"
|
||||||
|
impl_fn_for_zst ! {
|
||||||
|
# [ derive ( Clone ) ]
|
||||||
|
struct CharEscapeDebugContinue impl Fn = | c : char | -> char :: EscapeDebug {
|
||||||
|
c . escape_debug_ext ( false )
|
||||||
|
} ;
|
||||||
|
|
||||||
|
# [ derive ( Clone ) ]
|
||||||
|
struct CharEscapeUnicode impl Fn = | c : char | -> char :: EscapeUnicode {
|
||||||
|
c . escape_unicode ( )
|
||||||
|
} ;
|
||||||
|
# [ derive ( Clone ) ]
|
||||||
|
struct CharEscapeDefault impl Fn = | c : char | -> char :: EscapeDefault {
|
||||||
|
c . escape_default ( )
|
||||||
|
} ;
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
"fn foo () {}");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_impl_nonzero_fmt() {
|
||||||
|
// from https://github.com/rust-lang/rust/blob/316a391dcb7d66dc25f1f9a4ec9d368ef7615005/src/libcore/num/mod.rs#L12
|
||||||
|
let rules = create_rules(
|
||||||
|
r#"
|
||||||
|
macro_rules! impl_nonzero_fmt {
|
||||||
|
( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => {
|
||||||
|
fn foo() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_expansion(&rules, r#"impl_nonzero_fmt ! { # [ stable ( feature = "nonzero" , since = "1.28.0" ) ] ( Debug , Display , Binary , Octal , LowerHex , UpperHex ) for NonZeroU8 }"#,
|
||||||
|
"fn foo () {}");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tuple_impls() {
|
||||||
|
// from https://github.com/rust-lang/rust/blob/316a391dcb7d66dc25f1f9a4ec9d368ef7615005/src/libcore/num/mod.rs#L12
|
||||||
|
let rules = create_rules(
|
||||||
|
r#"
|
||||||
|
macro_rules! tuple_impls {
|
||||||
|
($(
|
||||||
|
$Tuple:ident {
|
||||||
|
$(($idx:tt) -> $T:ident)+
|
||||||
|
}
|
||||||
|
)+) => {
|
||||||
|
$(
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
impl<$($T:PartialEq),+> PartialEq for ($($T,)+) where last_type!($($T,)+): ?Sized {
|
||||||
|
#[inline]
|
||||||
|
fn eq(&self, other: &($($T,)+)) -> bool {
|
||||||
|
$(self.$idx == other.$idx)&&+
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn ne(&self, other: &($($T,)+)) -> bool {
|
||||||
|
$(self.$idx != other.$idx)||+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
impl<$($T:Eq),+> Eq for ($($T,)+) where last_type!($($T,)+): ?Sized {}
|
||||||
|
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
impl<$($T:PartialOrd + PartialEq),+> PartialOrd for ($($T,)+)
|
||||||
|
where last_type!($($T,)+): ?Sized {
|
||||||
|
#[inline]
|
||||||
|
fn partial_cmp(&self, other: &($($T,)+)) -> Option<Ordering> {
|
||||||
|
lexical_partial_cmp!($(self.$idx, other.$idx),+)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn lt(&self, other: &($($T,)+)) -> bool {
|
||||||
|
lexical_ord!(lt, $(self.$idx, other.$idx),+)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn le(&self, other: &($($T,)+)) -> bool {
|
||||||
|
lexical_ord!(le, $(self.$idx, other.$idx),+)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn ge(&self, other: &($($T,)+)) -> bool {
|
||||||
|
lexical_ord!(ge, $(self.$idx, other.$idx),+)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn gt(&self, other: &($($T,)+)) -> bool {
|
||||||
|
lexical_ord!(gt, $(self.$idx, other.$idx),+)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
impl<$($T:Ord),+> Ord for ($($T,)+) where last_type!($($T,)+): ?Sized {
|
||||||
|
#[inline]
|
||||||
|
fn cmp(&self, other: &($($T,)+)) -> Ordering {
|
||||||
|
lexical_cmp!($(self.$idx, other.$idx),+)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
impl<$($T:Default),+> Default for ($($T,)+) {
|
||||||
|
#[inline]
|
||||||
|
fn default() -> ($($T,)+) {
|
||||||
|
($({ let x: $T = Default::default(); x},)+)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)+
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_expansion(
|
||||||
|
&rules,
|
||||||
|
r#"tuple_impls ! {
|
||||||
|
Tuple1 {
|
||||||
|
( 0 ) -> A
|
||||||
|
}
|
||||||
|
Tuple2 {
|
||||||
|
( 0 ) -> A
|
||||||
|
( 1 ) -> B
|
||||||
|
}
|
||||||
|
Tuple3 {
|
||||||
|
( 0 ) -> A
|
||||||
|
( 1 ) -> B
|
||||||
|
( 2 ) -> C
|
||||||
|
}
|
||||||
|
Tuple4 {
|
||||||
|
( 0 ) -> A
|
||||||
|
( 1 ) -> B
|
||||||
|
( 2 ) -> C
|
||||||
|
( 3 ) -> D
|
||||||
|
}
|
||||||
|
Tuple5 {
|
||||||
|
( 0 ) -> A
|
||||||
|
( 1 ) -> B
|
||||||
|
( 2 ) -> C
|
||||||
|
( 3 ) -> D
|
||||||
|
( 4 ) -> E
|
||||||
|
}
|
||||||
|
Tuple6 {
|
||||||
|
( 0 ) -> A
|
||||||
|
( 1 ) -> B
|
||||||
|
( 2 ) -> C
|
||||||
|
( 3 ) -> D
|
||||||
|
( 4 ) -> E
|
||||||
|
( 5 ) -> F
|
||||||
|
}
|
||||||
|
Tuple7 {
|
||||||
|
( 0 ) -> A
|
||||||
|
( 1 ) -> B
|
||||||
|
( 2 ) -> C
|
||||||
|
( 3 ) -> D
|
||||||
|
( 4 ) -> E
|
||||||
|
( 5 ) -> F
|
||||||
|
( 6 ) -> G
|
||||||
|
}
|
||||||
|
Tuple8 {
|
||||||
|
( 0 ) -> A
|
||||||
|
( 1 ) -> B
|
||||||
|
( 2 ) -> C
|
||||||
|
( 3 ) -> D
|
||||||
|
( 4 ) -> E
|
||||||
|
( 5 ) -> F
|
||||||
|
( 6 ) -> G
|
||||||
|
( 7 ) -> H
|
||||||
|
}
|
||||||
|
Tuple9 {
|
||||||
|
( 0 ) -> A
|
||||||
|
( 1 ) -> B
|
||||||
|
( 2 ) -> C
|
||||||
|
( 3 ) -> D
|
||||||
|
( 4 ) -> E
|
||||||
|
( 5 ) -> F
|
||||||
|
( 6 ) -> G
|
||||||
|
( 7 ) -> H
|
||||||
|
( 8 ) -> I
|
||||||
|
}
|
||||||
|
Tuple10 {
|
||||||
|
( 0 ) -> A
|
||||||
|
( 1 ) -> B
|
||||||
|
( 2 ) -> C
|
||||||
|
( 3 ) -> D
|
||||||
|
( 4 ) -> E
|
||||||
|
( 5 ) -> F
|
||||||
|
( 6 ) -> G
|
||||||
|
( 7 ) -> H
|
||||||
|
( 8 ) -> I
|
||||||
|
( 9 ) -> J
|
||||||
|
}
|
||||||
|
Tuple11 {
|
||||||
|
( 0 ) -> A
|
||||||
|
( 1 ) -> B
|
||||||
|
( 2 ) -> C
|
||||||
|
( 3 ) -> D
|
||||||
|
( 4 ) -> E
|
||||||
|
( 5 ) -> F
|
||||||
|
( 6 ) -> G
|
||||||
|
( 7 ) -> H
|
||||||
|
( 8 ) -> I
|
||||||
|
( 9 ) -> J
|
||||||
|
( 10 ) -> K
|
||||||
|
}
|
||||||
|
Tuple12 {
|
||||||
|
( 0 ) -> A
|
||||||
|
( 1 ) -> B
|
||||||
|
( 2 ) -> C
|
||||||
|
( 3 ) -> D
|
||||||
|
( 4 ) -> E
|
||||||
|
( 5 ) -> F
|
||||||
|
( 6 ) -> G
|
||||||
|
( 7 ) -> H
|
||||||
|
( 8 ) -> I
|
||||||
|
( 9 ) -> J
|
||||||
|
( 10 ) -> K
|
||||||
|
( 11 ) -> L
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
"fn foo () {}",
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -179,10 +179,10 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings,
|
||||||
// Enable followiing code when everything is fixed
|
// Enable followiing code when everything is fixed
|
||||||
// At least we can dogfood itself to not stackoverflow
|
// At least we can dogfood itself to not stackoverflow
|
||||||
//
|
//
|
||||||
// "tt" => {
|
"tt" => {
|
||||||
// let token = input.eat().ok_or(ExpandError::UnexpectedToken)?.clone();
|
let token = input.eat().ok_or(ExpandError::UnexpectedToken)?.clone();
|
||||||
// res.inner.insert(text.clone(), Binding::Simple(token.into()));
|
res.inner.insert(text.clone(), Binding::Simple(token.into()));
|
||||||
// }
|
}
|
||||||
"item" => {
|
"item" => {
|
||||||
let item =
|
let item =
|
||||||
input.eat_item().ok_or(ExpandError::UnexpectedToken)?.clone();
|
input.eat_item().ok_or(ExpandError::UnexpectedToken)?.clone();
|
||||||
|
@ -226,18 +226,36 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings,
|
||||||
// This should be replaced by a propper macro-by-example implementation
|
// This should be replaced by a propper macro-by-example implementation
|
||||||
let mut limit = 128;
|
let mut limit = 128;
|
||||||
let mut counter = 0;
|
let mut counter = 0;
|
||||||
while let Ok(nested) = match_lhs(subtree, input) {
|
|
||||||
counter += 1;
|
let mut memento = input.save();
|
||||||
limit -= 1;
|
|
||||||
if limit == 0 {
|
loop {
|
||||||
break;
|
match match_lhs(subtree, input) {
|
||||||
}
|
Ok(nested) => {
|
||||||
res.push_nested(nested)?;
|
counter += 1;
|
||||||
if let Some(separator) = *separator {
|
limit -= 1;
|
||||||
if !input.is_eof() {
|
if limit == 0 {
|
||||||
if input.eat_punct().map(|p| p.char) != Some(separator) {
|
break;
|
||||||
return Err(ExpandError::UnexpectedToken);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memento = input.save();
|
||||||
|
res.push_nested(nested)?;
|
||||||
|
if counter == 1 {
|
||||||
|
if let crate::RepeatKind::ZeroOrOne = kind {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(separator) = *separator {
|
||||||
|
if input.eat_punct().map(|p| p.char) != Some(separator) {
|
||||||
|
input.rollback(memento);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
input.rollback(memento);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -246,10 +264,6 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings,
|
||||||
crate::RepeatKind::OneOrMore if counter == 0 => {
|
crate::RepeatKind::OneOrMore if counter == 0 => {
|
||||||
return Err(ExpandError::UnexpectedToken);
|
return Err(ExpandError::UnexpectedToken);
|
||||||
}
|
}
|
||||||
crate::RepeatKind::ZeroOrOne if counter > 1 => {
|
|
||||||
return Err(ExpandError::UnexpectedToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -333,10 +347,7 @@ fn expand_tt(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nesting.pop().unwrap();
|
nesting.pop().unwrap();
|
||||||
|
if has_sep {
|
||||||
// Dirty hack for remove the last sep
|
|
||||||
// if it is a "," undo the push
|
|
||||||
if has_sep && repeat.separator.unwrap() == ',' {
|
|
||||||
token_trees.pop();
|
token_trees.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,10 @@ pub(crate) struct TtCursor<'a> {
|
||||||
pos: usize,
|
pos: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) struct TtCursorMemento {
|
||||||
|
pos: usize,
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> TtCursor<'a> {
|
impl<'a> TtCursor<'a> {
|
||||||
pub(crate) fn new(subtree: &'a tt::Subtree) -> TtCursor<'a> {
|
pub(crate) fn new(subtree: &'a tt::Subtree) -> TtCursor<'a> {
|
||||||
TtCursor { subtree, pos: 0 }
|
TtCursor { subtree, pos: 0 }
|
||||||
|
@ -157,4 +161,13 @@ impl<'a> TtCursor<'a> {
|
||||||
Err(ParseError::Expected(format!("`{}`", char)))
|
Err(ParseError::Expected(format!("`{}`", char)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub(crate) fn save(&self) -> TtCursorMemento {
|
||||||
|
TtCursorMemento { pos: self.pos }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn rollback(&mut self, memento: TtCursorMemento) {
|
||||||
|
self.pos = memento.pos;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue