Skip to content

Commit

Permalink
Fix rationale number parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
danhper committed Jul 23, 2024
1 parent 1b316be commit 64bece3
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 29 deletions.
32 changes: 3 additions & 29 deletions src/interpreter/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use super::builtins;
use super::functions::{FunctionDef, UserDefinedFunction};
use super::parsing::ParsedCode;
use super::types::{HashableIndexMap, Type};
use super::utils::parse_rational_literal;
use super::{env::Env, parsing, value::Value};

pub const SETUP_FUNCTION_NAME: &str = "setUp";
Expand Down Expand Up @@ -320,35 +321,8 @@ pub fn evaluate_expression(env: &mut Env, expr: Box<Expression>) -> BoxFuture<'_
}

Expression::RationalNumberLiteral(_, whole, raw_fraction, raw_exponent, _) => {
let mut n = if whole.is_empty() {
U256::from(0)
} else {
U256::from_str(&whole).map_err(|e| anyhow!("{}", e.to_string()))?
};
let exponent = if raw_exponent.is_empty() {
U256::from(0)
} else {
U256::from_str(&raw_exponent)?
};
n *= U256::from(10).pow(exponent);

let fraction = if raw_fraction.is_empty() {
U256::from(0)
} else {
U256::from_str(&raw_fraction)?
};
let decimals_count = if fraction.is_zero() {
U256::from(0)
} else {
U256::from(fraction.log10() + 1)
};
if decimals_count > exponent {
bail!("fraction has more digits than decimals");
}
let adjusted_fraction = fraction * U256::from(10).pow(exponent - decimals_count);
n += adjusted_fraction;

Ok(Value::Uint(n, 256))
parse_rational_literal(&whole, &raw_fraction, &raw_exponent)
.map(|v| Value::Uint(v, 256))
}

Expression::And(_, lexpr, rexpr) => {
Expand Down
101 changes: 101 additions & 0 deletions src/interpreter/utils.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
use anyhow::{bail, Result};
use std::str::FromStr;

use alloy::primitives::U256;

pub fn join_with_final<T>(separator: &str, final_separator: &str, strings: Vec<T>) -> String
where
T: std::string::ToString,
Expand All @@ -17,3 +22,99 @@ where
result.push_str(&strings[strings.len() - 1].to_string());
result
}

pub fn parse_rational_literal(whole: &str, raw_fraction: &str, raw_exponent: &str) -> Result<U256> {
let mut n = if whole.is_empty() {
U256::from(0)
} else {
U256::from_str(whole)?
};
let exponent = if raw_exponent.is_empty() {
U256::from(0)
} else {
U256::from_str(raw_exponent)?
};
n *= U256::from(10).pow(exponent);

if !raw_fraction.is_empty() {
let removed_zeros = raw_fraction.trim_end_matches('0');
let decimals_count = U256::from(removed_zeros.len());
let fraction = U256::from_str(removed_zeros)?;
if decimals_count > exponent {
bail!("fraction has more digits than decimals");
}
let adjusted_fraction = fraction * U256::from(10).pow(exponent - decimals_count);
n += adjusted_fraction;
};

Ok(n)
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_join_with_final() {
assert_eq!(
join_with_final(", ", " and ", vec!["a", "b", "c"]),
"a, b and c"
);
assert_eq!(join_with_final(", ", " and ", vec!["a", "b"]), "a and b");
assert_eq!(join_with_final(", ", " and ", vec!["a"]), "a");
}

#[test]
fn test_parse_rational_literal() {
// 1e3
assert_eq!(
parse_rational_literal("1", "", "3").unwrap(),
U256::from(1000)
);
// 123
assert_eq!(
parse_rational_literal("123", "", "").unwrap(),
U256::from(123)
);
// 1.2e3
assert_eq!(
parse_rational_literal("1", "2", "3").unwrap(),
U256::from(1200)
);
// 1.0
assert_eq!(
parse_rational_literal("1", "0", "").unwrap(),
U256::from(1)
);
// 1.01e3
assert_eq!(
parse_rational_literal("1", "01", "3").unwrap(),
U256::from(1010)
);
// 1.1234e4
assert_eq!(
parse_rational_literal("1", "1234", "4").unwrap(),
U256::from(11234)
);
// 1.12340e4
assert_eq!(
parse_rational_literal("1", "12340", "4").unwrap(),
U256::from(11234)
);
// 1.1234e5
assert_eq!(
parse_rational_literal("1", "1234", "5").unwrap(),
U256::from(112340)
);
// 1.01234e5
assert_eq!(
parse_rational_literal("1", "01234", "5").unwrap(),
U256::from(101234)
);
// .1e3
assert_eq!(
parse_rational_literal("", "1", "3").unwrap(),
U256::from(100)
);
}
}

0 comments on commit 64bece3

Please sign in to comment.