use crate::js::lexer::scanner::Scanner;
use crate::js::lexer::token::TokenKind;
fn scan_digits(scanner: &mut Scanner, radix: u32, allow_separator: bool) -> bool {
let mut found = false;
loop {
match scanner.peek() {
Some(ch) if ch.is_digit(radix) || (allow_separator && ch == '_') => {
scanner.advance();
found = true;
}
_ => break,
}
}
found
}
fn scan_exponent(scanner: &mut Scanner) {
match scanner.peek() {
Some('e') | Some('E') => {
scanner.advance();
let _ = scanner.advance_if(|c| c == '+' || c == '-');
scan_digits(scanner, 10, true);
}
_ => {}
}
}
pub fn scan_number(scanner: &mut Scanner) -> TokenKind {
if scanner.peek() == Some('0') {
scanner.advance();
match scanner.peek() {
Some('x') | Some('X') => {
scanner.advance();
let _ = scan_digits(scanner, 16, true);
return check_bigint(scanner);
}
Some('b') | Some('B') => {
scanner.advance();
let _ = scan_digits(scanner, 2, true);
return check_bigint(scanner);
}
Some('o') | Some('O') => {
scanner.advance();
let _ = scan_digits(scanner, 8, true);
return check_bigint(scanner);
}
Some('0'..='7') => {
let _ = scan_digits(scanner, 8, false);
if matches!(scanner.peek(), Some('8') | Some('9')) {
scan_digits(scanner, 10, true);
scan_exponent(scanner);
return TokenKind::Number;
}
if scanner.peek() == Some('.') || matches!(scanner.peek(), Some('e') | Some('E')) {
scan_fraction(scanner);
scan_exponent(scanner);
}
return check_bigint(scanner);
}
Some('_') => {
scan_digits(scanner, 10, true);
scan_fraction_part(scanner);
scan_exponent(scanner);
return check_bigint(scanner);
}
Some('.') => {
scan_fraction(scanner);
scan_exponent(scanner);
return TokenKind::Number;
}
Some('e') | Some('E') => {
scan_exponent(scanner);
return TokenKind::Number;
}
Some('n') => {
scanner.advance();
return TokenKind::BigInt;
}
_ => {}
}
return check_bigint(scanner);
}
if scanner.peek() == Some('.') {
scan_fraction(scanner);
scan_exponent(scanner);
return TokenKind::Number;
}
scan_digits(scanner, 10, true);
scan_fraction_part(scanner);
scan_exponent(scanner);
check_bigint(scanner)
}
fn scan_fraction_part(scanner: &mut Scanner) {
if scanner.peek() == Some('.') {
scan_fraction(scanner);
}
}
fn scan_fraction(scanner: &mut Scanner) {
scanner.advance(); let _ = scan_digits(scanner, 10, true);
}
fn check_bigint(scanner: &mut Scanner) -> TokenKind {
if scanner.peek() == Some('n') && is_bigint_end(scanner) {
scanner.advance();
TokenKind::BigInt
} else {
TokenKind::Number
}
}
fn is_bigint_end(scanner: &mut Scanner) -> bool {
if scanner
.peek_ahead(1)
.is_some_and(|c| c.is_alphanumeric() || c == '_' || c == '.')
{
return false;
}
true
}