Scan hex values

master
Araozu 2022-11-28 17:05:43 -05:00
parent 730c5391d9
commit a788a12eb3
3 changed files with 52 additions and 24 deletions

View File

@ -34,7 +34,7 @@ fn next_token(chars: &Chars, current_pos: usize) -> (Option<Token>, usize) {
// Test number // Test number
if utils::is_digit(next_char) { if utils::is_digit(next_char) {
let (token, next_pos) = scanner::number(chars, current_pos); let (token, next_pos) = scanner::number(chars, current_pos).unwrap();
(Some(token), next_pos) (Some(token), next_pos)
} else { } else {
(None, current_pos) (None, current_pos)

View File

@ -2,7 +2,7 @@ use super::token::Token;
mod number; mod number;
pub fn number(chars: &Vec<char>, start_pos: usize) -> (Token, usize) { pub fn number(chars: &Vec<char>, start_pos: usize) -> Result<(Token, usize), String> {
number::scan(chars, start_pos) number::scan(chars, start_pos)
} }

View File

@ -1,6 +1,10 @@
use crate::syntax::{token::{Token, self}, utils}; use crate::syntax::{token::{Token, self}, utils};
pub fn scan(chars: &Vec<char>, start_pos: usize) -> (Token, usize) { /// Function to scan a number
///
/// This function assumes that the character at `start_pos` is a number [0-9],
/// if not it will panic
pub fn scan(chars: &Vec<char>, start_pos: usize) -> Result<(Token, usize), String> {
let next_char = chars.get(start_pos); let next_char = chars.get(start_pos);
// Try to scan a HEX value // Try to scan a HEX value
@ -17,10 +21,12 @@ pub fn scan(chars: &Vec<char>, start_pos: usize) -> (Token, usize) {
} }
scan_decimal(chars, start_pos, String::from("")) Ok(scan_decimal(chars, start_pos, String::from("")))
} }
/// Scans an integer. /// Recursively scans an integer
///
/// Since the first call will always have a char [0-9], always returns.
fn scan_decimal(chars: &Vec<char>, start_pos: usize, current: String) -> (Token, usize) { fn scan_decimal(chars: &Vec<char>, start_pos: usize, current: String) -> (Token, usize) {
let next_char = chars.get(start_pos); let next_char = chars.get(start_pos);
@ -40,12 +46,12 @@ fn scan_decimal(chars: &Vec<char>, start_pos: usize, current: String) -> (Token,
(token::new_number(current, start_pos as i32), start_pos) (token::new_number(current, start_pos as i32), start_pos)
} }
/// Scans a hex number. If successful, always returns '0x...', never '0X...' /// Recursively scans a hex number
/// ///
/// `current == ""` /// This function expects the following:
/// /// - The char at `start_pos` is a value between [0-9a-fA-F]. If not, will return an error.
/// `start_pos` indicates the start of the hex value /// - On the first call, `current == "0x"`. If not will return an incorrect value, or panic.
fn scan_hex(chars: &Vec<char>, start_pos: usize, current: String) -> (Token, usize) { fn scan_hex(chars: &Vec<char>, start_pos: usize, current: String) -> Result<(Token, usize), String> {
let next_char = chars.get(start_pos); let next_char = chars.get(start_pos);
if let Some(c) = next_char { if let Some(c) = next_char {
@ -56,8 +62,13 @@ fn scan_hex(chars: &Vec<char>, start_pos: usize, current: String) -> (Token, usi
} }
} }
// Return current value // If the current value is "0x" that means that there wasn't any hex number thereafter
(token::new_number(current, start_pos as i32), start_pos) 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))
}
} }
@ -77,7 +88,7 @@ mod tests {
let input = str_to_vec("123"); let input = str_to_vec("123");
let start_pos = 0; let start_pos = 0;
let (token, next) = scan(&input, start_pos); let (token, next) = scan(&input, start_pos).unwrap();
assert_eq!(3, next); assert_eq!(3, next);
assert_eq!(TokenType::Number, token.token_type); assert_eq!(TokenType::Number, token.token_type);
assert_eq!("123", token.value); assert_eq!("123", token.value);
@ -86,7 +97,7 @@ mod tests {
let input = str_to_vec("0123 "); let input = str_to_vec("0123 ");
let start_pos = 0; let start_pos = 0;
let (token, next) = scan(&input, start_pos); let (token, next) = scan(&input, start_pos).unwrap();
assert_eq!(4, next); assert_eq!(4, next);
assert_eq!(TokenType::Number, token.token_type); assert_eq!(TokenType::Number, token.token_type);
assert_eq!("0123", token.value); assert_eq!("0123", token.value);
@ -95,7 +106,7 @@ mod tests {
let input = str_to_vec(" 123456 789"); let input = str_to_vec(" 123456 789");
let start_pos = 2; let start_pos = 2;
let (token, next) = scan(&input, start_pos); let (token, next) = scan(&input, start_pos).unwrap();
assert_eq!(8, next); assert_eq!(8, next);
assert_eq!(TokenType::Number, token.token_type); assert_eq!(TokenType::Number, token.token_type);
assert_eq!("123456", token.value); assert_eq!("123456", token.value);
@ -106,7 +117,7 @@ mod tests {
let input = str_to_vec("0x20 "); let input = str_to_vec("0x20 ");
let start_pos = 0; let start_pos = 0;
let (token, next) = scan(&input, start_pos); let (token, next) = scan(&input, start_pos).unwrap();
assert_eq!(4, next); assert_eq!(4, next);
assert_eq!(TokenType::Number, token.token_type); assert_eq!(TokenType::Number, token.token_type);
assert_eq!("0x20", token.value); assert_eq!("0x20", token.value);
@ -115,7 +126,7 @@ mod tests {
let input = str_to_vec(" 0Xff23DA "); let input = str_to_vec(" 0Xff23DA ");
let start_pos = 4; let start_pos = 4;
let (token, next) = scan(&input, start_pos); let (token, next) = scan(&input, start_pos).unwrap();
assert_eq!(12, next); assert_eq!(12, next);
assert_eq!(TokenType::Number, token.token_type); assert_eq!(TokenType::Number, token.token_type);
assert_eq!("0xff23DA", token.value); assert_eq!("0xff23DA", token.value);
@ -124,12 +135,29 @@ mod tests {
// Should not scan an incomplete hex value // Should not scan an incomplete hex value
#[test] #[test]
fn test_hex_2() { fn test_hex_2() {
let input = str_to_vec("0x20"); let input = str_to_vec("0x ");
let start_pos = 0; let start_pos = 0;
let (token, next) = scan(&input, start_pos); match scan(&input, start_pos) {
assert_eq!(4, next); Ok(_) => panic!(),
Err(reason) => assert_eq!("Tried to scan an incomplete hex value", reason)
}
let input = str_to_vec("0 x20 ");
let start_pos = 0;
let (token, _) = scan(&input, start_pos).unwrap();
assert_eq!(TokenType::Number, token.token_type); assert_eq!(TokenType::Number, token.token_type);
assert_eq!("0x20", token.value); assert_eq!("0", token.value);
}
// Should not scan a hex value if it doesn't start with 0x
#[test]
fn test_hex_3() {
let input = str_to_vec("1x20");
let start_pos = 0;
let (token, _) = scan(&input, start_pos).unwrap();
assert_eq!(TokenType::Number, token.token_type);
assert_eq!("1", token.value);
} }
} }