Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change lexer to treat 'e' after number as suffix unless it is followed by a valid exponent. #79912

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_lexer/src/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ impl<'a> Cursor<'a> {
/// If requested position doesn't exist, `EOF_CHAR` is returned.
/// However, getting `EOF_CHAR` doesn't always mean actual end of file,
/// it should be checked with `is_eof` method.
fn nth_char(&self, n: usize) -> char {
pub(crate) fn nth_char(&self, n: usize) -> char {
self.chars().nth(n).unwrap_or(EOF_CHAR)
}

Expand Down
55 changes: 42 additions & 13 deletions compiler/rustc_lexer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -541,23 +541,28 @@ impl Cursor<'_> {
// might have stuff after the ., and if it does, it needs to start
// with a number
self.bump();
let mut empty_exponent = false;
if self.first().is_digit(10) {
self.eat_decimal_digits();
match self.first() {
'e' | 'E' => {
self.bump();
empty_exponent = !self.eat_float_exponent();
}
_ => (),
self.eat_decimal_digits();
if matches!(self.first(), 'e' | 'E') {
if self.is_next_exponent() {
self.bump(); // 'e'
let empty_exponent = !self.eat_float_exponent();
Float { base, empty_exponent }
} else {
// the 'e' should be part of the suffix, don't consume.
Float { base, empty_exponent: false }
}
} else {
Float { base, empty_exponent: false }
}
Float { base, empty_exponent }
}
'e' | 'E' => {
self.bump();
let empty_exponent = !self.eat_float_exponent();
Float { base, empty_exponent }
if self.is_next_exponent() {
self.bump();
let empty_exponent = !self.eat_float_exponent();
Float { base, empty_exponent }
} else {
Int { base, empty_int: false }
}
}
_ => Int { base, empty_int: false },
}
Expand Down Expand Up @@ -782,6 +787,30 @@ impl Cursor<'_> {
has_digits
}

/// Is an exponent the first thing after the cursor? It might be empty. Includes the `'e' | 'E'`
fn is_next_exponent(&mut self) -> bool {
debug_assert!(self.first() == 'e' || self.first() == 'E'); // checked elsewhere
if self.second() == '-' || self.second() == '+' {
// + and - are only allowed in an exponential
true
} else {
let mut found_exponent = false;
// After we've seen 3 sequential underscores, assume it is text and
// not a number. We do this to avoid unbounded lookahead.
for nth in 1..=3 {
match self.nth_char(nth) {
'0'..='9' => {
found_exponent = true;
break;
}
'_' => (), // continue
_ => break,
}
}
found_exponent
}
}

/// Eats the float exponent. Returns true if at least one digit was met,
/// and returns false otherwise.
fn eat_float_exponent(&mut self) -> bool {
Expand Down