Scan simple hex value

This commit is contained in:
Araozu 2022-11-28 16:45:39 -05:00
parent c2946e7a9b
commit 730c5391d9
2 changed files with 86 additions and 7 deletions

View File

@ -1,24 +1,65 @@
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) { pub fn scan(chars: &Vec<char>, start_pos: usize) -> (Token, usize) {
let next_char = chars.get(start_pos);
// Try to scan a HEX value
if let Some(c) = next_char {
if *c == '0' {
// May be an 'x' or 'X'
let next_next_char = chars.get(start_pos + 1);
if let Some(c2) = next_next_char {
if *c2 == 'x' || *c2 == 'X' {
return scan_hex(chars, start_pos + 2, String::from("0x"));
}
}
}
}
scan_decimal(chars, start_pos, String::from("")) scan_decimal(chars, start_pos, String::from(""))
} }
/// Scans an integer.
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);
// If a char is found
if let Some(c) = next_char { if let Some(c) = next_char {
if utils::is_digit(*c) { let c = *c;
let new_value = format!("{}{}", current, *c);
scan_decimal(chars, start_pos + 1, new_value) // Scan a decimal number
} else { if utils::is_digit(c) {
let new_value = format!("{}{}", current, c);
return scan_decimal(chars, start_pos + 1, new_value)
}
}
// Return the current value
(token::new_number(current, start_pos as i32), start_pos) (token::new_number(current, start_pos as i32), start_pos)
} }
} else {
(token::new_number(current, start_pos as i32), start_pos) /// Scans a hex number. If successful, always returns '0x...', never '0X...'
///
/// `current == ""`
///
/// `start_pos` indicates the start of the hex value
fn scan_hex(chars: &Vec<char>, start_pos: usize, current: String) -> (Token, usize) {
let next_char = chars.get(start_pos);
if let Some(c) = next_char {
let c = *c;
if utils::is_hex_digit(c) {
return scan_hex(chars, start_pos + 1, utils::str_append(current, c))
} }
} }
// Return current value
(token::new_number(current, start_pos as i32), start_pos)
}
#[cfg(test)] #[cfg(test)]
@ -59,4 +100,36 @@ mod tests {
assert_eq!(TokenType::Number, token.token_type); assert_eq!(TokenType::Number, token.token_type);
assert_eq!("123456", token.value); assert_eq!("123456", token.value);
} }
#[test]
fn test_hex() {
let input = str_to_vec("0x20");
let start_pos = 0;
let (token, next) = scan(&input, start_pos);
assert_eq!(4, next);
assert_eq!(TokenType::Number, token.token_type);
assert_eq!("0x20", token.value);
let input = str_to_vec(" 0Xff23DA");
let start_pos = 4;
let (token, next) = scan(&input, start_pos);
assert_eq!(12, next);
assert_eq!(TokenType::Number, token.token_type);
assert_eq!("0xff23DA", token.value);
}
// Should not scan an incomplete hex value
#[test]
fn test_hex_2() {
let input = str_to_vec("0x20");
let start_pos = 0;
let (token, next) = scan(&input, start_pos);
assert_eq!(4, next);
assert_eq!(TokenType::Number, token.token_type);
assert_eq!("0x20", token.value);
}
} }

View File

@ -3,4 +3,10 @@ pub fn is_digit(c: char) -> bool {
'0' <= c && c <= '9' '0' <= c && c <= '9'
} }
pub fn is_hex_digit(c: char) -> bool {
is_digit(c) || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F'
}
pub fn str_append(current: String, c: char) -> String {
format!("{}{}", current, c)
}