From 85a5b005cbabfb65f203dffd7ce8bd6aedd080ed Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Sun, 5 Jul 2020 17:59:48 +0800 Subject: [PATCH] refactor keyframes and number parsing logic --- src/parse/keyframes.rs | 74 +++++++++++++++++------------------------- src/utils/number.rs | 74 ++++++++++++++++++++---------------------- 2 files changed, 64 insertions(+), 84 deletions(-) diff --git a/src/parse/keyframes.rs b/src/parse/keyframes.rs index fad7f22..232ecc7 100644 --- a/src/parse/keyframes.rs +++ b/src/parse/keyframes.rs @@ -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 { 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 = + 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 = 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 { diff --git a/src/utils/number.rs b/src/utils/number.rs index c84ac4f..7102607 100644 --- a/src/utils/number.rs +++ b/src/utils/number.rs @@ -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>( toks: &mut PeekMoreIterator, ) -> SassResult> { - 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>( }); } - 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>( toks: &mut PeekMoreIterator, - 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>( let tok = toks.next().unwrap(); buf.push(tok.kind); } + buf }