use crate::error::LexerError;
use crate::position::InputReader;
pub(crate) fn read_number(reader: &mut InputReader) -> Result<String, LexerError> {
let mut number = String::new();
let start_line = reader.line();
let start_column = reader.column();
if reader.peek() == Some('-') {
number.push('-');
reader.advance();
}
if reader.peek() == Some('0') {
if let Some(next) = reader.peek_ahead(1) {
if next == 'x' || next == 'X' {
parse_hexadecimal(reader, &mut number, start_line, start_column)
} else if next == 'b' || next == 'B' {
parse_binary(reader, &mut number, start_line, start_column)
} else {
parse_decimal_starting_with_zero(reader, &mut number)
}
} else {
number.push('0');
reader.advance();
Ok(number)
}
} else {
parse_decimal(reader, &mut number);
validate_number(number, start_line, start_column)
}
}
fn parse_hexadecimal(
reader: &mut InputReader,
number: &mut String,
start_line: usize,
start_column: usize
) -> Result<String, LexerError> {
let next = reader.peek_ahead(1).unwrap();
number.push('0');
reader.advance(); number.push(next); reader.advance();
let mut has_digits = false;
while let Some(ch) = reader.peek() {
if ch.is_ascii_hexdigit() {
number.push(ch);
reader.advance();
has_digits = true;
} else {
break;
}
}
if !has_digits {
return Err(LexerError::InvalidNumberFormat {
line: start_line,
column: start_column,
value: number.clone(),
});
}
Ok(number.clone())
}
fn parse_binary(
reader: &mut InputReader,
number: &mut String,
start_line: usize,
start_column: usize
) -> Result<String, LexerError> {
let next = reader.peek_ahead(1).unwrap();
number.push('0');
reader.advance(); number.push(next); reader.advance();
let mut has_digits = false;
while let Some(ch) = reader.peek() {
if ch == '0' || ch == '1' {
number.push(ch);
reader.advance();
has_digits = true;
} else {
break;
}
}
if !has_digits {
return Err(LexerError::InvalidNumberFormat {
line: start_line,
column: start_column,
value: number.clone(),
});
}
Ok(number.clone())
}
fn parse_decimal_starting_with_zero(reader: &mut InputReader, number: &mut String) -> Result<String, LexerError> {
while let Some(ch) = reader.peek() {
if ch.is_ascii_digit() {
number.push(ch);
reader.advance();
} else {
break;
}
}
Ok(number.clone())
}
fn parse_decimal(reader: &mut InputReader, number: &mut String) {
while let Some(ch) = reader.peek() {
if ch.is_ascii_digit() {
number.push(ch);
reader.advance();
} else {
break;
}
}
}
fn validate_number(number: String, start_line: usize, start_column: usize) -> Result<String, LexerError> {
if number.is_empty() || number == "-" {
return Err(LexerError::InvalidNumberFormat {
line: start_line,
column: start_column,
value: number,
});
}
Ok(number)
}