further reduce allocations in @if

This commit is contained in:
Connor Skees 2020-07-07 19:36:13 -04:00
parent 11e859705a
commit fd4073aaca
3 changed files with 144 additions and 28 deletions

View File

@ -39,6 +39,7 @@ mod keyframes;
mod media; mod media;
mod mixin; mod mixin;
mod style; mod style;
mod throw_away;
mod value; mod value;
mod variable; mod variable;
@ -508,23 +509,6 @@ impl<'a> Parser<'a> {
} }
impl<'a> Parser<'a> { impl<'a> Parser<'a> {
fn throw_away_until_closing_curly_brace(&mut self) {
let mut scope = 0;
while let Some(tok) = self.toks.next() {
match tok.kind {
'}' => {
if scope == 0 {
break;
} else {
scope -= 1;
}
}
'{' => scope += 1,
_ => continue,
}
}
}
fn parse_if(&mut self) -> SassResult<Vec<Stmt>> { fn parse_if(&mut self) -> SassResult<Vec<Stmt>> {
self.whitespace_or_comment(); self.whitespace_or_comment();
@ -536,7 +520,7 @@ impl<'a> Parser<'a> {
// consume the open curly brace // consume the open curly brace
let span_before = match self.toks.next() { let span_before = match self.toks.next() {
Some(Token { kind: '{', pos }) => pos, Some(Token { kind: '{', pos }) => pos,
Some(..) | None => return Err(("expected \"}\".", self.span_before).into()), Some(..) | None => return Err(("expected \"{\".", self.span_before).into()),
}; };
if self.toks.peek().is_none() { if self.toks.peek().is_none() {
@ -563,7 +547,7 @@ impl<'a> Parser<'a> {
} }
.parse_stmt()?; .parse_stmt()?;
} else { } else {
self.throw_away_until_closing_curly_brace(); self.throw_away_until_closing_curly_brace()?;
} }
self.whitespace_or_comment(); self.whitespace_or_comment();
@ -590,10 +574,20 @@ impl<'a> Parser<'a> {
{ {
self.toks.next(); self.toks.next();
self.toks.next(); self.toks.next();
let cond = read_until_open_curly_brace(self.toks)?; let cond = if !found_true {
// todo: ensure there is a `{` let v = self.parse_value()?.node.is_true();
self.toks.next(); match self.toks.next() {
if !found_true && self.parse_value_from_vec(cond)?.is_true() { Some(Token { kind: '{', .. }) => {}
Some(..) | None => {
return Err(("expected \"{\".", self.span_before).into())
}
}
v
} else {
self.throw_away_until_open_curly_brace()?;
false
};
if cond {
found_true = true; found_true = true;
body = Parser { body = Parser {
toks: self.toks, toks: self.toks,
@ -610,17 +604,15 @@ impl<'a> Parser<'a> {
extender: self.extender, extender: self.extender,
} }
.parse_stmt()?; .parse_stmt()?;
// todo: ensure there is a `{`
self.toks.next();
} else { } else {
self.throw_away_until_closing_curly_brace(); self.throw_away_until_closing_curly_brace()?;
} }
self.whitespace(); self.whitespace();
} }
'{' => { '{' => {
self.toks.next(); self.toks.next();
if found_true { if found_true {
self.throw_away_until_closing_curly_brace(); self.throw_away_until_closing_curly_brace()?;
break; break;
} else { } else {
return Parser { return Parser {

125
src/parse/throw_away.rs Normal file
View File

@ -0,0 +1,125 @@
//! Consume tokens without allocating
use crate::{error::SassResult, Token};
use super::Parser;
impl<'a> Parser<'a> {
pub(super) fn throw_away_until_newline(&mut self) {
while let Some(tok) = self.toks.next() {
if tok.kind == '\n' {
break;
}
}
}
pub(super) fn throw_away_quoted_string(&mut self, q: char) -> SassResult<()> {
while let Some(tok) = self.toks.next() {
match tok.kind {
'"' if q == '"' => {
return Ok(());
}
'\'' if q == '\'' => {
return Ok(());
}
'\\' => {
if self.toks.next().is_none() {
return Err((format!("Expected {}.", q), tok.pos).into());
}
}
'#' => {
self.toks.next();
self.throw_away_until_closing_curly_brace()?;
}
_ => {}
}
}
return Err((format!("Expected {}.", q), self.span_before).into());
}
pub(super) fn throw_away_until_open_curly_brace(&mut self) -> SassResult<()> {
while let Some(tok) = self.toks.next() {
match tok.kind {
'{' => return Ok(()),
'/' => {
match self.toks.peek() {
Some(Token { kind: '/', .. }) => self.throw_away_until_newline(),
_ => {}
};
continue;
}
'\\' | '#' => {
self.toks.next();
}
q @ '"' | q @ '\'' => {
self.throw_away_quoted_string(q)?;
continue;
}
_ => {}
}
}
Err(("expected \"{\".", self.span_before).into())
}
pub(super) fn throw_away_until_closing_curly_brace(&mut self) -> SassResult<()> {
let mut nesting = 0;
while let Some(tok) = self.toks.next() {
match tok.kind {
q @ '"' | q @ '\'' => {
self.throw_away_quoted_string(q)?;
}
'{' => {
nesting += 1;
}
'}' => {
if nesting == 0 {
return Ok(());
} else {
nesting -= 1;
}
}
'/' => match self.toks.peek() {
Some(Token { kind: '/', .. }) => {
self.throw_away_until_newline();
}
Some(..) | None => continue,
},
'(' => {
self.throw_away_until_closing_paren()?;
}
'\\' => {
self.toks.next();
}
_ => {}
}
}
Err(("expected \"}\".", self.span_before).into())
}
pub(super) fn throw_away_until_closing_paren(&mut self) -> SassResult<()> {
let mut scope = 0;
while let Some(tok) = self.toks.next() {
match tok.kind {
')' => {
if scope < 1 {
return Ok(());
} else {
scope -= 1;
}
}
'(' => scope += 1,
'"' | '\'' => {
self.throw_away_quoted_string(tok.kind)?;
}
'\\' => {
match self.toks.next() {
Some(tok) => tok,
None => continue,
};
}
_ => {}
}
}
Err(("expected \")\".", self.span_before).into())
}
}

View File

@ -224,7 +224,6 @@ pub(crate) fn read_until_closing_paren<I: Iterator<Item = Token>>(
continue; continue;
} }
'\\' => { '\\' => {
t.push(toks.next().unwrap());
t.push(match toks.next() { t.push(match toks.next() {
Some(tok) => tok, Some(tok) => tok,
None => continue, None => continue,