From 2df5e1b274610e4575b322678e8d54cc9463b208 Mon Sep 17 00:00:00 2001 From: Connor Skees Date: Sun, 2 Aug 2020 22:24:37 -0400 Subject: [PATCH 01/11] resolve panic on malformed args missing closing parenthesis --- src/parse/args.rs | 4 ++-- tests/args.rs | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/parse/args.rs b/src/parse/args.rs index 2702b0e..8de7c39 100644 --- a/src/parse/args.rs +++ b/src/parse/args.rs @@ -345,9 +345,9 @@ impl<'a> Parser<'a> { None => return Err(("expected \")\".", span).into()), } } - Some(c) => { + Some(Token { pos, .. }) => { value?; - unreachable!("{:?}", c) + return Err(("expected \")\".", *pos).into()); } None => return Err(("expected \")\".", span).into()), } diff --git a/tests/args.rs b/tests/args.rs index 37bb585..e06da77 100644 --- a/tests/args.rs +++ b/tests/args.rs @@ -168,6 +168,10 @@ error!( filter_value_after_equal_is_last_char, "a {\n color: foo(a=a", "Error: expected \")\"." ); +error!( + unclosed_paren_in_nested_args, + "a { color: a(b(red); }", "Error: expected \")\"." +); test!( space_after_loud_comment, "@mixin foo($x) { From 3e5f69118b90cd03ecfe1663b1568e5843e28b63 Mon Sep 17 00:00:00 2001 From: Connor Skees Date: Sun, 2 Aug 2020 23:00:00 -0400 Subject: [PATCH 02/11] disallow more at-rules in `@function` --- src/parse/function.rs | 4 ++ src/parse/import.rs | 4 ++ src/parse/keyframes.rs | 4 ++ src/parse/mixin.rs | 4 ++ src/parse/mod.rs | 31 ++++++++++++ tests/functions.rs | 110 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 157 insertions(+) diff --git a/src/parse/function.rs b/src/parse/function.rs index fb8b516..4560abe 100644 --- a/src/parse/function.rs +++ b/src/parse/function.rs @@ -31,6 +31,10 @@ impl<'a> Parser<'a> { return Err(("Functions may not be declared in control directives.", span).into()); } + if self.flags.in_function() { + return Err(("This at-rule is not allowed here.", self.span_before).into()); + } + if RESERVED_IDENTIFIERS.contains(&unvendor(&name)) { return Err(("Invalid function name.", span).into()); } diff --git a/src/parse/import.rs b/src/parse/import.rs index dbcfcb6..ce6d918 100644 --- a/src/parse/import.rs +++ b/src/parse/import.rs @@ -111,6 +111,10 @@ impl<'a> Parser<'a> { } pub(super) fn import(&mut self) -> SassResult> { + if self.flags.in_function() { + return Err(("This at-rule is not allowed here.", self.span_before).into()); + } + self.whitespace(); match self.toks.peek() { diff --git a/src/parse/keyframes.rs b/src/parse/keyframes.rs index 0e6e1fe..c02092f 100644 --- a/src/parse/keyframes.rs +++ b/src/parse/keyframes.rs @@ -185,6 +185,10 @@ impl<'a> Parser<'a> { } pub(super) fn parse_keyframes(&mut self, rule: String) -> SassResult { + if self.flags.in_function() { + return Err(("This at-rule is not allowed here.", self.span_before).into()); + } + let name = self.parse_keyframes_name()?; self.whitespace(); diff --git a/src/parse/mixin.rs b/src/parse/mixin.rs index db4a5a1..7b55003 100644 --- a/src/parse/mixin.rs +++ b/src/parse/mixin.rs @@ -66,6 +66,10 @@ impl<'a> Parser<'a> { } pub(super) fn parse_include(&mut self) -> SassResult> { + if self.flags.in_function() { + return Err(("This at-rule is not allowed here.", self.span_before).into()); + } + self.whitespace_or_comment(); let name = self.parse_identifier()?.map_node(Into::into); diff --git a/src/parse/mod.rs b/src/parse/mod.rs index 06f4dc3..0fd3eb5 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -131,6 +131,14 @@ impl<'a> Parser<'a> { } } AtRuleKind::AtRoot => { + if self.flags.in_function() { + return Err(( + "This at-rule is not allowed here.", + kind_string.span, + ) + .into()); + } + if self.at_root { stmts.append(&mut self.parse_at_root()?); } else { @@ -186,6 +194,14 @@ impl<'a> Parser<'a> { AtRuleKind::For => stmts.append(&mut self.parse_for()?), AtRuleKind::While => stmts.append(&mut self.parse_while()?), AtRuleKind::Charset => { + if self.flags.in_function() { + return Err(( + "This at-rule is not allowed here.", + kind_string.span, + ) + .into()); + } + read_until_semicolon_or_closing_curly_brace(self.toks)?; if let Some(Token { kind: ';', .. }) = self.toks.peek() { self.toks.next(); @@ -532,6 +548,10 @@ impl<'a> Parser<'a> { impl<'a> Parser<'a> { fn parse_unknown_at_rule(&mut self, name: String) -> SassResult { + if self.flags.in_function() { + return Err(("This at-rule is not allowed here.", self.span_before).into()); + } + let mut params = String::new(); self.whitespace(); if let Some(Token { kind: ';', .. }) | None = self.toks.peek() { @@ -595,6 +615,10 @@ impl<'a> Parser<'a> { } fn parse_media(&mut self) -> SassResult { + if self.flags.in_function() { + return Err(("This at-rule is not allowed here.", self.span_before).into()); + } + let query = self.parse_media_query_list()?; self.whitespace(); @@ -690,6 +714,9 @@ impl<'a> Parser<'a> { } fn parse_extend(&mut self) -> SassResult<()> { + if self.flags.in_function() { + return Err(("This at-rule is not allowed here.", self.span_before).into()); + } // todo: track when inside ruleset or `@content` // if !self.in_style_rule && !self.in_mixin && !self.in_content_block { // return Err(("@extend may only be used within style rules.", self.span_before).into()); @@ -757,6 +784,10 @@ impl<'a> Parser<'a> { } fn parse_supports(&mut self) -> SassResult { + if self.flags.in_function() { + return Err(("This at-rule is not allowed here.", self.span_before).into()); + } + let params = self.parse_media_args()?; if params.is_empty() { diff --git a/tests/functions.rs b/tests/functions.rs index 4b569a0..007dc25 100644 --- a/tests/functions.rs +++ b/tests/functions.rs @@ -195,3 +195,113 @@ test!( }", "a {\n color: foo;\n color: bar;\n}\n" ); +error!( + disallows_unknown_at_rule, + "@function foo() { + @foo; + } + + a { + color: foo(); + }", + "Error: This at-rule is not allowed here." +); +error!( + disallows_media_query, + "@function foo() { + @media screen {}; + } + + a { + color: foo(); + }", + "Error: This at-rule is not allowed here." +); +error!( + disallows_at_root, + "@function foo() { + @at-root {}; + } + + a { + color: foo(); + }", + "Error: This at-rule is not allowed here." +); +error!( + disallows_charset, + "@function foo() { + @charset 'utf-8'; + } + + a { + color: foo(); + }", + "Error: This at-rule is not allowed here." +); +error!( + disallows_extend, + "@function foo() { + @extend a; + } + + a { + color: foo(); + }", + "Error: This at-rule is not allowed here." +); +error!( + disallows_keyframes, + "@function foo() { + @keyframes foo {} + } + + a { + color: foo(); + }", + "Error: This at-rule is not allowed here." +); +error!( + disallows_supports, + "@function foo() { + @supports foo {} + } + + a { + color: foo(); + }", + "Error: This at-rule is not allowed here." +); +error!( + disallows_import, + "@function foo() { + @import \"foo.css\"; + } + + a { + color: foo(); + }", + "Error: This at-rule is not allowed here." +); +error!( + disallows_inner_function_declaration, + "@function foo() { + @function bar() {} + } + + a { + color: foo(); + }", + "Error: This at-rule is not allowed here." +); +error!( + disallows_include, + "@function foo() { + @include bar; + } + + a { + color: foo(); + }", + "Error: This at-rule is not allowed here." +); From 622d44ac635fba6e8439e228e45786145a426d03 Mon Sep 17 00:00:00 2001 From: Connor Skees Date: Mon, 3 Aug 2020 01:18:00 -0400 Subject: [PATCH 03/11] disallow selectors and styles in functions --- src/parse/mod.rs | 7 +++++++ tests/functions.rs | 13 +++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/parse/mod.rs b/src/parse/mod.rs index 0fd3eb5..c8793bb 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -245,6 +245,13 @@ impl<'a> Parser<'a> { // dart-sass seems to special-case the error message here? '!' | '{' => return Err(("expected \"}\".", *pos).into()), _ => { + if self.flags.in_function() { + return Err(( + "Functions can only contain variable declarations and control directives.", + self.span_before + ) + .into()); + } if self.flags.in_keyframes() { match self.is_selector_or_style()? { SelectorOrStyle::Style(property, value) => { diff --git a/tests/functions.rs b/tests/functions.rs index 007dc25..973dbe0 100644 --- a/tests/functions.rs +++ b/tests/functions.rs @@ -305,3 +305,16 @@ error!( }", "Error: This at-rule is not allowed here." ); +error!( + disallows_selectors, + "@function foo($a) { + functiona { + @return $a; + } + } + + a { + color: foo(nul); + }", + "Error: Functions can only contain variable declarations and control directives." +); From 55bcd1d1ddbb141751480693663845eecb202f85 Mon Sep 17 00:00:00 2001 From: Connor Skees Date: Tue, 4 Aug 2020 01:35:49 -0400 Subject: [PATCH 04/11] resolve panic from malformed filter argument --- src/parse/args.rs | 4 +++- tests/args.rs | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/parse/args.rs b/src/parse/args.rs index 8de7c39..d8875d2 100644 --- a/src/parse/args.rs +++ b/src/parse/args.rs @@ -341,7 +341,9 @@ impl<'a> Parser<'a> { return Err(("expected \")\".", pos).into()); } } - Some(..) => unreachable!(), + Some(Token { pos, .. }) => { + return Err(("expected \")\".", *pos).into()); + } None => return Err(("expected \")\".", span).into()), } } diff --git a/tests/args.rs b/tests/args.rs index e06da77..adde390 100644 --- a/tests/args.rs +++ b/tests/args.rs @@ -172,6 +172,10 @@ error!( unclosed_paren_in_nested_args, "a { color: a(b(red); }", "Error: expected \")\"." ); +error!( + filter_rhs_missing_closing_paren, + "a { color: lighten(red=(green); }", "Error: expected \")\"." +); test!( space_after_loud_comment, "@mixin foo($x) { From a79c62c2fa909dcc03150affeaec51a7215848e6 Mon Sep 17 00:00:00 2001 From: Connor Skees Date: Tue, 4 Aug 2020 02:05:59 -0400 Subject: [PATCH 05/11] allow escaped `!` in selectors --- src/parse/mod.rs | 6 ++++++ src/utils/peek_until.rs | 3 ++- tests/error.rs | 1 + tests/selectors.rs | 5 +++++ 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/parse/mod.rs b/src/parse/mod.rs index c8793bb..81a3422 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -364,6 +364,12 @@ impl<'a> Parser<'a> { found_curly = true; break; } + '\\' => { + string.push('\\'); + if let Some(Token { kind, .. }) = self.toks.next() { + string.push(kind); + } + } '!' => { if peek_ident_no_interpolation(self.toks, false, self.span_before)?.node == "optional" diff --git a/src/utils/peek_until.rs b/src/utils/peek_until.rs index e81ffa3..69de6dc 100644 --- a/src/utils/peek_until.rs +++ b/src/utils/peek_until.rs @@ -133,7 +133,8 @@ pub(crate) fn peek_escape(toks: &mut PeekMoreIterator>) -> SassR toks.peek_forward(1); } } else { - value = toks.peek_forward(1).unwrap().kind as u32; + value = first.kind as u32; + toks.advance_cursor(); } let c = std::char::from_u32(value).ok_or(("Invalid escape sequence.", span))?; diff --git a/tests/error.rs b/tests/error.rs index 7b9a359..ffa3fc1 100644 --- a/tests/error.rs +++ b/tests/error.rs @@ -245,3 +245,4 @@ error!( "a {foo: {bar: red", "Error: Expected identifier." ); error!(toplevel_nullbyte, "\u{0}", "Error: expected selector."); +error!(double_escaped_bang_at_toplevel, "\\!\\!", "Error: expected \"{\"."); diff --git a/tests/selectors.rs b/tests/selectors.rs index 7b415fd..64fb23d 100644 --- a/tests/selectors.rs +++ b/tests/selectors.rs @@ -350,6 +350,11 @@ test!( "ul li#foo {\n foo: bar;\n}\n" ); test!(escaped_space, "a\\ b {\n color: foo;\n}\n"); +test!( + escaped_bang, + "\\! {\n color: red;\n}\n", + "\\! {\n color: red;\n}\n" +); test!( multiple_consecutive_immediate_child, "> > foo {\n color: foo;\n}\n" From 9c2d1200f797dd942064484a48ab2e0d22d7cb50 Mon Sep 17 00:00:00 2001 From: Connor Skees Date: Tue, 4 Aug 2020 02:13:15 -0400 Subject: [PATCH 06/11] allow multiline comments in functions --- src/parse/mod.rs | 6 +++++- tests/functions.rs | 12 ++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/parse/mod.rs b/src/parse/mod.rs index 81a3422..de5d5ee 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -232,7 +232,11 @@ impl<'a> Parser<'a> { self.whitespace(); match comment.node { Comment::Silent => continue, - Comment::Loud(s) => stmts.push(Stmt::Comment(s)), + Comment::Loud(s) => { + if !self.flags.in_function() { + stmts.push(Stmt::Comment(s)); + } + } } } '\u{0}'..='\u{8}' | '\u{b}'..='\u{1f}' => { diff --git a/tests/functions.rs b/tests/functions.rs index 973dbe0..333d4a1 100644 --- a/tests/functions.rs +++ b/tests/functions.rs @@ -318,3 +318,15 @@ error!( }", "Error: Functions can only contain variable declarations and control directives." ); +test!( + allows_multiline_comment, + "@function foo($a) { + /* foo */ + @return $a; + } + + a { + color: foo(nul); + }", + "a {\n color: nul;\n}\n" +); From 5c8e88d16b22b48267d841beada282f91dd45e4a Mon Sep 17 00:00:00 2001 From: Connor Skees Date: Tue, 4 Aug 2020 02:18:48 -0400 Subject: [PATCH 07/11] remove panic on malformed bracketed list --- src/utils/read_until.rs | 2 +- tests/error.rs | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/utils/read_until.rs b/src/utils/read_until.rs index e1dac0f..5eb4505 100644 --- a/src/utils/read_until.rs +++ b/src/utils/read_until.rs @@ -259,7 +259,7 @@ pub(crate) fn read_until_closing_square_brace( continue; } '\\' => { - t.push(toks.next().unwrap()); + t.push(tok); t.push(match toks.next() { Some(tok) => tok, None => continue, diff --git a/tests/error.rs b/tests/error.rs index ffa3fc1..997d9c2 100644 --- a/tests/error.rs +++ b/tests/error.rs @@ -245,4 +245,11 @@ error!( "a {foo: {bar: red", "Error: Expected identifier." ); error!(toplevel_nullbyte, "\u{0}", "Error: expected selector."); -error!(double_escaped_bang_at_toplevel, "\\!\\!", "Error: expected \"{\"."); +error!( + double_escaped_bang_at_toplevel, + "\\!\\!", "Error: expected \"{\"." +); +error!( + nothing_after_escape_inside_brackets, + "a { color: [\\", "Error: expected \"]\"." +); From b2e727068167f99907f9b2f50216fde4ac4edb2c Mon Sep 17 00:00:00 2001 From: Connor Skees Date: Tue, 4 Aug 2020 23:18:16 -0400 Subject: [PATCH 08/11] resolve panic when extending certain psuedo selectors containing combinators without rhs selector --- src/selector/extend/functions.rs | 8 +++++++- tests/extend.rs | 8 ++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/selector/extend/functions.rs b/src/selector/extend/functions.rs index ccd1383..548173a 100644 --- a/src/selector/extend/functions.rs +++ b/src/selector/extend/functions.rs @@ -186,7 +186,13 @@ fn weave_parents( for group in lcs { choices.push( chunks(&mut groups_one, &mut groups_two, |sequence| { - complex_is_parent_superselector(sequence.get(0).unwrap().clone(), group.clone()) + complex_is_parent_superselector( + match sequence.get(0) { + Some(v) => v.clone(), + None => return true, + }, + group.clone(), + ) }) .into_iter() .map(|chunk| chunk.into_iter().flatten().collect()) diff --git a/tests/extend.rs b/tests/extend.rs index 2f6c52d..47d0ab1 100644 --- a/tests/extend.rs +++ b/tests/extend.rs @@ -1874,6 +1874,14 @@ test!( }", "foo, a:current(foo),\n:current(foo) {\n color: black;\n}\n" ); +test!( + extend_pseudo_selector_class_containing_combinator_without_rhs_selector, + ":has(a >) b { + @extend b; + color: red; + }", + ":has(a >) b, :has(a >) :has(a >) :has(a >) b, :has(a >) :has(a >) :has(a >) b {\n color: red;\n}\n" +); // todo: extend_loop (massive test) // todo: extend tests in folders From df1456f9b1f664562fb1622134c45968bba89037 Mon Sep 17 00:00:00 2001 From: Connor Skees Date: Wed, 5 Aug 2020 03:03:58 -0400 Subject: [PATCH 09/11] use new predicate parsing for bracketed lists --- src/parse/value/parse.rs | 70 +++++++++++++++++----------------------- src/utils/read_until.rs | 36 --------------------- tests/error.rs | 2 +- 3 files changed, 30 insertions(+), 78 deletions(-) diff --git a/src/parse/value/parse.rs b/src/parse/value/parse.rs index 094573a..29ee79c 100644 --- a/src/parse/value/parse.rs +++ b/src/parse/value/parse.rs @@ -15,8 +15,7 @@ use crate::{ error::SassResult, unit::Unit, utils::{ - devour_whitespace, eat_whole_number, read_until_closing_paren, - read_until_closing_square_brace, IsWhitespace, ParsedNumber, + devour_whitespace, eat_whole_number, read_until_closing_paren, IsWhitespace, ParsedNumber, }, value::{Number, SassFunction, SassMap, Value}, Token, @@ -30,7 +29,6 @@ use super::super::Parser; enum IntermediateValue { Value(HigherIntermediateValue), Op(Op), - Bracketed(Vec), Paren(Vec), Comma, Whitespace, @@ -127,22 +125,6 @@ impl<'a> Parser<'a> { ); } } - IntermediateValue::Bracketed(t) => { - last_was_whitespace = false; - space_separated.push( - HigherIntermediateValue::Literal( - match iter.parser.parse_value_from_vec(t, in_paren)?.node { - Value::List(v, sep, Brackets::None) => { - Value::List(v, sep, Brackets::Bracketed) - } - v => { - Value::List(vec![v], ListSeparator::Space, Brackets::Bracketed) - } - }, - ) - .span(val.span), - ) - } IntermediateValue::Paren(t) => { last_was_whitespace = false; space_separated.push(iter.parse_paren(Spanned { @@ -608,28 +590,42 @@ impl<'a> Parser<'a> { .span(span_start.merge(span)) } '[' => { - let mut span = self.toks.next().unwrap().pos(); + let mut span = self.span_before; + self.toks.next(); self.whitespace_or_comment(); - let mut inner = match read_until_closing_square_brace(self.toks) { - Ok(v) => v, - Err(e) => return Some(Err(e)), - }; - if let Some(last_tok) = inner.pop() { - if last_tok.kind != ']' { - return Some(Err(("expected \"]\".", span).into())); - } - span = span.merge(last_tok.pos()); - } - if inner.is_empty() { + + if let Some(Token { kind: ']', pos }) = self.toks.peek() { + span = span.merge(*pos); + self.toks.next(); IntermediateValue::Value(HigherIntermediateValue::Literal(Value::List( Vec::new(), ListSeparator::Space, Brackets::Bracketed, ))) + .span(span) } else { - IntermediateValue::Bracketed(inner) + // 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: ']', .. })) + }) { + Ok(v) => v, + Err(e) => return Some(Err(e)), + }; + + span = span.merge(inner.span); + + if !matches!(self.toks.next(), Some(Token { kind: ']', .. })) { + return Some(Err(("expected \"]\".", span).into())); + } + + IntermediateValue::Value(HigherIntermediateValue::Literal(match inner.node { + Value::List(els, sep, Brackets::None) => { + Value::List(els, sep, Brackets::Bracketed) + } + v => Value::List(vec![v], ListSeparator::Space, Brackets::Bracketed), + })) + .span(span) } - .span(span) } '$' => { self.toks.next(); @@ -1131,14 +1127,6 @@ impl<'a, 'b: 'a> IntermediateValueIterator<'a, 'b> { IntermediateValue::Comma => { return Err(("Expected expression.", self.parser.span_before).into()) } - IntermediateValue::Bracketed(t) => { - let v = self.parser.parse_value_from_vec(t, in_paren)?; - HigherIntermediateValue::Literal(match v.node { - Value::List(v, sep, Brackets::None) => Value::List(v, sep, Brackets::Bracketed), - v => Value::List(vec![v], ListSeparator::Space, Brackets::Bracketed), - }) - .span(v.span) - } IntermediateValue::Paren(t) => { let val = self.parse_paren(Spanned { node: t, diff --git a/src/utils/read_until.rs b/src/utils/read_until.rs index 5eb4505..8cbf193 100644 --- a/src/utils/read_until.rs +++ b/src/utils/read_until.rs @@ -235,39 +235,3 @@ pub(crate) fn read_until_closing_paren( } Ok(t) } - -pub(crate) fn read_until_closing_square_brace( - toks: &mut PeekMoreIterator>, -) -> SassResult> { - let mut t = Vec::new(); - let mut scope = 0; - while let Some(tok) = toks.next() { - // TODO: comments - match tok.kind { - ']' => { - if scope < 1 { - t.push(tok); - return Ok(t); - } else { - scope -= 1; - } - } - '[' => scope += 1, - '"' | '\'' => { - t.push(tok); - t.extend(read_until_closing_quote(toks, tok.kind)?); - continue; - } - '\\' => { - t.push(tok); - t.push(match toks.next() { - Some(tok) => tok, - None => continue, - }); - } - _ => {} - } - t.push(tok) - } - Ok(t) -} diff --git a/tests/error.rs b/tests/error.rs index 997d9c2..ce0f151 100644 --- a/tests/error.rs +++ b/tests/error.rs @@ -251,5 +251,5 @@ error!( ); error!( nothing_after_escape_inside_brackets, - "a { color: [\\", "Error: expected \"]\"." + "a { color: [\\", "Error: Expected expression." ); From 61ef52eb3f4b777e8b644bb2961e544aeae84c2b Mon Sep 17 00:00:00 2001 From: Connor Skees Date: Wed, 5 Aug 2020 03:09:10 -0400 Subject: [PATCH 10/11] replace `.get(0)` with `.first()` --- src/builtin/selector.rs | 2 +- src/output.rs | 10 +++++----- src/parse/value/parse.rs | 2 +- src/selector/parse.rs | 2 +- src/selector/simple.rs | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/builtin/selector.rs b/src/builtin/selector.rs index 4015796..dae2d00 100644 --- a/src/builtin/selector.rs +++ b/src/builtin/selector.rs @@ -33,7 +33,7 @@ fn simple_selectors(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult vals.extend(self.parse_stmt(rule)?), - Stmt::Style(s) => vals.get_mut(0).unwrap().push_style(s), - Stmt::Comment(s) => vals.get_mut(0).unwrap().push_comment(s), + Stmt::Style(s) => vals.first_mut().unwrap().push_style(s), + Stmt::Comment(s) => vals.first_mut().unwrap().push_comment(s), Stmt::Media(m) => { let MediaRule { query, body, .. } = *m; vals.push(Toplevel::Media { query, body }) @@ -167,7 +167,7 @@ impl Css { k @ Stmt::KeyframesRuleSet(..) => { unreachable!("@keyframes ruleset {:?}", k) } - Stmt::Import(s) => vals.get_mut(0).unwrap().push_import(s), + Stmt::Import(s) => vals.first_mut().unwrap().push_import(s), }; } vals @@ -204,7 +204,7 @@ impl Css { let mut vals = vec![Toplevel::new_keyframes_rule(selector)]; for rule in body { match rule { - Stmt::Style(s) => vals.get_mut(0).unwrap().push_style(s), + Stmt::Style(s) => vals.first_mut().unwrap().push_style(s), Stmt::KeyframesRuleSet(..) => vals.extend(self.parse_stmt(rule)?), _ => todo!(), } @@ -221,7 +221,7 @@ impl Css { // this is how we print newlines between unrelated styles // it could probably be refactored if !v.is_empty() { - if let Some(Toplevel::MultilineComment(..)) = v.get(0) { + if let Some(Toplevel::MultilineComment(..)) = v.first() { } else if is_first { is_first = false; } else { diff --git a/src/parse/value/parse.rs b/src/parse/value/parse.rs index 29ee79c..6a9dba1 100644 --- a/src/parse/value/parse.rs +++ b/src/parse/value/parse.rs @@ -105,7 +105,7 @@ impl<'a> Parser<'a> { comma_separated.push(space_separated.pop().unwrap()); } else { let mut span = space_separated - .get(0) + .first() .ok_or(("Expected expression.", val.span))? .span; comma_separated.push( diff --git a/src/selector/parse.rs b/src/selector/parse.rs index 9c52257..cc7c001 100644 --- a/src/selector/parse.rs +++ b/src/selector/parse.rs @@ -561,7 +561,7 @@ fn is_simple_selector_start(c: char) -> bool { /// with pseudo-class syntax (`:before`, `:after`, `:first-line`, or /// `:first-letter`) fn is_fake_pseudo_element(name: &str) -> bool { - match name.as_bytes().get(0) { + match name.as_bytes().first() { Some(b'a') | Some(b'A') => name.to_ascii_lowercase() == "after", Some(b'b') | Some(b'B') => name.to_ascii_lowercase() == "before", Some(b'f') | Some(b'F') => match name.to_ascii_lowercase().as_str() { diff --git a/src/selector/simple.rs b/src/selector/simple.rs index 82ae23a..fb1c6b5 100644 --- a/src/selector/simple.rs +++ b/src/selector/simple.rs @@ -364,7 +364,7 @@ impl SimpleSelector { }; complex .components - .get(0) + .first() .unwrap() .as_compound() .components From 8fabda63632f83fc72211acf2d0ca94801f2845f Mon Sep 17 00:00:00 2001 From: Connor Skees Date: Wed, 5 Aug 2020 03:22:54 -0400 Subject: [PATCH 11/11] use `back()` rather than indexing at `len - 1` --- src/parse/value/parse.rs | 2 +- src/selector/extend/functions.rs | 28 ++++++---------------------- 2 files changed, 7 insertions(+), 23 deletions(-) diff --git a/src/parse/value/parse.rs b/src/parse/value/parse.rs index 6a9dba1..3c66b6e 100644 --- a/src/parse/value/parse.rs +++ b/src/parse/value/parse.rs @@ -594,7 +594,7 @@ impl<'a> Parser<'a> { self.toks.next(); self.whitespace_or_comment(); - if let Some(Token { kind: ']', pos }) = self.toks.peek() { + if let Some(Token { kind: ']', pos }) = self.toks.peek() { span = span.merge(*pos); self.toks.next(); IntermediateValue::Value(HigherIntermediateValue::Literal(Value::List( diff --git a/src/selector/extend/functions.rs b/src/selector/extend/functions.rs index 548173a..1ee8d94 100644 --- a/src/selector/extend/functions.rs +++ b/src/selector/extend/functions.rs @@ -346,16 +346,8 @@ fn merge_final_combinators( ) -> Option>>> { let mut result = result.unwrap_or_default(); - if (components_one.is_empty() - || !components_one - .get(components_one.len() - 1) - .unwrap() - .is_combinator()) - && (components_two.is_empty() - || !components_two - .get(components_two.len() - 1) - .unwrap() - .is_combinator()) + if (components_one.is_empty() || !components_one.back().unwrap().is_combinator()) + && (components_two.is_empty() || !components_two.back().unwrap().is_combinator()) { return Some(Vec::from(result)); } @@ -539,12 +531,8 @@ fn merge_final_combinators( } (Some(combinator_one), None) => { if *combinator_one == Combinator::Child && !components_two.is_empty() { - if let Some(ComplexSelectorComponent::Compound(c1)) = - components_one.get(components_one.len() - 1) - { - if let Some(ComplexSelectorComponent::Compound(c2)) = - components_two.get(components_two.len() - 1) - { + if let Some(ComplexSelectorComponent::Compound(c1)) = components_one.back() { + if let Some(ComplexSelectorComponent::Compound(c2)) = components_two.back() { if c2.is_super_selector(c1, &None) { components_two.pop_back(); } @@ -561,12 +549,8 @@ fn merge_final_combinators( } (None, Some(combinator_two)) => { if *combinator_two == Combinator::Child && !components_one.is_empty() { - if let Some(ComplexSelectorComponent::Compound(c1)) = - components_one.get(components_one.len() - 1) - { - if let Some(ComplexSelectorComponent::Compound(c2)) = - components_two.get(components_two.len() - 1) - { + if let Some(ComplexSelectorComponent::Compound(c1)) = components_one.back() { + if let Some(ComplexSelectorComponent::Compound(c2)) = components_two.back() { if c1.is_super_selector(c2, &None) { components_one.pop_back(); }