diff --git a/src/mango/util/parsetxt/int.rs b/src/mango/util/parsetxt/int.rs index d2d22b55..0408acf0 100644 --- a/src/mango/util/parsetxt/int.rs +++ b/src/mango/util/parsetxt/int.rs @@ -1,21 +1,63 @@ +use mango::util::strslice::char_ops::char_drop; use regex::Regex; +#[derive(Debug)] +pub enum IntParseFailReason { + Invalid, + Overflow, + Underflow, +} + /// This matches integer literals, either just numbers in base 10, or base 2-36 with prefix. /// The syntax for -37 in base 16 is -16b25 and 2748 is 16bABC. /// Incorrect values like 4b7 or 0b0 are not handled at the lexing stage. pub fn int_pattern() -> &'static str { - r"(?:\+|-*)(?:[1-9][0-9]*b(?:_?[0-9a-zA-Z])+|[0-9](?:_?[0-9])*)" + r"(?P\+|-?)(?:(?P[1-9][0-9]*)b(?P(?:_?[0-9a-zA-Z])+)|(?P[0-9](?:_?[0-9])*))" } /// Convert a String that matches [int_pattern] to an i64 integer. Overflow is possible. -pub fn parse_int>(text: S) -> Option { +pub fn parse_int>(text: S) -> Result { let text = text.into(); - debug_assert!( - Regex::new(&format!("^{}$", int_pattern())) - .unwrap() - .is_match(&text) - ); - Some(0i64) + match Regex::new(&format!("^{}$", int_pattern())) + .unwrap() + .captures(&text) + { + None => return Err(IntParseFailReason::Invalid), + Some(captures) => { + // Sign + let sign_str = captures.name("sign").unwrap().as_str(); + let sign = if sign_str == "+" || sign_str == "" { + 1 // positive + } else { + -1 // negative + }; + // Check if base10 or special + match captures.name("b10_val") { + None => { + // There is a base provided. + if let Some(base) = captures.name("base") { + if let Some(value) = captures.name("reb_val") { + // TODO: implement + panic!(format!( + "Do not yet know how to deal with {} in base {}", + char_drop(value.as_str(), &'_'), + base.as_str() + )) + } else { + panic!("Expected 'reb_val' match in regex") + } + } else { + panic!("Expected 'base' match in regex") + } + } + Some(value) => { + // This is a 'normal' (base10) value. + // TODO: check for over/underflow + return Ok(char_drop(value.as_str(), &'_').parse::().unwrap()); + } + } + } + } } // TODO: possibly add a i32 version? @@ -27,6 +69,8 @@ mod tests { #[test] fn test_parse_int() { - assert_eq!(42, parse_int("42").unwrap()) + assert_eq!(42, parse_int("42").unwrap()); + assert_eq!(42, parse_int("4_2").unwrap()); + // assert_eq!(42, parse_int("10b4_2").unwrap()); } } diff --git a/src/mango/util/parsetxt/real.rs b/src/mango/util/parsetxt/real.rs index 9d858a55..1ba756c6 100644 --- a/src/mango/util/parsetxt/real.rs +++ b/src/mango/util/parsetxt/real.rs @@ -1,5 +1,13 @@ use regex::Regex; +#[derive(Debug)] +pub enum RealParseFailReason { + Invalid, + Overflow, + Underflow, + PrecisionLoss(f64), +} + /// This matches real literals (base 10), which look like this: /// sign / int1 / period / int2 / e / sign / int /// Here int is a series of 0-9 digits separated by at most one underscore. @@ -8,18 +16,18 @@ pub fn real_pattern() -> &'static str { // TODO: do I want to allow numbers to start with a period? // TODO: for now, only base10 for reals (would 8b11e2 be 9*8^2 or 9*10^2?) // TODO: does not deal with NaN of infinity - r"(?:\+|-*)(?:\d(?:_?\d)*\.\d(?:_?\d)*|\d(?:_?\d)*\.|\.\d(?:_?\d)*)(?:e(?:\+|-|)\d(?:_?\d)*)?" + r"(?P\+|-?)(?:\d(?:_?\d)*\.\d(?:_?\d)*|\d(?:_?\d)*\.|\.\d(?:_?\d)*)(?:e(?P\+|-?)\d(?:_?\d)*)?" } /// Convert a String that matches [real_pattern] to an f64 real. Overflow and loss of precision is possible. -pub fn parse_real>(text: S) -> Option { +pub fn parse_real>(text: S) -> Result { let text = text.into(); debug_assert!( Regex::new(&format!("^{}$", real_pattern())) .unwrap() .is_match(&text) ); - Some(0.0f64) + Ok(0.0f64) } // TODO: possibly add a i32 version? @@ -30,7 +38,7 @@ mod tests { use super::parse_real; #[test] - fn test_parse_int() { + fn test_parse_real() { assert_eq!(42., parse_real("42.").unwrap()) } } diff --git a/src/mango/util/strslice/char_ops.rs b/src/mango/util/strslice/char_ops.rs new file mode 100644 index 00000000..a2e351f4 --- /dev/null +++ b/src/mango/util/strslice/char_ops.rs @@ -0,0 +1,6 @@ +/// Remove all matching characters from the string. +// Signature may be changed to support a set of characters, if the need arises. +pub fn char_drop>(text: S, strip: &char) -> String { + let text = text.into(); + text.chars().filter(|chr| chr != strip).collect() +} diff --git a/src/mango/util/strslice/mod.rs b/src/mango/util/strslice/mod.rs index 5846d94a..08a0519c 100644 --- a/src/mango/util/strslice/mod.rs +++ b/src/mango/util/strslice/mod.rs @@ -2,3 +2,5 @@ pub mod slice; pub use self::slice::charslice; pub use self::slice::charslicefrom; pub use self::slice::charsliceto; + +pub mod char_ops;