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

View File

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