refactor keyframes and number parsing logic

This commit is contained in:
Ivan Tham 2020-07-05 17:59:48 +08:00 committed by Connor Skees
parent 91ef5dcfd5
commit 85a5b005cb
2 changed files with 64 additions and 84 deletions

View File

@ -55,8 +55,7 @@ impl<'a, 'b> KeyframesSelectorParser<'a, 'b> {
}
}
'0'..='9' => {
let mut num = String::new();
eat_whole_number(self.parser.toks, &mut num);
let num = eat_whole_number(self.parser.toks);
if !matches!(self.parser.toks.next(), Some(Token { kind: '%', .. })) {
return Err(("expected \"%\".", tok.pos).into());
}
@ -81,7 +80,6 @@ impl<'a, 'b> KeyframesSelectorParser<'a, 'b> {
impl<'a> Parser<'a> {
fn parse_keyframes_name(&mut self) -> SassResult<String> {
let mut name = String::new();
let mut found_open_brace = false;
self.whitespace_or_comment();
while let Some(tok) = self.toks.next() {
match tok.kind {
@ -98,19 +96,14 @@ impl<'a> Parser<'a> {
name.push(' ');
}
'{' => {
found_open_brace = true;
break;
// todo: we can avoid the reallocation by trimming before emitting
// (in `output.rs`)
return Ok(name.trim().to_string());
}
_ => name.push(tok.kind),
}
}
if !found_open_brace {
return Err(("expected \"{\".", self.span_before).into());
}
// todo: we can avoid the reallocation by trimming before emitting (in `output.rs`)
Ok(name.trim().to_string())
Err(("expected \"{\".", self.span_before).into())
}
pub(super) fn parse_keyframes_selector(
@ -125,8 +118,6 @@ impl<'a> Parser<'a> {
self.span_before = span;
let mut found_curly = false;
while let Some(tok) = self.toks.next() {
span = span.merge(tok.pos());
match tok.kind {
@ -157,41 +148,34 @@ impl<'a> Parser<'a> {
string.push(' ');
}
'{' => {
found_curly = true;
break;
let sel_toks: Vec<Token> =
string.chars().map(|x| Token::new(span, x)).collect();
let selector = KeyframesSelectorParser::new(&mut Parser {
toks: &mut sel_toks.into_iter().peekmore(),
map: self.map,
path: self.path,
scopes: self.scopes,
global_scope: self.global_scope,
super_selectors: self.super_selectors,
span_before: self.span_before,
content: self.content,
in_mixin: self.in_mixin,
in_function: self.in_function,
in_control_flow: self.in_control_flow,
at_root: self.at_root,
at_root_has_selector: self.at_root_has_selector,
extender: self.extender,
in_keyframes: self.in_keyframes,
})
.parse_keyframes_selector()?;
return Ok(selector);
}
c => string.push(c),
}
}
if !found_curly {
return Err(("expected \"{\".", span).into());
}
let sel_toks: Vec<Token> = string.chars().map(|x| Token::new(span, x)).collect();
let mut iter = sel_toks.into_iter().peekmore();
let selector = KeyframesSelectorParser::new(&mut Parser {
toks: &mut iter,
map: self.map,
path: self.path,
scopes: self.scopes,
global_scope: self.global_scope,
super_selectors: self.super_selectors,
span_before: self.span_before,
content: self.content,
in_mixin: self.in_mixin,
in_function: self.in_function,
in_control_flow: self.in_control_flow,
at_root: self.at_root,
at_root_has_selector: self.at_root_has_selector,
extender: self.extender,
in_keyframes: self.in_keyframes,
})
.parse_keyframes_selector()?;
Ok(selector)
Err(("expected \"{\".", span).into())
}
pub(super) fn parse_keyframes(&mut self) -> SassResult<Stmt> {

View File

@ -1,5 +1,4 @@
use codemap::Spanned;
use peekmore::PeekMoreIterator;
use crate::{error::SassResult, Token};
@ -49,10 +48,8 @@ impl ParsedNumber {
pub(crate) fn eat_number<I: Iterator<Item = Token>>(
toks: &mut PeekMoreIterator<I>,
) -> SassResult<Spanned<ParsedNumber>> {
let mut whole = String::with_capacity(1);
// TODO: merge this span with chars
let span = toks.peek().unwrap().pos;
eat_whole_number(toks, &mut whole);
let mut span = toks.peek().unwrap().pos;
let mut whole = eat_whole_number(toks);
if toks.peek().is_none() {
return Ok(Spanned {
@ -61,66 +58,64 @@ pub(crate) fn eat_number<I: Iterator<Item = Token>>(
});
}
let mut dec = String::new();
let next_tok = *toks.peek().unwrap();
if next_tok.kind == '.' {
let dec_len = if next_tok.kind == '.' {
toks.next();
eat_whole_number(toks, &mut dec);
let dec = eat_whole_number(toks);
if dec.is_empty() {
return Err(("Expected digit.", next_tok.pos()).into());
}
}
whole.push_str(&dec);
dec.len()
} else {
0
};
let mut times_ten = String::new();
let mut times_ten_is_postive = true;
#[allow(clippy::never_loop)]
loop {
if let Some(Token { kind: 'e', .. }) | Some(Token { kind: 'E', .. }) = toks.peek() {
let t = if let Some(tok) = toks.peek_forward(1) {
*tok
} else {
break;
};
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;
match t.kind {
'-' => {
toks.next();
times_ten_is_postive = false;
toks.next();
times_ten = eat_whole_number(toks);
if times_ten.is_empty() {
return Err(("Expected digit.", toks.peek().unwrap_or(&tok).pos).into());
}
'0'..='9' => {}
_ => break,
}
} else if matches!(tok.kind, '0'..='9') {
toks.next();
times_ten = eat_whole_number(toks);
toks.next();
eat_whole_number(toks, &mut times_ten);
if times_ten.is_empty() && !times_ten_is_postive {
return Err(("Expected digit.", toks.peek().unwrap_or(&t).pos).into());
} else if times_ten.len() > 2 {
return Err(("Exponent too large.", toks.peek().unwrap_or(&t).pos).into());
if times_ten.len() > 2 {
return Err(("Exponent too large.", toks.peek().unwrap_or(&tok).pos).into());
}
}
}
break;
}
if let Ok(Some(Token { pos, .. })) = toks.peek_previous() {
span = span.merge(*pos);
}
toks.reset_cursor();
whole.push_str(&dec);
Ok(Spanned {
node: ParsedNumber::new(whole, dec.len(), times_ten, times_ten_is_postive),
node: ParsedNumber::new(whole, dec_len, times_ten, times_ten_is_postive),
span,
})
}
pub(crate) fn eat_whole_number<I: Iterator<Item = Token>>(
toks: &mut PeekMoreIterator<I>,
buf: &mut String,
) {
) -> String {
let mut buf = String::new();
while let Some(c) = toks.peek() {
if !c.kind.is_ascii_digit() {
break;
@ -128,4 +123,5 @@ pub(crate) fn eat_whole_number<I: Iterator<Item = Token>>(
let tok = toks.next().unwrap();
buf.push(tok.kind);
}
buf
}