use crate::tokenizer::Tokenizer;
pub fn is_varname_char(ch: char) -> bool {
ch.is_alphanumeric() || ch == '_'
}
pub fn read_int(ptr: &mut Tokenizer) -> Option<String> {
let mut p = ptr.clone();
let mut result = String::new();
let mut missing_digits = true;
if p.is('+') || p.is('-') {
result.push(p.next().unwrap());
}
let mut radix = 10;
if p.is('0') {
result.push(p.next().unwrap());
if p.is('x') {
result.push(p.next().unwrap());
radix = 16;
} else {
missing_digits = false;
}
}
while p.has(|ch| ch.is_digit(radix)) {
missing_digits = false;
result.push(p.next().unwrap());
}
if result.is_empty() || missing_digits {
None
} else {
ptr.skip_over(result.len());
Some(result)
}
}
pub fn read_float(ptr: &mut Tokenizer) -> Option<String> {
let mut p = ptr.clone();
let mut result = String::new();
let mut missing_mantissa = true;
let mut missing_exponent = false;
if p.is('+') || p.is('-') {
result.push(p.next().unwrap());
}
if p.is('I') || p.is('i') {
result.push(p.next().unwrap());
if p.is('N') || p.is('n') {
result.push(p.next().unwrap());
} else {
return None;
}
if p.is('F') || p.is('f') {
result.push(p.next().unwrap());
ptr.skip_over(result.len());
return Some(result);
} else {
return None;
}
}
while p.has(|ch| ch.is_digit(10)) {
missing_mantissa = false;
result.push(p.next().unwrap());
}
if p.is('.') {
result.push(p.next().unwrap());
while p.has(|ch| ch.is_digit(10)) {
missing_mantissa = false;
result.push(p.next().unwrap());
}
}
if p.is('e') || p.is('E') {
missing_exponent = true;
result.push(p.next().unwrap());
if p.is('+') || p.is('-') {
result.push(p.next().unwrap());
}
while p.has(|ch| ch.is_digit(10)) {
missing_exponent = false;
result.push(p.next().unwrap());
}
}
if result.is_empty() || missing_mantissa || missing_exponent {
None
} else {
ptr.skip_over(result.len());
Some(result)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_util_read_int() {
let mut p = Tokenizer::new("abc");
assert_eq!(None, read_int(&mut p));
assert_eq!(Some('a'), p.peek());
let mut p = Tokenizer::new("-abc");
assert_eq!(None, read_int(&mut p));
assert_eq!(Some('-'), p.peek());
let mut p = Tokenizer::new("+abc");
assert_eq!(None, read_int(&mut p));
assert_eq!(Some('+'), p.peek());
let mut p = Tokenizer::new("123");
assert_eq!(Some("123".into()), read_int(&mut p));
assert_eq!(None, p.peek());
let mut p = Tokenizer::new("123abc");
assert_eq!(Some("123".into()), read_int(&mut p));
assert_eq!(Some('a'), p.peek());
let mut p = Tokenizer::new("+123abc");
assert_eq!(Some("+123".into()), read_int(&mut p));
assert_eq!(Some('a'), p.peek());
let mut p = Tokenizer::new("-123abc");
assert_eq!(Some("-123".into()), read_int(&mut p));
assert_eq!(Some('a'), p.peek());
}
#[test]
#[allow(clippy::cognitive_complexity)]
fn test_util_read_float() {
let mut p = Tokenizer::new("abc");
assert_eq!(None, read_float(&mut p));
assert_eq!(Some('a'), p.peek());
let mut p = Tokenizer::new("-abc");
assert_eq!(None, read_float(&mut p));
assert_eq!(Some('-'), p.peek());
let mut p = Tokenizer::new("+abc");
assert_eq!(None, read_float(&mut p));
assert_eq!(Some('+'), p.peek());
let mut p = Tokenizer::new("123");
assert_eq!(Some("123".into()), read_float(&mut p));
assert_eq!(None, p.peek());
let mut p = Tokenizer::new("123abc");
assert_eq!(Some("123".into()), read_float(&mut p));
assert_eq!(Some('a'), p.peek());
let mut p = Tokenizer::new("123.");
assert_eq!(Some("123.".into()), read_float(&mut p));
assert_eq!(None, p.peek());
let mut p = Tokenizer::new(".123");
assert_eq!(Some(".123".into()), read_float(&mut p));
assert_eq!(None, p.peek());
let mut p = Tokenizer::new("123.123");
assert_eq!(Some("123.123".into()), read_float(&mut p));
assert_eq!(None, p.peek());
let mut p = Tokenizer::new("1e5");
assert_eq!(Some("1e5".into()), read_float(&mut p));
assert_eq!(None, p.peek());
let mut p = Tokenizer::new("1e+5");
assert_eq!(Some("1e+5".into()), read_float(&mut p));
assert_eq!(None, p.peek());
let mut p = Tokenizer::new("1e-5");
assert_eq!(Some("1e-5".into()), read_float(&mut p));
assert_eq!(None, p.peek());
let mut p = Tokenizer::new("1.1e1a");
assert_eq!(Some("1.1e1".into()), read_float(&mut p));
assert_eq!(Some('a'), p.peek());
let mut p = Tokenizer::new("+123abc");
assert_eq!(Some("+123".into()), read_float(&mut p));
assert_eq!(Some('a'), p.peek());
let mut p = Tokenizer::new("-123abc");
assert_eq!(Some("-123".into()), read_float(&mut p));
assert_eq!(Some('a'), p.peek());
}
}