2020-04-20 14:49:29 -04:00
|
|
|
use std::iter::Iterator;
|
|
|
|
|
|
|
|
use codemap::Spanned;
|
|
|
|
|
|
|
|
use peekmore::PeekMoreIterator;
|
|
|
|
|
|
|
|
use crate::error::SassResult;
|
|
|
|
use crate::Token;
|
|
|
|
|
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 13:18:54 -04:00
|
|
|
pub num: String,
|
|
|
|
pub dec_len: usize,
|
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 12:15:10 -04:00
|
|
|
pub times_ten_is_postive: bool,
|
2020-04-28 13:18:54 -04:00
|
|
|
pub is_float: bool,
|
2020-04-28 12:15:10 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ParsedNumber {
|
2020-04-28 13:18:54 -04:00
|
|
|
pub fn new(
|
|
|
|
num: String,
|
|
|
|
dec_len: usize,
|
|
|
|
times_ten: String,
|
|
|
|
times_ten_is_postive: bool,
|
|
|
|
is_float: 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-04-28 13:18:54 -04:00
|
|
|
is_float,
|
2020-04-28 12:15:10 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn eat_number<'a, I: Iterator<Item = Token>>(
|
2020-04-20 14:49:29 -04:00
|
|
|
toks: &mut PeekMoreIterator<I>,
|
2020-04-28 12:15:10 -04:00
|
|
|
) -> SassResult<Spanned<ParsedNumber>> {
|
2020-04-28 13:18:54 -04:00
|
|
|
let mut whole = String::with_capacity(1);
|
2020-04-28 12:15:10 -04:00
|
|
|
// TODO: merge this span with chars
|
|
|
|
let span = if let Some(tok) = toks.peek() {
|
2020-04-20 14:49:29 -04:00
|
|
|
tok.pos()
|
|
|
|
} else {
|
|
|
|
todo!()
|
|
|
|
};
|
2020-04-28 12:15:10 -04:00
|
|
|
eat_whole_number(toks, &mut whole);
|
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 13:18:54 -04:00
|
|
|
node: ParsedNumber::new(whole, 0, String::new(), true, false),
|
2020-04-28 12:15:10 -04:00
|
|
|
span,
|
|
|
|
});
|
2020-04-20 14:49:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
let mut dec = String::new();
|
2020-04-28 13:18:54 -04:00
|
|
|
let mut is_float = false;
|
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
|
|
|
|
|
|
|
if next_tok.kind == '.' {
|
|
|
|
toks.next();
|
2020-04-28 13:18:54 -04:00
|
|
|
is_float = true;
|
2020-04-28 12:15:10 -04:00
|
|
|
eat_whole_number(toks, &mut dec);
|
2020-04-20 14:49:29 -04:00
|
|
|
}
|
|
|
|
|
2020-04-28 13:18:54 -04:00
|
|
|
if dec.is_empty() && is_float {
|
2020-04-20 14:49:29 -04:00
|
|
|
return Err(("Expected digit.", next_tok.pos()).into());
|
|
|
|
}
|
|
|
|
|
2020-04-28 12:15:10 -04:00
|
|
|
let mut times_ten = String::new();
|
|
|
|
let mut times_ten_is_postive = true;
|
|
|
|
loop {
|
|
|
|
match toks.peek() {
|
|
|
|
// TODO: https://github.com/rust-lang/rust/issues/54883
|
|
|
|
Some(Token { kind: 'e', .. }) | Some(Token { kind: 'E', .. }) => {
|
|
|
|
if toks.peek_forward(1).is_none() {
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
let Token { kind, pos } = toks.peek().unwrap().clone();
|
|
|
|
match kind {
|
|
|
|
'-' => {
|
|
|
|
toks.next();
|
|
|
|
times_ten_is_postive = false;
|
|
|
|
}
|
|
|
|
'0'..='9' => {}
|
|
|
|
_ => break,
|
|
|
|
}
|
|
|
|
|
|
|
|
toks.next();
|
|
|
|
|
|
|
|
eat_whole_number(toks, &mut times_ten);
|
|
|
|
|
|
|
|
if times_ten.is_empty() && !times_ten_is_postive {
|
|
|
|
if let Some(t) = toks.peek() {
|
|
|
|
return Err(("Expected digit.", t.pos()).into());
|
|
|
|
}
|
|
|
|
return Err(("Expected digit.", pos).into());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Some(..) | None => break,
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
toks.reset_view();
|
|
|
|
|
2020-04-20 14:49:29 -04:00
|
|
|
whole.push_str(&dec);
|
2020-04-28 12:15:10 -04:00
|
|
|
|
|
|
|
Ok(Spanned {
|
|
|
|
node: ParsedNumber::new(
|
|
|
|
whole,
|
2020-04-28 13:18:54 -04:00
|
|
|
dec.len(),
|
2020-04-28 12:15:10 -04:00
|
|
|
if !times_ten.is_empty() {
|
2020-04-28 13:18:54 -04:00
|
|
|
times_ten
|
2020-04-28 12:15:10 -04:00
|
|
|
} else {
|
2020-04-28 13:18:54 -04:00
|
|
|
String::new()
|
2020-04-28 12:15:10 -04:00
|
|
|
},
|
|
|
|
times_ten_is_postive,
|
2020-04-28 13:18:54 -04:00
|
|
|
is_float,
|
2020-04-28 12:15:10 -04:00
|
|
|
),
|
|
|
|
span,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn eat_whole_number<I: Iterator<Item = Token>>(toks: &mut PeekMoreIterator<I>, buf: &mut String) {
|
|
|
|
while let Some(c) = toks.peek() {
|
|
|
|
if !c.kind.is_numeric() {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
let tok = toks.next().unwrap();
|
|
|
|
buf.push(tok.kind);
|
|
|
|
}
|
2020-04-20 14:49:29 -04:00
|
|
|
}
|