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