use crate::{
errors::{syntax_error, ParseResult},
ParserCore,
};
use super::NumberParserSettings;
pub fn parse_decimal_float(
parser: &mut ParserCore,
negative: bool,
settings: &NumberParserSettings,
) -> ParseResult<f64> {
let loc = parser.loc();
let mut digits = String::new();
if negative {
digits.push('-');
}
let wholedigs = if settings.permit_underscores {
parser.take_while_unless(|ch| ch.is_ascii_digit(), |ch| ch == '_')
} else {
parser.take_while(|ch| ch.is_ascii_digit())
};
digits.push_str(wholedigs.as_str());
let mut fraction_empty = false;
if parser.peek_and_consume('.') {
let fracdigs = if settings.permit_underscores {
parser.take_while_unless(|ch| ch.is_ascii_digit(), |ch| ch == '_')
} else {
parser.take_while(|ch| ch.is_ascii_digit())
};
digits.push('.');
digits.push_str(fracdigs.as_str());
fraction_empty = fracdigs.is_empty();
}
let ch = parser.peek();
if ch == 'e' || ch == 'p' || ch == 'P' || ch == 'E' {
parser.consume();
let negexp = if parser.peek_and_consume('-') {
true
} else {
parser.peek_and_consume('+');
false
};
let expdigits = if settings.permit_underscores {
parser.take_while_unless(|ch| ch.is_ascii_digit(), |ch| ch == '_')
} else {
parser.take_while(|ch| ch.is_ascii_digit())
};
digits.push('e');
if negexp {
digits.push('-');
}
digits.push_str(expdigits.as_str());
}
if (!settings.permit_leading_zero) && wholedigs.starts_with('0') && wholedigs.len() > 1 {
return Err(syntax_error(
loc,
"A leading zero is not permitted for a non-zero whole part of a number.",
));
}
if wholedigs.is_empty() && !settings.permit_empty_whole {
return Err(syntax_error(
loc,
"An empty whole part is not permitted; there must be digits to the left of the decimal."
));
}
if fraction_empty && !settings.permit_empty_fraction {
return Err(syntax_error(
loc,
"An empty fraction part is not permitted; there must be digits to the right of the decimal, if present."
));
}
match digits.parse::<f64>() {
Ok(value) => Ok(value),
Err(msg) => Err(syntax_error(loc, &msg.to_string())),
}
}
#[cfg(test)]
mod test {
use crate::{
decoder::Decode,
numbers::{decimal_float::parse_decimal_float, NumberParserSettings},
ParserCore,
};
fn parse(value: &str) -> ParserCore {
let decoder = Decode::from_string(value);
ParserCore::new("<string>>", decoder)
}
#[test]
fn zero_test() {
let mut settings = NumberParserSettings::new();
settings.permit_underscores = false;
assert!(parse_decimal_float(&mut parse(""), false, &settings).is_err());
assert_eq!(
parse_decimal_float(&mut parse("0"), false, &settings).unwrap(),
0.0
);
assert_eq!(
parse_decimal_float(&mut parse("0"), true, &settings).unwrap(),
0.0
);
}
#[test]
fn one_test() {
let mut settings = NumberParserSettings::new();
settings.permit_underscores = false;
assert_eq!(
parse_decimal_float(&mut parse("1"), false, &settings).unwrap(),
1.0
);
assert_eq!(
parse_decimal_float(&mut parse("1"), true, &settings).unwrap(),
-1.0
);
assert_eq!(
parse_decimal_float(&mut parse("01"), false, &settings).unwrap(),
1.0
);
assert_eq!(
parse_decimal_float(&mut parse("001"), true, &settings).unwrap(),
-1.0
);
}
#[test]
fn integer_test_1() {
let mut settings = NumberParserSettings::new();
settings.permit_underscores = false;
assert_eq!(
parse_decimal_float(&mut parse("15"), false, &settings).unwrap(),
15.0
);
assert_eq!(
parse_decimal_float(&mut parse("8"), true, &settings).unwrap(),
-8.0
);
assert_eq!(
parse_decimal_float(&mut parse("33252"), true, &settings).unwrap(),
-33252.0
);
assert_eq!(
parse_decimal_float(&mut parse("8480"), true, &settings).unwrap(),
-8480.0
);
}
#[test]
fn integer_test_2() {
let mut settings = NumberParserSettings::new();
settings.permit_underscores = false;
assert_eq!(
parse_decimal_float(&mut parse("111"), false, &settings).unwrap(),
111.0
);
settings.permit_underscores = true;
assert_eq!(
parse_decimal_float(&mut parse("18658"), false, &settings).unwrap(),
18658.0
);
assert_eq!(
parse_decimal_float(&mut parse("7177605032489779"), true, &settings).unwrap(),
-7177605032489779.0
);
settings.permit_underscores = true;
assert_eq!(
parse_decimal_float(&mut parse("665"), false, &settings).unwrap(),
665.0
);
}
#[test]
fn fraction_test_1() {
let mut settings = NumberParserSettings::new();
settings.permit_underscores = false;
assert_eq!(
parse_decimal_float(&mut parse("0.1"), false, &settings).unwrap(),
0.1
);
assert_eq!(
parse_decimal_float(&mut parse("0.02"), false, &settings).unwrap(),
0.02
);
assert_eq!(
parse_decimal_float(&mut parse("0.8"), false, &settings).unwrap(),
0.8
);
assert_eq!(
parse_decimal_float(&mut parse("1.8"), false, &settings).unwrap(),
1.8
);
}
#[test]
fn fraction_test_2() {
let mut settings = NumberParserSettings::new();
settings.permit_underscores = false;
assert_eq!(
parse_decimal_float(&mut parse("0.08"), false, &settings).unwrap(),
0.08
);
assert_eq!(
parse_decimal_float(&mut parse("10.008"), false, &settings).unwrap(),
10.008
);
assert_eq!(
parse_decimal_float(&mut parse("14.014"), false, &settings).unwrap(),
14.014
);
assert_eq!(
parse_decimal_float(&mut parse("000.0000"), false, &settings).unwrap(),
0.0
);
}
#[test]
fn exponent_test_1() {
let mut settings = NumberParserSettings::new();
settings.permit_underscores = false;
assert_eq!(
parse_decimal_float(&mut parse("0p1000"), false, &settings).unwrap(),
0.0
);
assert_eq!(
parse_decimal_float(&mut parse("10p1"), false, &settings).unwrap(),
100.0
);
assert_eq!(
parse_decimal_float(&mut parse("10p-1"), false, &settings).unwrap(),
1.0
);
assert_eq!(
parse_decimal_float(&mut parse("0.001p3"), false, &settings).unwrap(),
1.0
);
}
#[test]
fn exponent_test_2() {
let mut settings = NumberParserSettings::new();
settings.permit_underscores = false;
assert_eq!(
parse_decimal_float(&mut parse("1021p-3"), false, &settings).unwrap(),
1.021
);
assert_eq!(
parse_decimal_float(&mut parse("44p-3"), false, &settings).unwrap(),
0.044
);
}
#[test]
fn limits_test() {
let mut settings = NumberParserSettings::new();
settings.permit_underscores = true;
assert_eq!(
parse_decimal_float(&mut parse("1.7976931348623157E+308"), false, &settings).unwrap(),
f64::MAX
);
assert_eq!(
parse_decimal_float(&mut parse("1.7976931348623157E+308"), true, &settings).unwrap(),
f64::MIN
);
assert_eq!(
parse_decimal_float(&mut parse("2.2250738585072014E-308"), false, &settings).unwrap(),
f64::MIN_POSITIVE
);
}
#[test]
fn overflow_test() {
let mut settings = NumberParserSettings::new();
settings.permit_underscores = false;
assert_eq!(
parse_decimal_float(&mut parse("2p309"), false, &settings).unwrap(),
f64::INFINITY
);
assert_eq!(
parse_decimal_float(&mut parse("1p-324"), false, &settings).unwrap(),
0.0
);
}
#[test]
fn leading_zero_test() {
let mut settings = NumberParserSettings::new();
settings.permit_leading_zero = false;
assert!(parse_decimal_float(&mut parse("01.1"), false, &settings).is_err());
settings.permit_leading_zero = true;
assert_eq!(
parse_decimal_float(&mut parse("01.1"), false, &settings).unwrap(),
1.1
);
}
#[test]
fn empty_parts_test() {
let mut settings = NumberParserSettings::new();
settings.permit_empty_fraction = false;
settings.permit_empty_whole = false;
assert!(parse_decimal_float(&mut parse("1.e1"), false, &settings).is_err());
assert!(parse_decimal_float(&mut parse("1."), false, &settings).is_err());
assert!(parse_decimal_float(&mut parse(".1e1"), false, &settings).is_err());
assert!(parse_decimal_float(&mut parse(".1"), false, &settings).is_err());
}
}