make predicate optional for callers

This commit is contained in:
Connor Skees 2020-08-08 02:27:54 -04:00
parent a9bef0e24e
commit fda7f340ce
8 changed files with 134 additions and 107 deletions

View File

@ -184,28 +184,31 @@ impl<'a> Parser<'a> {
self.whitespace_or_comment(); self.whitespace_or_comment();
let value = self.parse_value(true, &|c| match c.peek() { let value = self.parse_value(
Some(Token { kind: ')', .. }) | Some(Token { kind: ',', .. }) => true, true,
Some(Token { kind: '.', .. }) => { Some(&|c| match c.peek() {
if matches!(c.peek_next(), Some(Token { kind: '.', .. })) { Some(Token { kind: ')', .. }) | Some(Token { kind: ',', .. }) => true,
c.reset_cursor(); Some(Token { kind: '.', .. }) => {
true if matches!(c.peek_next(), Some(Token { kind: '.', .. })) {
} else { c.reset_cursor();
c.reset_cursor(); true
false } else {
c.reset_cursor();
false
}
} }
} Some(Token { kind: '=', .. }) => {
Some(Token { kind: '=', .. }) => { if matches!(c.peek_next(), Some(Token { kind: '=', .. })) {
if matches!(c.peek_next(), Some(Token { kind: '=', .. })) { c.reset_cursor();
c.reset_cursor(); false
false } else {
} else { c.reset_cursor();
c.reset_cursor(); true
true }
} }
} Some(..) | None => false,
Some(..) | None => false, }),
}); );
match self.toks.peek() { match self.toks.peek() {
Some(Token { kind: ')', .. }) => { Some(Token { kind: ')', .. }) => {
@ -293,19 +296,22 @@ impl<'a> Parser<'a> {
self.toks.next(); self.toks.next();
let left = value?; let left = value?;
let right = self.parse_value(true, &|c| match c.peek() { let right = self.parse_value(
Some(Token { kind: ')', .. }) | Some(Token { kind: ',', .. }) => true, true,
Some(Token { kind: '.', .. }) => { Some(&|c| match c.peek() {
if matches!(c.peek_next(), Some(Token { kind: '.', .. })) { Some(Token { kind: ')', .. }) | Some(Token { kind: ',', .. }) => true,
c.reset_cursor(); Some(Token { kind: '.', .. }) => {
true if matches!(c.peek_next(), Some(Token { kind: '.', .. })) {
} else { c.reset_cursor();
c.reset_cursor(); true
false } else {
c.reset_cursor();
false
}
} }
} Some(..) | None => false,
Some(..) | None => false, }),
})?; )?;
let value_span = left.span.merge(right.span); let value_span = left.span.merge(right.span);
span = span.merge(value_span); span = span.merge(value_span);

View File

@ -21,7 +21,7 @@ impl<'a> Parser<'a> {
let mut found_true = false; let mut found_true = false;
let mut body = Vec::new(); let mut body = Vec::new();
let init_cond = self.parse_value(true, &|_| false)?.node; let init_cond = self.parse_value(true, None)?.node;
self.expect_char('{')?; self.expect_char('{')?;
@ -83,7 +83,7 @@ impl<'a> Parser<'a> {
self.throw_away_until_open_curly_brace()?; self.throw_away_until_open_curly_brace()?;
false false
} else { } else {
let v = self.parse_value(true, &|_| false)?.node.is_true(); let v = self.parse_value(true, None)?.node.is_true();
self.expect_char('{')?; self.expect_char('{')?;
v v
}; };
@ -171,25 +171,28 @@ impl<'a> Parser<'a> {
} }
self.whitespace_or_comment(); self.whitespace_or_comment();
let from_val = self.parse_value(false, &|toks| match toks.peek() { let from_val = self.parse_value(
Some(Token { kind: 't', pos }) false,
| Some(Token { kind: 'T', pos }) Some(&|toks| match toks.peek() {
| Some(Token { kind: '\\', pos }) => { Some(Token { kind: 't', pos })
let span = *pos; | Some(Token { kind: 'T', pos })
let mut ident = match peek_ident_no_interpolation(toks, false, span) { | Some(Token { kind: '\\', pos }) => {
Ok(s) => s, let span = *pos;
Err(..) => return false, let mut ident = match peek_ident_no_interpolation(toks, false, span) {
}; Ok(s) => s,
ident.node.make_ascii_lowercase(); Err(..) => return false,
let v = match ident.node.to_ascii_lowercase().as_str() { };
"to" | "through" => true, ident.node.make_ascii_lowercase();
_ => false, let v = match ident.node.to_ascii_lowercase().as_str() {
}; "to" | "through" => true,
toks.reset_cursor(); _ => false,
v };
} toks.reset_cursor();
Some(..) | None => false, v
})?; }
Some(..) | None => false,
}),
)?;
let through = if self.scan_identifier("through")? { let through = if self.scan_identifier("through")? {
1 1
@ -216,7 +219,7 @@ impl<'a> Parser<'a> {
} }
}; };
let to_val = self.parse_value(true, &|_| false)?; let to_val = self.parse_value(true, None)?;
let to = match to_val.node { let to = match to_val.node {
Value::Dimension(Some(n), ..) => match n.to_i32() { Value::Dimension(Some(n), ..) => match n.to_i32() {
Some(std::i32::MAX) | Some(std::i32::MIN) | None => { Some(std::i32::MAX) | Some(std::i32::MIN) | None => {

View File

@ -144,7 +144,7 @@ impl<'a> Parser<'a> {
let Spanned { let Spanned {
node: file_name_as_value, node: file_name_as_value,
span, span,
} = self.parse_value(true, &|_| false)?; } = self.parse_value(true, None)?;
match file_name_as_value { match file_name_as_value {
Value::String(s, QuoteKind::Quoted) => { Value::String(s, QuoteKind::Quoted) => {

View File

@ -28,22 +28,25 @@ impl<'a> Parser<'a> {
} }
pub fn expression_until_comparison(&mut self) -> SassResult<Cow<'static, str>> { pub fn expression_until_comparison(&mut self) -> SassResult<Cow<'static, str>> {
let value = self.parse_value(false, &|toks| match toks.peek() { let value = self.parse_value(
Some(Token { kind: '>', .. }) false,
| Some(Token { kind: '<', .. }) Some(&|toks| match toks.peek() {
| Some(Token { kind: ':', .. }) Some(Token { kind: '>', .. })
| Some(Token { kind: ')', .. }) => true, | Some(Token { kind: '<', .. })
Some(Token { kind: '=', .. }) => { | Some(Token { kind: ':', .. })
if matches!(toks.peek_next(), Some(Token { kind: '=', .. })) { | Some(Token { kind: ')', .. }) => true,
toks.reset_cursor(); Some(Token { kind: '=', .. }) => {
true if matches!(toks.peek_next(), Some(Token { kind: '=', .. })) {
} else { toks.reset_cursor();
toks.reset_cursor(); true
false } else {
toks.reset_cursor();
false
}
} }
} _ => false,
_ => false, }),
})?; )?;
value.node.unquote().to_css_string(value.span) value.node.unquote().to_css_string(value.span)
} }
@ -82,10 +85,13 @@ impl<'a> Parser<'a> {
buf.push(':'); buf.push(':');
buf.push(' '); buf.push(' ');
let value = self.parse_value(false, &|toks| match toks.peek() { let value = self.parse_value(
Some(Token { kind: ')', .. }) => true, false,
_ => false, Some(&|toks| match toks.peek() {
})?; Some(Token { kind: ')', .. }) => true,
_ => false,
}),
)?;
self.expect_char(')')?; self.expect_char(')')?;
buf.push_str(&value.node.to_css_string(value.span)?); buf.push_str(&value.node.to_css_string(value.span)?);

View File

@ -191,7 +191,7 @@ impl<'a> Parser<'a> {
let Spanned { let Spanned {
node: message, node: message,
span, span,
} = self.parse_value(false, &|_| false)?; } = self.parse_value(false, None)?;
return Err(( return Err((
message.inspect(span)?.to_string(), message.inspect(span)?.to_string(),
@ -203,7 +203,7 @@ impl<'a> Parser<'a> {
let Spanned { let Spanned {
node: message, node: message,
span, span,
} = self.parse_value(false, &|_| false)?; } = self.parse_value(false, None)?;
span.merge(kind_string.span); span.merge(kind_string.span);
if let Some(Token { kind: ';', pos }) = self.toks.peek() { if let Some(Token { kind: ';', pos }) = self.toks.peek() {
kind_string.span.merge(*pos); kind_string.span.merge(*pos);
@ -218,7 +218,7 @@ impl<'a> Parser<'a> {
let Spanned { let Spanned {
node: message, node: message,
span, span,
} = self.parse_value(false, &|_| false)?; } = self.parse_value(false, None)?;
span.merge(kind_string.span); span.merge(kind_string.span);
if let Some(Token { kind: ';', pos }) = self.toks.peek() { if let Some(Token { kind: ';', pos }) = self.toks.peek() {
kind_string.span.merge(*pos); kind_string.span.merge(*pos);
@ -521,7 +521,7 @@ impl<'a> Parser<'a> {
} }
pub fn parse_interpolation(&mut self) -> SassResult<Spanned<Value>> { pub fn parse_interpolation(&mut self) -> SassResult<Spanned<Value>> {
let val = self.parse_value(true, &|_| false)?; let val = self.parse_value(true, None)?;
self.span_before = val.span; self.span_before = val.span;

View File

@ -68,10 +68,13 @@ impl<'a> Parser<'a> {
self.expect_char(':')?; self.expect_char(':')?;
self.whitespace_or_comment(); self.whitespace_or_comment();
let value = self.parse_value(false, &|toks| match toks.peek() { let value = self.parse_value(
Some(Token { kind: ',', .. }) | Some(Token { kind: ')', .. }) => true, false,
_ => false, Some(&|toks| match toks.peek() {
})?; Some(Token { kind: ',', .. }) | Some(Token { kind: ')', .. }) => true,
_ => false,
}),
)?;
config.insert(name.map_node(|n| n.into()), value)?; config.insert(name.map_node(|n| n.into()), value)?;

View File

@ -192,7 +192,7 @@ impl<'a> Parser<'a> {
} }
fn parse_style_value(&mut self) -> SassResult<Spanned<Value>> { fn parse_style_value(&mut self) -> SassResult<Spanned<Value>> {
self.parse_value(false, &|_| false) self.parse_value(false, None)
} }
pub(super) fn parse_style_group( pub(super) fn parse_style_group(

View File

@ -53,7 +53,7 @@ impl<'a> Parser<'a> {
pub(crate) fn parse_value( pub(crate) fn parse_value(
&mut self, &mut self,
in_paren: bool, in_paren: bool,
predicate: &dyn Fn(&mut PeekMoreIterator<IntoIter<Token>>) -> bool, predicate: Option<&dyn Fn(&mut PeekMoreIterator<IntoIter<Token>>) -> bool>,
) -> SassResult<Spanned<Value>> { ) -> SassResult<Spanned<Value>> {
self.whitespace(); self.whitespace();
@ -65,14 +65,16 @@ impl<'a> Parser<'a> {
Some(Token { pos, .. }) => *pos, Some(Token { pos, .. }) => *pos,
}; };
if predicate(self.toks) { if let Some(predicate) = predicate {
return Err(("Expected expression.", span).into()); if predicate(self.toks) {
return Err(("Expected expression.", span).into());
}
} }
let mut last_was_whitespace = false; let mut last_was_whitespace = false;
let mut space_separated = Vec::new(); let mut space_separated = Vec::new();
let mut comma_separated = Vec::new(); let mut comma_separated = Vec::new();
let mut iter = IntermediateValueIterator::new(self, &predicate); let mut iter = IntermediateValueIterator::new(self, predicate);
while let Some(val) = iter.next() { while let Some(val) = iter.next() {
let val = val?; let val = val?;
match val.node { match val.node {
@ -190,7 +192,7 @@ impl<'a> Parser<'a> {
modules: self.modules, modules: self.modules,
module_config: self.module_config, module_config: self.module_config,
} }
.parse_value(in_paren, &|_| false) .parse_value(in_paren, None)
} }
#[allow(clippy::eval_order_dependence)] #[allow(clippy::eval_order_dependence)]
@ -234,7 +236,7 @@ impl<'a> Parser<'a> {
fn parse_ident_value( fn parse_ident_value(
&mut self, &mut self,
predicate: &dyn Fn(&mut PeekMoreIterator<IntoIter<Token>>) -> bool, predicate: Option<&dyn Fn(&mut PeekMoreIterator<IntoIter<Token>>) -> bool>,
) -> SassResult<Spanned<IntermediateValue>> { ) -> SassResult<Spanned<IntermediateValue>> {
let Spanned { node: mut s, span } = self.parse_identifier()?; let Spanned { node: mut s, span } = self.parse_identifier()?;
@ -315,9 +317,11 @@ impl<'a> Parser<'a> {
.span(span)); .span(span));
} }
Some(Token { kind: '.', .. }) => { Some(Token { kind: '.', .. }) => {
if !predicate(self.toks) { if let Some(predicate) = predicate {
self.toks.next(); if !predicate(self.toks) {
return self.parse_module_item(&s, span); self.toks.next();
return self.parse_module_item(&s, span);
}
} }
} }
_ => {} _ => {}
@ -356,12 +360,12 @@ impl<'a> Parser<'a> {
fn parse_number( fn parse_number(
&mut self, &mut self,
predicate: &dyn Fn(&mut PeekMoreIterator<IntoIter<Token>>) -> bool, predicate: Option<&dyn Fn(&mut PeekMoreIterator<IntoIter<Token>>) -> bool>,
) -> SassResult<Spanned<ParsedNumber>> { ) -> SassResult<Spanned<ParsedNumber>> {
let mut span = self.toks.peek().unwrap().pos; let mut span = self.toks.peek().unwrap().pos;
let mut whole = eat_whole_number(self.toks); let mut whole = eat_whole_number(self.toks);
if self.toks.peek().is_none() || predicate(self.toks) { if self.toks.peek().is_none() || predicate.map_or(false, |p| p(self.toks)) {
return Ok(Spanned { return Ok(Spanned {
node: ParsedNumber::new(whole, 0, String::new(), true), node: ParsedNumber::new(whole, 0, String::new(), true),
span, span,
@ -441,7 +445,7 @@ impl<'a> Parser<'a> {
let mut map = SassMap::new(); let mut map = SassMap::new();
let key = self.parse_value( let key = self.parse_value(
true, true,
&|c| matches!(c.peek(), Some(Token { kind: ':', .. }) | Some(Token { kind: ')', .. })), Some(&|c| matches!(c.peek(), Some(Token { kind: ':', .. }) | Some(Token { kind: ')', .. }))),
)?; )?;
match self.toks.next() { match self.toks.next() {
@ -457,7 +461,7 @@ impl<'a> Parser<'a> {
let val = self.parse_value( let val = self.parse_value(
true, true,
&|c| matches!(c.peek(), Some(Token { kind: ',', .. }) | Some(Token { kind: ')', .. })), Some(&|c| matches!(c.peek(), Some(Token { kind: ',', .. }) | Some(Token { kind: ')', .. }))),
)?; )?;
map.insert(key.node, val.node); map.insert(key.node, val.node);
@ -491,14 +495,16 @@ impl<'a> Parser<'a> {
} }
loop { loop {
let key = let key = self.parse_value(
self.parse_value(true, &|c| matches!(c.peek(), Some(Token { kind: ':', .. })))?; true,
Some(&|c| matches!(c.peek(), Some(Token { kind: ':', .. }))),
)?;
self.expect_char(':')?; self.expect_char(':')?;
self.whitespace_or_comment(); self.whitespace_or_comment();
let val = let val =
self.parse_value(true, &|c| matches!(c.peek(), Some(Token { kind: ',', .. }) | Some(Token { kind: ')', .. })))?; self.parse_value(true, Some(&|c| matches!(c.peek(), Some(Token { kind: ',', .. }) | Some(Token { kind: ')', .. }))))?;
span = span.merge(val.span); span = span.merge(val.span);
@ -527,10 +533,12 @@ impl<'a> Parser<'a> {
fn parse_intermediate_value( fn parse_intermediate_value(
&mut self, &mut self,
predicate: &dyn Fn(&mut PeekMoreIterator<IntoIter<Token>>) -> bool, predicate: Option<&dyn Fn(&mut PeekMoreIterator<IntoIter<Token>>) -> bool>,
) -> Option<SassResult<Spanned<IntermediateValue>>> { ) -> Option<SassResult<Spanned<IntermediateValue>>> {
if predicate(self.toks) { if let Some(predicate) = predicate {
return None; if predicate(self.toks) {
return None;
}
} }
let (kind, span) = match self.toks.peek() { let (kind, span) = match self.toks.peek() {
Some(v) => (v.kind, v.pos()), Some(v) => (v.kind, v.pos()),
@ -705,9 +713,10 @@ impl<'a> Parser<'a> {
.span(span) .span(span)
} else { } else {
// todo: we don't know if we're `in_paren` here // todo: we don't know if we're `in_paren` here
let inner = match self.parse_value(false, &|toks| { let inner = match self.parse_value(
matches!(toks.peek(), Some(Token { kind: ']', .. })) false,
}) { Some(&|toks| matches!(toks.peek(), Some(Token { kind: ']', .. }))),
) {
Ok(v) => v, Ok(v) => v,
Err(e) => return Some(Err(e)), Err(e) => return Some(Err(e)),
}; };
@ -914,7 +923,7 @@ impl<'a> Parser<'a> {
struct IntermediateValueIterator<'a, 'b: 'a> { struct IntermediateValueIterator<'a, 'b: 'a> {
parser: &'a mut Parser<'b>, parser: &'a mut Parser<'b>,
peek: Option<SassResult<Spanned<IntermediateValue>>>, peek: Option<SassResult<Spanned<IntermediateValue>>>,
predicate: &'a dyn Fn(&mut PeekMoreIterator<IntoIter<Token>>) -> bool, predicate: Option<&'a dyn Fn(&mut PeekMoreIterator<IntoIter<Token>>) -> bool>,
} }
impl<'a, 'b: 'a> Iterator for IntermediateValueIterator<'a, 'b> { impl<'a, 'b: 'a> Iterator for IntermediateValueIterator<'a, 'b> {
@ -931,7 +940,7 @@ impl<'a, 'b: 'a> Iterator for IntermediateValueIterator<'a, 'b> {
impl<'a, 'b: 'a> IntermediateValueIterator<'a, 'b> { impl<'a, 'b: 'a> IntermediateValueIterator<'a, 'b> {
pub fn new( pub fn new(
parser: &'a mut Parser<'b>, parser: &'a mut Parser<'b>,
predicate: &'a dyn Fn(&mut PeekMoreIterator<IntoIter<Token>>) -> bool, predicate: Option<&'a dyn Fn(&mut PeekMoreIterator<IntoIter<Token>>) -> bool>,
) -> Self { ) -> Self {
Self { Self {
parser, parser,