grass/src/utils/number.rs

136 lines
3.4 KiB
Rust
Raw Normal View History

use std::iter::Iterator;
use codemap::Spanned;
use peekmore::PeekMoreIterator;
use crate::error::SassResult;
use crate::Token;
2020-04-28 12:15:10 -04:00
pub(crate) struct ParsedNumber {
pub num: String,
pub dec_len: usize,
2020-04-28 12:15:10 -04:00
// TODO: maybe we just return a bigint?
pub times_ten: String,
2020-04-28 12:15:10 -04:00
pub times_ten_is_postive: bool,
pub is_float: bool,
2020-04-28 12:15:10 -04:00
}
impl ParsedNumber {
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 {
num,
dec_len,
2020-04-28 12:15:10 -04:00
times_ten,
times_ten_is_postive,
is_float,
2020-04-28 12:15:10 -04:00
}
}
}
pub(crate) fn eat_number<'a, I: Iterator<Item = Token>>(
toks: &mut PeekMoreIterator<I>,
2020-04-28 12:15:10 -04:00
) -> SassResult<Spanned<ParsedNumber>> {
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() {
tok.pos()
} else {
todo!()
};
2020-04-28 12:15:10 -04:00
eat_whole_number(toks, &mut whole);
if toks.peek().is_none() {
2020-04-28 12:15:10 -04:00
return Ok(Spanned {
node: ParsedNumber::new(whole, 0, String::new(), true, false),
2020-04-28 12:15:10 -04:00
span,
});
}
let mut dec = String::new();
let mut is_float = false;
2020-04-21 18:22:26 -04:00
let next_tok = *toks.peek().unwrap();
if next_tok.kind == '.' {
toks.next();
is_float = true;
2020-04-28 12:15:10 -04:00
eat_whole_number(toks, &mut dec);
}
if dec.is_empty() && is_float {
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();
whole.push_str(&dec);
2020-04-28 12:15:10 -04:00
Ok(Spanned {
node: ParsedNumber::new(
whole,
dec.len(),
2020-04-28 12:15:10 -04:00
if !times_ten.is_empty() {
times_ten
2020-04-28 12:15:10 -04:00
} else {
String::new()
2020-04-28 12:15:10 -04:00
},
times_ten_is_postive,
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);
}
}