Skip to content

Commit ff98fbe

Browse files
authored
parser: Make list of arbitrary substitution functions configurable. (#416)
This prevents needing cssparser changes every time we add one, and makes them configurable at runtime.
1 parent 1de9d4a commit ff98fbe

File tree

4 files changed

+47
-28
lines changed

4 files changed

+47
-28
lines changed

src/parser.rs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,10 @@ macro_rules! expect {
380380
}
381381
}
382382

383+
/// A list of arbitrary substitution functions. Should be lowercase ascii.
384+
/// See https://drafts.csswg.org/css-values-5/#arbitrary-substitution
385+
pub type ArbitrarySubstitutionFunctions<'a> = &'a [&'static str];
386+
383387
impl<'i: 't, 't> Parser<'i, 't> {
384388
/// Create a new parser
385389
#[inline]
@@ -546,19 +550,23 @@ impl<'i: 't, 't> Parser<'i, 't> {
546550
self.at_start_of = state.at_start_of;
547551
}
548552

549-
/// Start looking for `var()` / `env()` functions. (See the
550-
/// `.seen_var_or_env_functions()` method.)
553+
/// Start looking for arbitrary substitution functions like `var()` / `env()` functions.
554+
/// (See the `.seen_arbitrary_substitution_functions()` method.)
551555
#[inline]
552-
pub fn look_for_var_or_env_functions(&mut self) {
553-
self.input.tokenizer.look_for_var_or_env_functions()
556+
pub fn look_for_arbitrary_substitution_functions(
557+
&mut self,
558+
fns: ArbitrarySubstitutionFunctions<'i>,
559+
) {
560+
self.input
561+
.tokenizer
562+
.look_for_arbitrary_substitution_functions(fns)
554563
}
555564

556-
/// Return whether a `var()` or `env()` function has been seen by the
557-
/// tokenizer since either `look_for_var_or_env_functions` was called, and
558-
/// stop looking.
565+
/// Return whether a relevant function has been seen by the tokenizer since
566+
/// `look_for_arbitrary_substitution_functions` was called, and stop looking.
559567
#[inline]
560-
pub fn seen_var_or_env_functions(&mut self) -> bool {
561-
self.input.tokenizer.seen_var_or_env_functions()
568+
pub fn seen_arbitrary_substitution_functions(&mut self) -> bool {
569+
self.input.tokenizer.seen_arbitrary_substitution_functions()
562570
}
563571

564572
/// The old name of `try_parse`, which requires raw identifiers in the Rust 2018 edition.

src/size_of_tests.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ size_of_test!(token, Token, 32);
4242
size_of_test!(std_cow_str, std::borrow::Cow<'static, str>, 24, 32);
4343
size_of_test!(cow_rc_str, CowRcStr, 16);
4444

45-
size_of_test!(tokenizer, crate::tokenizer::Tokenizer, 72);
46-
size_of_test!(parser_input, crate::parser::ParserInput, 136);
45+
size_of_test!(tokenizer, crate::tokenizer::Tokenizer, 96);
46+
size_of_test!(parser_input, crate::parser::ParserInput, 160);
4747
size_of_test!(parser, crate::parser::Parser, 16);
4848
size_of_test!(source_position, crate::SourcePosition, 8);
4949
size_of_test!(parser_state, crate::ParserState, 24);

src/tests.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ extern crate test;
77

88
use serde_json::{json, Map, Value};
99

10+
#[cfg(feature = "bench")]
11+
use crate::parser::ArbitrarySubstitutionFunctions;
12+
1013
#[cfg(feature = "bench")]
1114
use self::test::Bencher;
1215

@@ -795,20 +798,25 @@ fn delimiter_from_byte(b: &mut Bencher) {
795798
#[cfg(feature = "bench")]
796799
const BACKGROUND_IMAGE: &str = include_str!("big-data-url.css");
797800

801+
#[cfg(feature = "bench")]
802+
const ARBITRARY_SUBSTITUTION_FUNCTIONS: ArbitrarySubstitutionFunctions = &["var", "env"];
803+
798804
#[cfg(feature = "bench")]
799805
#[bench]
800806
fn unquoted_url(b: &mut Bencher) {
801807
b.iter(|| {
802808
let mut input = ParserInput::new(BACKGROUND_IMAGE);
803809
let mut input = Parser::new(&mut input);
804-
input.look_for_var_or_env_functions();
810+
input.look_for_arbitrary_substitution_functions(ARBITRARY_SUBSTITUTION_FUNCTIONS);
805811

806812
let result = input.try_parse(|input| input.expect_url());
807813

808814
assert!(result.is_ok());
809815

810-
input.seen_var_or_env_functions();
811-
(result.is_ok(), input.seen_var_or_env_functions())
816+
(
817+
result.is_ok(),
818+
input.seen_arbitrary_substitution_functions(),
819+
)
812820
})
813821
}
814822

src/tokenizer.rs

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
use self::Token::*;
88
use crate::cow_rc_str::CowRcStr;
9-
use crate::parser::ParserState;
9+
use crate::parser::{ArbitrarySubstitutionFunctions, ParserState};
1010
use std::char;
1111
use std::ops::Range;
1212

@@ -215,15 +215,15 @@ pub struct Tokenizer<'a> {
215215
/// of UTF-16 characters.
216216
current_line_start_position: usize,
217217
current_line_number: u32,
218-
var_or_env_functions: SeenStatus,
218+
arbitrary_substitution_functions: SeenStatus<'a>,
219219
source_map_url: Option<&'a str>,
220220
source_url: Option<&'a str>,
221221
}
222222

223223
#[derive(Copy, Clone, PartialEq, Eq)]
224-
enum SeenStatus {
224+
enum SeenStatus<'a> {
225225
DontCare,
226-
LookingForThem,
226+
LookingForThem(ArbitrarySubstitutionFunctions<'a>),
227227
SeenAtLeastOne,
228228
}
229229

@@ -235,30 +235,33 @@ impl<'a> Tokenizer<'a> {
235235
position: 0,
236236
current_line_start_position: 0,
237237
current_line_number: 0,
238-
var_or_env_functions: SeenStatus::DontCare,
238+
arbitrary_substitution_functions: SeenStatus::DontCare,
239239
source_map_url: None,
240240
source_url: None,
241241
}
242242
}
243243

244244
#[inline]
245-
pub fn look_for_var_or_env_functions(&mut self) {
246-
self.var_or_env_functions = SeenStatus::LookingForThem;
245+
pub fn look_for_arbitrary_substitution_functions(
246+
&mut self,
247+
fns: ArbitrarySubstitutionFunctions<'a>,
248+
) {
249+
self.arbitrary_substitution_functions = SeenStatus::LookingForThem(fns);
247250
}
248251

249252
#[inline]
250-
pub fn seen_var_or_env_functions(&mut self) -> bool {
251-
let seen = self.var_or_env_functions == SeenStatus::SeenAtLeastOne;
252-
self.var_or_env_functions = SeenStatus::DontCare;
253+
pub fn seen_arbitrary_substitution_functions(&mut self) -> bool {
254+
let seen = self.arbitrary_substitution_functions == SeenStatus::SeenAtLeastOne;
255+
self.arbitrary_substitution_functions = SeenStatus::DontCare;
253256
seen
254257
}
255258

256259
#[inline]
257260
pub fn see_function(&mut self, name: &str) {
258-
if self.var_or_env_functions == SeenStatus::LookingForThem
259-
&& (name.eq_ignore_ascii_case("var") || name.eq_ignore_ascii_case("env"))
260-
{
261-
self.var_or_env_functions = SeenStatus::SeenAtLeastOne;
261+
if let SeenStatus::LookingForThem(fns) = self.arbitrary_substitution_functions {
262+
if fns.iter().any(|a| name.eq_ignore_ascii_case(a)) {
263+
self.arbitrary_substitution_functions = SeenStatus::SeenAtLeastOne;
264+
}
262265
}
263266
}
264267

0 commit comments

Comments
 (0)