From c75cf718f23fdc0c0de88f58af2c69d5bc373012 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Mon, 24 Aug 2026 23:54:07 +0200 Subject: [PATCH] parser: Remove ParserInput. This avoids unnecessary indirection during parsing. We only create nested parsers in two places, and it seems easy to avoid. --- color/lib.rs | 22 ++-- color/tests.rs | 11 +- fuzz/Cargo.lock | 167 ++++++++--------------- fuzz/fuzz_targets/cssparser.rs | 12 +- src/lib.rs | 2 +- src/nth.rs | 5 +- src/parser.rs | 233 ++++++++++++++------------------- src/rules_and_declarations.rs | 38 +++--- src/size_of_tests.rs | 3 +- src/tests.rs | 149 ++++++++------------- 10 files changed, 252 insertions(+), 390 deletions(-) diff --git a/color/lib.rs b/color/lib.rs index bc59daff..d05426cc 100644 --- a/color/lib.rs +++ b/color/lib.rs @@ -44,7 +44,7 @@ where /// value on success. pub fn parse_color_with<'i, P>( color_parser: &P, - input: &mut Parser<'i, '_>, + input: &mut Parser<'i>, ) -> Result> where P: ColorParser<'i>, @@ -112,7 +112,7 @@ where /// Parse the alpha component by itself from either number or percentage, /// clipping the result to [0.0..1.0]. #[inline] -fn parse_alpha_component<'i, 't, P>( +fn parse_alpha_component<'i, P>( color_parser: &P, arguments: &mut Parser, ) -> Result> @@ -125,7 +125,7 @@ where .clamp(0.0, OPAQUE)) } -fn parse_legacy_alpha<'i, 't, P>( +fn parse_legacy_alpha<'i, P>( color_parser: &P, arguments: &mut Parser, ) -> Result> @@ -140,7 +140,7 @@ where }) } -fn parse_modern_alpha<'i, 't, P>( +fn parse_modern_alpha<'i, P>( color_parser: &P, arguments: &mut Parser, ) -> Result, ParseError> @@ -156,7 +156,7 @@ where } #[inline] -fn parse_rgb<'i, 't, P>( +fn parse_rgb<'i, P>( color_parser: &P, arguments: &mut Parser, ) -> Result> @@ -222,7 +222,7 @@ where /// /// #[inline] -fn parse_hsl<'i, 't, P>( +fn parse_hsl<'i, P>( color_parser: &P, arguments: &mut Parser, ) -> Result> @@ -261,7 +261,7 @@ where /// /// #[inline] -fn parse_hwb<'i, 't, P>( +fn parse_hwb<'i, P>( color_parser: &P, arguments: &mut Parser, ) -> Result> @@ -340,7 +340,7 @@ type IntoColorFn = fn(l: Option, a: Option, b: Option, alpha: Option) -> Output; #[inline] -fn parse_lab_like<'i, 't, P>( +fn parse_lab_like<'i, P>( color_parser: &P, arguments: &mut Parser, lightness_range: f32, @@ -366,7 +366,7 @@ where } #[inline] -fn parse_lch_like<'i, 't, P>( +fn parse_lch_like<'i, P>( color_parser: &P, arguments: &mut Parser, lightness_range: f32, @@ -393,7 +393,7 @@ where /// Parse the color() function. #[inline] -fn parse_color_with_color_space<'i, 't, P>( +fn parse_color_with_color_space<'i, P>( color_parser: &P, arguments: &mut Parser, ) -> Result> @@ -427,7 +427,7 @@ type ComponentParseResult = Result<(Option, Option, Option, Option), ParseError>; /// Parse the color components and alpha with the modern [color-4] syntax. -pub fn parse_components<'i, 't, P, F1, F2, F3, R1, R2, R3>( +pub fn parse_components<'i, P, F1, F2, F3, R1, R2, R3>( color_parser: &P, input: &mut Parser, f1: F1, diff --git a/color/tests.rs b/color/tests.rs index 98db40a3..7d609b00 100644 --- a/color/tests.rs +++ b/color/tests.rs @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use super::*; -use cssparser::ParserInput; use serde_json::{json, Value}; fn almost_equals(a: &Value, b: &Value) -> bool { @@ -60,8 +59,7 @@ fn run_raw_json_tests(json_data: &str, run: F) { fn run_json_tests Value>(json_data: &str, parse: F) { run_raw_json_tests(json_data, |input, expected| match input { Value::String(input) => { - let mut parse_input = ParserInput::new(&input); - let result = parse(&mut Parser::new(&mut parse_input)); + let result = parse(&mut Parser::new(&input)); assert_json_eq(result, expected, &input); } _ => panic!("Unexpected JSON"), @@ -149,9 +147,7 @@ fn color4_color_function() { macro_rules! parse_single_color { ($i:expr) => {{ - let input = $i; - let mut input = ParserInput::new(input); - let mut input = Parser::new(&mut input); + let mut input = Parser::new($i); Color::parse(&mut input).map_err(Into::>::into) }}; } @@ -355,8 +351,7 @@ fn generic_parser() { ]; for (input, expected) in TESTS { - let mut input = ParserInput::new(input); - let mut input = Parser::new(&mut input); + let mut input = Parser::new(input); let actual: OutputType = parse_color_with(&TestColorParser, &mut input).unwrap(); assert_eq!(actual, *expected); diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock index da45b9a2..656d7a45 100644 --- a/fuzz/Cargo.lock +++ b/fuzz/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "arbitrary" @@ -14,25 +14,15 @@ version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - [[package]] name = "cssparser" -version = "0.28.1" +version = "0.38.0" dependencies = [ "cssparser-macros", "dtoa-short", "itoa", - "matches", "phf", - "proc-macro2", - "quote", "smallvec", - "syn", ] [[package]] @@ -45,10 +35,10 @@ dependencies = [ [[package]] name = "cssparser-macros" -version = "0.6.0" +version = "0.7.0" dependencies = [ "quote", - "syn", + "syn 3.0.4", ] [[package]] @@ -67,27 +57,16 @@ dependencies = [ ] [[package]] -name = "getrandom" -version = "0.1.16" +name = "fastrand" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" [[package]] name = "itoa" -version = "0.4.7" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" - -[[package]] -name = "libc" -version = "0.2.88" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b07a082330a35e43f63177cc01689da34fbffa0105e1246cf0311472cac73a" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "libfuzzer-sys" @@ -99,142 +78,101 @@ dependencies = [ "cc", ] -[[package]] -name = "matches" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" - [[package]] name = "phf" -version = "0.8.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" +checksum = "010378780309880b08997fae13be7834dba947d36393bd372f2b1556deb2a2f6" dependencies = [ "phf_macros", "phf_shared", - "proc-macro-hack", + "serde", ] [[package]] name = "phf_generator" -version = "0.8.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" +checksum = "aeb62e0959d5a1bebc965f4d15d9e2b7cea002b6b0f5ba8cde6cc26738467100" dependencies = [ + "fastrand", "phf_shared", - "rand", ] [[package]] name = "phf_macros" -version = "0.8.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c" +checksum = "5fa8d0ca26d424d27630da600c6624696e7dec8bf7b3b492b383c5dc49e5e085" dependencies = [ "phf_generator", "phf_shared", - "proc-macro-hack", "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] name = "phf_shared" -version = "0.8.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" +checksum = "c6fd9027e2d9319be6349febd1db4e8d02aa544921200c9b777720ac34a3aa89" dependencies = [ "siphasher", ] -[[package]] -name = "ppv-lite86" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" - -[[package]] -name = "proc-macro-hack" -version = "0.5.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" - [[package]] name = "proc-macro2" -version = "1.0.24" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] name = "quote" -version = "1.0.9" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" dependencies = [ "proc-macro2", ] [[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom", - "libc", - "rand_chacha", - "rand_core", - "rand_hc", - "rand_pcg", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.5.1" +name = "serde" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" dependencies = [ - "getrandom", + "serde_core", ] [[package]] -name = "rand_hc" -version = "0.2.0" +name = "serde_core" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" dependencies = [ - "rand_core", + "serde_derive", ] [[package]] -name = "rand_pcg" -version = "0.2.1" +name = "serde_derive" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ - "rand_core", + "proc-macro2", + "quote", + "syn 3.0.4", ] [[package]] name = "siphasher" -version = "0.3.3" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa8f3741c7372e75519bd9346068370c9cdaabcc1f9599cbcf2a2719352286b7" +checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" [[package]] name = "smallvec" @@ -244,23 +182,28 @@ checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" [[package]] name = "syn" -version = "1.0.63" +version = "2.0.119" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd9bc7ccc2688b3344c2f48b9b546648b25ce0b20fc717ee7fa7981a8ca9717" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", ] [[package]] -name = "unicode-xid" -version = "0.2.1" +name = "syn" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +checksum = "e6275cddf4610d1775e6d1fe9469b2e77d0f39fd98fb7450901b821e0c53649f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] [[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" +name = "unicode-ident" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" diff --git a/fuzz/fuzz_targets/cssparser.rs b/fuzz/fuzz_targets/cssparser.rs index a9d89388..6740cbdd 100644 --- a/fuzz/fuzz_targets/cssparser.rs +++ b/fuzz/fuzz_targets/cssparser.rs @@ -5,13 +5,12 @@ use cssparser::*; const DEBUG: bool = false; fn parse_and_serialize(input: &str, preserving_comments: bool) -> String { - let mut input = ParserInput::new(input); - let mut parser = Parser::new(&mut input); + let mut parser = Parser::new(input); let mut serialization = String::new(); let result = do_parse_and_serialize( &mut parser, preserving_comments, - TokenSerializationType::nothing(), + TokenSerializationType::Nothing, &mut serialization, 0, ); @@ -21,13 +20,13 @@ fn parse_and_serialize(input: &str, preserving_comments: bool) -> String { serialization } -fn do_parse_and_serialize<'i>( +fn do_parse_and_serialize( input: &mut Parser, preserving_comments: bool, mut previous_token_type: TokenSerializationType, serialization: &mut String, indent_level: usize, -) -> Result<(), ParseError<'i, ()>> { +) -> Result<(), ParseError<()>> { loop { let token = if preserving_comments { input.next_including_whitespace_and_comments() @@ -45,8 +44,7 @@ fn do_parse_and_serialize<'i>( println!("{:?}", token); } if token.is_parse_error() { - let token = token.clone(); - return Err(input.new_unexpected_token_error(token)); + return Err(ParseError::unexpected_token()); } let token_type = token.serialization_type(); if previous_token_type.needs_separator_when_before(token_type) { diff --git a/src/lib.rs b/src/lib.rs index 0f48c1f9..94c7cc7e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -73,7 +73,7 @@ pub use crate::from_bytes::{stylesheet_encoding, EncodingSupport}; pub use crate::macros::_cssparser_internal_to_lowercase; pub use crate::nth::parse_nth; pub use crate::parser::{BasicParseError, BasicParseErrorKind, ParseError, ParseErrorKind}; -pub use crate::parser::{Delimiter, Delimiters, Parser, ParserInput, ParserState}; +pub use crate::parser::{Delimiter, Delimiters, Parser, ParserState}; pub use crate::rules_and_declarations::{parse_important, parse_one_declaration}; pub use crate::rules_and_declarations::{parse_one_rule, StyleSheetParser}; pub use crate::rules_and_declarations::{AtRuleParser, QualifiedRuleParser}; diff --git a/src/nth.rs b/src/nth.rs index 69f06f77..40affc40 100644 --- a/src/nth.rs +++ b/src/nth.rs @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use super::{BasicParseError, Parser, ParserInput, Token}; +use super::{BasicParseError, Parser, Token}; /// Parse the *An+B* notation, as found in the `:nth-child()` selector. /// The input is typically the arguments of a function, @@ -117,8 +117,7 @@ fn parse_n_dash_digits(string: &str) -> Result { } fn parse_number_saturate(string: &str) -> Result { - let mut input = ParserInput::new(string); - let mut parser = Parser::new(&mut input); + let mut parser = Parser::new(string); let int = if let Ok(&Token::Number { int_value: Some(int), .. diff --git a/src/parser.rs b/src/parser.rs index 1466ac7b..67c01bf7 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -220,12 +220,17 @@ impl fmt::Display for ParseError { impl std::error::Error for ParseError {} -/// The owned input for a parser. -pub struct ParserInput<'i> { +/// A CSS parser that borrows its `&str` input, yields `Token`s, and keeps track of nested blocks +/// and functions. +pub struct Parser<'i> { tokenizer: Tokenizer<'i>, cached_token: Option>, current_block_depth: u8, nested_block_limit: u8, + /// If `Some(_)`, .parse_nested_block() can be called. + at_start_of: Option, + /// For parsers from `parse_until` or `parse_nested_block` + stop_before: Delimiters, } struct CachedToken<'i> { @@ -234,44 +239,6 @@ struct CachedToken<'i> { end_state: ParserState, } -impl<'i> ParserInput<'i> { - /// 75 nested blocks seems reasonable enough. - const REASONABLE_NESTED_BLOCK_LIMIT: u8 = 75; - - /// Create a new input for a parser. - pub fn new(input: &'i str) -> ParserInput<'i> { - ParserInput { - tokenizer: Tokenizer::new(input), - nested_block_limit: Self::REASONABLE_NESTED_BLOCK_LIMIT, - current_block_depth: 0, - cached_token: None, - } - } - - /// Sets a limit for how many nested blocks we're allowed to parse. This is useful to avoid - /// running out of stack space. By default, it's set to `REASONABLE_NESTED_BLOCK_LIMIT`, but it - /// can be overridden or cleared. A limit of 0 will be equivalent to no limit at all. - pub fn set_nested_block_limit(&mut self, limit: u8) { - self.nested_block_limit = limit; - } - - #[inline] - fn cached_token_ref(&self) -> &Token<'i> { - &self.cached_token.as_ref().unwrap().token - } -} - -/// A CSS parser that borrows its `&str` input, -/// yields `Token`s, -/// and keeps track of nested blocks and functions. -pub struct Parser<'i, 't> { - input: &'t mut ParserInput<'i>, - /// If `Some(_)`, .parse_nested_block() can be called. - at_start_of: Option, - /// For parsers from `parse_until` or `parse_nested_block` - stop_before: Delimiters, -} - #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub(crate) enum BlockType { Parenthesis, @@ -391,20 +358,38 @@ macro_rules! expect { /// See https://drafts.csswg.org/css-values-5/#arbitrary-substitution pub type ArbitrarySubstitutionFunctions<'a> = &'a [&'static str]; -impl<'i: 't, 't> Parser<'i, 't> { - /// Create a new parser +impl<'i> Parser<'i> { + /// 75 nested blocks seems reasonable enough. + const REASONABLE_NESTED_BLOCK_LIMIT: u8 = 75; + + /// Create a new parser for the given input. #[inline] - pub fn new(input: &'t mut ParserInput<'i>) -> Parser<'i, 't> { - Parser { - input, + pub fn new(input: &'i str) -> Self { + Self { + tokenizer: Tokenizer::new(input), at_start_of: None, stop_before: Delimiter::None, + nested_block_limit: Self::REASONABLE_NESTED_BLOCK_LIMIT, + current_block_depth: 0, + cached_token: None, } } + /// Sets a limit for how many nested blocks we're allowed to parse. This is useful to avoid + /// running out of stack space. By default, it's set to `REASONABLE_NESTED_BLOCK_LIMIT`, but it + /// can be overridden or cleared. A limit of 0 will be equivalent to no limit at all. + pub fn set_nested_block_limit(&mut self, limit: u8) { + self.nested_block_limit = limit; + } + + #[inline] + fn cached_token_ref(&self) -> &Token<'i> { + &self.cached_token.as_ref().unwrap().token + } + /// Return the current line that is being parsed. pub fn current_line(&self) -> &'i str { - self.input.tokenizer.current_source_line() + self.tokenizer.current_source_line() } /// Check whether the input is exhausted. That is, if `.next()` would return a token. @@ -439,13 +424,13 @@ impl<'i: 't, 't> Parser<'i, 't> { /// This can be used with the `Parser::slice` and `slice_from` methods. #[inline] pub fn position(&self) -> SourcePosition { - self.input.tokenizer.position() + self.tokenizer.position() } /// The current line number and column number. #[inline] pub fn current_source_location(&self) -> SourceLocation { - self.input.tokenizer.current_source_location() + self.tokenizer.current_source_location() } /// The source map URL, if known. @@ -454,7 +439,7 @@ impl<'i: 't, 't> Parser<'i, 't> { /// comment. The last such comment is used, so this value may /// change as parsing proceeds. pub fn current_source_map_url(&self) -> Option<&str> { - self.input.tokenizer.current_source_map_url() + self.tokenizer.current_source_map_url() } /// The source URL, if known. @@ -463,7 +448,7 @@ impl<'i: 't, 't> Parser<'i, 't> { /// comment. The last such comment is used, so this value may /// change as parsing proceeds. pub fn current_source_url(&self) -> Option<&str> { - self.input.tokenizer.current_source_url() + self.tokenizer.current_source_url() } /// Create a new unexpected token or EOF ParseError at the current location @@ -482,7 +467,7 @@ impl<'i: 't, 't> Parser<'i, 't> { pub fn state(&self) -> ParserState { ParserState { at_start_of: self.at_start_of, - ..self.input.tokenizer.state() + ..self.tokenizer.state() } } @@ -490,24 +475,24 @@ impl<'i: 't, 't> Parser<'i, 't> { #[inline] pub fn skip_whitespace(&mut self) { if let Some(block_type) = self.at_start_of.take() { - consume_until_end_of_block(block_type, &mut self.input.tokenizer); + consume_until_end_of_block(block_type, &mut self.tokenizer); } - self.input.tokenizer.skip_whitespace() + self.tokenizer.skip_whitespace() } #[inline] pub(crate) fn skip_cdc_and_cdo(&mut self) { if let Some(block_type) = self.at_start_of.take() { - consume_until_end_of_block(block_type, &mut self.input.tokenizer); + consume_until_end_of_block(block_type, &mut self.tokenizer); } - self.input.tokenizer.skip_cdc_and_cdo() + self.tokenizer.skip_cdc_and_cdo() } #[inline] pub(crate) fn next_byte(&self) -> Option { - let byte = self.input.tokenizer.next_byte(); + let byte = self.tokenizer.next_byte(); if self.stop_before.contains(Delimiters::from_byte(byte)) { return None; } @@ -520,7 +505,7 @@ impl<'i: 't, 't> Parser<'i, 't> { /// Should only be used with `SourcePosition` values from the same `Parser` instance. #[inline] pub fn reset(&mut self, state: &ParserState) { - self.input.tokenizer.reset(state); + self.tokenizer.reset(state); self.at_start_of = state.at_start_of; } @@ -531,8 +516,7 @@ impl<'i: 't, 't> Parser<'i, 't> { &mut self, fns: ArbitrarySubstitutionFunctions<'i>, ) { - self.input - .tokenizer + self.tokenizer .look_for_arbitrary_substitution_functions(fns) } @@ -540,14 +524,14 @@ impl<'i: 't, 't> Parser<'i, 't> { /// `look_for_arbitrary_substitution_functions` was called, and stop looking. #[inline] pub fn seen_arbitrary_substitution_functions(&mut self) -> bool { - self.input.tokenizer.seen_arbitrary_substitution_functions() + self.tokenizer.seen_arbitrary_substitution_functions() } /// The old name of `try_parse`, which requires raw identifiers in the Rust 2018 edition. #[inline] pub fn r#try(&mut self, thing: F) -> Result where - F: FnOnce(&mut Parser<'i, 't>) -> Result, + F: FnOnce(&mut Parser<'i>) -> Result, { self.try_parse(thing) } @@ -559,7 +543,7 @@ impl<'i: 't, 't> Parser<'i, 't> { #[inline] pub fn try_parse(&mut self, thing: F) -> Result where - F: FnOnce(&mut Parser<'i, 't>) -> Result, + F: FnOnce(&mut Parser<'i>) -> Result, { let start = self.state(); let result = thing(self); @@ -572,13 +556,13 @@ impl<'i: 't, 't> Parser<'i, 't> { /// Return a slice of the CSS input #[inline] pub fn slice(&self, range: Range) -> &'i str { - self.input.tokenizer.slice(range) + self.tokenizer.slice(range) } /// Return a slice of the CSS input, from the given position to the current one. #[inline] pub fn slice_from(&self, start_position: SourcePosition) -> &'i str { - self.input.tokenizer.slice_from(start_position) + self.tokenizer.slice_from(start_position) } /// Return the next token in the input that is neither whitespace or a comment, @@ -607,7 +591,7 @@ impl<'i: 't, 't> Parser<'i, 't> { _ => break, } } - Ok(self.input.cached_token_ref()) + Ok(self.cached_token_ref()) } /// Same as `Parser::next`, but does not skip whitespace or comment tokens. @@ -620,37 +604,36 @@ impl<'i: 't, 't> Parser<'i, 't> { &mut self, ) -> Result<&Token<'i>, BasicParseError> { if let Some(block_type) = self.at_start_of.take() { - consume_until_end_of_block(block_type, &mut self.input.tokenizer); + consume_until_end_of_block(block_type, &mut self.tokenizer); } - let byte = self.input.tokenizer.next_byte(); + let byte = self.tokenizer.next_byte(); if self.stop_before.contains(Delimiters::from_byte(byte)) { return Err(BasicParseError::new(BasicParseErrorKind::EndOfInput)); } - let token_start_position = self.input.tokenizer.position(); + let token_start_position = self.tokenizer.position(); let using_cached_token = self - .input .cached_token .as_ref() .is_some_and(|cached_token| cached_token.start_position == token_start_position); let token = if using_cached_token { - let cached_token = self.input.cached_token.as_ref().unwrap(); - self.input.tokenizer.reset(&cached_token.end_state); + let cached_token = self.cached_token.as_ref().unwrap(); + self.tokenizer.reset(&cached_token.end_state); if let Token::Function(ref name) = cached_token.token { - self.input.tokenizer.see_function(name) + self.tokenizer.see_function(name) } &cached_token.token } else { - let Ok(new_token) = self.input.tokenizer.next() else { + let Ok(new_token) = self.tokenizer.next() else { return Err(BasicParseError::new(BasicParseErrorKind::EndOfInput)); }; - self.input.cached_token = Some(CachedToken { + self.cached_token = Some(CachedToken { token: new_token, start_position: token_start_position, - end_state: self.input.tokenizer.state(), + end_state: self.tokenizer.state(), }); - self.input.cached_token_ref() + &self.cached_token.as_ref().unwrap().token }; if let Some(block_type) = BlockType::opening(token) { @@ -666,7 +649,7 @@ impl<'i: 't, 't> Parser<'i, 't> { #[inline] pub fn parse_entirely(&mut self, parse: F) -> Result> where - F: FnOnce(&mut Parser<'i, 't>) -> Result>, + F: FnOnce(&mut Parser<'i>) -> Result>, { let result = parse(self)?; self.expect_exhausted()?; @@ -687,7 +670,7 @@ impl<'i: 't, 't> Parser<'i, 't> { #[inline] pub fn parse_comma_separated(&mut self, parse_one: F) -> Result, ParseError> where - F: for<'tt> FnMut(&mut Parser<'i, 'tt>) -> Result>, + F: FnMut(&mut Parser<'i>) -> Result>, { self.parse_comma_separated_internal(parse_one, /* ignore_errors = */ false) } @@ -700,7 +683,7 @@ impl<'i: 't, 't> Parser<'i, 't> { #[inline] pub fn parse_comma_separated_ignoring_errors(&mut self, parse_one: F) -> Vec where - F: for<'tt> FnMut(&mut Parser<'i, 'tt>) -> Result>, + F: FnMut(&mut Parser<'i>) -> Result>, { match self.parse_comma_separated_internal(parse_one, /* ignore_errors = */ true) { Ok(values) => values, @@ -715,7 +698,7 @@ impl<'i: 't, 't> Parser<'i, 't> { ignore_errors: bool, ) -> Result, ParseError> where - F: for<'tt> FnMut(&mut Parser<'i, 'tt>) -> Result>, + F: FnMut(&mut Parser<'i>) -> Result>, { // Vec grows from 0 to 4 by default on first push(). So allocate with // capacity 1, so in the somewhat common case of only one item we don't @@ -751,7 +734,7 @@ impl<'i: 't, 't> Parser<'i, 't> { #[inline] pub fn parse_nested_block(&mut self, parse: F) -> Result> where - F: for<'tt> FnOnce(&mut Parser<'i, 'tt>) -> Result>, + F: FnOnce(&mut Parser<'i>) -> Result>, { parse_nested_block(self, parse) } @@ -771,7 +754,7 @@ impl<'i: 't, 't> Parser<'i, 't> { parse: F, ) -> Result> where - F: for<'tt> FnOnce(&mut Parser<'i, 'tt>) -> Result>, + F: FnOnce(&mut Parser<'i>) -> Result>, { parse_until_before(self, delimiters, ParseUntilErrorBehavior::Consume, parse) } @@ -788,7 +771,7 @@ impl<'i: 't, 't> Parser<'i, 't> { parse: F, ) -> Result> where - F: for<'tt> FnOnce(&mut Parser<'i, 'tt>) -> Result>, + F: FnOnce(&mut Parser<'i>) -> Result>, { parse_until_after(self, delimiters, ParseUntilErrorBehavior::Consume, parse) } @@ -1009,40 +992,34 @@ impl<'i: 't, 't> Parser<'i, 't> { } } -pub fn parse_until_before<'i: 't, 't, F, T, E>( - parser: &mut Parser<'i, 't>, +pub fn parse_until_before<'i, F, T, E>( + parser: &mut Parser<'i>, delimiters: Delimiters, error_behavior: ParseUntilErrorBehavior, parse: F, ) -> Result> where - F: for<'tt> FnOnce(&mut Parser<'i, 'tt>) -> Result>, + F: FnOnce(&mut Parser<'i>) -> Result>, { + let old_stop_before = parser.stop_before; let delimiters = parser.stop_before | delimiters; - let result; - // Introduce a new scope to limit duration of nested_parser’s borrow - { - let mut delimited_parser = Parser { - input: parser.input, - at_start_of: parser.at_start_of.take(), - stop_before: delimiters, - }; - result = delimited_parser.parse_entirely(parse); - if error_behavior == ParseUntilErrorBehavior::Stop && result.is_err() { - return result; - } - if let Some(block_type) = delimited_parser.at_start_of { - consume_until_end_of_block(block_type, &mut delimited_parser.input.tokenizer); - } + parser.stop_before = delimiters; + let result = parser.parse_entirely(parse); + parser.stop_before = old_stop_before; + if error_behavior == ParseUntilErrorBehavior::Stop && result.is_err() { + return result; + } + if let Some(block_type) = parser.at_start_of.take() { + consume_until_end_of_block(block_type, &mut parser.tokenizer); } // FIXME: have a special-purpose tokenizer method for this that does less work. loop { - if delimiters.contains(Delimiters::from_byte(parser.input.tokenizer.next_byte())) { + if delimiters.contains(Delimiters::from_byte(parser.tokenizer.next_byte())) { break; } - if let Ok(token) = parser.input.tokenizer.next() { + if let Ok(token) = parser.tokenizer.next() { if let Some(block_type) = BlockType::opening(&token) { - consume_until_end_of_block(block_type, &mut parser.input.tokenizer); + consume_until_end_of_block(block_type, &mut parser.tokenizer); } } else { break; @@ -1051,20 +1028,20 @@ where result } -pub fn parse_until_after<'i: 't, 't, F, T, E>( - parser: &mut Parser<'i, 't>, +pub fn parse_until_after<'i, F, T, E>( + parser: &mut Parser<'i>, delimiters: Delimiters, error_behavior: ParseUntilErrorBehavior, parse: F, ) -> Result> where - F: for<'tt> FnOnce(&mut Parser<'i, 'tt>) -> Result>, + F: FnOnce(&mut Parser<'i>) -> Result>, { let result = parse_until_before(parser, delimiters, error_behavior, parse); if error_behavior == ParseUntilErrorBehavior::Stop && result.is_err() { return result; } - let next_byte = parser.input.tokenizer.next_byte(); + let next_byte = parser.tokenizer.next_byte(); if next_byte.is_some() && !parser .stop_before @@ -1072,20 +1049,20 @@ where { debug_assert!(delimiters.contains(Delimiters::from_byte(next_byte))); // We know this byte is ASCII. - parser.input.tokenizer.advance(1); + parser.tokenizer.advance(1); if next_byte == Some(b'{') { - consume_until_end_of_block(BlockType::CurlyBracket, &mut parser.input.tokenizer); + consume_until_end_of_block(BlockType::CurlyBracket, &mut parser.tokenizer); } } result } -pub fn parse_nested_block<'i: 't, 't, F, T, E>( - parser: &mut Parser<'i, 't>, +pub fn parse_nested_block<'i, F, T, E>( + parser: &mut Parser<'i>, parse: F, ) -> Result> where - F: for<'tt> FnOnce(&mut Parser<'i, 'tt>) -> Result>, + F: FnOnce(&mut Parser<'i>) -> Result>, { let block_type = parser.at_start_of.take().expect( "\ @@ -1094,37 +1071,27 @@ where token was just consumed.\ ", ); - if parser.input.current_block_depth >= parser.input.nested_block_limit - && parser.input.nested_block_limit != 0 - { + if parser.current_block_depth >= parser.nested_block_limit && parser.nested_block_limit != 0 { return Err(ParseError::from_basic_kind( BasicParseErrorKind::TooManyNestedBlocks, )); } // Fine to use wrapping addition, overflow can only occur without a limit. - parser.input.current_block_depth = parser.input.current_block_depth.wrapping_add(1); + parser.current_block_depth = parser.current_block_depth.wrapping_add(1); - let closing_delimiter = match block_type { + let old_stop_before = parser.stop_before; + parser.stop_before = match block_type { BlockType::CurlyBracket => ClosingDelimiter::CloseCurlyBracket, BlockType::SquareBracket => ClosingDelimiter::CloseSquareBracket, BlockType::Parenthesis => ClosingDelimiter::CloseParenthesis, }; - let result; - // Introduce a new scope to limit duration of nested_parser’s borrow - { - let mut nested_parser = Parser { - input: parser.input, - at_start_of: None, - stop_before: closing_delimiter, - }; - result = nested_parser.parse_entirely(parse); - if let Some(block_type) = nested_parser.at_start_of { - consume_until_end_of_block(block_type, &mut nested_parser.input.tokenizer); - } + let result = parser.parse_entirely(parse); + if let Some(nested_block_type) = parser.at_start_of.take() { + consume_until_end_of_block(nested_block_type, &mut parser.tokenizer); } - consume_until_end_of_block(block_type, &mut parser.input.tokenizer); - // See above. - parser.input.current_block_depth = parser.input.current_block_depth.wrapping_sub(1); + consume_until_end_of_block(block_type, &mut parser.tokenizer); + parser.stop_before = old_stop_before; + parser.current_block_depth = parser.current_block_depth.wrapping_sub(1); result } diff --git a/src/rules_and_declarations.rs b/src/rules_and_declarations.rs index e28dc1b6..241d6252 100644 --- a/src/rules_and_declarations.rs +++ b/src/rules_and_declarations.rs @@ -49,7 +49,7 @@ pub trait DeclarationParser<'i> { fn parse_value( &mut self, _name: CowRcStr<'i>, - _input: &mut Parser<'i, '_>, + _input: &mut Parser<'i>, _declaration_start: &ParserState, ) -> Result> { Err(ParseError::unexpected_token()) @@ -93,7 +93,7 @@ pub trait AtRuleParser<'i> { fn parse_prelude( &mut self, _name: CowRcStr<'i>, - _input: &mut Parser<'i, '_>, + _input: &mut Parser<'i>, ) -> Result> { Err(ParseError::from_basic_kind( BasicParseErrorKind::AtRuleInvalid, @@ -133,7 +133,7 @@ pub trait AtRuleParser<'i> { &mut self, prelude: Self::Prelude, start: &ParserState, - _input: &mut Parser<'i, '_>, + _input: &mut Parser<'i>, ) -> Result> { let _ = prelude; let _ = start; @@ -174,7 +174,7 @@ pub trait QualifiedRuleParser<'i> { /// that ends where the prelude should end (before the next `{`). fn parse_prelude( &mut self, - _input: &mut Parser<'i, '_>, + _input: &mut Parser<'i>, ) -> Result> { Err(ParseError::from_basic_kind( BasicParseErrorKind::QualifiedRuleInvalid, @@ -192,7 +192,7 @@ pub trait QualifiedRuleParser<'i> { &mut self, prelude: Self::Prelude, start: &ParserState, - _input: &mut Parser<'i, '_>, + _input: &mut Parser<'i>, ) -> Result> { let _ = prelude; let _ = start; @@ -203,9 +203,9 @@ pub trait QualifiedRuleParser<'i> { } /// Provides an iterator for rule bodies and declaration lists. -pub struct RuleBodyParser<'i, 't, 'a, P, I, E> { +pub struct RuleBodyParser<'i, 'a, P, I, E> { /// The input given to the parser. - pub input: &'a mut Parser<'i, 't>, + pub input: &'a mut Parser<'i>, /// The parser given to `RuleBodyParser::new` pub parser: &'a mut P, @@ -226,7 +226,7 @@ pub trait RuleBodyItemParser<'i, DeclOrRule, Error>: fn parse_qualified(&self) -> bool; } -impl<'i, 't, 'a, P, I, E> RuleBodyParser<'i, 't, 'a, P, I, E> { +impl<'i, 'a, P, I, E> RuleBodyParser<'i, 'a, P, I, E> { /// Create a new `RuleBodyParser` for the given `input` and `parser`. /// /// Note that all CSS declaration lists can on principle contain at-rules. @@ -241,7 +241,7 @@ impl<'i, 't, 'a, P, I, E> RuleBodyParser<'i, 't, 'a, P, I, E> { /// The return type for finished declarations and at-rules also needs to be the same, /// since `::next` can return either. /// It could be a custom enum. - pub fn new(input: &'a mut Parser<'i, 't>, parser: &'a mut P) -> Self { + pub fn new(input: &'a mut Parser<'i>, parser: &'a mut P) -> Self { Self { input, parser, @@ -251,7 +251,7 @@ impl<'i, 't, 'a, P, I, E> RuleBodyParser<'i, 't, 'a, P, I, E> { } /// https://drafts.csswg.org/css-syntax/#consume-a-blocks-contents -impl<'i, I, P, E> Iterator for RuleBodyParser<'i, '_, '_, P, I, E> +impl<'i, I, P, E> Iterator for RuleBodyParser<'i, '_, P, I, E> where P: RuleBodyItemParser<'i, I, E>, { @@ -339,9 +339,9 @@ where } /// Provides an iterator for rule list parsing at the top-level of a stylesheet. -pub struct StyleSheetParser<'i, 't, 'a, P> { +pub struct StyleSheetParser<'i, 'a, P> { /// The input given. - pub input: &'a mut Parser<'i, 't>, + pub input: &'a mut Parser<'i>, /// The parser given. pub parser: &'a mut P, @@ -349,7 +349,7 @@ pub struct StyleSheetParser<'i, 't, 'a, P> { any_rule_so_far: bool, } -impl<'i, 't, 'a, R, P, E> StyleSheetParser<'i, 't, 'a, P> +impl<'i, 'a, R, P, E> StyleSheetParser<'i, 'a, P> where P: QualifiedRuleParser<'i, QualifiedRule = R, Error = E> + AtRuleParser<'i, AtRule = R, Error = E>, @@ -360,7 +360,7 @@ where /// /// The return type for finished qualified rules and at-rules also needs to be the same, /// since `::next` can return either. It could be a custom enum. - pub fn new(input: &'a mut Parser<'i, 't>, parser: &'a mut P) -> Self { + pub fn new(input: &'a mut Parser<'i>, parser: &'a mut P) -> Self { Self { input, parser, @@ -370,7 +370,7 @@ where } /// `StyleSheetParser` is an iterator that yields `Ok(_)` for a rule or an `Err(..)` for an invalid one. -impl<'i, R, P, E> Iterator for StyleSheetParser<'i, '_, '_, P> +impl<'i, R, P, E> Iterator for StyleSheetParser<'i, '_, P> where P: QualifiedRuleParser<'i, QualifiedRule = R, Error = E> + AtRuleParser<'i, AtRule = R, Error = E>, @@ -429,7 +429,7 @@ where /// Parse a single declaration, such as an `( /* ... */ )` parenthesis in an `@supports` prelude. pub fn parse_one_declaration<'i, P, E>( - input: &mut Parser<'i, '_>, + input: &mut Parser<'i>, parser: &mut P, ) -> Result<

>::Declaration, (ParseError, &'i str, SourceLocation)> where @@ -448,7 +448,7 @@ where /// Parse a single rule, such as for CSSOM’s `CSSStyleSheet.insertRule`. pub fn parse_one_rule<'i, R, P, E>( - input: &mut Parser<'i, '_>, + input: &mut Parser<'i>, parser: &mut P, ) -> Result> where @@ -481,7 +481,7 @@ where fn parse_at_rule<'i, P, E>( start: &ParserState, name: CowRcStr<'i>, - input: &mut Parser<'i, '_>, + input: &mut Parser<'i>, parser: &mut P, ) -> Result<

>::AtRule, (ParseError, &'i str, SourceLocation)> where @@ -536,7 +536,7 @@ fn looks_like_a_custom_property(input: &mut Parser) -> bool { // https://drafts.csswg.org/css-syntax/#consume-a-qualified-rule fn parse_qualified_rule<'i, P, E>( start: &ParserState, - input: &mut Parser<'i, '_>, + input: &mut Parser<'i>, parser: &mut P, nested: bool, ) -> Result<

>::QualifiedRule, ParseError> diff --git a/src/size_of_tests.rs b/src/size_of_tests.rs index 1a53cc0f..e407578b 100644 --- a/src/size_of_tests.rs +++ b/src/size_of_tests.rs @@ -43,8 +43,7 @@ size_of_test!(std_cow_str, std::borrow::Cow<'static, str>, 24, 32); size_of_test!(cow_rc_str, CowRcStr, 16); size_of_test!(tokenizer, crate::tokenizer::Tokenizer, 96); -size_of_test!(parser_input, crate::parser::ParserInput, 168); -size_of_test!(parser, crate::parser::Parser, 16); +size_of_test!(parser, crate::parser::Parser, 168); size_of_test!(source_position, crate::SourcePosition, 8); size_of_test!(parser_state, crate::ParserState, 24); diff --git a/src/tests.rs b/src/tests.rs index fd5127d9..a80ab651 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -16,9 +16,9 @@ use self::test::Bencher; use super::{ parse_important, parse_nth, parse_one_declaration, parse_one_rule, stylesheet_encoding, AtRuleParser, BasicParseError, BasicParseErrorKind, CowRcStr, DeclarationParser, Delimiter, - EncodingSupport, ParseError, ParseErrorKind, Parser, ParserInput, ParserState, - QualifiedRuleParser, RuleBodyItemParser, RuleBodyParser, SourceLocation, StyleSheetParser, - ToCss, Token, TokenSerializationType, UnicodeRange, + EncodingSupport, ParseError, ParseErrorKind, Parser, ParserState, QualifiedRuleParser, + RuleBodyItemParser, RuleBodyParser, SourceLocation, StyleSheetParser, ToCss, Token, + TokenSerializationType, UnicodeRange, }; macro_rules! JArray { @@ -97,8 +97,7 @@ fn run_raw_json_tests(json_data: &str, run: F) { fn run_json_tests Value>(json_data: &str, parse: F) { run_raw_json_tests(json_data, |input, expected| match input { Value::String(input) => { - let mut parse_input = ParserInput::new(&input); - let result = parse(&mut Parser::new(&mut parse_input)); + let result = parse(&mut Parser::new(&input)); assert_json_eq(result, expected, &input); } _ => panic!("Unexpected JSON"), @@ -228,9 +227,8 @@ fn stylesheet_from_bytes() { environment_encoding, ); let (css_unicode, used_encoding, _) = encoding.decode(&css); - let mut input = ParserInput::new(&css_unicode); - let input = &mut Parser::new(&mut input); - let rules = StyleSheetParser::new(input, &mut JsonParser) + let mut parser = Parser::new(&css_unicode); + let rules = StyleSheetParser::new(&mut parser, &mut JsonParser) .map(|result| result.unwrap_or(JArray!["error", "invalid"])) .collect::>(); JArray![rules, used_encoding.name().to_lowercase()] @@ -251,29 +249,22 @@ fn stylesheet_from_bytes() { #[test] fn expect_no_error_token() { - let mut input = ParserInput::new("foo 4px ( / { !bar }"); - assert!(Parser::new(&mut input).expect_no_error_token().is_ok()); - let mut input = ParserInput::new(")"); - assert!(Parser::new(&mut input).expect_no_error_token().is_err()); - let mut input = ParserInput::new("}"); - assert!(Parser::new(&mut input).expect_no_error_token().is_err()); - let mut input = ParserInput::new("(a){]"); - assert!(Parser::new(&mut input).expect_no_error_token().is_err()); - let mut input = ParserInput::new("'\n'"); - assert!(Parser::new(&mut input).expect_no_error_token().is_err()); - let mut input = ParserInput::new("url('\n'"); - assert!(Parser::new(&mut input).expect_no_error_token().is_err()); - let mut input = ParserInput::new("url(a b)"); - assert!(Parser::new(&mut input).expect_no_error_token().is_err()); - let mut input = ParserInput::new("url(\u{7F}))"); - assert!(Parser::new(&mut input).expect_no_error_token().is_err()); + assert!(Parser::new("foo 4px ( / { !bar }") + .expect_no_error_token() + .is_ok()); + assert!(Parser::new(")").expect_no_error_token().is_err()); + assert!(Parser::new("}").expect_no_error_token().is_err()); + assert!(Parser::new("(a){]").expect_no_error_token().is_err()); + assert!(Parser::new("'\n'").expect_no_error_token().is_err()); + assert!(Parser::new("url('\n'").expect_no_error_token().is_err()); + assert!(Parser::new("url(a b)").expect_no_error_token().is_err()); + assert!(Parser::new("url(\u{7F}))").expect_no_error_token().is_err()); } /// https://github.com/servo/rust-cssparser/issues/71 #[test] fn outer_block_end_consumed() { - let mut input = ParserInput::new("(calc(true))"); - let mut input = Parser::new(&mut input); + let mut input = Parser::new("(calc(true))"); assert!(input.expect_parenthesis_block().is_ok()); assert!(input .parse_nested_block(|input| input @@ -287,8 +278,7 @@ fn outer_block_end_consumed() { /// https://github.com/servo/rust-cssparser/issues/174 #[test] fn bad_url_slice_out_of_bounds() { - let mut input = ParserInput::new("url(\u{1}\\"); - let mut parser = Parser::new(&mut input); + let mut parser = Parser::new("url(\u{1}\\"); let result = parser.next_including_whitespace_and_comments(); // This used to panic assert_eq!(result, Ok(&Token::BadUrl("\u{1}\\".into()))); } @@ -296,8 +286,7 @@ fn bad_url_slice_out_of_bounds() { /// https://bugzilla.mozilla.org/show_bug.cgi?id=1383975 #[test] fn bad_url_slice_not_at_char_boundary() { - let mut input = ParserInput::new("url(9\n۰"); - let mut parser = Parser::new(&mut input); + let mut parser = Parser::new("url(9\n۰"); let result = parser.next_including_whitespace_and_comments(); // This used to panic assert_eq!(result, Ok(&Token::BadUrl("9\n۰".into()))); } @@ -325,31 +314,23 @@ fn unquoted_url_escaping() { )\ " ); - let mut input = ParserInput::new(&serialized); - assert_eq!(Parser::new(&mut input).next(), Ok(&token)); + assert_eq!(Parser::new(&serialized).next(), Ok(&token)); } #[test] fn test_expect_url() { - fn parse<'a>(s: &mut ParserInput<'a>) -> Result, BasicParseError> { + fn parse<'a>(s: &'a str) -> Result, BasicParseError> { Parser::new(s).expect_url() } - let mut input = ParserInput::new("url()"); - assert_eq!(parse(&mut input).unwrap(), ""); - let mut input = ParserInput::new("url( "); - assert_eq!(parse(&mut input).unwrap(), ""); - let mut input = ParserInput::new("url( abc"); - assert_eq!(parse(&mut input).unwrap(), "abc"); - let mut input = ParserInput::new("url( abc \t)"); - assert_eq!(parse(&mut input).unwrap(), "abc"); - let mut input = ParserInput::new("url( 'abc' \t)"); - assert_eq!(parse(&mut input).unwrap(), "abc"); - let mut input = ParserInput::new("url(abc more stuff)"); - assert!(parse(&mut input).is_err()); + assert_eq!(parse("url()").unwrap(), ""); + assert_eq!(parse("url( ").unwrap(), ""); + assert_eq!(parse("url( abc").unwrap(), "abc"); + assert_eq!(parse("url( abc \t)").unwrap(), "abc"); + assert_eq!(parse("url( 'abc' \t)").unwrap(), "abc"); + assert!(parse("url(abc more stuff)").is_err()); // The grammar at https://drafts.csswg.org/css-values/#urls plans for `*` // at the position of "more stuff", but no such modifier is defined yet. - let mut input = ParserInput::new("url('abc' more stuff)"); - assert!(parse(&mut input).is_err()); + assert!(parse("url('abc' more stuff)").is_err()); } #[test] @@ -369,8 +350,7 @@ fn nth() { #[test] fn parse_comma_separated_ignoring_errors() { let input = "red, green something, yellow, whatever, blue"; - let mut input = ParserInput::new(input); - let mut input = Parser::new(&mut input); + let mut input = Parser::new(input); let result = input.parse_comma_separated_ignoring_errors(|input| { let ident = input.expect_ident()?; crate::color::parse_named_color(ident).map_err(|()| ParseError::<()>::unexpected_token()) @@ -465,8 +445,7 @@ fn serializer(preserve_comments: bool) { &mut serialized, preserve_comments, ); - let mut input = ParserInput::new(&serialized); - let parser = &mut Parser::new(&mut input); + let parser = &mut Parser::new(&serialized); Value::Array(component_values_to_json(parser)) }, ); @@ -474,8 +453,7 @@ fn serializer(preserve_comments: bool) { #[test] fn serialize_bad_tokens() { - let mut input = ParserInput::new("url(foo\\) b\\)ar)'ba\\'\"z\n4"); - let mut parser = Parser::new(&mut input); + let mut parser = Parser::new("url(foo\\) b\\)ar)'ba\\'\"z\n4"); let token = parser.next().unwrap().clone(); assert!(matches!(token, Token::BadUrl(_))); @@ -494,7 +472,7 @@ fn serialize_bad_tokens() { #[test] fn line_numbers() { - let mut input = ParserInput::new(concat!( + let mut input = Parser::new(concat!( "fo\\30\r\n", "0o bar/*\n", "*/baz\r\n", @@ -504,7 +482,6 @@ fn line_numbers() { ")\"a\\\r\n", "b\"" )); - let mut input = Parser::new(&mut input); assert_eq!( input.current_source_location(), SourceLocation { line: 0, column: 1 } @@ -612,8 +589,7 @@ fn overflow() { " .replace("{309 zeros}", &"0".repeat(309)); - let mut input = ParserInput::new(&css); - let mut input = Parser::new(&mut input); + let mut input = Parser::new(&css); assert_eq!(input.expect_integer(), Ok(2147483646)); assert_eq!(input.expect_integer(), Ok(2147483647)); @@ -640,8 +616,7 @@ fn overflow() { #[test] fn line_delimited() { - let mut input = ParserInput::new(" { foo ; bar } baz;,"); - let mut input = Parser::new(&mut input); + let mut input = Parser::new(" { foo ; bar } baz;,"); assert_eq!(input.next(), Ok(&Token::CurlyBracketBlock)); assert!({ let result: Result<_, ParseError<()>> = @@ -802,8 +777,7 @@ const ARBITRARY_SUBSTITUTION_FUNCTIONS: ArbitrarySubstitutionFunctions = &["var" #[bench] fn unquoted_url(b: &mut Bencher) { b.iter(|| { - let mut input = ParserInput::new(BACKGROUND_IMAGE); - let mut input = Parser::new(&mut input); + let mut input = Parser::new(BACKGROUND_IMAGE); input.look_for_arbitrary_substitution_functions(ARBITRARY_SUBSTITUTION_FUNCTIONS); let result = input.try_parse(|input| input.expect_url()); @@ -823,8 +797,7 @@ fn unquoted_url(b: &mut Bencher) { fn numeric(b: &mut Bencher) { b.iter(|| { for _ in 0..1000000 { - let mut input = ParserInput::new("10px"); - let mut input = Parser::new(&mut input); + let mut input = Parser::new("10px"); let _ = test::black_box(input.next()); } }) @@ -840,8 +813,7 @@ fn no_stack_overflow_multiple_nested_blocks() { let dup = input.clone(); input.push_str(&dup); } - let mut input = ParserInput::new(&input); - let mut input = Parser::new(&mut input); + let mut input = Parser::new(&input); while input.next().is_ok() {} } @@ -861,19 +833,17 @@ fn nested_block_limit() { // Returns `Err(())` if (and only if) parsing bailed out due to the nesting limit. fn parse(depth: usize, limit: Option) -> Result<(), ()> { let css = format!("{}1{}", "calc(".repeat(depth), ")".repeat(depth)); - let mut input = ParserInput::new(&css); + let mut parser = Parser::new(&css); if let Some(limit) = limit { - input.set_nested_block_limit(limit); + parser.set_nested_block_limit(limit); } - Parser::new(&mut input) - .parse_entirely(parse_calc) - .map_err(|e| match e.kind { - ParseErrorKind::Basic(BasicParseErrorKind::TooManyNestedBlocks) => (), - other => panic!( - "Unexpected error parsing {} nested blocks: {:?}", - depth, other - ), - }) + parser.parse_entirely(parse_calc).map_err(|e| match e.kind { + ParseErrorKind::Basic(BasicParseErrorKind::TooManyNestedBlocks) => (), + other => panic!( + "Unexpected error parsing {} nested blocks: {:?}", + depth, other + ), + }) } // The default limit is 75 nested blocks. @@ -1172,11 +1142,9 @@ fn parse_until_before_stops_at_delimiter_or_end_of_input() { for equivalent in inputs { for (j, x) in equivalent.1.iter().enumerate() { for y in equivalent.1[j + 1..].iter() { - let mut ix = ParserInput::new(x); - let mut ix = Parser::new(&mut ix); + let mut ix = Parser::new(x); - let mut iy = ParserInput::new(y); - let mut iy = Parser::new(&mut iy); + let mut iy = Parser::new(y); let _ = ix.parse_until_before::<_, _, ()>(equivalent.0, |ix| { iy.parse_until_before::<_, _, ()>(equivalent.0, |iy| { @@ -1198,8 +1166,7 @@ fn parse_until_before_stops_at_delimiter_or_end_of_input() { #[test] fn parser_maintains_current_line() { - let mut input = ParserInput::new("ident ident;\nident ident ident;\nident"); - let mut parser = Parser::new(&mut input); + let mut parser = Parser::new("ident ident;\nident ident ident;\nident"); assert_eq!(parser.current_line(), "ident ident;"); assert_eq!(parser.next(), Ok(&Token::Ident("ident".into()))); assert_eq!(parser.next(), Ok(&Token::Ident("ident".into()))); @@ -1217,8 +1184,7 @@ fn parser_maintains_current_line() { #[test] fn cdc_regression_test() { - let mut input = ParserInput::new("-->x"); - let mut parser = Parser::new(&mut input); + let mut parser = Parser::new("-->x"); parser.skip_cdc_and_cdo(); assert_eq!(parser.next(), Ok(&Token::Ident("x".into()))); assert_eq!( @@ -1235,8 +1201,7 @@ fn parse_entirely_reports_first_error() { enum E { Foo, } - let mut input = ParserInput::new("ident"); - let mut parser = Parser::new(&mut input); + let mut parser = Parser::new("ident"); let result: Result<(), _> = parser.parse_entirely(|_| Err(ParseError::custom(E::Foo))); assert_eq!( result, @@ -1266,8 +1231,7 @@ fn parse_sourcemapping_comments() { ]; for test in tests { - let mut input = ParserInput::new(test.0); - let mut parser = Parser::new(&mut input); + let mut parser = Parser::new(test.0); while parser.next_including_whitespace().is_ok() {} assert_eq!(parser.current_source_map_url(), test.1); } @@ -1290,8 +1254,7 @@ fn parse_sourceurl_comments() { ]; for test in tests { - let mut input = ParserInput::new(test.0); - let mut parser = Parser::new(&mut input); + let mut parser = Parser::new(test.0); while parser.next_including_whitespace().is_ok() {} assert_eq!(parser.current_source_url(), test.1); } @@ -1301,8 +1264,7 @@ fn parse_sourceurl_comments() { #[test] fn roundtrip_percentage_token() { fn test_roundtrip(value: &str) { - let mut input = ParserInput::new(value); - let mut parser = Parser::new(&mut input); + let mut parser = Parser::new(value); let token = parser.next().unwrap(); assert_eq!(token.to_css_string(), value); } @@ -1353,8 +1315,7 @@ fn utf16_columns() { ]; for test in tests { - let mut input = ParserInput::new(test.0); - let mut parser = Parser::new(&mut input); + let mut parser = Parser::new(test.0); // Read all tokens. loop {