Skip to content

Commit

Permalink
Parsing of base10 integers implemented #52
Browse files Browse the repository at this point in the history
  • Loading branch information
mverleg committed Jun 17, 2018
1 parent 28bc91a commit fd12412
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 13 deletions.
62 changes: 53 additions & 9 deletions src/mango/util/parsetxt/int.rs
Original file line number Diff line number Diff line change
@@ -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<sign>\+|-?)(?:(?P<base>[1-9][0-9]*)b(?P<reb_val>(?:_?[0-9a-zA-Z])+)|(?P<b10_val>[0-9](?:_?[0-9])*))"
}

/// Convert a String that matches [int_pattern] to an i64 integer. Overflow is possible.
pub fn parse_int<S: Into<String>>(text: S) -> Option<i64> {
pub fn parse_int<S: Into<String>>(text: S) -> Result<i64, IntParseFailReason> {
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::<i64>().unwrap());
}
}
}
}
}

// TODO: possibly add a i32 version?
Expand All @@ -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());
}
}
16 changes: 12 additions & 4 deletions src/mango/util/parsetxt/real.rs
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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<sign>\+|-?)(?:\d(?:_?\d)*\.\d(?:_?\d)*|\d(?:_?\d)*\.|\.\d(?:_?\d)*)(?:e(?P<exp_sign>\+|-?)\d(?:_?\d)*)?"
}

/// Convert a String that matches [real_pattern] to an f64 real. Overflow and loss of precision is possible.
pub fn parse_real<S: Into<String>>(text: S) -> Option<f64> {
pub fn parse_real<S: Into<String>>(text: S) -> Result<f64, RealParseFailReason> {
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?
Expand All @@ -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())
}
}
6 changes: 6 additions & 0 deletions src/mango/util/strslice/char_ops.rs
Original file line number Diff line number Diff line change
@@ -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<S: Into<String>>(text: S, strip: &char) -> String {
let text = text.into();
text.chars().filter(|chr| chr != strip).collect()
}
2 changes: 2 additions & 0 deletions src/mango/util/strslice/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

0 comments on commit fd12412

Please sign in to comment.