From fd685ee36fdd9c7653cfee711b302b87fd41425b Mon Sep 17 00:00:00 2001 From: Connor Skees Date: Tue, 20 Jul 2021 10:37:29 -0400 Subject: [PATCH] include full parser context in predicate --- src/parse/args.rs | 12 ++++++---- src/parse/control_flow.rs | 6 ++--- src/parse/media.rs | 10 ++++---- src/parse/module.rs | 4 ++-- src/parse/value/parse.rs | 50 +++++++++++++++++++-------------------- src/parse/variable.rs | 8 +++---- 6 files changed, 46 insertions(+), 44 deletions(-) diff --git a/src/parse/args.rs b/src/parse/args.rs index e6ad863..b3fa2ac 100644 --- a/src/parse/args.rs +++ b/src/parse/args.rs @@ -183,15 +183,16 @@ impl<'a> Parser<'a> { self.whitespace_or_comment(); - let value = self.parse_value(true, &|c| match c.peek() { + let value = self.parse_value(true, &|parser| match parser.toks.peek() { Some(Token { kind: ')', .. }) | Some(Token { kind: ',', .. }) => true, Some(Token { kind: '.', .. }) => { - let next_is_dot = matches!(c.peek_n(1), Some(Token { kind: '.', .. })); + let next_is_dot = + matches!(parser.toks.peek_n(1), Some(Token { kind: '.', .. })); next_is_dot } Some(Token { kind: '=', .. }) => { - let next_is_eq = matches!(c.peek_n(1), Some(Token { kind: '=', .. })); + let next_is_eq = matches!(parser.toks.peek_n(1), Some(Token { kind: '=', .. })); !next_is_eq } @@ -283,10 +284,11 @@ impl<'a> Parser<'a> { self.toks.next(); let left = value?; - let right = self.parse_value(true, &|c| match c.peek() { + let right = self.parse_value(true, &|parser| match parser.toks.peek() { Some(Token { kind: ')', .. }) | Some(Token { kind: ',', .. }) => true, Some(Token { kind: '.', .. }) => { - let next_is_dot = matches!(c.peek_n(1), Some(Token { kind: '.', .. })); + let next_is_dot = + matches!(parser.toks.peek_n(1), Some(Token { kind: '.', .. })); next_is_dot } diff --git a/src/parse/control_flow.rs b/src/parse/control_flow.rs index a228fb4..a9684a6 100644 --- a/src/parse/control_flow.rs +++ b/src/parse/control_flow.rs @@ -176,18 +176,18 @@ impl<'a> Parser<'a> { } self.whitespace_or_comment(); - let from_val = self.parse_value(false, &|toks| match toks.peek() { + let from_val = self.parse_value(false, &|parser| match parser.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) { + let mut ident = match peek_ident_no_interpolation(parser.toks, false, span) { Ok(s) => s, Err(..) => return false, }; ident.node.make_ascii_lowercase(); let v = matches!(ident.node.to_ascii_lowercase().as_str(), "to" | "through"); - toks.reset_cursor(); + parser.toks.reset_cursor(); v } Some(..) | None => false, diff --git a/src/parse/media.rs b/src/parse/media.rs index 2830fa5..bd70340 100644 --- a/src/parse/media.rs +++ b/src/parse/media.rs @@ -34,14 +34,14 @@ impl<'a> Parser<'a> { } pub fn expression_until_comparison(&mut self) -> SassResult> { - let value = self.parse_value(false, &|toks| match toks.peek() { + let value = self.parse_value(false, &|parser| match parser.toks.peek() { Some(Token { kind: '>', .. }) | Some(Token { kind: '<', .. }) | Some(Token { kind: ':', .. }) | Some(Token { kind: ')', .. }) => true, Some(Token { kind: '=', .. }) => { - let is_double_eq = matches!(toks.peek_next(), Some(Token { kind: '=', .. })); - toks.reset_cursor(); + let is_double_eq = matches!(parser.toks.peek_next(), Some(Token { kind: '=', .. })); + parser.toks.reset_cursor(); // if it is a double eq, then parse as normal // // otherwise, it is a single eq and we should @@ -88,8 +88,8 @@ impl<'a> Parser<'a> { buf.push(':'); buf.push(' '); - let value = self.parse_value(false, &|toks| { - matches!(toks.peek(), Some(Token { kind: ')', .. })) + let value = self.parse_value(false, &|parser| { + matches!(parser.toks.peek(), Some(Token { kind: ')', .. })) })?; self.expect_char(')')?; diff --git a/src/parse/module.rs b/src/parse/module.rs index 5ff9844..d980fa9 100644 --- a/src/parse/module.rs +++ b/src/parse/module.rs @@ -78,9 +78,9 @@ impl<'a> Parser<'a> { self.expect_char(':')?; self.whitespace_or_comment(); - let value = self.parse_value(false, &|toks| { + let value = self.parse_value(false, &|parser| { matches!( - toks.peek(), + parser.toks.peek(), Some(Token { kind: ',', .. }) | Some(Token { kind: ')', .. }) ) })?; diff --git a/src/parse/value/parse.rs b/src/parse/value/parse.rs index 00f4cbb..627886c 100644 --- a/src/parse/value/parse.rs +++ b/src/parse/value/parse.rs @@ -45,6 +45,9 @@ impl IsWhitespace for IntermediateValue { } } +/// We parse a value until the predicate returns true +type Predicate<'a> = &'a dyn Fn(&mut Parser<'_>) -> bool; + impl<'a> Parser<'a> { /// Parse a value from a stream of tokens /// @@ -52,7 +55,7 @@ impl<'a> Parser<'a> { pub(crate) fn parse_value( &mut self, in_paren: bool, - predicate: &dyn Fn(&mut Lexer) -> bool, + predicate: Predicate<'_>, ) -> SassResult> { self.whitespace(); @@ -64,7 +67,7 @@ impl<'a> Parser<'a> { Some(Token { pos, .. }) => pos, }; - if predicate(self.toks) { + if predicate(self) { return Err(("Expected expression.", span).into()); } @@ -290,7 +293,7 @@ impl<'a> Parser<'a> { fn parse_ident_value( &mut self, - predicate: &dyn Fn(&mut Lexer) -> bool, + predicate: Predicate<'_>, ) -> SassResult> { let Spanned { node: mut s, span } = self.parse_identifier()?; @@ -320,7 +323,7 @@ impl<'a> Parser<'a> { return self.parse_fn_call(s, lower); } Some(Token { kind: '.', .. }) => { - if !predicate(self.toks) { + if !predicate(self) { self.toks.next(); return self.parse_module_item(&s, span); } @@ -360,14 +363,11 @@ impl<'a> Parser<'a> { } } - fn parse_number( - &mut self, - predicate: &dyn Fn(&mut Lexer) -> bool, - ) -> SassResult> { + fn parse_number(&mut self, predicate: Predicate<'_>) -> 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(self) { return Ok(Spanned { node: ParsedNumber::new(whole, 0, String::new(), true), span, @@ -452,8 +452,8 @@ impl<'a> Parser<'a> { .span(span) } else { // todo: we don't know if we're `in_paren` here - let inner = self.parse_value(false, &|toks| { - matches!(toks.peek(), Some(Token { kind: ']', .. })) + let inner = self.parse_value(false, &|parser| { + matches!(parser.toks.peek(), Some(Token { kind: ']', .. })) })?; span = span.merge(inner.span); @@ -470,7 +470,7 @@ impl<'a> Parser<'a> { fn parse_intermediate_value_dimension( &mut self, - predicate: &dyn Fn(&mut Lexer) -> bool, + predicate: Predicate<'_>, ) -> SassResult> { let Spanned { node, span } = self.parse_dimension(predicate)?; @@ -479,7 +479,7 @@ impl<'a> Parser<'a> { pub(crate) fn parse_dimension( &mut self, - predicate: &dyn Fn(&mut Lexer) -> bool, + predicate: Predicate<'_>, ) -> SassResult> { let Spanned { node: val, @@ -568,9 +568,9 @@ impl<'a> Parser<'a> { } let mut map = SassMap::new(); - let key = self.parse_value(true, &|c| { + let key = self.parse_value(true, &|parser| { matches!( - c.peek(), + parser.toks.peek(), Some(Token { kind: ':', .. }) | Some(Token { kind: ')', .. }) ) })?; @@ -586,9 +586,9 @@ impl<'a> Parser<'a> { Some(..) | None => return Err(("expected \")\".", key.span).into()), } - let val = self.parse_value(true, &|c| { + let val = self.parse_value(true, &|parser| { matches!( - c.peek(), + parser.toks.peek(), Some(Token { kind: ',', .. }) | Some(Token { kind: ')', .. }) ) })?; @@ -624,9 +624,9 @@ impl<'a> Parser<'a> { } loop { - let key = self.parse_value(true, &|c| { + let key = self.parse_value(true, &|parser| { matches!( - c.peek(), + parser.toks.peek(), Some(Token { kind: ':', .. }) | Some(Token { kind: ',', .. }) ) })?; @@ -634,9 +634,9 @@ impl<'a> Parser<'a> { self.expect_char(':')?; self.whitespace_or_comment(); - let val = self.parse_value(true, &|c| { + let val = self.parse_value(true, &|parser| { matches!( - c.peek(), + parser.toks.peek(), Some(Token { kind: ',', .. }) | Some(Token { kind: ')', .. }) ) })?; @@ -763,9 +763,9 @@ impl<'a> Parser<'a> { fn parse_intermediate_value( &mut self, - predicate: &dyn Fn(&mut Lexer) -> bool, + predicate: Predicate<'_>, ) -> Option>> { - if predicate(self.toks) { + if predicate(self) { return None; } let (kind, span) = match self.toks.peek() { @@ -1038,7 +1038,7 @@ impl<'a> Parser<'a> { struct IntermediateValueIterator<'a, 'b: 'a> { parser: &'a mut Parser<'b>, peek: Option>>, - predicate: &'a dyn Fn(&mut Lexer) -> bool, + predicate: Predicate<'a>, } impl<'a, 'b: 'a> Iterator for IntermediateValueIterator<'a, 'b> { @@ -1053,7 +1053,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 Lexer) -> bool) -> Self { + pub fn new(parser: &'a mut Parser<'b>, predicate: Predicate<'a>) -> Self { Self { parser, peek: None, diff --git a/src/parse/variable.rs b/src/parse/variable.rs index c50679c..d6c4af5 100644 --- a/src/parse/variable.rs +++ b/src/parse/variable.rs @@ -111,15 +111,15 @@ impl<'a> Parser<'a> { let mut default = false; let mut global = false; - let value = self.parse_value(true, &|toks| { - if matches!(toks.peek(), Some(Token { kind: '!', .. })) { + let value = self.parse_value(true, &|parser| { + if matches!(parser.toks.peek(), Some(Token { kind: '!', .. })) { let is_important = matches!( - toks.peek_next(), + parser.toks.peek_next(), Some(Token { kind: 'i', .. }) | Some(Token { kind: 'I', .. }) | Some(Token { kind: '=', .. }) ); - toks.reset_cursor(); + parser.toks.reset_cursor(); !is_important } else { false