Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/syntax/src/ast/token_ext.rs359
1 files changed, 146 insertions, 213 deletions
diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs
index cc7e5150b3..3b0a1c5ddc 100644
--- a/crates/syntax/src/ast/token_ext.rs
+++ b/crates/syntax/src/ast/token_ext.rs
@@ -288,124 +288,142 @@ pub trait HasFormatSpecifier: AstToken {
Some(char_ranges) => char_ranges,
None => return,
};
- let mut chars = char_ranges.iter().peekable();
+ let mut chars = char_ranges
+ .iter()
+ .filter_map(|(range, res)| Some((*range, *res.as_ref().ok()?)))
+ .peekable();
while let Some((range, first_char)) = chars.next() {
- match first_char {
- Ok('{') => {
- // Format specifier, see syntax at https://doc.rust-lang.org/std/fmt/index.html#syntax
- if let Some((_, Ok('{'))) = chars.peek() {
- // Escaped format specifier, `{{`
- chars.next();
- continue;
- }
+ if let '{' = first_char {
+ // Format specifier, see syntax at https://doc.rust-lang.org/std/fmt/index.html#syntax
+ if let Some((_, '{')) = chars.peek() {
+ // Escaped format specifier, `{{`
+ chars.next();
+ continue;
+ }
- callback(*range, FormatSpecifier::Open);
+ callback(range, FormatSpecifier::Open);
- // check for integer/identifier
- match chars
- .peek()
- .and_then(|next| next.1.as_ref().ok())
- .copied()
- .unwrap_or_default()
- {
- '0'..='9' => {
- // integer
- read_integer(&mut chars, &mut callback);
+ // check for integer/identifier
+ let (_, int_char) = chars.peek().copied().unwrap_or_default();
+ match int_char {
+ // integer
+ '0'..='9' => read_integer(&mut chars, &mut callback),
+ // identifier
+ c if c == '_' || c.is_alphabetic() => {
+ read_identifier(&mut chars, &mut callback)
+ }
+ _ => {}
+ }
+
+ if let Some((_, ':')) = chars.peek() {
+ skip_char_and_emit(&mut chars, FormatSpecifier::Colon, &mut callback);
+
+ // check for fill/align
+ let mut cloned = chars.clone().take(2);
+ let (_, first) = cloned.next().unwrap_or_default();
+ let (_, second) = cloned.next().unwrap_or_default();
+ match second {
+ '<' | '^' | '>' => {
+ // alignment specifier, first char specifies fillment
+ skip_char_and_emit(&mut chars, FormatSpecifier::Fill, &mut callback);
+ skip_char_and_emit(&mut chars, FormatSpecifier::Align, &mut callback);
}
- c if c == '_' || c.is_alphabetic() => {
- // identifier
- read_identifier(&mut chars, &mut callback);
+ _ => {
+ if let '<' | '^' | '>' = first {
+ skip_char_and_emit(
+ &mut chars,
+ FormatSpecifier::Align,
+ &mut callback,
+ );
+ }
+ }
+ }
+
+ // check for sign
+ match chars.peek().copied().unwrap_or_default().1 {
+ '+' | '-' => {
+ skip_char_and_emit(&mut chars, FormatSpecifier::Sign, &mut callback);
}
_ => {}
}
- if let Some((_, Ok(':'))) = chars.peek() {
- skip_char_and_emit(&mut chars, FormatSpecifier::Colon, &mut callback);
-
- // check for fill/align
- let mut cloned = chars.clone().take(2);
- let first = cloned
- .next()
- .and_then(|next| next.1.as_ref().ok())
- .copied()
- .unwrap_or_default();
- let second = cloned
- .next()
- .and_then(|next| next.1.as_ref().ok())
- .copied()
- .unwrap_or_default();
- match second {
- '<' | '^' | '>' => {
- // alignment specifier, first char specifies fillment
+ // check for `#`
+ if let Some((_, '#')) = chars.peek() {
+ skip_char_and_emit(&mut chars, FormatSpecifier::NumberSign, &mut callback);
+ }
+
+ // check for `0`
+ let mut cloned = chars.clone().take(2);
+ let first = cloned.next().map(|next| next.1);
+ let second = cloned.next().map(|next| next.1);
+
+ if first == Some('0') && second != Some('$') {
+ skip_char_and_emit(&mut chars, FormatSpecifier::Zero, &mut callback);
+ }
+
+ // width
+ match chars.peek().copied().unwrap_or_default().1 {
+ '0'..='9' => {
+ read_integer(&mut chars, &mut callback);
+ if let Some((_, '$')) = chars.peek() {
skip_char_and_emit(
&mut chars,
- FormatSpecifier::Fill,
+ FormatSpecifier::DollarSign,
&mut callback,
);
+ }
+ }
+ c if c == '_' || c.is_alphabetic() => {
+ read_identifier(&mut chars, &mut callback);
+
+ if chars.peek().map(|&(_, c)| c) == Some('?') {
skip_char_and_emit(
&mut chars,
- FormatSpecifier::Align,
+ FormatSpecifier::QuestionMark,
&mut callback,
);
}
- _ => match first {
- '<' | '^' | '>' => {
+
+ // can be either width (indicated by dollar sign, or type in which case
+ // the next sign has to be `}`)
+ let next = chars.peek().map(|&(_, c)| c);
+
+ match next {
+ Some('$') => skip_char_and_emit(
+ &mut chars,
+ FormatSpecifier::DollarSign,
+ &mut callback,
+ ),
+ Some('}') => {
skip_char_and_emit(
&mut chars,
- FormatSpecifier::Align,
+ FormatSpecifier::Close,
&mut callback,
);
+ continue;
}
- _ => {}
- },
+ _ => continue,
+ };
}
+ _ => {}
+ }
- // check for sign
- match chars
- .peek()
- .and_then(|next| next.1.as_ref().ok())
- .copied()
- .unwrap_or_default()
- {
- '+' | '-' => {
+ // precision
+ if let Some((_, '.')) = chars.peek() {
+ skip_char_and_emit(&mut chars, FormatSpecifier::Dot, &mut callback);
+
+ match chars.peek().copied().unwrap_or_default().1 {
+ '*' => {
skip_char_and_emit(
&mut chars,
- FormatSpecifier::Sign,
+ FormatSpecifier::Asterisk,
&mut callback,
);
}
- _ => {}
- }
-
- // check for `#`
- if let Some((_, Ok('#'))) = chars.peek() {
- skip_char_and_emit(
- &mut chars,
- FormatSpecifier::NumberSign,
- &mut callback,
- );
- }
-
- // check for `0`
- let mut cloned = chars.clone().take(2);
- let first = cloned.next().and_then(|next| next.1.as_ref().ok()).copied();
- let second = cloned.next().and_then(|next| next.1.as_ref().ok()).copied();
-
- if first == Some('0') && second != Some('$') {
- skip_char_and_emit(&mut chars, FormatSpecifier::Zero, &mut callback);
- }
-
- // width
- match chars
- .peek()
- .and_then(|next| next.1.as_ref().ok())
- .copied()
- .unwrap_or_default()
- {
'0'..='9' => {
read_integer(&mut chars, &mut callback);
- if let Some((_, Ok('$'))) = chars.peek() {
+ if let Some((_, '$')) = chars.peek() {
skip_char_and_emit(
&mut chars,
FormatSpecifier::DollarSign,
@@ -415,160 +433,75 @@ pub trait HasFormatSpecifier: AstToken {
}
c if c == '_' || c.is_alphabetic() => {
read_identifier(&mut chars, &mut callback);
-
- if chars.peek().and_then(|next| next.1.as_ref().ok()).copied()
- == Some('?')
- {
- skip_char_and_emit(
- &mut chars,
- FormatSpecifier::QuestionMark,
- &mut callback,
- );
+ if chars.peek().map(|&(_, c)| c) != Some('$') {
+ continue;
}
-
- // can be either width (indicated by dollar sign, or type in which case
- // the next sign has to be `}`)
- let next =
- chars.peek().and_then(|next| next.1.as_ref().ok()).copied();
-
- match next {
- Some('$') => skip_char_and_emit(
- &mut chars,
- FormatSpecifier::DollarSign,
- &mut callback,
- ),
- Some('}') => {
- skip_char_and_emit(
- &mut chars,
- FormatSpecifier::Close,
- &mut callback,
- );
- continue;
- }
- _ => continue,
- };
+ skip_char_and_emit(
+ &mut chars,
+ FormatSpecifier::DollarSign,
+ &mut callback,
+ );
+ }
+ _ => {
+ continue;
}
- _ => {}
}
+ }
- // precision
- if let Some((_, Ok('.'))) = chars.peek() {
- skip_char_and_emit(&mut chars, FormatSpecifier::Dot, &mut callback);
-
- match chars
- .peek()
- .and_then(|next| next.1.as_ref().ok())
- .copied()
- .unwrap_or_default()
- {
- '*' => {
- skip_char_and_emit(
- &mut chars,
- FormatSpecifier::Asterisk,
- &mut callback,
- );
- }
- '0'..='9' => {
- read_integer(&mut chars, &mut callback);
- if let Some((_, Ok('$'))) = chars.peek() {
- skip_char_and_emit(
- &mut chars,
- FormatSpecifier::DollarSign,
- &mut callback,
- );
- }
- }
- c if c == '_' || c.is_alphabetic() => {
- read_identifier(&mut chars, &mut callback);
- if chars.peek().and_then(|next| next.1.as_ref().ok()).copied()
- != Some('$')
- {
- continue;
- }
- skip_char_and_emit(
- &mut chars,
- FormatSpecifier::DollarSign,
- &mut callback,
- );
- }
- _ => {
- continue;
- }
- }
+ // type
+ match chars.peek().copied().unwrap_or_default().1 {
+ '?' => {
+ skip_char_and_emit(
+ &mut chars,
+ FormatSpecifier::QuestionMark,
+ &mut callback,
+ );
}
+ c if c == '_' || c.is_alphabetic() => {
+ read_identifier(&mut chars, &mut callback);
- // type
- match chars
- .peek()
- .and_then(|next| next.1.as_ref().ok())
- .copied()
- .unwrap_or_default()
- {
- '?' => {
+ if chars.peek().map(|&(_, c)| c) == Some('?') {
skip_char_and_emit(
&mut chars,
FormatSpecifier::QuestionMark,
&mut callback,
);
}
- c if c == '_' || c.is_alphabetic() => {
- read_identifier(&mut chars, &mut callback);
-
- if chars.peek().and_then(|next| next.1.as_ref().ok()).copied()
- == Some('?')
- {
- skip_char_and_emit(
- &mut chars,
- FormatSpecifier::QuestionMark,
- &mut callback,
- );
- }
- }
- _ => {}
}
- }
-
- match chars.peek() {
- Some((_, Ok('}'))) => {
- skip_char_and_emit(&mut chars, FormatSpecifier::Close, &mut callback);
- }
- Some((_, _)) | None => continue,
+ _ => {}
}
}
- _ => {
- while let Some((_, Ok(next_char))) = chars.peek() {
- if next_char == &'{' {
- break;
- }
- chars.next();
- }
+
+ if let Some((_, '}')) = chars.peek() {
+ skip_char_and_emit(&mut chars, FormatSpecifier::Close, &mut callback);
}
- };
+ continue;
+ }
}
- fn skip_char_and_emit<'a, I, F>(
+ fn skip_char_and_emit<I, F>(
chars: &mut std::iter::Peekable<I>,
emit: FormatSpecifier,
callback: &mut F,
) where
- I: Iterator<Item = &'a (TextRange, Result<char, rustc_lexer::unescape::EscapeError>)>,
+ I: Iterator<Item = (TextRange, char)>,
F: FnMut(TextRange, FormatSpecifier),
{
let (range, _) = chars.next().unwrap();
- callback(*range, emit);
+ callback(range, emit);
}
- fn read_integer<'a, I, F>(chars: &mut std::iter::Peekable<I>, callback: &mut F)
+ fn read_integer<I, F>(chars: &mut std::iter::Peekable<I>, callback: &mut F)
where
- I: Iterator<Item = &'a (TextRange, Result<char, rustc_lexer::unescape::EscapeError>)>,
+ I: Iterator<Item = (TextRange, char)>,
F: FnMut(TextRange, FormatSpecifier),
{
let (mut range, c) = chars.next().unwrap();
- assert!(c.as_ref().unwrap().is_ascii_digit());
- while let Some((r, Ok(next_char))) = chars.peek() {
+ assert!(c.is_ascii_digit());
+ while let Some(&(r, next_char)) = chars.peek() {
if next_char.is_ascii_digit() {
chars.next();
- range = range.cover(*r);
+ range = range.cover(r);
} else {
break;
}
@@ -576,17 +509,17 @@ pub trait HasFormatSpecifier: AstToken {
callback(range, FormatSpecifier::Integer);
}
- fn read_identifier<'a, I, F>(chars: &mut std::iter::Peekable<I>, callback: &mut F)
+ fn read_identifier<I, F>(chars: &mut std::iter::Peekable<I>, callback: &mut F)
where
- I: Iterator<Item = &'a (TextRange, Result<char, rustc_lexer::unescape::EscapeError>)>,
+ I: Iterator<Item = (TextRange, char)>,
F: FnMut(TextRange, FormatSpecifier),
{
let (mut range, c) = chars.next().unwrap();
- assert!(c.as_ref().unwrap().is_alphabetic() || *c.as_ref().unwrap() == '_');
- while let Some((r, Ok(next_char))) = chars.peek() {
- if *next_char == '_' || next_char.is_ascii_digit() || next_char.is_alphabetic() {
+ assert!(c.is_alphabetic() || c == '_');
+ while let Some(&(r, next_char)) = chars.peek() {
+ if next_char == '_' || next_char.is_ascii_digit() || next_char.is_alphabetic() {
chars.next();
- range = range.cover(*r);
+ range = range.cover(r);
} else {
break;
}