2020-07-09 11:56:58 -04:00
|
|
|
use std::vec::IntoIter;
|
|
|
|
|
2020-04-20 14:49:29 -04:00
|
|
|
use codemap::Spanned;
|
|
|
|
use peekmore::PeekMoreIterator;
|
|
|
|
|
2020-06-16 20:00:11 -04:00
|
|
|
use crate::{error::SassResult, Token};
|
2020-04-20 14:49:29 -04:00
|
|
|
|
2020-04-28 14:46:40 -04:00
|
|
|
#[derive(Debug)]
|
2020-04-28 12:15:10 -04:00
|
|
|
pub(crate) struct ParsedNumber {
|
2020-04-28 15:28:50 -04:00
|
|
|
/// The full number excluding the decimal
|
|
|
|
///
|
|
|
|
/// E.g. for `1.23`, this would be `"123"`
|
2020-04-28 13:18:54 -04:00
|
|
|
pub num: String,
|
2020-04-28 15:28:50 -04:00
|
|
|
|
|
|
|
/// The length of the decimal
|
|
|
|
///
|
|
|
|
/// E.g. for `1.23`, this would be `2`
|
2020-04-28 13:18:54 -04:00
|
|
|
pub dec_len: usize,
|
2020-04-28 15:28:50 -04:00
|
|
|
|
|
|
|
/// The number following e in a scientific notated number
|
|
|
|
///
|
|
|
|
/// E.g. for `1e23`, this would be `"23"`,
|
|
|
|
/// for `1`, this would be an empty string
|
2020-04-28 12:15:10 -04:00
|
|
|
// TODO: maybe we just return a bigint?
|
2020-04-28 13:18:54 -04:00
|
|
|
pub times_ten: String,
|
2020-04-28 15:28:50 -04:00
|
|
|
|
|
|
|
/// Whether or not `times_ten` is negative
|
|
|
|
///
|
|
|
|
/// E.g. for `1e-23` this would be `true`,
|
|
|
|
/// for `1e23` this would be `false`
|
2020-04-28 12:15:10 -04:00
|
|
|
pub times_ten_is_postive: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ParsedNumber {
|
2020-04-28 15:14:44 -04:00
|
|
|
pub const fn new(
|
2020-04-28 13:18:54 -04:00
|
|
|
num: String,
|
|
|
|
dec_len: usize,
|
|
|
|
times_ten: String,
|
|
|
|
times_ten_is_postive: bool,
|
|
|
|
) -> Self {
|
2020-04-28 12:15:10 -04:00
|
|
|
Self {
|
2020-04-28 13:18:54 -04:00
|
|
|
num,
|
|
|
|
dec_len,
|
2020-04-28 12:15:10 -04:00
|
|
|
times_ten,
|
|
|
|
times_ten_is_postive,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-09 11:56:58 -04:00
|
|
|
pub(crate) fn eat_number(
|
|
|
|
toks: &mut PeekMoreIterator<IntoIter<Token>>,
|
2020-04-28 12:15:10 -04:00
|
|
|
) -> SassResult<Spanned<ParsedNumber>> {
|
2020-07-05 17:59:48 +08:00
|
|
|
let mut span = toks.peek().unwrap().pos;
|
|
|
|
let mut whole = eat_whole_number(toks);
|
2020-04-20 14:49:29 -04:00
|
|
|
|
|
|
|
if toks.peek().is_none() {
|
2020-04-28 12:15:10 -04:00
|
|
|
return Ok(Spanned {
|
2020-04-28 15:28:50 -04:00
|
|
|
node: ParsedNumber::new(whole, 0, String::new(), true),
|
2020-04-28 12:15:10 -04:00
|
|
|
span,
|
|
|
|
});
|
2020-04-20 14:49:29 -04:00
|
|
|
}
|
|
|
|
|
2020-04-21 18:22:26 -04:00
|
|
|
let next_tok = *toks.peek().unwrap();
|
2020-04-20 14:49:29 -04:00
|
|
|
|
2020-07-05 17:59:48 +08:00
|
|
|
let dec_len = if next_tok.kind == '.' {
|
2020-04-20 14:49:29 -04:00
|
|
|
toks.next();
|
|
|
|
|
2020-07-05 17:59:48 +08:00
|
|
|
let dec = eat_whole_number(toks);
|
2020-04-28 15:49:19 -04:00
|
|
|
if dec.is_empty() {
|
|
|
|
return Err(("Expected digit.", next_tok.pos()).into());
|
|
|
|
}
|
2020-07-05 17:59:48 +08:00
|
|
|
|
|
|
|
whole.push_str(&dec);
|
|
|
|
|
|
|
|
dec.len()
|
|
|
|
} else {
|
|
|
|
0
|
|
|
|
};
|
2020-04-20 14:49:29 -04:00
|
|
|
|
2020-04-28 12:15:10 -04:00
|
|
|
let mut times_ten = String::new();
|
|
|
|
let mut times_ten_is_postive = true;
|
2020-07-05 17:59:48 +08:00
|
|
|
if let Some(Token { kind: 'e', .. }) | Some(Token { kind: 'E', .. }) = toks.peek() {
|
|
|
|
if let Some(&tok) = toks.peek_next() {
|
|
|
|
if tok.kind == '-' {
|
|
|
|
toks.next();
|
|
|
|
times_ten_is_postive = false;
|
2020-04-28 12:15:10 -04:00
|
|
|
|
2020-07-05 17:59:48 +08:00
|
|
|
toks.next();
|
|
|
|
times_ten = eat_whole_number(toks);
|
2020-04-28 12:15:10 -04:00
|
|
|
|
2020-07-05 17:59:48 +08:00
|
|
|
if times_ten.is_empty() {
|
|
|
|
return Err(("Expected digit.", toks.peek().unwrap_or(&tok).pos).into());
|
|
|
|
}
|
|
|
|
} else if matches!(tok.kind, '0'..='9') {
|
|
|
|
toks.next();
|
|
|
|
times_ten = eat_whole_number(toks);
|
2020-05-23 01:49:21 -04:00
|
|
|
|
2020-07-05 17:59:48 +08:00
|
|
|
if times_ten.len() > 2 {
|
|
|
|
return Err(("Exponent too large.", toks.peek().unwrap_or(&tok).pos).into());
|
|
|
|
}
|
2020-04-28 12:15:10 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-05 17:59:48 +08:00
|
|
|
if let Ok(Some(Token { pos, .. })) = toks.peek_previous() {
|
|
|
|
span = span.merge(*pos);
|
|
|
|
}
|
2020-04-28 12:15:10 -04:00
|
|
|
|
2020-07-05 17:59:48 +08:00
|
|
|
toks.reset_cursor();
|
2020-04-28 12:15:10 -04:00
|
|
|
|
|
|
|
Ok(Spanned {
|
2020-07-05 17:59:48 +08:00
|
|
|
node: ParsedNumber::new(whole, dec_len, times_ten, times_ten_is_postive),
|
2020-04-28 12:15:10 -04:00
|
|
|
span,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-07-09 11:56:58 -04:00
|
|
|
pub(crate) fn eat_whole_number(toks: &mut PeekMoreIterator<IntoIter<Token>>) -> String {
|
2020-07-05 17:59:48 +08:00
|
|
|
let mut buf = String::new();
|
2020-04-28 12:15:10 -04:00
|
|
|
while let Some(c) = toks.peek() {
|
2020-05-24 13:08:31 -04:00
|
|
|
if !c.kind.is_ascii_digit() {
|
2020-04-28 12:15:10 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
let tok = toks.next().unwrap();
|
|
|
|
buf.push(tok.kind);
|
|
|
|
}
|
2020-07-05 17:59:48 +08:00
|
|
|
buf
|
2020-04-20 14:49:29 -04:00
|
|
|
}
|