optimize parsing of numbers
This makes parsing of floats roughly 10x faster
This commit is contained in:
parent
2ee4396978
commit
a183a9ffa2
@ -1,4 +1,3 @@
|
||||
use std::borrow::Cow;
|
||||
use std::iter::Iterator;
|
||||
|
||||
use codemap::Spanned;
|
||||
@ -9,18 +8,28 @@ use crate::error::SassResult;
|
||||
use crate::Token;
|
||||
|
||||
pub(crate) struct ParsedNumber {
|
||||
pub v: String,
|
||||
pub num: String,
|
||||
pub dec_len: usize,
|
||||
// TODO: maybe we just return a bigint?
|
||||
pub times_ten: Cow<'static, str>,
|
||||
pub times_ten: String,
|
||||
pub times_ten_is_postive: bool,
|
||||
pub is_float: bool,
|
||||
}
|
||||
|
||||
impl ParsedNumber {
|
||||
pub fn new(v: String, times_ten: Cow<'static, str>, times_ten_is_postive: bool) -> Self {
|
||||
pub fn new(
|
||||
num: String,
|
||||
dec_len: usize,
|
||||
times_ten: String,
|
||||
times_ten_is_postive: bool,
|
||||
is_float: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
v,
|
||||
num,
|
||||
dec_len,
|
||||
times_ten,
|
||||
times_ten_is_postive,
|
||||
is_float,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -28,7 +37,7 @@ impl ParsedNumber {
|
||||
pub(crate) fn eat_number<'a, I: Iterator<Item = Token>>(
|
||||
toks: &mut PeekMoreIterator<I>,
|
||||
) -> SassResult<Spanned<ParsedNumber>> {
|
||||
let mut whole = String::new();
|
||||
let mut whole = String::with_capacity(1);
|
||||
// TODO: merge this span with chars
|
||||
let span = if let Some(tok) = toks.peek() {
|
||||
tok.pos()
|
||||
@ -39,22 +48,23 @@ pub(crate) fn eat_number<'a, I: Iterator<Item = Token>>(
|
||||
|
||||
if toks.peek().is_none() {
|
||||
return Ok(Spanned {
|
||||
node: ParsedNumber::new(whole, Cow::from("0"), true),
|
||||
node: ParsedNumber::new(whole, 0, String::new(), true, false),
|
||||
span,
|
||||
});
|
||||
}
|
||||
|
||||
let mut dec = String::new();
|
||||
let mut is_float = false;
|
||||
|
||||
let next_tok = *toks.peek().unwrap();
|
||||
|
||||
if next_tok.kind == '.' {
|
||||
toks.next();
|
||||
dec.push('.');
|
||||
is_float = true;
|
||||
eat_whole_number(toks, &mut dec);
|
||||
}
|
||||
|
||||
if dec.len() == 1 {
|
||||
if dec.is_empty() && is_float {
|
||||
return Err(("Expected digit.", next_tok.pos()).into());
|
||||
}
|
||||
|
||||
@ -101,12 +111,14 @@ pub(crate) fn eat_number<'a, I: Iterator<Item = Token>>(
|
||||
Ok(Spanned {
|
||||
node: ParsedNumber::new(
|
||||
whole,
|
||||
dec.len(),
|
||||
if !times_ten.is_empty() {
|
||||
Cow::from(times_ten)
|
||||
times_ten
|
||||
} else {
|
||||
Cow::from("0")
|
||||
String::new()
|
||||
},
|
||||
times_ten_is_postive,
|
||||
is_float,
|
||||
),
|
||||
span,
|
||||
})
|
||||
|
@ -3,7 +3,7 @@ use std::mem;
|
||||
|
||||
use num_bigint::BigInt;
|
||||
use num_rational::BigRational;
|
||||
use num_traits::{pow, One, ToPrimitive};
|
||||
use num_traits::{pow, One, ToPrimitive, Zero};
|
||||
|
||||
use codemap::{Span, Spanned};
|
||||
|
||||
@ -630,36 +630,25 @@ impl Value {
|
||||
Unit::None
|
||||
};
|
||||
|
||||
let times_ten = pow(
|
||||
let times_ten = if val.times_ten.is_empty() {
|
||||
BigInt::zero()
|
||||
} else {
|
||||
pow(
|
||||
BigInt::from(10),
|
||||
val.times_ten
|
||||
.parse::<BigInt>()
|
||||
.unwrap()
|
||||
.to_usize()
|
||||
.ok_or(("Exponent too large (expected usize).", span))?,
|
||||
);
|
||||
)
|
||||
};
|
||||
|
||||
let n = if let Ok(v) = val.v.parse::<BigRational>() {
|
||||
// the number is an integer!
|
||||
v
|
||||
// the number is floating point
|
||||
let n = if val.is_float {
|
||||
BigRational::new(val.num.parse().unwrap(), pow(BigInt::from(10), val.dec_len))
|
||||
} else {
|
||||
let mut num = String::new();
|
||||
let mut chars = val.v.chars();
|
||||
let mut num_dec = 0;
|
||||
while let Some(c) = chars.next() {
|
||||
if c == '.' {
|
||||
break;
|
||||
}
|
||||
num.push(c);
|
||||
}
|
||||
for c in chars {
|
||||
num_dec += 1;
|
||||
num.push(c);
|
||||
}
|
||||
BigRational::new(num.parse().unwrap(), pow(BigInt::from(10), num_dec))
|
||||
BigRational::new_raw(val.num.parse::<BigInt>().unwrap(), BigInt::one())
|
||||
} * if val.times_ten_is_postive {
|
||||
BigRational::new(times_ten, BigInt::one())
|
||||
BigRational::new_raw(times_ten, BigInt::one())
|
||||
} else {
|
||||
BigRational::new(BigInt::one(), times_ten)
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user