Skip to content

Commit 505bdae

Browse files
committed
Refactor parsing numbers.
1 parent 3abb9ef commit 505bdae

File tree

1 file changed

+34
-49
lines changed

1 file changed

+34
-49
lines changed

Diff for: rsass/src/parser/value.rs

+34-49
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ use crate::value::{ListSeparator, Number, Numeric, Operator, Rgba};
1414
use nom::branch::alt;
1515
use nom::bytes::complete::{tag, tag_no_case};
1616
use nom::character::complete::{
17-
alphanumeric1, char, multispace0, multispace1, one_of,
17+
alphanumeric1, char, digit1, multispace0, multispace1, one_of,
1818
};
1919
use nom::combinator::{
20-
cut, into, map, map_res, not, opt, peek, recognize, value, verify,
20+
cut, into, map, map_res, not, opt, peek, recognize, success, value,
21+
verify,
2122
};
2223
use nom::error::context;
2324
use nom::multi::{fold_many0, fold_many1, many0, many_m_n, separated_list1};
2425
use nom::sequence::{delimited, pair, preceded, terminated, tuple};
25-
use num_traits::Zero;
2626
use std::str::from_utf8;
2727

2828
pub fn value_expression(input: Span) -> PResult<Value> {
@@ -326,11 +326,6 @@ pub fn bracket_list(input: Span) -> PResult<Value> {
326326
))
327327
}
328328

329-
fn sign_prefix(input: Span) -> PResult<Option<&[u8]>> {
330-
opt(alt((tag("-"), tag("+"))))(input)
331-
.map(|(r, s)| (r, s.map(|s| s.fragment())))
332-
}
333-
334329
pub fn numeric(input: Span) -> PResult<Numeric> {
335330
map(pair(number, unit), |(number, unit)| {
336331
Numeric::new(number, unit)
@@ -340,46 +335,45 @@ pub fn numeric(input: Span) -> PResult<Numeric> {
340335
pub fn number(input: Span) -> PResult<Number> {
341336
map(
342337
tuple((
343-
sign_prefix,
338+
sign_neg,
344339
alt((
345340
map(pair(decimal_integer, decimal_decimals), |(n, d)| n + d),
346341
decimal_decimals,
347342
decimal_integer,
348343
)),
349344
opt(preceded(
350345
alt((tag("e"), tag("E"))),
351-
tuple((sign_prefix, decimal_i32)),
346+
tuple((sign_neg, decimal_i32)),
352347
)),
353348
)),
354-
|(sign, num, exp)| {
355-
let value = if sign == Some(b"-") {
356-
// Only f64-based Number can represent negative zero.
357-
if num.is_zero() {
358-
(-0.0).into()
359-
} else {
360-
-num
361-
}
362-
} else {
363-
num
364-
};
365-
if let Some((e_sign, e_val)) = exp {
366-
let e_val = if e_sign == Some(b"-") { -e_val } else { e_val };
349+
|(is_neg, num, exp)| {
350+
let value = if is_neg { -num } else { num };
351+
Number::from(if let Some((e_neg, e_val)) = exp {
352+
let e_val = if e_neg { -e_val } else { e_val };
367353
// Note: powi sounds right, but looses some precision.
368-
value * Number::from(10f64.powf(e_val.into()))
354+
value * 10f64.powf(e_val.into())
369355
} else {
370356
value
371-
}
357+
})
372358
},
373359
)(input)
374360
}
375361

376-
pub fn decimal_integer(input: Span) -> PResult<Number> {
377-
fold_many1(
378-
// Note: We should use bytes directly, one_of returns a char.
379-
one_of("0123456789"),
380-
|| Number::from(0),
381-
|r, d| (r * 10) + Number::from(i64::from(d as u8 - b'0')),
382-
)(input)
362+
/// Parse true on `-` and false on `+` or no sign.
363+
fn sign_neg(input: Span) -> PResult<bool> {
364+
alt((
365+
value(true, char('-')),
366+
value(false, char('+')),
367+
success(false),
368+
))(input)
369+
}
370+
371+
pub fn decimal_integer(input: Span) -> PResult<f64> {
372+
map(digit1, |s: Span| {
373+
s.fragment()
374+
.iter()
375+
.fold(0.0, |r, d| (r * 10.) + f64::from(d - b'0'))
376+
})(input)
383377
}
384378
pub fn decimal_i32(input: Span) -> PResult<i32> {
385379
fold_many1(
@@ -390,23 +384,14 @@ pub fn decimal_i32(input: Span) -> PResult<i32> {
390384
)(input)
391385
}
392386

393-
pub fn decimal_decimals(input: Span) -> PResult<Number> {
394-
map(
395-
preceded(
396-
tag("."),
397-
fold_many1(
398-
one_of("0123456789"),
399-
|| (Number::from(0), Number::from(1)),
400-
|(r, n), d| {
401-
(
402-
(r * 10) + Number::from(i64::from(d as u8 - b'0')),
403-
n * 10,
404-
)
405-
},
406-
),
407-
),
408-
|(r, d)| r / d,
409-
)(input)
387+
pub fn decimal_decimals(input: Span) -> PResult<f64> {
388+
map(preceded(char('.'), digit1), |s: Span| {
389+
let digits = s.fragment();
390+
digits
391+
.iter()
392+
.fold(0.0, |r, d| (r * 10.) + f64::from(d - b'0'))
393+
* (10f64).powf(-(digits.len() as f64))
394+
})(input)
410395
}
411396

412397
pub fn variable_nomod(input: Span) -> PResult<Value> {

0 commit comments

Comments
 (0)