From fda7f340cea60a90031aa8edffd8ab3a06d05992 Mon Sep 17 00:00:00 2001 From: Connor Skees Date: Sat, 8 Aug 2020 02:27:54 -0400 Subject: [PATCH] make predicate optional for callers --- src/parse/args.rs | 70 +++++++++++++++++++++------------------ src/parse/control_flow.rs | 47 ++++++++++++++------------ src/parse/import.rs | 2 +- src/parse/media.rs | 44 +++++++++++++----------- src/parse/mod.rs | 8 ++--- src/parse/module.rs | 11 +++--- src/parse/style.rs | 2 +- src/parse/value/parse.rs | 57 +++++++++++++++++-------------- 8 files changed, 134 insertions(+), 107 deletions(-) diff --git a/src/parse/args.rs b/src/parse/args.rs index ea22cc4..88b84cf 100644 --- a/src/parse/args.rs +++ b/src/parse/args.rs @@ -184,28 +184,31 @@ impl<'a> Parser<'a> { self.whitespace_or_comment(); - let value = self.parse_value(true, &|c| match c.peek() { - Some(Token { kind: ')', .. }) | Some(Token { kind: ',', .. }) => true, - Some(Token { kind: '.', .. }) => { - if matches!(c.peek_next(), Some(Token { kind: '.', .. })) { - c.reset_cursor(); - true - } else { - c.reset_cursor(); - false + let value = self.parse_value( + true, + Some(&|c| match c.peek() { + Some(Token { kind: ')', .. }) | Some(Token { kind: ',', .. }) => true, + Some(Token { kind: '.', .. }) => { + if matches!(c.peek_next(), Some(Token { kind: '.', .. })) { + c.reset_cursor(); + true + } else { + c.reset_cursor(); + false + } } - } - Some(Token { kind: '=', .. }) => { - if matches!(c.peek_next(), Some(Token { kind: '=', .. })) { - c.reset_cursor(); - false - } else { - c.reset_cursor(); - true + Some(Token { kind: '=', .. }) => { + if matches!(c.peek_next(), Some(Token { kind: '=', .. })) { + c.reset_cursor(); + false + } else { + c.reset_cursor(); + true + } } - } - Some(..) | None => false, - }); + Some(..) | None => false, + }), + ); match self.toks.peek() { Some(Token { kind: ')', .. }) => { @@ -293,19 +296,22 @@ impl<'a> Parser<'a> { self.toks.next(); let left = value?; - let right = self.parse_value(true, &|c| match c.peek() { - Some(Token { kind: ')', .. }) | Some(Token { kind: ',', .. }) => true, - Some(Token { kind: '.', .. }) => { - if matches!(c.peek_next(), Some(Token { kind: '.', .. })) { - c.reset_cursor(); - true - } else { - c.reset_cursor(); - false + let right = self.parse_value( + true, + Some(&|c| match c.peek() { + Some(Token { kind: ')', .. }) | Some(Token { kind: ',', .. }) => true, + Some(Token { kind: '.', .. }) => { + if matches!(c.peek_next(), Some(Token { kind: '.', .. })) { + c.reset_cursor(); + true + } else { + c.reset_cursor(); + false + } } - } - Some(..) | None => false, - })?; + Some(..) | None => false, + }), + )?; let value_span = left.span.merge(right.span); span = span.merge(value_span); diff --git a/src/parse/control_flow.rs b/src/parse/control_flow.rs index d61320d..3b8e506 100644 --- a/src/parse/control_flow.rs +++ b/src/parse/control_flow.rs @@ -21,7 +21,7 @@ impl<'a> Parser<'a> { let mut found_true = false; 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('{')?; @@ -83,7 +83,7 @@ impl<'a> Parser<'a> { self.throw_away_until_open_curly_brace()?; false } else { - let v = self.parse_value(true, &|_| false)?.node.is_true(); + let v = self.parse_value(true, None)?.node.is_true(); self.expect_char('{')?; v }; @@ -171,25 +171,28 @@ impl<'a> Parser<'a> { } self.whitespace_or_comment(); - let from_val = self.parse_value(false, &|toks| match toks.peek() { - Some(Token { kind: 't', pos }) - | Some(Token { kind: 'T', pos }) - | Some(Token { kind: '\\', pos }) => { - let span = *pos; - let mut ident = match peek_ident_no_interpolation(toks, false, span) { - Ok(s) => s, - Err(..) => return false, - }; - ident.node.make_ascii_lowercase(); - let v = match ident.node.to_ascii_lowercase().as_str() { - "to" | "through" => true, - _ => false, - }; - toks.reset_cursor(); - v - } - Some(..) | None => false, - })?; + let from_val = self.parse_value( + false, + Some(&|toks| match toks.peek() { + Some(Token { kind: 't', pos }) + | Some(Token { kind: 'T', pos }) + | Some(Token { kind: '\\', pos }) => { + let span = *pos; + let mut ident = match peek_ident_no_interpolation(toks, false, span) { + Ok(s) => s, + Err(..) => return false, + }; + ident.node.make_ascii_lowercase(); + let v = match ident.node.to_ascii_lowercase().as_str() { + "to" | "through" => true, + _ => false, + }; + toks.reset_cursor(); + v + } + Some(..) | None => false, + }), + )?; let through = if self.scan_identifier("through")? { 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 { Value::Dimension(Some(n), ..) => match n.to_i32() { Some(std::i32::MAX) | Some(std::i32::MIN) | None => { diff --git a/src/parse/import.rs b/src/parse/import.rs index c00ca46..839d6ac 100644 --- a/src/parse/import.rs +++ b/src/parse/import.rs @@ -144,7 +144,7 @@ impl<'a> Parser<'a> { let Spanned { node: file_name_as_value, span, - } = self.parse_value(true, &|_| false)?; + } = self.parse_value(true, None)?; match file_name_as_value { Value::String(s, QuoteKind::Quoted) => { diff --git a/src/parse/media.rs b/src/parse/media.rs index ff93a99..48c8548 100644 --- a/src/parse/media.rs +++ b/src/parse/media.rs @@ -28,22 +28,25 @@ impl<'a> Parser<'a> { } pub fn expression_until_comparison(&mut self) -> SassResult> { - let value = self.parse_value(false, &|toks| match toks.peek() { - Some(Token { kind: '>', .. }) - | Some(Token { kind: '<', .. }) - | Some(Token { kind: ':', .. }) - | Some(Token { kind: ')', .. }) => true, - Some(Token { kind: '=', .. }) => { - if matches!(toks.peek_next(), Some(Token { kind: '=', .. })) { - toks.reset_cursor(); - true - } else { - toks.reset_cursor(); - false + let value = self.parse_value( + false, + Some(&|toks| match toks.peek() { + Some(Token { kind: '>', .. }) + | Some(Token { kind: '<', .. }) + | Some(Token { kind: ':', .. }) + | Some(Token { kind: ')', .. }) => true, + Some(Token { kind: '=', .. }) => { + if matches!(toks.peek_next(), Some(Token { kind: '=', .. })) { + toks.reset_cursor(); + true + } else { + toks.reset_cursor(); + false + } } - } - _ => false, - })?; + _ => false, + }), + )?; value.node.unquote().to_css_string(value.span) } @@ -82,10 +85,13 @@ impl<'a> Parser<'a> { buf.push(':'); buf.push(' '); - let value = self.parse_value(false, &|toks| match toks.peek() { - Some(Token { kind: ')', .. }) => true, - _ => false, - })?; + let value = self.parse_value( + false, + Some(&|toks| match toks.peek() { + Some(Token { kind: ')', .. }) => true, + _ => false, + }), + )?; self.expect_char(')')?; buf.push_str(&value.node.to_css_string(value.span)?); diff --git a/src/parse/mod.rs b/src/parse/mod.rs index fe12241..c47add1 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -191,7 +191,7 @@ impl<'a> Parser<'a> { let Spanned { node: message, span, - } = self.parse_value(false, &|_| false)?; + } = self.parse_value(false, None)?; return Err(( message.inspect(span)?.to_string(), @@ -203,7 +203,7 @@ impl<'a> Parser<'a> { let Spanned { node: message, span, - } = self.parse_value(false, &|_| false)?; + } = self.parse_value(false, None)?; span.merge(kind_string.span); if let Some(Token { kind: ';', pos }) = self.toks.peek() { kind_string.span.merge(*pos); @@ -218,7 +218,7 @@ impl<'a> Parser<'a> { let Spanned { node: message, span, - } = self.parse_value(false, &|_| false)?; + } = self.parse_value(false, None)?; span.merge(kind_string.span); if let Some(Token { kind: ';', pos }) = self.toks.peek() { kind_string.span.merge(*pos); @@ -521,7 +521,7 @@ impl<'a> Parser<'a> { } pub fn parse_interpolation(&mut self) -> SassResult> { - let val = self.parse_value(true, &|_| false)?; + let val = self.parse_value(true, None)?; self.span_before = val.span; diff --git a/src/parse/module.rs b/src/parse/module.rs index f6a056b..7e12d48 100644 --- a/src/parse/module.rs +++ b/src/parse/module.rs @@ -68,10 +68,13 @@ impl<'a> Parser<'a> { self.expect_char(':')?; self.whitespace_or_comment(); - let value = self.parse_value(false, &|toks| match toks.peek() { - Some(Token { kind: ',', .. }) | Some(Token { kind: ')', .. }) => true, - _ => false, - })?; + let value = self.parse_value( + false, + Some(&|toks| match toks.peek() { + Some(Token { kind: ',', .. }) | Some(Token { kind: ')', .. }) => true, + _ => false, + }), + )?; config.insert(name.map_node(|n| n.into()), value)?; diff --git a/src/parse/style.rs b/src/parse/style.rs index ff42866..e781fbc 100644 --- a/src/parse/style.rs +++ b/src/parse/style.rs @@ -192,7 +192,7 @@ impl<'a> Parser<'a> { } fn parse_style_value(&mut self) -> SassResult> { - self.parse_value(false, &|_| false) + self.parse_value(false, None) } pub(super) fn parse_style_group( diff --git a/src/parse/value/parse.rs b/src/parse/value/parse.rs index d58bfd8..1d63e20 100644 --- a/src/parse/value/parse.rs +++ b/src/parse/value/parse.rs @@ -53,7 +53,7 @@ impl<'a> Parser<'a> { pub(crate) fn parse_value( &mut self, in_paren: bool, - predicate: &dyn Fn(&mut PeekMoreIterator>) -> bool, + predicate: Option<&dyn Fn(&mut PeekMoreIterator>) -> bool>, ) -> SassResult> { self.whitespace(); @@ -65,14 +65,16 @@ impl<'a> Parser<'a> { Some(Token { pos, .. }) => *pos, }; - if predicate(self.toks) { - return Err(("Expected expression.", span).into()); + if let Some(predicate) = predicate { + if predicate(self.toks) { + return Err(("Expected expression.", span).into()); + } } let mut last_was_whitespace = false; let mut space_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() { let val = val?; match val.node { @@ -190,7 +192,7 @@ impl<'a> Parser<'a> { modules: self.modules, module_config: self.module_config, } - .parse_value(in_paren, &|_| false) + .parse_value(in_paren, None) } #[allow(clippy::eval_order_dependence)] @@ -234,7 +236,7 @@ impl<'a> Parser<'a> { fn parse_ident_value( &mut self, - predicate: &dyn Fn(&mut PeekMoreIterator>) -> bool, + predicate: Option<&dyn Fn(&mut PeekMoreIterator>) -> bool>, ) -> SassResult> { let Spanned { node: mut s, span } = self.parse_identifier()?; @@ -315,9 +317,11 @@ impl<'a> Parser<'a> { .span(span)); } Some(Token { kind: '.', .. }) => { - if !predicate(self.toks) { - self.toks.next(); - return self.parse_module_item(&s, span); + if let Some(predicate) = predicate { + if !predicate(self.toks) { + self.toks.next(); + return self.parse_module_item(&s, span); + } } } _ => {} @@ -356,12 +360,12 @@ impl<'a> Parser<'a> { fn parse_number( &mut self, - predicate: &dyn Fn(&mut PeekMoreIterator>) -> bool, + predicate: Option<&dyn Fn(&mut PeekMoreIterator>) -> bool>, ) -> SassResult> { let mut span = self.toks.peek().unwrap().pos; 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 { node: ParsedNumber::new(whole, 0, String::new(), true), span, @@ -441,7 +445,7 @@ impl<'a> Parser<'a> { let mut map = SassMap::new(); let key = self.parse_value( 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() { @@ -457,7 +461,7 @@ impl<'a> Parser<'a> { let val = self.parse_value( 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); @@ -491,14 +495,16 @@ impl<'a> Parser<'a> { } loop { - let key = - self.parse_value(true, &|c| matches!(c.peek(), Some(Token { kind: ':', .. })))?; + let key = self.parse_value( + true, + Some(&|c| matches!(c.peek(), Some(Token { kind: ':', .. }))), + )?; self.expect_char(':')?; self.whitespace_or_comment(); 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); @@ -527,10 +533,12 @@ impl<'a> Parser<'a> { fn parse_intermediate_value( &mut self, - predicate: &dyn Fn(&mut PeekMoreIterator>) -> bool, + predicate: Option<&dyn Fn(&mut PeekMoreIterator>) -> bool>, ) -> Option>> { - if predicate(self.toks) { - return None; + if let Some(predicate) = predicate { + if predicate(self.toks) { + return None; + } } let (kind, span) = match self.toks.peek() { Some(v) => (v.kind, v.pos()), @@ -705,9 +713,10 @@ impl<'a> Parser<'a> { .span(span) } else { // todo: we don't know if we're `in_paren` here - let inner = match self.parse_value(false, &|toks| { - matches!(toks.peek(), Some(Token { kind: ']', .. })) - }) { + let inner = match self.parse_value( + false, + Some(&|toks| matches!(toks.peek(), Some(Token { kind: ']', .. }))), + ) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -914,7 +923,7 @@ impl<'a> Parser<'a> { struct IntermediateValueIterator<'a, 'b: 'a> { parser: &'a mut Parser<'b>, peek: Option>>, - predicate: &'a dyn Fn(&mut PeekMoreIterator>) -> bool, + predicate: Option<&'a dyn Fn(&mut PeekMoreIterator>) -> bool>, } 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> { pub fn new( parser: &'a mut Parser<'b>, - predicate: &'a dyn Fn(&mut PeekMoreIterator>) -> bool, + predicate: Option<&'a dyn Fn(&mut PeekMoreIterator>) -> bool>, ) -> Self { Self { parser,