Support scientific notation for Decimal parsing.
This commit is contained in:
parent
fc21756785
commit
40e4a92401
@ -302,7 +302,7 @@ mod float_functions {
|
|||||||
#[cfg(feature = "decimal")]
|
#[cfg(feature = "decimal")]
|
||||||
#[export_module]
|
#[export_module]
|
||||||
mod decimal_functions {
|
mod decimal_functions {
|
||||||
use rust_decimal::Decimal;
|
use rust_decimal::{prelude::FromStr, Decimal};
|
||||||
|
|
||||||
#[rhai_fn(name = "floor", get = "floor")]
|
#[rhai_fn(name = "floor", get = "floor")]
|
||||||
pub fn floor(x: Decimal) -> Decimal {
|
pub fn floor(x: Decimal) -> Decimal {
|
||||||
@ -433,8 +433,8 @@ mod decimal_functions {
|
|||||||
}
|
}
|
||||||
#[rhai_fn(return_raw)]
|
#[rhai_fn(return_raw)]
|
||||||
pub fn parse_decimal(s: &str) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn parse_decimal(s: &str) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
s.trim()
|
Decimal::from_str(s)
|
||||||
.parse::<Decimal>()
|
.or_else(|_| Decimal::from_scientific(s))
|
||||||
.map(Into::<Dynamic>::into)
|
.map(Into::<Dynamic>::into)
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
EvalAltResult::ErrorArithmetic(
|
EvalAltResult::ErrorArithmetic(
|
||||||
|
15
src/token.rs
15
src/token.rs
@ -22,6 +22,10 @@ use rust_decimal::Decimal;
|
|||||||
|
|
||||||
type LERR = LexError;
|
type LERR = LexError;
|
||||||
|
|
||||||
|
/// Separator character for numbers.
|
||||||
|
const NUM_SEP: char = '_';
|
||||||
|
|
||||||
|
/// A stream of tokens.
|
||||||
pub type TokenStream<'a, 't> = Peekable<TokenIterator<'a, 't>>;
|
pub type TokenStream<'a, 't> = Peekable<TokenIterator<'a, 't>>;
|
||||||
|
|
||||||
/// A location (line number + character position) in the input script.
|
/// A location (line number + character position) in the input script.
|
||||||
@ -1079,7 +1083,7 @@ fn get_next_token_inner(
|
|||||||
|
|
||||||
while let Some(next_char) = stream.peek_next() {
|
while let Some(next_char) = stream.peek_next() {
|
||||||
match next_char {
|
match next_char {
|
||||||
ch if valid(ch) || ch == '_' => {
|
ch if valid(ch) || ch == NUM_SEP => {
|
||||||
result.push(next_char);
|
result.push(next_char);
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
}
|
}
|
||||||
@ -1174,7 +1178,7 @@ fn get_next_token_inner(
|
|||||||
|
|
||||||
// Parse number
|
// Parse number
|
||||||
if let Some(radix) = radix_base {
|
if let Some(radix) = radix_base {
|
||||||
let out: String = result.iter().skip(2).filter(|&&c| c != '_').collect();
|
let out: String = result.iter().skip(2).filter(|&&c| c != NUM_SEP).collect();
|
||||||
|
|
||||||
return Some((
|
return Some((
|
||||||
INT::from_str_radix(&out, radix)
|
INT::from_str_radix(&out, radix)
|
||||||
@ -1185,7 +1189,7 @@ fn get_next_token_inner(
|
|||||||
start_pos,
|
start_pos,
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
let out: String = result.iter().filter(|&&c| c != '_').collect();
|
let out: String = result.iter().filter(|&&c| c != NUM_SEP).collect();
|
||||||
let num = INT::from_str(&out).map(Token::IntegerConstant);
|
let num = INT::from_str(&out).map(Token::IntegerConstant);
|
||||||
|
|
||||||
// If integer parsing is unnecessary, try float instead
|
// If integer parsing is unnecessary, try float instead
|
||||||
@ -1197,6 +1201,11 @@ fn get_next_token_inner(
|
|||||||
#[cfg(feature = "decimal")]
|
#[cfg(feature = "decimal")]
|
||||||
let num = num.or_else(|_| Decimal::from_str(&out).map(Token::DecimalConstant));
|
let num = num.or_else(|_| Decimal::from_str(&out).map(Token::DecimalConstant));
|
||||||
|
|
||||||
|
// Then try decimal in scientific notation
|
||||||
|
#[cfg(feature = "decimal")]
|
||||||
|
let num =
|
||||||
|
num.or_else(|_| Decimal::from_scientific(&out).map(Token::DecimalConstant));
|
||||||
|
|
||||||
return Some((
|
return Some((
|
||||||
num.unwrap_or_else(|_| {
|
num.unwrap_or_else(|_| {
|
||||||
Token::LexError(LERR::MalformedNumber(result.into_iter().collect()))
|
Token::LexError(LERR::MalformedNumber(result.into_iter().collect()))
|
||||||
|
Loading…
Reference in New Issue
Block a user