Refactor number scanners
This commit is contained in:
parent
53fd824e8d
commit
c46291ed8a
@ -5,52 +5,37 @@ use crate::lexic::{token::{Token, self}, utils};
|
|||||||
/// This function assumes that the character at `start_pos` is a number [0-9],
|
/// This function assumes that the character at `start_pos` is a number [0-9],
|
||||||
/// if not it will panic
|
/// if not it will panic
|
||||||
pub fn scan(chars: &Vec<char>, start_pos: usize) -> Result<(Token, usize), String> {
|
pub fn scan(chars: &Vec<char>, start_pos: usize) -> Result<(Token, usize), String> {
|
||||||
let next_char = chars.get(start_pos);
|
let next_char_1 = chars.get(start_pos);
|
||||||
|
let next_char_2 = chars.get(start_pos + 1);
|
||||||
|
|
||||||
// Try to scan a HEX value
|
match (next_char_1, next_char_2) {
|
||||||
if let Some(c) = next_char {
|
// Test if the input contains a hex number
|
||||||
if *c == '0' {
|
(Some(c1), Some(c2)) if *c1 == '0' && (*c2 == 'x' || *c2 == 'X') => {
|
||||||
// May be an 'x' or 'X'
|
scan_hex(chars, start_pos + 2, String::from("0x"))
|
||||||
let next_next_char = chars.get(start_pos + 1);
|
},
|
||||||
if let Some(c2) = next_next_char {
|
// Scan decimal/double/scientific otherwise
|
||||||
if *c2 == 'x' || *c2 == 'X' {
|
_ => scan_decimal(chars, start_pos, String::from(""))
|
||||||
return scan_hex(chars, start_pos + 2, String::from("0x"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
scan_decimal(chars, start_pos, String::from(""))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Recursively scans an integer. If a dot `.` is found, scans a double,
|
/// Recursively scans an integer. If a dot `.` is found, scans a double,
|
||||||
/// if a `e` is found, scans a number in scientific notation
|
/// if a `e` is found, scans a number in scientific notation
|
||||||
fn scan_decimal(chars: &Vec<char>, start_pos: usize, current: String) -> Result<(Token, usize), String> {
|
fn scan_decimal(chars: &Vec<char>, start_pos: usize, current: String) -> Result<(Token, usize), String> {
|
||||||
let next_char = chars.get(start_pos);
|
match chars.get(start_pos) {
|
||||||
|
Some(c) if *c == '.' => {
|
||||||
|
scan_double(chars, start_pos + 1, utils::str_append(current, *c))
|
||||||
// If a char is found
|
},
|
||||||
if let Some(c) = next_char {
|
Some(c) if *c == 'e' => {
|
||||||
let c = *c;
|
scan_scientific(chars, start_pos + 1, utils::str_append(current, *c))
|
||||||
|
},
|
||||||
// If a dot is found scan a double
|
Some(c) if utils::is_digit(*c) => {
|
||||||
if c == '.' {
|
scan_decimal(chars, start_pos + 1, utils::str_append(current, *c))
|
||||||
return scan_double(chars, start_pos + 1, utils::str_append(current, c))
|
},
|
||||||
}
|
_ => {
|
||||||
// If a `e` is found scan a double with exponent
|
Ok((token::new_number(current, start_pos as i32), start_pos))
|
||||||
else if c == 'e' {
|
|
||||||
return scan_scientific(chars, start_pos + 1, utils::str_append(current, c))
|
|
||||||
}
|
|
||||||
// Scan a decimal number
|
|
||||||
else if utils::is_digit(c) {
|
|
||||||
return scan_decimal(chars, start_pos + 1, utils::str_append(current, c))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the current value
|
|
||||||
Ok((token::new_number(current, start_pos as i32), start_pos))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -60,26 +45,14 @@ fn scan_decimal(chars: &Vec<char>, start_pos: usize, current: String) -> Result<
|
|||||||
/// - The char at `start_pos` is a value between [0-9a-fA-F]. If not, will return an error.
|
/// - The char at `start_pos` is a value between [0-9a-fA-F]. If not, will return an error.
|
||||||
/// - `current == "0x"`. If not will return an incorrect value, or panic.
|
/// - `current == "0x"`. If not will return an incorrect value, or panic.
|
||||||
fn scan_hex(chars: &Vec<char>, start_pos: usize, current: String) -> Result<(Token, usize), String> {
|
fn scan_hex(chars: &Vec<char>, start_pos: usize, current: String) -> Result<(Token, usize), String> {
|
||||||
let next_char = chars.get(start_pos);
|
match chars.get(start_pos) {
|
||||||
|
Some(c) if utils::is_hex_digit(*c) => {
|
||||||
if let Some(c) = next_char {
|
Ok(scan_hex_digits(chars, start_pos + 1, utils::str_append(current, *c)))
|
||||||
let c = *c;
|
},
|
||||||
|
_ => Err(String::from("Tried to scan an incomplete hex value"))
|
||||||
if utils::is_hex_digit(c) {
|
|
||||||
return scan_hex(chars, start_pos + 1, utils::str_append(current, c))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the current value is "0x" that means that there wasn't any hex number thereafter
|
|
||||||
if current.len() == 2 {
|
|
||||||
Err(String::from("Tried to scan an incomplete hex value"))
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Ok((token::new_number(current, start_pos as i32), start_pos))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Scans a floating point number
|
/// Scans a floating point number
|
||||||
///
|
///
|
||||||
/// This function expects the following:
|
/// This function expects the following:
|
||||||
@ -87,15 +60,14 @@ fn scan_hex(chars: &Vec<char>, start_pos: usize, current: String) -> Result<(Tok
|
|||||||
///
|
///
|
||||||
/// Returns a syntax error if the char at `start_pos` is not a value between [0-9]
|
/// Returns a syntax error if the char at `start_pos` is not a value between [0-9]
|
||||||
fn scan_double(chars: &Vec<char>, start_pos: usize, current: String) -> Result<(Token, usize), String> {
|
fn scan_double(chars: &Vec<char>, start_pos: usize, current: String) -> Result<(Token, usize), String> {
|
||||||
let next_char = chars.get(start_pos);
|
match chars.get(start_pos) {
|
||||||
|
Some(c) if utils::is_digit(*c) => {
|
||||||
// Check that the first characters exists and is a number
|
Ok(scan_digits(chars, start_pos, current))
|
||||||
if let Some(c) = next_char {
|
},
|
||||||
if utils::is_digit(*c) { Ok(scan_digits(chars, start_pos, current)) }
|
Some(_) => {
|
||||||
else {Err(String::from("The character after the dot when scanning a double is not a number."))}
|
Err(String::from("The character after the dot when scanning a double is not a number."))
|
||||||
}
|
},
|
||||||
else {
|
_ => Err(String::from("EOF when scanning a double number."))
|
||||||
Err(String::from("EOF when scanning a double number."))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,18 +96,22 @@ fn scan_scientific(chars: &Vec<char>, start_pos: usize, current: String) -> Resu
|
|||||||
|
|
||||||
/// Scans chars between [0-9], returns when none is found
|
/// Scans chars between [0-9], returns when none is found
|
||||||
fn scan_digits(chars: &Vec<char>, start_pos: usize, current: String) -> (Token, usize) {
|
fn scan_digits(chars: &Vec<char>, start_pos: usize, current: String) -> (Token, usize) {
|
||||||
let next_char = chars.get(start_pos);
|
match chars.get(start_pos) {
|
||||||
|
Some(c) if utils::is_digit(*c) => {
|
||||||
if let Some(c) = next_char {
|
scan_digits(chars, start_pos + 1, utils::str_append(current, *c))
|
||||||
let c = *c;
|
},
|
||||||
|
_ => (token::new_number(current, start_pos as i32), start_pos)
|
||||||
if utils::is_digit(c) {
|
|
||||||
return scan_digits(chars, start_pos + 1, utils::str_append(current, c))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Return current value
|
/// Scans chars between [0-9a-fA-F], returns when none is found
|
||||||
(token::new_number(current, start_pos as i32), start_pos)
|
fn scan_hex_digits(chars: &Vec<char>, start_pos: usize, current: String) -> (Token, usize) {
|
||||||
|
match chars.get(start_pos) {
|
||||||
|
Some(c) if utils::is_hex_digit(*c) => {
|
||||||
|
scan_hex_digits(chars, start_pos + 1, utils::str_append(current, *c))
|
||||||
|
},
|
||||||
|
_ => (token::new_number(current, start_pos as i32), start_pos)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user